Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions sea-orm-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ pub enum GenerateSubcommands {
)]
serde_skip_hidden_column: bool,

#[arg(
long,
default_value = "false",
help = "Include generated columns in entity files. These fields must remain unset when inserting or updating rows"
)]
include_generated_columns: bool,

#[arg(
long,
default_value = "false",
Expand Down
61 changes: 56 additions & 5 deletions sea-orm-cli/src/commands/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ fn sqlite_column_is_generated(col: &sea_schema::sqlite::def::ColumnInfo) -> bool
)
}

#[cfg(feature = "sqlx-postgres")]
fn remove_postgres_partial_unique_constraints(table: &mut sea_schema::postgres::def::TableDef) {
table
.unique_constraints
.retain(|constraint| !constraint.is_partial);
}

pub async fn run_generate_command(
command: GenerateSubcommands,
verbose: bool,
Expand All @@ -113,6 +120,7 @@ pub async fn run_generate_command(
with_serde,
serde_skip_deserializing_primary_key,
serde_skip_hidden_column,
include_generated_columns,
with_copy_enums,
date_time_crate,
big_integer_type,
Expand Down Expand Up @@ -230,7 +238,9 @@ pub async fn run_generate_command(
.filter(|schema| filter_skip_tables(&schema.info.name))
.map(|mut schema| {
// Skip generated columns (see #3094).
schema.columns.retain(|col| !col.extra.generated);
if !include_generated_columns {
schema.columns.retain(|col| !col.extra.generated);
}
schema.write()
})
.collect();
Expand Down Expand Up @@ -271,9 +281,11 @@ pub async fn run_generate_command(
// Skip generated columns: codegen can't round-trip them, and
// emitting them as ordinary fields makes INSERT/UPDATE fail
// ("cannot INSERT/UPDATE a generated column"). See #3094.
schema
.columns
.retain(|col| !sqlite_column_is_generated(col));
if !include_generated_columns {
schema
.columns
.retain(|col| !sqlite_column_is_generated(col));
}
schema.write()
})
.collect();
Expand Down Expand Up @@ -310,7 +322,10 @@ pub async fn run_generate_command(
.filter(|schema| filter_skip_tables(&schema.info.name))
.map(|mut schema| {
// Skip generated columns (see #3094).
schema.columns.retain(|col| col.generated.is_none());
if !include_generated_columns {
schema.columns.retain(|col| col.generated.is_none());
}
remove_postgres_partial_unique_constraints(&mut schema);
schema.write()
})
.collect();
Expand Down Expand Up @@ -816,4 +831,40 @@ mod tests {
.collect();
assert_eq!(kept, ["id", "w", "h"]);
}

#[cfg(feature = "sqlx-postgres")]
#[test]
fn test_generate_entity_skips_postgres_partial_unique_constraints() {
use sea_schema::postgres::def::{TableDef, TableInfo, Unique};

let mut table = TableDef {
info: TableInfo {
name: "login".to_owned(),
of_type: None,
},
columns: vec![],
check_constraints: vec![],
not_null_constraints: vec![],
unique_constraints: vec![
Unique {
name: "login_email_key".to_owned(),
columns: vec!["email".to_owned()],
is_partial: false,
},
Unique {
name: "login_human_login_id_key".to_owned(),
columns: vec!["human_login_id".to_owned()],
is_partial: true,
},
],
primary_key_constraints: vec![],
reference_constraints: vec![],
exclusion_constraints: vec![],
};

super::remove_postgres_partial_unique_constraints(&mut table);

assert_eq!(table.unique_constraints.len(), 1);
assert_eq!(table.unique_constraints[0].name, "login_email_key");
}
}
2 changes: 1 addition & 1 deletion sea-orm-macros/src/derives/active_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ impl ActiveEnum {
impl std::convert::TryFrom<&str> for #ident {
type Error = sea_orm::DbErr;

fn try_from(source: &str) -> std::result::Result<Self, Self::Error> {
fn try_from(source: &str) -> std::result::Result<Self, <Self as std::convert::TryFrom<&str>>::Error> {
Comment thread
k-bx marked this conversation as resolved.
Outdated
match source {
#( #variant_values => Ok(Self::#variant_idents), )*
_ => Err(sea_orm::DbErr::Type(format!(
Expand Down
16 changes: 8 additions & 8 deletions sea-orm-macros/src/derives/from_query_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl ToTokens for TryFromQueryResultCheck<'_> {
.to_owned()
.unwrap_or_else(|| ident.unraw().to_string());
tokens.extend(quote! {
let #ident = match row.try_get_nullable(pre, #name) {
let #ident = match __sea_orm_row.try_get_nullable(__sea_orm_pre, #name) {
Err(v @ sea_orm::TryGetError::DbErr(_)) => {
return Err(v);
}
Expand All @@ -62,16 +62,16 @@ impl ToTokens for TryFromQueryResultCheck<'_> {
}
ItemType::Nested { prefix } => {
let prefix = match (self.0, prefix) {
(_, Some(p)) => quote! { &format!("{pre}{}", #p) },
(_, Some(p)) => quote! { &format!("{}{}", __sea_orm_pre, #p) },
(true, None) => {
let name = ident.unraw().to_string();
quote! { &format!("{pre}{}_", #name) }
quote! { &format!("{}{}_", __sea_orm_pre, #name) }
}
(false, None) => quote! { pre },
(false, None) => quote! { __sea_orm_pre },
};

tokens.extend(quote! {
let #ident = match sea_orm::FromQueryResult::from_query_result_nullable(row, #prefix) {
let #ident = match sea_orm::FromQueryResult::from_query_result_nullable(__sea_orm_row, #prefix) {
Err(v @ sea_orm::TryGetError::DbErr(_)) => {
return Err(v);
}
Expand Down Expand Up @@ -223,11 +223,11 @@ impl DeriveFromQueryResult {
quote!(
#[automatically_derived]
impl #impl_generics sea_orm::FromQueryResult for #ident #ty_generics #where_clause {
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::DbErr> {
Ok(Self::from_query_result_nullable(row, pre)?)
fn from_query_result(__sea_orm_row: &sea_orm::QueryResult, __sea_orm_pre: &str) -> std::result::Result<Self, sea_orm::DbErr> {
Ok(Self::from_query_result_nullable(__sea_orm_row, __sea_orm_pre)?)
}

fn from_query_result_nullable(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::TryGetError> {
fn from_query_result_nullable(__sea_orm_row: &sea_orm::QueryResult, __sea_orm_pre: &str) -> std::result::Result<Self, sea_orm::TryGetError> {
#(#ident_try_init)*

Ok(Self {
Expand Down
10 changes: 5 additions & 5 deletions sea-orm-macros/src/derives/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ impl DeriveModel {
} else {
let reader = quote! {
let #field_ident =
row.try_get_nullable::<Option<#field_type>>(
pre,
__sea_orm_row.try_get_nullable::<Option<#field_type>>(
__sea_orm_pre,
sea_orm::IdenStatic::as_str(
&<<Self as sea_orm::ModelTrait>::Entity
as sea_orm::entity::EntityTrait>::Column::#column_ident
Expand Down Expand Up @@ -169,11 +169,11 @@ impl DeriveModel {
quote!(
#[automatically_derived]
impl sea_orm::FromQueryResult for #ident {
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::DbErr> {
Self::from_query_result_nullable(row, pre).map_err(Into::into)
fn from_query_result(__sea_orm_row: &sea_orm::QueryResult, __sea_orm_pre: &str) -> std::result::Result<Self, sea_orm::DbErr> {
Self::from_query_result_nullable(__sea_orm_row, __sea_orm_pre).map_err(Into::into)
}

fn from_query_result_nullable(row: &sea_orm::QueryResult, pre: &str) -> std::result::Result<Self, sea_orm::TryGetError> {
fn from_query_result_nullable(__sea_orm_row: &sea_orm::QueryResult, __sea_orm_pre: &str) -> std::result::Result<Self, sea_orm::TryGetError> {
#(#field_readers)*

if #all_null_check {
Expand Down
15 changes: 15 additions & 0 deletions sea-orm-macros/tests/derive_active_enum_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ pub enum TestEnum3 {
HelloWorld,
}

#[derive(Debug, EnumIter, DeriveActiveEnum, Eq, PartialEq)]
#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "error_variant")]
enum ErrorVariantEnum {
#[sea_orm(string_value = "error")]
Error,
}

#[test]
fn derive_active_enum_value() {
assert_eq!(TestEnum::DefaultVariant.to_value(), "defaultVariant");
Expand All @@ -96,6 +103,14 @@ fn derive_active_enum_value() {
assert_eq!(TestEnum::CustomStringValue.to_value(), "CuStOmStRiNgVaLuE");
}

#[test]
fn derive_active_enum_with_error_variant() {
assert_eq!(
<ErrorVariantEnum as TryFrom<&str>>::try_from("error"),
Ok(ErrorVariantEnum::Error)
);
}

#[test]
fn derive_active_enum_from_value() {
assert_eq!(
Expand Down
26 changes: 26 additions & 0 deletions sea-orm-macros/tests/derive_entity_model_column_name_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,29 @@ fn test_column_names() {
Column::from_str("lAsTnAmE").expect("column from str should recognize column_name attr");
assert!(matches!(col, Column::LastName));
}

#[allow(dead_code)]
mod query_parameter_name_collisions {
use sea_orm::entity::prelude::*;
use sea_orm_macros::{DeriveEntityModel, FromQueryResult};

#[derive(FromQueryResult)]
struct QueryResultProjection {
row: String,
pre: String,
}

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "query_parameter_name_collision")]
pub struct Model {
#[sea_orm(primary_key)]
id: i32,
row: String,
pre: String,
}

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

impl ActiveModelBehavior for ActiveModel {}
}
Loading