Skip to content

FromQueryResult fails for PartialModel when having nested Option<Model> where the nested Model has optional fields #2939

@ryanduan-stedi

Description

@ryanduan-stedi

Description

FromQueryResult fails for PartialModel when having nested Option where the nested Model has optional fields

Steps to Reproduce

#[derive(DerivePartialModel, Debug, Clone)]
#[sea_orm(entity = "crate::definition::user::User)"]
pub struct User {
    id: Uuid,
    #[sea_orm(nested)]
    post: Option<Post>,
}

// Post Model
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Serialize, Deserialize)]
pub struct Model {
    pub id: Uuid,
    pub foo: Option<String>,
}

If you try to do a left join and there are no matching user posts, and then call .into_partial_model it throws an error Missing value for column id

Expected Behavior

The query should be successful

Actual Behavior

Throws error Missing value for column id

Reproduces How Often

Always, I believe the bug is in this PR #2845
The below code always wraps the field in Option<> so you will end up with Option<Option<String>> for the Post model

let reader = quote! {
                    let #field_ident =
                        row.try_get_nullable::<Option<#field_type>>(
                            pre,
                            sea_orm::IdenStatic::as_str(
                                &<<Self as sea_orm::ModelTrait>::Entity
                                    as sea_orm::entity::EntityTrait>::Column::#column_ident
                            ).into()
                        )?;

and then when checking if the entire nested model is None, this below check is faulty because calling .is_none() on an Option<Option> value returns false when the value is
Some(None)

let all_null_check = {
            let checks: Vec<_> = izip!(field_idents, ignore_attrs)
                .filter_map(|(field_ident, &ignore)| {
                    if ignore {
                        None
                    } else {
                        Some(quote! { #field_ident.is_none() })
                    }
                })
                .collect();

            quote! { true #( && #checks )* }
        };

Workarounds

If I implement FromQueryResult myself and change the all_null_check function to properly evaluate Option<Option>, then the partial model query works properly

if true
&& id.is_none()
&& (foo.is_none() || (foo == Some(None)))
{
return Err(sea_orm::TryGetError::Null(
"All fields of nested model are null".into(),
));
}

Versions

  • sea-orm v2.0.0-rc.30
  • postgres 15.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions