* Cli serde skip deserialize for primary key option (#1186) * Add CLI option to skip primary keys with serde Implements: https://github.com/SeaQL/sea-orm/issues/841 * Codegen: fix tests * complete skip_deserialize cli feature * run fmt * fix tests Co-authored-by: witcher <witcher@wiredspace.de> * [cli] should be `#[serde(skip_deserializing)]` * [CLI] code refactor * [cli] rename Co-authored-by: Isaiah Gamble <77396670+tsar-boomba@users.noreply.github.com> Co-authored-by: witcher <witcher@wiredspace.de>
This commit is contained in:
parent
1f27837f49
commit
3f00725ee2
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
@ -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);
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
@ -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,
|
||||
@ -111,6 +113,7 @@ impl EntityWriterContext {
|
||||
date_time_crate,
|
||||
schema_name,
|
||||
lib,
|
||||
serde_skip_deserializing_primary_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
@ -153,6 +161,7 @@ impl EntityWriter {
|
||||
&context.with_serde,
|
||||
&context.date_time_crate,
|
||||
&context.schema_name,
|
||||
serde_skip_deserializing_primary_key,
|
||||
)
|
||||
} else {
|
||||
Self::gen_compact_code_blocks(
|
||||
@ -160,6 +169,7 @@ impl EntityWriter {
|
||||
&context.with_serde,
|
||||
&context.date_time_crate,
|
||||
&context.schema_name,
|
||||
serde_skip_deserializing_primary_key,
|
||||
)
|
||||
};
|
||||
Self::write(&mut lines, code_blocks);
|
||||
@ -259,6 +269,7 @@ 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));
|
||||
@ -266,7 +277,12 @@ impl EntityWriter {
|
||||
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),
|
||||
@ -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));
|
||||
@ -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,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
@ -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 });
|
||||
@ -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) {
|
||||
@ -1260,7 +1296,8 @@ mod tests {
|
||||
entity,
|
||||
&crate::WithSerde::None,
|
||||
&crate::DateTimeCrate::Chrono,
|
||||
&None
|
||||
&None,
|
||||
false,
|
||||
)
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
@ -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)
|
||||
@ -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)
|
||||
@ -1344,7 +1383,8 @@ mod tests {
|
||||
entity,
|
||||
&crate::WithSerde::None,
|
||||
&crate::DateTimeCrate::Chrono,
|
||||
&None
|
||||
&None,
|
||||
false,
|
||||
)
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
@ -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)
|
||||
@ -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)
|
||||
@ -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())?;
|
||||
|
||||
@ -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| {
|
||||
|
@ -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> ,
|
||||
|
@ -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> ,
|
||||
|
@ -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> ,
|
||||
}
|
||||
|
@ -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> ,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user