Skip to content

Commit

Permalink
Cli serde skip deserialize for primary key option (#1186) (#1318)
Browse files Browse the repository at this point in the history
* Cli serde skip deserialize for primary key option (#1186)

* Add CLI option to skip primary keys with serde

Implements: #841

* Codegen: fix tests

* complete skip_deserialize cli feature

* run fmt

* fix tests

Co-authored-by: witcher <[email protected]>

* [cli] should be `#[serde(skip_deserializing)]`

* [CLI] code refactor

* [cli] rename

Co-authored-by: Isaiah Gamble <[email protected]>
Co-authored-by: witcher <[email protected]>
  • Loading branch information
3 people authored Dec 19, 2022
1 parent 1f27837 commit 3f00725
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 17 deletions.
7 changes: 7 additions & 0 deletions sea-orm-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ pub enum GenerateSubcommands {
help = "Generate index file as `lib.rs` instead of `mod.rs`."
)]
lib: bool,

#[clap(
action,
long,
help = "Generate a serde field attribute, '#[serde(skip_deserializing)]', for the primary key fields to skip them during deserialization, this flag will be affective only when '--with-serde' is 'both' or 'deserialize'"
)]
serde_skip_deserializing_primary_key: bool,
},
}

Expand Down
2 changes: 2 additions & 0 deletions sea-orm-cli/src/commands/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub async fn run_generate_command(
with_copy_enums,
date_time_crate,
lib,
serde_skip_deserializing_primary_key,
} => {
if verbose {
let _ = tracing_subscriber::fmt()
Expand Down Expand Up @@ -164,6 +165,7 @@ pub async fn run_generate_command(
date_time_crate.into(),
schema_name,
lib,
serde_skip_deserializing_primary_key,
);
let output = EntityTransformer::transform(table_stmts)?.generate(&writer_context);

Expand Down
16 changes: 16 additions & 0 deletions sea-orm-codegen/src/entity/base_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,22 @@ impl Entity {
// if exist, return nothing
.map_or(quote! {, Eq}, |_| quote! {})
}

pub fn get_serde_skip_deserializing(
&self,
serde_skip_deserializing_primary_key: bool,
) -> Vec<TokenStream> {
self.columns
.iter()
.map(|col| {
let is_primary_key = self.primary_keys.iter().any(|pk| pk.name == col.name);
col.get_serde_skip_deserializing(
is_primary_key,
serde_skip_deserializing_primary_key,
)
})
.collect()
}
}

#[cfg(test)]
Expand Down
12 changes: 12 additions & 0 deletions sea-orm-codegen/src/entity/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,18 @@ impl Column {
}
info
}

pub fn get_serde_skip_deserializing(
&self,
is_primary_key: bool,
serde_skip_deserializing_primary_key: bool,
) -> TokenStream {
if serde_skip_deserializing_primary_key && is_primary_key {
quote! { #[serde(skip_deserializing)] }
} else {
quote! {}
}
}
}

impl From<ColumnDef> for Column {
Expand Down
80 changes: 63 additions & 17 deletions sea-orm-codegen/src/entity/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct EntityWriterContext {
pub(crate) date_time_crate: DateTimeCrate,
pub(crate) schema_name: Option<String>,
pub(crate) lib: bool,
pub(crate) serde_skip_deserializing_primary_key: bool,
}

impl WithSerde {
Expand Down Expand Up @@ -103,6 +104,7 @@ impl EntityWriterContext {
date_time_crate: DateTimeCrate,
schema_name: Option<String>,
lib: bool,
serde_skip_deserializing_primary_key: bool,
) -> Self {
Self {
expanded_format,
Expand All @@ -111,6 +113,7 @@ impl EntityWriterContext {
date_time_crate,
schema_name,
lib,
serde_skip_deserializing_primary_key,
}
}
}
Expand Down Expand Up @@ -139,6 +142,11 @@ impl EntityWriter {
.iter()
.map(|column| column.get_info(&context.date_time_crate))
.collect::<Vec<String>>();
// use must have serde enabled to use this
let serde_skip_deserializing_primary_key = context
.serde_skip_deserializing_primary_key
&& (context.with_serde == WithSerde::Both
|| context.with_serde == WithSerde::Deserialize);

info!("Generating {}", entity_file);
for info in column_info.iter() {
Expand All @@ -153,13 +161,15 @@ impl EntityWriter {
&context.with_serde,
&context.date_time_crate,
&context.schema_name,
serde_skip_deserializing_primary_key,
)
} else {
Self::gen_compact_code_blocks(
entity,
&context.with_serde,
&context.date_time_crate,
&context.schema_name,
serde_skip_deserializing_primary_key,
)
};
Self::write(&mut lines, code_blocks);
Expand Down Expand Up @@ -259,14 +269,20 @@ impl EntityWriter {
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
) -> Vec<TokenStream> {
let mut imports = Self::gen_import(with_serde);
imports.extend(Self::gen_import_active_enum(entity));
let mut code_blocks = vec![
imports,
Self::gen_entity_struct(),
Self::gen_impl_entity_name(entity, schema_name),
Self::gen_model_struct(entity, with_serde, date_time_crate),
Self::gen_model_struct(
entity,
with_serde,
date_time_crate,
serde_skip_deserializing_primary_key,
),
Self::gen_column_enum(entity),
Self::gen_primary_key_enum(entity),
Self::gen_impl_primary_key(entity, date_time_crate),
Expand All @@ -285,12 +301,19 @@ impl EntityWriter {
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
) -> Vec<TokenStream> {
let mut imports = Self::gen_import(with_serde);
imports.extend(Self::gen_import_active_enum(entity));
let mut code_blocks = vec![
imports,
Self::gen_compact_model_struct(entity, with_serde, date_time_crate, schema_name),
Self::gen_compact_model_struct(
entity,
with_serde,
date_time_crate,
schema_name,
serde_skip_deserializing_primary_key,
),
Self::gen_compact_relation_enum(entity),
];
code_blocks.extend(Self::gen_impl_related(entity));
Expand Down Expand Up @@ -378,16 +401,22 @@ impl EntityWriter {
entity: &Entity,
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
serde_skip_deserializing_primary_key: bool,
) -> TokenStream {
let column_names_snake_case = entity.get_column_names_snake_case();
let column_rs_types = entity.get_column_rs_types(date_time_crate);
let if_eq_needed = entity.get_eq_needed();
let serde_skip_deserializing =
entity.get_serde_skip_deserializing(serde_skip_deserializing_primary_key);
let extra_derive = with_serde.extra_derive();

quote! {
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel #if_eq_needed #extra_derive)]
pub struct Model {
#(pub #column_names_snake_case: #column_rs_types,)*
#(
#serde_skip_deserializing
pub #column_names_snake_case: #column_rs_types,
)*
}
}
}
Expand Down Expand Up @@ -566,6 +595,7 @@ impl EntityWriter {
with_serde: &WithSerde,
date_time_crate: &DateTimeCrate,
schema_name: &Option<String>,
serde_skip_deserializing_primary_key: bool,
) -> TokenStream {
let table_name = entity.table_name.as_str();
let column_names_snake_case = entity.get_column_names_snake_case();
Expand All @@ -581,11 +611,12 @@ impl EntityWriter {
.iter()
.map(|col| {
let mut attrs: Punctuated<_, Comma> = Punctuated::new();
let is_primary_key = primary_keys.contains(&col.name);
if !col.is_snake_case_name() {
let column_name = &col.name;
attrs.push(quote! { column_name = #column_name });
}
if primary_keys.contains(&col.name) {
if is_primary_key {
attrs.push(quote! { primary_key });
if !col.auto_increment {
attrs.push(quote! { auto_increment = false });
Expand All @@ -600,20 +631,25 @@ impl EntityWriter {
if col.unique {
attrs.push(quote! { unique });
}
let mut ts = quote! {};
if !attrs.is_empty() {
let mut ts = TokenStream::new();
for (i, attr) in attrs.into_iter().enumerate() {
if i > 0 {
ts = quote! { #ts, };
}
ts = quote! { #ts #attr };
}
quote! {
#[sea_orm(#ts)]
}
} else {
TokenStream::new()
ts = quote! { #[sea_orm(#ts)] };
}
let serde_skip_deserializing = col.get_serde_skip_deserializing(
is_primary_key,
serde_skip_deserializing_primary_key,
);
ts = quote! {
#ts
#serde_skip_deserializing
};
ts
})
.collect();
let schema_name = match Self::gen_schema_name(schema_name) {
Expand Down Expand Up @@ -1260,7 +1296,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&None
&None,
false,
)
.into_iter()
.skip(1)
Expand All @@ -1276,7 +1313,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("public".to_owned())
&Some("public".to_owned()),
false,
)
.into_iter()
.skip(1)
Expand All @@ -1292,7 +1330,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("schema_name".to_owned())
&Some("schema_name".to_owned()),
false,
)
.into_iter()
.skip(1)
Expand Down Expand Up @@ -1344,7 +1383,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&None
&None,
false,
)
.into_iter()
.skip(1)
Expand All @@ -1360,7 +1400,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("public".to_owned())
&Some("public".to_owned()),
false,
)
.into_iter()
.skip(1)
Expand All @@ -1376,7 +1417,8 @@ mod tests {
entity,
&crate::WithSerde::None,
&crate::DateTimeCrate::Chrono,
&Some("schema_name".to_owned())
&Some("schema_name".to_owned()),
false,
)
.into_iter()
.skip(1)
Expand Down Expand Up @@ -1481,11 +1523,13 @@ mod tests {
cake_entity: &Entity,
entity_serde_variant: &(String, WithSerde, Option<String>),
generator: Box<
dyn Fn(&Entity, &WithSerde, &DateTimeCrate, &Option<String>) -> Vec<TokenStream>,
dyn Fn(&Entity, &WithSerde, &DateTimeCrate, &Option<String>, bool) -> Vec<TokenStream>,
>,
) -> io::Result<()> {
let mut reader = BufReader::new(entity_serde_variant.0.as_bytes());
let mut lines: Vec<String> = Vec::new();
let serde_skip_deserializing_primary_key = entity_serde_variant.1 == WithSerde::Both
|| entity_serde_variant.1 == WithSerde::Deserialize;

reader.read_until(b'\n', &mut Vec::new())?;

Expand All @@ -1496,11 +1540,13 @@ mod tests {
}
let content = lines.join("");
let expected: TokenStream = content.parse().unwrap();
println!("{:?}", entity_serde_variant.1);
let generated = generator(
cake_entity,
&entity_serde_variant.1,
&DateTimeCrate::Chrono,
&entity_serde_variant.2,
serde_skip_deserializing_primary_key,
)
.into_iter()
.fold(TokenStream::new(), |mut acc, tok| {
Expand Down
1 change: 1 addition & 0 deletions sea-orm-codegen/tests/compact_with_serde/cake_both.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::Deserialize;
#[sea_orm(table_name = "cake")]
pub struct Model {
#[sea_orm(primary_key)]
#[serde(skip_deserializing)]
pub id: i32,
#[sea_orm(column_type = "Text", nullable)]
pub name: Option<String> ,
Expand Down
1 change: 1 addition & 0 deletions sea-orm-codegen/tests/expanded_with_serde/cake_both.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ impl EntityName for Entity {

#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Serialize, Deserialize)]
pub struct Model {
#[serde(skip_deserializing)]
pub id: i32,
pub name: Option<String> ,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ impl EntityName for Entity {

#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Eq, Deserialize)]
pub struct Model {
#[serde(skip_deserializing)]
pub id: i32,
pub name: Option<String> ,
}
Expand Down

0 comments on commit 3f00725

Please sign in to comment.