Introduce optional serde support for model code generation
This introduces several things to optionally support automatic derive attributes for `serde::{Deserialize, Serialize}` for the generated models: - introduces a `WithSerde` enum to indicate if Serialize, Deserialize, or even both should be derived from, - adds an optional cli argument `--with-serde [none: default, serialize, deserialize, both]` - adds test harness for both compact and expanded generation
This commit is contained in:
parent
664afa4b44
commit
b6c5d71fe2
@ -59,3 +59,4 @@ runtime-tokio-rustls = [
|
||||
"sqlx/runtime-tokio-rustls",
|
||||
"sea-schema/runtime-tokio-rustls",
|
||||
]
|
||||
|
||||
|
@ -63,6 +63,13 @@ pub fn build_cli() -> App<'static, 'static> {
|
||||
.help("Generate entity file of compact format")
|
||||
.takes_value(false)
|
||||
.conflicts_with("EXPANDED_FORMAT"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("WITH_SERDE")
|
||||
.long("with-serde")
|
||||
.help("Automatically derive serde Serialize / Deserialize traits for the entity (none, serialize, deserialize, both)")
|
||||
.takes_value(true)
|
||||
.default_value("none")
|
||||
),
|
||||
)
|
||||
.setting(AppSettings::SubcommandRequiredElseHelp);
|
||||
|
@ -1,8 +1,8 @@
|
||||
use clap::ArgMatches;
|
||||
use dotenv::dotenv;
|
||||
use log::LevelFilter;
|
||||
use sea_orm_codegen::{EntityTransformer, OutputFile};
|
||||
use std::{error::Error, fmt::Display, fs, io::Write, path::Path, process::Command};
|
||||
use sea_orm_codegen::{EntityTransformer, OutputFile, WithSerde};
|
||||
use std::{error::Error, fmt::Display, fs, io::Write, path::Path, process::Command, str::FromStr};
|
||||
|
||||
mod cli;
|
||||
|
||||
@ -26,8 +26,12 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box<dyn Er
|
||||
let url = args.value_of("DATABASE_URL").unwrap();
|
||||
let output_dir = args.value_of("OUTPUT_DIR").unwrap();
|
||||
let include_hidden_tables = args.is_present("INCLUDE_HIDDEN_TABLES");
|
||||
let tables = args.values_of("TABLES").unwrap_or_default().collect::<Vec<_>>();
|
||||
let tables = args
|
||||
.values_of("TABLES")
|
||||
.unwrap_or_default()
|
||||
.collect::<Vec<_>>();
|
||||
let expanded_format = args.is_present("EXPANDED_FORMAT");
|
||||
let with_serde = args.value_of("WITH_SERDE").unwrap();
|
||||
let filter_tables = |table: &str| -> bool {
|
||||
if tables.len() > 0 {
|
||||
return tables.contains(&table);
|
||||
@ -84,7 +88,8 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box<dyn Er
|
||||
panic!("This database is not supported ({})", url)
|
||||
};
|
||||
|
||||
let output = EntityTransformer::transform(table_stmts)?.generate(expanded_format);
|
||||
let output = EntityTransformer::transform(table_stmts)?
|
||||
.generate(expanded_format, WithSerde::from_str(with_serde).unwrap());
|
||||
|
||||
let dir = Path::new(output_dir);
|
||||
fs::create_dir_all(dir)?;
|
||||
|
@ -1,3 +1,5 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::Entity;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
@ -17,25 +19,52 @@ pub struct OutputFile {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum WithSerde {
|
||||
None,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Both,
|
||||
}
|
||||
|
||||
impl FromStr for WithSerde {
|
||||
type Err = crate::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"none" => Self::None,
|
||||
"serialize" => Self::Serialize,
|
||||
"deserialize" => Self::Deserialize,
|
||||
"both" => Self::Both,
|
||||
v => {
|
||||
return Err(crate::Error::TransformError(format!(
|
||||
"Unsupported enum variant '{}'",
|
||||
v
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityWriter {
|
||||
pub fn generate(self, expanded_format: bool) -> WriterOutput {
|
||||
pub fn generate(self, expanded_format: bool, with_serde: WithSerde) -> WriterOutput {
|
||||
let mut files = Vec::new();
|
||||
files.extend(self.write_entities(expanded_format));
|
||||
files.extend(self.write_entities(expanded_format, with_serde));
|
||||
files.push(self.write_mod());
|
||||
files.push(self.write_prelude());
|
||||
WriterOutput { files }
|
||||
}
|
||||
|
||||
pub fn write_entities(&self, expanded_format: bool) -> Vec<OutputFile> {
|
||||
pub fn write_entities(&self, expanded_format: bool, with_serde: WithSerde) -> Vec<OutputFile> {
|
||||
self.entities
|
||||
.iter()
|
||||
.map(|entity| {
|
||||
let mut lines = Vec::new();
|
||||
Self::write_doc_comment(&mut lines);
|
||||
let code_blocks = if expanded_format {
|
||||
Self::gen_expanded_code_blocks(entity)
|
||||
Self::gen_expanded_code_blocks(entity, &with_serde)
|
||||
} else {
|
||||
Self::gen_compact_code_blocks(entity)
|
||||
Self::gen_compact_code_blocks(entity, &with_serde)
|
||||
};
|
||||
Self::write(&mut lines, code_blocks);
|
||||
OutputFile {
|
||||
@ -102,12 +131,12 @@ impl EntityWriter {
|
||||
lines.push("".to_owned());
|
||||
}
|
||||
|
||||
pub fn gen_expanded_code_blocks(entity: &Entity) -> Vec<TokenStream> {
|
||||
pub fn gen_expanded_code_blocks(entity: &Entity, with_serde: &WithSerde) -> Vec<TokenStream> {
|
||||
let mut code_blocks = vec![
|
||||
Self::gen_import(),
|
||||
Self::gen_import(with_serde),
|
||||
Self::gen_entity_struct(),
|
||||
Self::gen_impl_entity_name(entity),
|
||||
Self::gen_model_struct(entity),
|
||||
Self::gen_model_struct(entity, with_serde),
|
||||
Self::gen_column_enum(entity),
|
||||
Self::gen_primary_key_enum(entity),
|
||||
Self::gen_impl_primary_key(entity),
|
||||
@ -121,8 +150,11 @@ impl EntityWriter {
|
||||
code_blocks
|
||||
}
|
||||
|
||||
pub fn gen_compact_code_blocks(entity: &Entity) -> Vec<TokenStream> {
|
||||
let mut code_blocks = vec![Self::gen_import(), Self::gen_compact_model_struct(entity)];
|
||||
pub fn gen_compact_code_blocks(entity: &Entity, with_serde: &WithSerde) -> Vec<TokenStream> {
|
||||
let mut code_blocks = vec![
|
||||
Self::gen_import(with_serde),
|
||||
Self::gen_compact_model_struct(entity, with_serde),
|
||||
];
|
||||
let relation_defs = if entity.get_relation_ref_tables_camel_case().is_empty() {
|
||||
vec![
|
||||
Self::gen_relation_enum(entity),
|
||||
@ -138,11 +170,35 @@ impl EntityWriter {
|
||||
code_blocks
|
||||
}
|
||||
|
||||
pub fn gen_import() -> TokenStream {
|
||||
pub fn gen_import(with_serde: &WithSerde) -> TokenStream {
|
||||
match with_serde {
|
||||
WithSerde::None => {
|
||||
quote! {
|
||||
use sea_orm::entity::prelude::*;
|
||||
}
|
||||
}
|
||||
WithSerde::Serialize => {
|
||||
quote! {
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::Serialize;
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Deserialize => {
|
||||
quote! {
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::Deserialize;
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Both => {
|
||||
quote! {
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize,Serialize};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_entity_struct() -> TokenStream {
|
||||
quote! {
|
||||
@ -162,9 +218,12 @@ impl EntityWriter {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_model_struct(entity: &Entity) -> TokenStream {
|
||||
pub fn gen_model_struct(entity: &Entity, with_serde: &WithSerde) -> TokenStream {
|
||||
let column_names_snake_case = entity.get_column_names_snake_case();
|
||||
let column_rs_types = entity.get_column_rs_types();
|
||||
|
||||
match with_serde {
|
||||
WithSerde::None => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
@ -172,6 +231,34 @@ impl EntityWriter {
|
||||
}
|
||||
}
|
||||
}
|
||||
WithSerde::Serialize => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize)]
|
||||
pub struct Model {
|
||||
#(pub #column_names_snake_case: #column_rs_types,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Deserialize => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Deserialize)]
|
||||
pub struct Model {
|
||||
#(pub #column_names_snake_case: #column_rs_types,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Both => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize, Deserialize)]
|
||||
pub struct Model {
|
||||
#(pub #column_names_snake_case: #column_rs_types,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_column_enum(entity: &Entity) -> TokenStream {
|
||||
let column_names_camel_case = entity.get_column_names_camel_case();
|
||||
@ -320,7 +407,7 @@ impl EntityWriter {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_compact_model_struct(entity: &Entity) -> TokenStream {
|
||||
pub fn gen_compact_model_struct(entity: &Entity, with_serde: &WithSerde) -> TokenStream {
|
||||
let table_name = entity.table_name.as_str();
|
||||
let column_names_snake_case = entity.get_column_names_snake_case();
|
||||
let column_rs_types = entity.get_column_rs_types();
|
||||
@ -365,6 +452,9 @@ impl EntityWriter {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
match with_serde {
|
||||
WithSerde::None => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = #table_name)]
|
||||
@ -376,6 +466,46 @@ impl EntityWriter {
|
||||
}
|
||||
}
|
||||
}
|
||||
WithSerde::Serialize => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)]
|
||||
#[sea_orm(table_name = #table_name)]
|
||||
pub struct Model {
|
||||
#(
|
||||
#attrs
|
||||
pub #column_names_snake_case: #column_rs_types,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Deserialize => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize)]
|
||||
#[sea_orm(table_name = #table_name)]
|
||||
pub struct Model {
|
||||
#(
|
||||
#attrs
|
||||
pub #column_names_snake_case: #column_rs_types,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WithSerde::Both => {
|
||||
quote! {
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = #table_name)]
|
||||
pub struct Model {
|
||||
#(
|
||||
#attrs
|
||||
pub #column_names_snake_case: #column_rs_types,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_compact_relation_enum(entity: &Entity) -> TokenStream {
|
||||
let relation_ref_tables_camel_case = entity.get_relation_ref_tables_camel_case();
|
||||
@ -396,6 +526,7 @@ impl EntityWriter {
|
||||
mod tests {
|
||||
use crate::{
|
||||
Column, ConjunctRelation, Entity, EntityWriter, PrimaryKey, Relation, RelationType,
|
||||
WithSerde,
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
use proc_macro2::TokenStream;
|
||||
@ -693,7 +824,7 @@ mod tests {
|
||||
}
|
||||
let content = lines.join("");
|
||||
let expected: TokenStream = content.parse().unwrap();
|
||||
let generated = EntityWriter::gen_expanded_code_blocks(entity)
|
||||
let generated = EntityWriter::gen_expanded_code_blocks(entity, &crate::WithSerde::None)
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.fold(TokenStream::new(), |mut acc, tok| {
|
||||
@ -733,7 +864,7 @@ mod tests {
|
||||
}
|
||||
let content = lines.join("");
|
||||
let expected: TokenStream = content.parse().unwrap();
|
||||
let generated = EntityWriter::gen_compact_code_blocks(entity)
|
||||
let generated = EntityWriter::gen_compact_code_blocks(entity, &crate::WithSerde::None)
|
||||
.into_iter()
|
||||
.skip(1)
|
||||
.fold(TokenStream::new(), |mut acc, tok| {
|
||||
@ -745,4 +876,109 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gen_with_serde() -> io::Result<()> {
|
||||
let cake_entity = setup().get(0).unwrap().clone();
|
||||
|
||||
assert_eq!(cake_entity.get_table_name_snake_case(), "cake");
|
||||
|
||||
// Compact code blocks
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/compact_with_serde/cake_none.rs").into(),
|
||||
WithSerde::None,
|
||||
),
|
||||
Box::new(EntityWriter::gen_compact_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/compact_with_serde/cake_serialize.rs").into(),
|
||||
WithSerde::Serialize,
|
||||
),
|
||||
Box::new(EntityWriter::gen_compact_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/compact_with_serde/cake_deserialize.rs").into(),
|
||||
WithSerde::Deserialize,
|
||||
),
|
||||
Box::new(EntityWriter::gen_compact_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/compact_with_serde/cake_both.rs").into(),
|
||||
WithSerde::Both,
|
||||
),
|
||||
Box::new(EntityWriter::gen_compact_code_blocks),
|
||||
)?;
|
||||
|
||||
// Expanded code blocks
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/expanded_with_serde/cake_none.rs").into(),
|
||||
WithSerde::None,
|
||||
),
|
||||
Box::new(EntityWriter::gen_expanded_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/expanded_with_serde/cake_serialize.rs").into(),
|
||||
WithSerde::Serialize,
|
||||
),
|
||||
Box::new(EntityWriter::gen_expanded_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/expanded_with_serde/cake_deserialize.rs").into(),
|
||||
WithSerde::Deserialize,
|
||||
),
|
||||
Box::new(EntityWriter::gen_expanded_code_blocks),
|
||||
)?;
|
||||
assert_serde_variant_results(
|
||||
&cake_entity,
|
||||
&(
|
||||
include_str!("../../tests/expanded_with_serde/cake_both.rs").into(),
|
||||
WithSerde::Both,
|
||||
),
|
||||
Box::new(EntityWriter::gen_expanded_code_blocks),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assert_serde_variant_results(
|
||||
cake_entity: &Entity,
|
||||
entity_serde_variant: &(String, WithSerde),
|
||||
generator: Box<dyn Fn(&Entity, &WithSerde) -> Vec<TokenStream>>,
|
||||
) -> io::Result<()> {
|
||||
let mut reader = BufReader::new(entity_serde_variant.0.as_bytes());
|
||||
let mut lines: Vec<String> = Vec::new();
|
||||
|
||||
reader.read_until(b'\n', &mut Vec::new())?;
|
||||
|
||||
let mut line = String::new();
|
||||
while reader.read_line(&mut line)? > 0 {
|
||||
lines.push(line.to_owned());
|
||||
line.clear();
|
||||
}
|
||||
let content = lines.join("");
|
||||
let expected: TokenStream = content.parse().unwrap();
|
||||
let generated = generator(&cake_entity, &entity_serde_variant.1)
|
||||
.into_iter()
|
||||
.fold(TokenStream::new(), |mut acc, tok| {
|
||||
acc.extend(tok);
|
||||
acc
|
||||
});
|
||||
|
||||
assert_eq!(expected.to_string(), generated.to_string());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
36
sea-orm-codegen/tests/compact_with_serde/cake_both.rs
Normal file
36
sea-orm-codegen/tests/compact_with_serde/cake_both.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
36
sea-orm-codegen/tests/compact_with_serde/cake_deserialize.rs
Normal file
36
sea-orm-codegen/tests/compact_with_serde/cake_deserialize.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
35
sea-orm-codegen/tests/compact_with_serde/cake_none.rs
Normal file
35
sea-orm-codegen/tests/compact_with_serde/cake_none.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
36
sea-orm-codegen/tests/compact_with_serde/cake_serialize.rs
Normal file
36
sea-orm-codegen/tests/compact_with_serde/cake_serialize.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
78
sea-orm-codegen/tests/expanded_with_serde/cake_both.rs
Normal file
78
sea-orm-codegen/tests/expanded_with_serde/cake_both.rs
Normal file
@ -0,0 +1,78 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::{Deserialize,Serialize};
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize, Deserialize)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = i32;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::Text.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
@ -0,0 +1,78 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Deserialize)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = i32;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::Text.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
77
sea-orm-codegen/tests/expanded_with_serde/cake_none.rs
Normal file
77
sea-orm-codegen/tests/expanded_with_serde/cake_none.rs
Normal file
@ -0,0 +1,77 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = i32;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::Text.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
78
sea-orm-codegen/tests/expanded_with_serde/cake_serialize.rs
Normal file
78
sea-orm-codegen/tests/expanded_with_serde/cake_serialize.rs
Normal file
@ -0,0 +1,78 @@
|
||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.1.0
|
||||
|
||||
use sea_orm::entity::prelude:: * ;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cake"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
pub name: Option<String> ,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Id,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = i32;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::Text.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Fruit => Entity::has_many(super::fruit::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::fruit::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Fruit.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::filling::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
super::cake_filling::Relation::Filling.def()
|
||||
}
|
||||
fn via() -> Option<RelationDef> {
|
||||
Some(super::cake_filling::Relation::Cake.def().rev())
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
Loading…
x
Reference in New Issue
Block a user