Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand SeaORM entity generator with Seaography related data #1599

Merged
merged 31 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f03864e
Add DeriveRelatedEntity macro
karatakis Apr 14, 2023
d9c6579
Add generation for related enum and seaography
karatakis Apr 14, 2023
0ecc57c
Add seaography cli param
karatakis Apr 14, 2023
474f471
update codegen tests
karatakis Apr 14, 2023
ff01616
Fix DeriveRelatedEntity macro doc and includes
karatakis Apr 14, 2023
e9ff1c0
Fix all RelatedEntity variants for RelationBuilder
karatakis Apr 15, 2023
04bd604
Add tests for code
karatakis Apr 15, 2023
516272b
Cargo format
karatakis Apr 15, 2023
f60d9d6
Fix clippy code
karatakis Apr 15, 2023
0e188ca
Fix format
karatakis Apr 15, 2023
5b37895
Merge branch 'SeaQL:master' into seaography-generator
karatakis Apr 15, 2023
f23cd63
Fix unit tests
karatakis Apr 15, 2023
77e46dc
Fix unit tests
karatakis Apr 15, 2023
215bd04
Provide default for seaography::RelationBuilder
karatakis Apr 15, 2023
eedc835
Update changelog
karatakis Apr 15, 2023
6428de1
Update tests
karatakis Apr 17, 2023
2616fd4
Modify code to match feedback
karatakis Apr 17, 2023
499ce88
Update documentation
karatakis Apr 17, 2023
cbbbf10
Update Changelog
karatakis Apr 17, 2023
b49d416
Fix format errors
karatakis Apr 17, 2023
fc5232c
Fix code generation
karatakis Apr 18, 2023
fa86415
Fix unit tests
karatakis Apr 18, 2023
9ebf2bf
Merge branch 'master' into seaography-generator
karatakis Apr 27, 2023
433f7c4
Update lib.rs
karatakis Apr 27, 2023
0833478
derive `seaography::RelationBuilder` only when `seaography` feature i…
billy1624 May 17, 2023
c84294e
Try constructing async-graphql root for "related entity" and "entity"…
billy1624 May 17, 2023
494d527
Merge branch 'master' into pr/1599
billy1624 May 18, 2023
2ecfdb9
Update demo
billy1624 May 18, 2023
4117664
CHANGELOG
billy1624 May 18, 2023
6b16698
Update Cargo.toml
billy1624 May 19, 2023
2e1f4a5
Revert "Update Cargo.toml"
billy1624 May 19, 2023
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
52 changes: 51 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,56 @@ pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
```

* Add `seaography` flag to `sea-orm-cli` https://github.com/SeaQL/sea-orm/pull/1599
* Add generation of `seaography` related information to `sea-orm-codegen` https://github.com/SeaQL/sea-orm/pull/1599
```rust
/// ... Entity File ...

/// the following information is added by `sea-orm-cli` when flag `seaography` is `true`
impl seaography::RelationBuilder for Relation {
fn get_relation(&self, context: & 'static seaography::BuilderContext) -> async_graphql::dynamic::Field {
let builder = seaography::EntityObjectRelationBuilder { context };
match self {
Self::Fruit => builder.get_relation:: <Entity, super::fruit::Entity>("fruit", Self::Fruit.def()),
_ => panic!("No relations for this entity")
}
}
}

impl seaography::RelationBuilder for RelatedEntity {
fn get_relation(&self, context: & 'static seaography::BuilderContext) -> async_graphql::dynamic::Field {
let builder = seaography::EntityObjectViaRelationBuilder { context };
match self {
Self::Fruit => builder.get_relation:: <Entity, super::fruit::Entity>("fruit"),
Self::Filling => builder.get_relation:: <Entity, super::filling::Entity>("filling"),
_ => panic!("No relations for this entity")
}
}
}

```
* Add `DeriveEntityRelated` macro https://github.com/SeaQL/sea-orm/pull/1599
```rust
/// when generating SeaORM entities on compact format the generator will output
/// instead of many blocks of `impl Related` trait

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelatedEntity)]
pub enum RelatedEntity {
#[sea_orm(
entity = "sea_orm::tests_cfg::fruit::Entity",
to = "sea_orm::tests_cfg::cake_expanded::Relation::Fruit.def()"
)]
Fruit,
#[sea_orm(
entity = "sea_orm::tests_cfg::filling::Entity",
to = "sea_orm::tests_cfg::cake_filling::Relation::Filling.def()",
via = "Some(sea_orm::tests_cfg::cake_filling::Relation::Cake.def().rev())"
)]
Filling
}
```
* When generating **compact** entities with `sea-orm-cli` the `sea-orm-codegen` uses `DeriveEntityRelated` macro instead of generating the `impl Related` code https://github.com/SeaQL/sea-orm/pull/1599

### Enhancements

* Added `Migration::name()` and `Migration::status()` getters for the name and status of `sea_orm_migration::Migration` https://github.com/SeaQL/sea-orm/pull/1519
Expand Down Expand Up @@ -410,7 +460,7 @@ impl ColumnTrait for Column {
### Breaking Changes

* [sea-orm-cli] Enable --universal-time by default https://github.com/SeaQL/sea-orm/pull/1420
* Added `RecordNotInserted` and `RecordNotUpdated` to `DbErr`
* Added `RecordNotInserted` and `RecordNotUpdated` to `DbErr`
* Added `ConnectionTrait::execute_unprepared` method https://github.com/SeaQL/sea-orm/pull/1327
* As part of https://github.com/SeaQL/sea-orm/pull/1311, the required method of `TryGetable` changed:
```rust
Expand Down
8 changes: 8 additions & 0 deletions sea-orm-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,14 @@ pub enum GenerateSubcommands {
help = r#"Add extra attributes to generated model struct, no need for `#[]` (comma separated), e.g. `--model-extra-attributes 'serde(rename_all = "camelCase")','ts(export)'`"#
)]
model_extra_attributes: Vec<String>,

#[clap(
action,
long,
default_value = "false",
long_help = "Generate helper Enumerations and Traits that are used by Seaography."
)]
seaography: 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 @@ -31,6 +31,7 @@ pub async fn run_generate_command(
lib,
model_extra_derives,
model_extra_attributes,
seaography,
} => {
if verbose {
let _ = tracing_subscriber::fmt()
Expand Down Expand Up @@ -172,6 +173,7 @@ pub async fn run_generate_command(
serde_skip_hidden_column,
model_extra_derives,
model_extra_attributes,
seaography,
);
let output = EntityTransformer::transform(table_stmts)?.generate(&writer_context);

Expand Down
101 changes: 101 additions & 0 deletions sea-orm-codegen/src/entity/base_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ impl Entity {
.collect()
}

pub fn get_related_enum_name(&self) -> Vec<Ident> {
let conjunct_related = self.get_conjunct_relations_to_upper_camel_case();

self.relations
.iter()
.filter(|rel| !rel.self_referencing && rel.num_suffix == 0 && rel.impl_related)
.map(|rel| rel.get_enum_name())
.chain(conjunct_related.into_iter())
.collect()
}

pub fn get_relation_defs(&self) -> Vec<TokenStream> {
self.relations.iter().map(|rel| rel.get_def()).collect()
}
Expand All @@ -100,6 +111,96 @@ impl Entity {
self.relations.iter().map(|rel| rel.get_attrs()).collect()
}

pub fn get_related_attrs(&self) -> Vec<TokenStream> {
let table_name_camel_case = self.get_table_name_camel_case_ident();
let via_snake_case = self.get_conjunct_relations_via_snake_case();
let to_snake_case = self.get_conjunct_relations_to_snake_case();
let to_upper_camel_case = self.get_conjunct_relations_to_upper_camel_case();

let conjunct_related = via_snake_case
.into_iter()
.zip(to_snake_case)
.zip(to_upper_camel_case)
.map(|((via_snake_case, to_snake_case), to_upper_camel_case)| {
let to = format!(
"super::{}::Relation::{}.def()",
via_snake_case, to_upper_camel_case
);
let via = format!(
"Some(super::{}::Relation::{}.def().rev())",
via_snake_case, table_name_camel_case
);
let entity = format!("super::{}::Entity", to_snake_case);

quote! {
#[sea_orm(
entity = #entity,
to = #to,
via = #via
)]
}
});

self.relations
.iter()
.filter(|rel| !rel.self_referencing && rel.num_suffix == 0 && rel.impl_related)
.map(|rel| rel.get_related_attrs())
.chain(conjunct_related)
.collect()
}

pub fn get_basic_relations(&self) -> Vec<TokenStream> {
self.relations
.iter()
.map(|rel| {
let enum_name = rel.get_enum_name();
let name = enum_name.to_string().to_snake_case();

let path = match rel.get_module_name() {
Some(module_name) => quote!{ super::#module_name::Entity },
None => quote!{ Entity },
};

quote! {
Self::#enum_name => builder.get_relation::<Entity, #path>(#name, Self::#enum_name.def())
}
}).collect()
}

pub fn get_related_relations(&self) -> Vec<TokenStream> {
let to_snake_case = self.get_conjunct_relations_to_snake_case();
let to_upper_camel_case = self.get_conjunct_relations_to_upper_camel_case();

let conj_related = to_snake_case
.into_iter()
.zip(to_upper_camel_case)
.map(|(to_snake_case, to_upper_camel_case)| {
let name = to_snake_case.to_string();
quote! {
Self::#to_upper_camel_case => builder.get_relation::<Entity, super::#to_snake_case::Entity>(#name)
}
});

self.relations
.iter()
.filter(|rel| !rel.self_referencing && rel.num_suffix == 0 && rel.impl_related)
.map(|rel| {
let enum_name = rel.get_enum_name();
let name = enum_name.to_string().to_snake_case();

let path = match rel.get_module_name() {
Some(module_name) => quote! { super::#module_name::Entity },
None => quote! { Entity },
};

quote! {
Self::#enum_name => builder.get_relation::<Entity, #path>(#name)
}
})
.chain(conj_related)
.collect()
}

pub fn get_primary_key_auto_increment(&self) -> Ident {
let auto_increment = self.columns.iter().any(|col| col.auto_increment);
format_ident!("{}", auto_increment)
Expand Down
15 changes: 15 additions & 0 deletions sea-orm-codegen/src/entity/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ impl Relation {
}
}

pub fn get_related_attrs(&self) -> TokenStream {
let enum_name = self.get_enum_name();

let entity = match self.get_module_name() {
Some(module_name) => format!("super::{}::Entity", module_name),
None => String::from("Entity"),
};

let to = format!("Relation::{}.def()", enum_name);

quote! {
#[sea_orm(entity = #entity, to = #to)]
}
}

pub fn get_rel_type(&self) -> Ident {
match self.rel_type {
RelationType::HasOne => format_ident!("has_one"),
Expand Down
1 change: 1 addition & 0 deletions sea-orm-codegen/src/entity/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ mod tests {
false,
&Default::default(),
&Default::default(),
false,
)
.into_iter()
.skip(1)
Expand Down
Loading