Brendonovich / prisma-client-rust

Type-safe database access for Rust
https://prisma.brendonovich.dev
Apache License 2.0
1.75k stars 106 forks source link

Implement `Serialize` for `QueryError` #305

Closed MachariaK closed 1 year ago

MachariaK commented 1 year ago

Note: I am relatively new to rust and I am not sure whether this is a bug or I need to level up my skills. Please bear with me.

I am using Tauri with SQLite to create a desktop application which handles large user information. I am storing user information using the following code:

use prisma_client_rust::QueryError;

pub type BatchingResult = Result<(), QueryError>;

#[tauri::command]
pub async fn upload_users_in_bulk( window: Window, company_id: i32, users_data: Vec<user>,) -> BatchingResult {
    let client = prisma::new_client().await.unwrap();
    let new_user_batch = create_user_batch(
        "Multiple".to_string(),
        users_data.clone().len().try_into().unwrap(),
        company_id,
    )
    .await;

    let batch_size = 999;
    let step = cmp::min(batch_size, users_data.len());
    let new_user_batch_id = new_user_batch.id.clone();
    for i in (0..users_data.len()).step_by(step) {
        let first = i;
        let mut last = i + batch_size;
        if last > users_data.len() {
            last = users_data.len();
        }
        let batch = &users_data[first..last];
        let user_creates = batch.into_iter().map(|user_data| {
            client.user().create(
                user_data.surname.to_string(),
                user_data.first_name.to_string(),
                user_data.gender.to_string(),
                user_data.date_of_birth.into(),
                user_batch::UniqueWhereParam::IdEquals(new_user_batch_id.clone()),
                vec![
                    user::title::set(Some(user_data.clone().title.unwrap_or_default())),
                    user::title::set(Some(user_data.clone().other_names.unwrap_or_default())),
                ],
            )
        });

        let new_users: Vec<user::Data> = client._batch(user_creates).await?;
        assert_eq!(new_users.len(), last - first);
    }
    Ok(())
}

This fails with the following error output:

the method async_kind exists for reference &impl Future<Output = Result<(), QueryError>>, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
impl Future<Output = Result<(), QueryError>>: user::_::_serde::Serialize
which is required by &impl Future<Output = Result<(), QueryError>>: tauri::command::private::SerializeKind
<&impl Future<Output = Result<(), QueryError>> as Future>::Output = Result<_, _>
which is required by &impl Future<Output = Result<(), QueryError>>: tauri::command::private::ResultFutureKind
&impl Future<Output = Result<(), QueryError>>: Future
which is required by &impl Future<Output = Result<(), QueryError>>: tauri::command::private::ResultFutureKind rustc ([object Object])
Brendonovich commented 1 year ago

I think Tauri commands require both the Ok and Err variants of a result to implement Serialize, and QueryError doesn't implement Serialize, hence why the Future doesn't either. I'm not sure if I should implement it.

MachariaK commented 1 year ago

Is there a way I can save about 5,000 rows faster? Saving one by one is taking too long.

Brendonovich commented 1 year ago

There's create_many, but I assume you're using SQLite so you'll need to enable the sqlite-create-many feature on the lib and CLI Also I'd suggest avoiding using UniqueWhereParam and using user_batch::id::equals. As for your Serialize problem, for now you could .map_err(|_| ()) after each query's await and use () as the error type.

MachariaK commented 1 year ago

Thanks a lot.

Brendonovich commented 1 year ago

Would you mind making a reproduction repo? This seems a bit specific to your use case.

talksik commented 1 year ago

Installing serde in the repo that uses the actual artifacts fixed a similar problem for me if it helps anyone