SeaQL / sea-orm

🐚 An async & dynamic ORM for Rust
https://www.sea-ql.org/SeaORM/
Apache License 2.0
6.56k stars 459 forks source link

serde rename_all not working correctly on ActiveModel #2257

Open thatoneprogrammer111 opened 2 weeks ago

thatoneprogrammer111 commented 2 weeks ago

Description

#[serde(rename_all = "camelCase")] on a Model derived with DeriveEntityModel is not working correctly on the ActiveModel

Steps to Reproduce

use sea_orm::prelude::*;
use serde_json::json;
use sqlx::types::chrono::Utc;

fn default_dt() -> DateTimeUtc {
    Utc::now()
}

#[derive(Debug, Clone, DeriveEntityModel, serde::Deserialize, serde::Serialize)]
#[sea_orm(table_name = "user")]
#[serde(rename_all = "camelCase")]
pub struct Model {
    #[sea_orm(primary_key)]
    #[serde(skip_deserializing)]
    pub id: i32,
    pub first_name: String,
    pub last_name: String,
    pub password: String,
    #[sea_orm(unique)]
    pub email: String,
    pub is_admin: bool,

    #[serde(default = "default_dt")]
    pub creation_date: DateTimeUtc,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for self::ActiveModel {}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut user = <ActiveModel as sea_orm::ActiveModelTrait>::default();
    user.set_from_json(json!(
        {
            "firstName": "Max",
            "lastName": "Hermit",
            "password": "SUPER_S3CURE!",
            "email": "max.Hermit@domain.com",
            "isAdmin": true,
        }
    ))?;

    println!("{user:#?}");

    Ok(())
}

Expected Behavior

Getting an ActiveModel that looks like

ActiveModel {
    id: NotSet,
    first_name: Set("Max"),
    last_name: Set("Hermit"),
    password: Set(
        "SUPER_S3CURE!",        
    ),
    email: Set(
        "max.Hermit@domain.com",
    ),
    is_admin: Set(true),
    creation_date: Set(...),      
}

Actual Behavior

A model with fields affected by rename_all unset:

ActiveModel {
    id: NotSet,
    first_name: NotSet,
    last_name: NotSet,
    password: Set(
        "SUPER_S3CURE!",        
    ),
    email: Set(
        "max.Hermit@domain.com",
    ),
    is_admin: NotSet,
    creation_date: NotSet,      
}

Reproduces How Often

always

Workarounds

If this is intended, Model::deserialize, then converting to a ActiveModel works:

let user: ActiveModel = Model::deserialize(json!(
        {
            "firstName": "Max",
            "lastName": "Mem",
            "password": "SUPER_S3CURE!",
            "email": "max.mem@domain.com",
            "isAdmin": true,
        }
    ))?
    .try_into()?;

Reproducible Example

See steps to reproduce

Versions

Windows 10, SeaORM 0.12.15

thangthan commented 3 days ago

Not only with rename_all, I also had trouble with single rename for individual field

thatoneprogrammer111 commented 3 days ago

Not only with rename_all, I also had trouble with single rename for individual field

Seems to be fixed for the 1.0.0-rc.6 version, the only slight inconvenience is that the fields in the DB will be camelCase. I am willing to take this tradeoff however.