commit
eca3949ea9
@ -1,55 +1,18 @@
|
||||
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)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: 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::String(None).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
|
@ -16,7 +16,9 @@ path = "src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "^1", default-features = false, features = [ "full", "derive", "clone-impls", "parsing", "proc-macro", "printing" ] }
|
||||
bae = "^0.1"
|
||||
syn = { version = "^1", default-features = false, features = [ "full", "derive", "clone-impls", "parsing", "proc-macro", "printing", "extra-traits" ] }
|
||||
quote = "^1"
|
||||
heck = "^0.3"
|
||||
proc-macro2 = "^1"
|
||||
convert_case = "0.4"
|
||||
|
29
sea-orm-macros/src/attributes.rs
Normal file
29
sea-orm-macros/src/attributes.rs
Normal file
@ -0,0 +1,29 @@
|
||||
pub mod derive_attr {
|
||||
use bae::FromAttributes;
|
||||
|
||||
#[derive(Default, FromAttributes)]
|
||||
pub struct SeaOrm {
|
||||
pub column: Option<syn::Ident>,
|
||||
pub entity: Option<syn::Ident>,
|
||||
pub model: Option<syn::Ident>,
|
||||
pub primary_key: Option<syn::Ident>,
|
||||
pub relation: Option<syn::Ident>,
|
||||
pub schema_name: Option<syn::Lit>,
|
||||
pub table_name: Option<syn::Lit>,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod field_attr {
|
||||
use bae::FromAttributes;
|
||||
|
||||
#[derive(Default, FromAttributes)]
|
||||
pub struct SeaOrm {
|
||||
pub belongs_to: Option<syn::Lit>,
|
||||
pub has_one: Option<syn::Lit>,
|
||||
pub has_many: Option<syn::Lit>,
|
||||
pub on_update: Option<syn::Lit>,
|
||||
pub on_delete: Option<syn::Lit>,
|
||||
pub from: Option<syn::Lit>,
|
||||
pub to: Option<syn::Lit>,
|
||||
}
|
||||
}
|
@ -46,13 +46,13 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<Token
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ActiveModel {
|
||||
impl std::default::Default for ActiveModel {
|
||||
fn default() -> Self {
|
||||
<Self as sea_orm::ActiveModelBehavior>::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<<Entity as EntityTrait>::Model> for ActiveModel {
|
||||
impl std::convert::From<<Entity as EntityTrait>::Model> for ActiveModel {
|
||||
fn from(m: <Entity as EntityTrait>::Model) -> Self {
|
||||
Self {
|
||||
#(#field: sea_orm::unchanged_active_value_not_intended_for_public_use(m.#field)),*
|
||||
|
@ -1,51 +1,135 @@
|
||||
use heck::SnakeCase;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{Attribute, Meta};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
fn get_entity_attr(attrs: &[Attribute]) -> Option<syn::Lit> {
|
||||
for attr in attrs {
|
||||
let name_value = match attr.parse_meta() {
|
||||
Ok(Meta::NameValue(nv)) => nv,
|
||||
_ => continue,
|
||||
};
|
||||
if name_value.path.is_ident("table") {
|
||||
return Some(name_value.lit);
|
||||
}
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
use crate::attributes::derive_attr;
|
||||
|
||||
struct DeriveEntity {
|
||||
column_ident: syn::Ident,
|
||||
ident: syn::Ident,
|
||||
model_ident: syn::Ident,
|
||||
primary_key_ident: syn::Ident,
|
||||
relation_ident: syn::Ident,
|
||||
schema_name: Option<syn::Lit>,
|
||||
table_name: Option<syn::Lit>,
|
||||
}
|
||||
|
||||
impl DeriveEntity {
|
||||
fn new(input: syn::DeriveInput) -> Result<Self, syn::Error> {
|
||||
let sea_attr = derive_attr::SeaOrm::try_from_attributes(&input.attrs)?.unwrap_or_default();
|
||||
|
||||
let ident = input.ident;
|
||||
let column_ident = sea_attr.column.unwrap_or_else(|| format_ident!("Column"));
|
||||
let model_ident = sea_attr.model.unwrap_or_else(|| format_ident!("Model"));
|
||||
let primary_key_ident = sea_attr
|
||||
.primary_key
|
||||
.unwrap_or_else(|| format_ident!("PrimaryKey"));
|
||||
let relation_ident = sea_attr
|
||||
.relation
|
||||
.unwrap_or_else(|| format_ident!("Relation"));
|
||||
|
||||
let table_name = sea_attr.table_name;
|
||||
let schema_name = sea_attr.schema_name;
|
||||
|
||||
Ok(DeriveEntity {
|
||||
column_ident,
|
||||
ident,
|
||||
model_ident,
|
||||
primary_key_ident,
|
||||
relation_ident,
|
||||
schema_name,
|
||||
table_name,
|
||||
})
|
||||
}
|
||||
|
||||
fn expand(&self) -> TokenStream {
|
||||
let expanded_impl_entity_name = self.impl_entity_name();
|
||||
let expanded_impl_entity_trait = self.impl_entity_trait();
|
||||
let expanded_impl_iden = self.impl_iden();
|
||||
let expanded_impl_iden_static = self.impl_iden_static();
|
||||
|
||||
TokenStream::from_iter([
|
||||
expanded_impl_entity_name,
|
||||
expanded_impl_entity_trait,
|
||||
expanded_impl_iden,
|
||||
expanded_impl_iden_static,
|
||||
])
|
||||
}
|
||||
|
||||
fn impl_entity_name(&self) -> TokenStream {
|
||||
let ident = &self.ident;
|
||||
let table_name = match &self.table_name {
|
||||
Some(table_name) => table_name,
|
||||
None => return TokenStream::new(), // No table name, do not derive EntityName
|
||||
};
|
||||
let expanded_schema_name = self
|
||||
.schema_name
|
||||
.as_ref()
|
||||
.map(|schema| quote!(Some(#schema)))
|
||||
.unwrap_or_else(|| quote!(None));
|
||||
|
||||
quote!(
|
||||
impl sea_orm::entity::EntityName for #ident {
|
||||
fn schema_name(&self) -> Option<&str> {
|
||||
#expanded_schema_name
|
||||
}
|
||||
|
||||
fn table_name(&self) -> &str {
|
||||
#table_name
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_entity_trait(&self) -> TokenStream {
|
||||
let Self {
|
||||
ident,
|
||||
model_ident,
|
||||
column_ident,
|
||||
primary_key_ident,
|
||||
relation_ident,
|
||||
..
|
||||
} = self;
|
||||
|
||||
quote!(
|
||||
impl sea_orm::entity::EntityTrait for #ident {
|
||||
type Model = #model_ident;
|
||||
|
||||
type Column = #column_ident;
|
||||
|
||||
type PrimaryKey = #primary_key_ident;
|
||||
|
||||
type Relation = #relation_ident;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_iden(&self) -> TokenStream {
|
||||
let ident = &self.ident;
|
||||
|
||||
quote!(
|
||||
impl sea_orm::Iden for #ident {
|
||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
||||
write!(s, "{}", self.as_str()).unwrap();
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_iden_static(&self) -> TokenStream {
|
||||
let ident = &self.ident;
|
||||
|
||||
quote!(
|
||||
impl sea_orm::IdenStatic for #ident {
|
||||
fn as_str(&self) -> &str {
|
||||
<Self as sea_orm::EntityName>::table_name(self)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn expand_derive_entity(ident: Ident, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
|
||||
let _entity_name = match get_entity_attr(&attrs) {
|
||||
Some(lit) => quote! { #lit },
|
||||
None => {
|
||||
let normalized = ident.to_string().to_snake_case();
|
||||
quote! { #normalized }
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote!(
|
||||
impl sea_orm::Iden for #ident {
|
||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
||||
write!(s, "{}", self.as_str()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl sea_orm::IdenStatic for #ident {
|
||||
fn as_str(&self) -> &str {
|
||||
<Self as sea_orm::EntityName>::table_name(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl EntityTrait for #ident {
|
||||
type Model = Model;
|
||||
|
||||
type Column = Column;
|
||||
|
||||
type PrimaryKey = PrimaryKey;
|
||||
|
||||
type Relation = Relation;
|
||||
}
|
||||
))
|
||||
pub fn expand_derive_entity(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||
Ok(DeriveEntity::new(input)?.expand())
|
||||
}
|
||||
|
248
sea-orm-macros/src/derives/entity_model.rs
Normal file
248
sea-orm-macros/src/derives/entity_model.rs
Normal file
@ -0,0 +1,248 @@
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parse::Error, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Fields,
|
||||
Lit, Meta,
|
||||
};
|
||||
|
||||
use convert_case::{Case, Casing};
|
||||
|
||||
pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Result<TokenStream> {
|
||||
// if #[sea_orm(table_name = "foo", schema_name = "bar")] specified, create Entity struct
|
||||
let mut table_name = None;
|
||||
let mut schema_name = quote! { None };
|
||||
attrs.iter().for_each(|attr| {
|
||||
if attr.path.get_ident().map(|i| i == "sea_orm") != Some(true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) {
|
||||
for meta in list.iter() {
|
||||
if let Meta::NameValue(nv) = meta {
|
||||
if let Some(ident) = nv.path.get_ident() {
|
||||
if ident == "table_name" {
|
||||
table_name = Some(nv.lit.clone());
|
||||
} else if ident == "schema_name" {
|
||||
let name = &nv.lit;
|
||||
schema_name = quote! { Some(#name) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let entity_def = table_name
|
||||
.map(|table_name| {
|
||||
quote! {
|
||||
#[derive(Copy, Clone, Default, Debug, sea_orm::prelude::DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl sea_orm::prelude::EntityName for Entity {
|
||||
fn schema_name(&self) -> Option<&str> {
|
||||
#schema_name
|
||||
}
|
||||
|
||||
fn table_name(&self) -> &str {
|
||||
#table_name
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
// generate Column enum and it's ColumnTrait impl
|
||||
let mut columns_enum: Punctuated<_, Comma> = Punctuated::new();
|
||||
let mut columns_trait: Punctuated<_, Comma> = Punctuated::new();
|
||||
let mut primary_keys: Punctuated<_, Comma> = Punctuated::new();
|
||||
let mut primary_key_types: Punctuated<_, Comma> = Punctuated::new();
|
||||
let mut auto_increment = true;
|
||||
if let Data::Struct(item_struct) = data {
|
||||
if let Fields::Named(fields) = item_struct.fields {
|
||||
for field in fields.named {
|
||||
if let Some(ident) = &field.ident {
|
||||
let field_name =
|
||||
Ident::new(&ident.to_string().to_case(Case::Pascal), Span::call_site());
|
||||
columns_enum.push(quote! { #field_name });
|
||||
|
||||
let mut nullable = false;
|
||||
let mut default_value = None;
|
||||
let mut default_expr = None;
|
||||
let mut indexed = false;
|
||||
let mut unique = false;
|
||||
let mut sql_type = None;
|
||||
// search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", nullable, indexed, unique)]
|
||||
for attr in field.attrs.iter() {
|
||||
if let Some(ident) = attr.path.get_ident() {
|
||||
if ident != "sea_orm" {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// single param
|
||||
if let Ok(list) =
|
||||
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
|
||||
{
|
||||
for meta in list.iter() {
|
||||
match meta {
|
||||
Meta::NameValue(nv) => {
|
||||
if let Some(name) = nv.path.get_ident() {
|
||||
if name == "column_type" {
|
||||
if let Lit::Str(litstr) = &nv.lit {
|
||||
let ty: TokenStream =
|
||||
syn::parse_str(&litstr.value())?;
|
||||
sql_type = Some(ty);
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
field.span(),
|
||||
format!("Invalid column_type {:?}", nv.lit),
|
||||
));
|
||||
}
|
||||
} else if name == "auto_increment" {
|
||||
if let Lit::Bool(litbool) = &nv.lit {
|
||||
auto_increment = litbool.value();
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
field.span(),
|
||||
format!(
|
||||
"Invalid auto_increment = {:?}",
|
||||
nv.lit
|
||||
),
|
||||
));
|
||||
}
|
||||
} else if name == "default_value" {
|
||||
default_value = Some(nv.lit.to_owned());
|
||||
} else if name == "default_expr" {
|
||||
default_expr = Some(nv.lit.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
Meta::Path(p) => {
|
||||
if let Some(name) = p.get_ident() {
|
||||
if name == "primary_key" {
|
||||
primary_keys.push(quote! { #field_name });
|
||||
primary_key_types.push(field.ty.clone());
|
||||
} else if name == "nullable" {
|
||||
nullable = true;
|
||||
} else if name == "indexed" {
|
||||
indexed = true;
|
||||
} else if name == "unique" {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let field_type = match sql_type {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
let field_type = &field.ty;
|
||||
let temp = quote! { #field_type }
|
||||
.to_string() //E.g.: "Option < String >"
|
||||
.replace(" ", "");
|
||||
let temp = if temp.starts_with("Option<") {
|
||||
nullable = true;
|
||||
&temp[7..(temp.len() - 1)]
|
||||
} else {
|
||||
temp.as_str()
|
||||
};
|
||||
match temp {
|
||||
"char" => quote! { Char(None) },
|
||||
"String" | "&str" => quote! { String(None) },
|
||||
"u8" | "i8" => quote! { TinyInteger },
|
||||
"u16" | "i16" => quote! { SmallInteger },
|
||||
"u32" | "u64" | "i32" | "i64" => quote! { Integer },
|
||||
"u128" | "i128" => quote! { BigInteger },
|
||||
"f32" => quote! { Float },
|
||||
"f64" => quote! { Double },
|
||||
"bool" => quote! { Boolean },
|
||||
"NaiveDate" => quote! { Date },
|
||||
"NaiveTime" => quote! { Time },
|
||||
"DateTime" | "NaiveDateTime" => quote! { DateTime },
|
||||
"Uuid" => quote! { Uuid },
|
||||
"Json" => quote! { Json },
|
||||
"Decimal" => quote! { Decimal },
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
field.span(),
|
||||
format!("unrecognized type {}", temp),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut match_row = quote! { Self::#field_name => sea_orm::prelude::ColumnType::#field_type.def() };
|
||||
if nullable {
|
||||
match_row = quote! { #match_row.nullable() };
|
||||
}
|
||||
if indexed {
|
||||
match_row = quote! { #match_row.indexed() };
|
||||
}
|
||||
if unique {
|
||||
match_row = quote! { #match_row.unique() };
|
||||
}
|
||||
if let Some(default_value) = default_value {
|
||||
match_row = quote! { #match_row.default_value(#default_value) };
|
||||
}
|
||||
if let Some(default_expr) = default_expr {
|
||||
match_row = quote! { #match_row.default_expr(#default_expr) };
|
||||
}
|
||||
columns_trait.push(match_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let primary_key = (!primary_keys.is_empty())
|
||||
.then(|| {
|
||||
let auto_increment = auto_increment && primary_keys.len() == 1;
|
||||
let primary_key_types = if primary_key_types.len() == 1 {
|
||||
let first = primary_key_types.first();
|
||||
quote! { #first }
|
||||
} else {
|
||||
quote! { (#primary_key_types) }
|
||||
};
|
||||
quote! {
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
#primary_keys
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = #primary_key_types;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
#auto_increment
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(quote! {
|
||||
#[derive(Copy, Clone, Debug, sea_orm::prelude::EnumIter, sea_orm::prelude::DeriveColumn)]
|
||||
pub enum Column {
|
||||
#columns_enum
|
||||
}
|
||||
|
||||
impl sea_orm::prelude::ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> sea_orm::prelude::ColumnDef {
|
||||
match self {
|
||||
#columns_trait
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#entity_def
|
||||
|
||||
#primary_key
|
||||
})
|
||||
}
|
@ -2,14 +2,18 @@ mod active_model;
|
||||
mod active_model_behavior;
|
||||
mod column;
|
||||
mod entity;
|
||||
mod entity_model;
|
||||
mod from_query_result;
|
||||
mod model;
|
||||
mod primary_key;
|
||||
mod relation;
|
||||
|
||||
pub use active_model::*;
|
||||
pub use active_model_behavior::*;
|
||||
pub use column::*;
|
||||
pub use entity::*;
|
||||
pub use entity_model::*;
|
||||
pub use from_query_result::*;
|
||||
pub use model::*;
|
||||
pub use primary_key::*;
|
||||
pub use relation::*;
|
||||
|
@ -1,57 +1,125 @@
|
||||
use crate::attributes::derive_attr;
|
||||
use heck::CamelCase;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use syn::{Data, DataStruct, Field, Fields};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
pub fn expand_derive_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||
let fields = match data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(named),
|
||||
..
|
||||
}) => named.named,
|
||||
_ => {
|
||||
return Ok(quote_spanned! {
|
||||
ident.span() => compile_error!("you can only derive DeriveModel on structs");
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let field: Vec<Ident> = fields
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string()))
|
||||
.collect();
|
||||
|
||||
let name: Vec<Ident> = fields
|
||||
.into_iter()
|
||||
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string().to_camel_case()))
|
||||
.collect();
|
||||
|
||||
Ok(quote!(
|
||||
impl sea_orm::ModelTrait for #ident {
|
||||
type Entity = Entity;
|
||||
|
||||
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> sea_orm::Value {
|
||||
match c {
|
||||
#(<Self::Entity as EntityTrait>::Column::#name => self.#field.clone().into(),)*
|
||||
_ => panic!("This Model does not have this field"),
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: sea_orm::Value) {
|
||||
match c {
|
||||
#(<Self::Entity as EntityTrait>::Column::#name => self.#field = v.unwrap(),)*
|
||||
_ => panic!("This Model does not have this field"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sea_orm::FromQueryResult for #ident {
|
||||
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result<Self, sea_orm::DbErr> {
|
||||
Ok(Self {
|
||||
#(#field: row.try_get(pre, <<Self as ModelTrait>::Entity as EntityTrait>::Column::#name.as_str().into())?),*
|
||||
})
|
||||
}
|
||||
}
|
||||
))
|
||||
enum Error {
|
||||
InputNotStruct,
|
||||
Syn(syn::Error),
|
||||
}
|
||||
|
||||
struct DeriveModel {
|
||||
column_idents: Vec<syn::Ident>,
|
||||
entity_ident: syn::Ident,
|
||||
field_idents: Vec<syn::Ident>,
|
||||
ident: syn::Ident,
|
||||
}
|
||||
|
||||
impl DeriveModel {
|
||||
fn new(input: syn::DeriveInput) -> Result<Self, Error> {
|
||||
let fields = match input.data {
|
||||
syn::Data::Struct(syn::DataStruct {
|
||||
fields: syn::Fields::Named(syn::FieldsNamed { named, .. }),
|
||||
..
|
||||
}) => named,
|
||||
_ => return Err(Error::InputNotStruct),
|
||||
};
|
||||
|
||||
let sea_attr = derive_attr::SeaOrm::try_from_attributes(&input.attrs)
|
||||
.map_err(Error::Syn)?
|
||||
.unwrap_or_default();
|
||||
|
||||
let ident = input.ident;
|
||||
let entity_ident = sea_attr.entity.unwrap_or_else(|| format_ident!("Entity"));
|
||||
|
||||
let field_idents = fields
|
||||
.iter()
|
||||
.map(|field| field.ident.as_ref().unwrap().clone())
|
||||
.collect();
|
||||
|
||||
let column_idents = fields
|
||||
.iter()
|
||||
.map(|field| {
|
||||
format_ident!(
|
||||
"{}",
|
||||
field.ident.as_ref().unwrap().to_string().to_camel_case()
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(DeriveModel {
|
||||
column_idents,
|
||||
entity_ident,
|
||||
field_idents,
|
||||
ident,
|
||||
})
|
||||
}
|
||||
|
||||
fn expand(&self) -> syn::Result<TokenStream> {
|
||||
let expanded_impl_from_query_result = self.impl_from_query_result();
|
||||
let expanded_impl_model_trait = self.impl_model_trait();
|
||||
|
||||
Ok(TokenStream::from_iter([
|
||||
expanded_impl_from_query_result,
|
||||
expanded_impl_model_trait,
|
||||
]))
|
||||
}
|
||||
|
||||
fn impl_from_query_result(&self) -> TokenStream {
|
||||
let ident = &self.ident;
|
||||
let field_idents = &self.field_idents;
|
||||
let column_idents = &self.column_idents;
|
||||
|
||||
quote!(
|
||||
impl sea_orm::FromQueryResult for #ident {
|
||||
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result<Self, sea_orm::DbErr> {
|
||||
Ok(Self {
|
||||
#(#field_idents: row.try_get(pre, sea_orm::IdenStatic::as_str(&<<Self as sea_orm::ModelTrait>::Entity as sea_orm::entity::EntityTrait>::Column::#column_idents).into())?),*
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn impl_model_trait(&self) -> TokenStream {
|
||||
let ident = &self.ident;
|
||||
let entity_ident = &self.entity_ident;
|
||||
let field_idents = &self.field_idents;
|
||||
let column_idents = &self.column_idents;
|
||||
|
||||
let missing_field_msg = format!("field does not exist on {}", ident);
|
||||
|
||||
quote!(
|
||||
impl sea_orm::ModelTrait for #ident {
|
||||
type Entity = #entity_ident;
|
||||
|
||||
fn get(&self, c: <Self::Entity as sea_orm::entity::EntityTrait>::Column) -> sea_orm::Value {
|
||||
match c {
|
||||
#(<Self::Entity as sea_orm::entity::EntityTrait>::Column::#column_idents => self.#field_idents.clone().into(),)*
|
||||
_ => panic!(#missing_field_msg),
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, c: <Self::Entity as sea_orm::entity::EntityTrait>::Column, v: sea_orm::Value) {
|
||||
match c {
|
||||
#(<Self::Entity as sea_orm::entity::EntityTrait>::Column::#column_idents => self.#field_idents = v.unwrap(),)*
|
||||
_ => panic!(#missing_field_msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_derive_model(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||
let ident_span = input.ident.span();
|
||||
|
||||
match DeriveModel::new(input) {
|
||||
Ok(model) => model.expand(),
|
||||
Err(Error::InputNotStruct) => Ok(quote_spanned! {
|
||||
ident_span => compile_error!("you can only derive DeriveModel on structs");
|
||||
}),
|
||||
Err(Error::Syn(err)) => Err(err),
|
||||
}
|
||||
}
|
||||
|
178
sea-orm-macros/src/derives/relation.rs
Normal file
178
sea-orm-macros/src/derives/relation.rs
Normal file
@ -0,0 +1,178 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
|
||||
use crate::attributes::{derive_attr, field_attr};
|
||||
|
||||
enum Error {
|
||||
InputNotEnum,
|
||||
Syn(syn::Error),
|
||||
}
|
||||
|
||||
struct DeriveRelation {
|
||||
entity_ident: syn::Ident,
|
||||
ident: syn::Ident,
|
||||
variants: syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>,
|
||||
}
|
||||
|
||||
impl DeriveRelation {
|
||||
fn new(input: syn::DeriveInput) -> Result<Self, Error> {
|
||||
let variants = match input.data {
|
||||
syn::Data::Enum(syn::DataEnum { variants, .. }) => variants,
|
||||
_ => return Err(Error::InputNotEnum),
|
||||
};
|
||||
|
||||
let sea_attr = derive_attr::SeaOrm::try_from_attributes(&input.attrs)
|
||||
.map_err(Error::Syn)?
|
||||
.unwrap_or_default();
|
||||
|
||||
let ident = input.ident;
|
||||
let entity_ident = sea_attr.entity.unwrap_or_else(|| format_ident!("Entity"));
|
||||
|
||||
Ok(DeriveRelation {
|
||||
entity_ident,
|
||||
ident,
|
||||
variants,
|
||||
})
|
||||
}
|
||||
|
||||
fn expand(&self) -> syn::Result<TokenStream> {
|
||||
let expanded_impl_relation_trait = self.impl_relation_trait()?;
|
||||
|
||||
Ok(expanded_impl_relation_trait)
|
||||
}
|
||||
|
||||
fn impl_relation_trait(&self) -> syn::Result<TokenStream> {
|
||||
let ident = &self.ident;
|
||||
let entity_ident = &self.entity_ident;
|
||||
let no_relation_def_msg = format!("No RelationDef for {}", ident);
|
||||
|
||||
let variant_relation_defs: Vec<TokenStream> = self
|
||||
.variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let variant_ident = &variant.ident;
|
||||
let attr = field_attr::SeaOrm::from_attributes(&variant.attrs)?;
|
||||
let mut relation_type = quote! { error };
|
||||
let related_to = if attr.belongs_to.is_some() {
|
||||
relation_type = quote! { belongs_to };
|
||||
attr.belongs_to
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'belongs_to'")
|
||||
})
|
||||
} else if attr.has_one.is_some() {
|
||||
relation_type = quote! { has_one };
|
||||
attr.has_one
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'has_one'")
|
||||
})
|
||||
} else if attr.has_many.is_some() {
|
||||
relation_type = quote! { has_many };
|
||||
attr.has_many
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'has_many'")
|
||||
})
|
||||
} else {
|
||||
Err(syn::Error::new_spanned(
|
||||
variant,
|
||||
"Missing one of 'has_one', 'has_many' or 'belongs_to'",
|
||||
))
|
||||
}??;
|
||||
|
||||
let mut result = quote!(
|
||||
Self::#variant_ident => #entity_ident::#relation_type(#related_to)
|
||||
);
|
||||
|
||||
if attr.from.is_some() {
|
||||
let from =
|
||||
attr.from
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'from'")
|
||||
})??;
|
||||
result = quote! { #result.from(#from) };
|
||||
} else if attr.belongs_to.is_some() {
|
||||
return Err(syn::Error::new_spanned(variant, "Missing attribute 'from'"));
|
||||
}
|
||||
|
||||
if attr.to.is_some() {
|
||||
let to = attr
|
||||
.to
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'to'")
|
||||
})??;
|
||||
result = quote! { #result.to(#to) };
|
||||
} else if attr.belongs_to.is_some() {
|
||||
return Err(syn::Error::new_spanned(variant, "Missing attribute 'to'"));
|
||||
}
|
||||
|
||||
if attr.on_update.is_some() {
|
||||
let on_update = attr
|
||||
.on_update
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'on_update'")
|
||||
})??;
|
||||
result = quote! { #result.on_update(sea_orm::prelude::ForeignKeyAction::#on_update) };
|
||||
}
|
||||
|
||||
if attr.on_delete.is_some() {
|
||||
let on_delete = attr
|
||||
.on_delete
|
||||
.as_ref()
|
||||
.map(Self::parse_lit_string)
|
||||
.ok_or_else(|| {
|
||||
syn::Error::new_spanned(variant, "Missing value for 'on_delete'")
|
||||
})??;
|
||||
result = quote! { #result.on_delete(sea_orm::prelude::ForeignKeyAction::#on_delete) };
|
||||
}
|
||||
|
||||
result = quote! { #result.into() };
|
||||
|
||||
Result::<_, syn::Error>::Ok(result)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
Ok(quote!(
|
||||
impl sea_orm::entity::RelationTrait for #ident {
|
||||
fn def(&self) -> sea_orm::entity::RelationDef {
|
||||
match self {
|
||||
#( #variant_relation_defs, )*
|
||||
_ => panic!(#no_relation_def_msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_lit_string(lit: &syn::Lit) -> syn::Result<TokenStream> {
|
||||
match lit {
|
||||
syn::Lit::Str(lit_str) => lit_str
|
||||
.value()
|
||||
.parse()
|
||||
.map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")),
|
||||
_ => Err(syn::Error::new_spanned(lit, "attribute must be a string")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expand_derive_relation(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||
let ident_span = input.ident.span();
|
||||
|
||||
match DeriveRelation::new(input) {
|
||||
Ok(model) => model.expand(),
|
||||
Err(Error::InputNotEnum) => Ok(quote_spanned! {
|
||||
ident_span => compile_error!("you can only derive DeriveRelation on enums");
|
||||
}),
|
||||
Err(Error::Syn(err)) => Err(err),
|
||||
}
|
||||
}
|
@ -1,18 +1,38 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
use syn::{parse_macro_input, DeriveInput, Error};
|
||||
|
||||
mod attributes;
|
||||
mod derives;
|
||||
|
||||
#[proc_macro_derive(DeriveEntity, attributes(table))]
|
||||
#[proc_macro_derive(DeriveEntity, attributes(sea_orm))]
|
||||
pub fn derive_entity(input: TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, attrs, .. } = parse_macro_input!(input);
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
derives::expand_derive_entity(input)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
match derives::expand_derive_entity(ident, attrs) {
|
||||
Ok(ts) => ts.into(),
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
#[proc_macro_derive(DeriveEntityModel, attributes(sea_orm))]
|
||||
pub fn derive_entity_model(input: TokenStream) -> TokenStream {
|
||||
let input_ts = input.clone();
|
||||
let DeriveInput {
|
||||
ident, data, attrs, ..
|
||||
} = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
if ident != "Model" {
|
||||
panic!("Struct name must be Model");
|
||||
}
|
||||
|
||||
let mut ts: TokenStream = derives::expand_derive_entity_model(data, attrs)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into();
|
||||
ts.extend(vec![
|
||||
derive_model(input_ts.clone()),
|
||||
derive_active_model(input_ts),
|
||||
]);
|
||||
ts
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DerivePrimaryKey)]
|
||||
@ -45,14 +65,12 @@ pub fn derive_custom_column(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DeriveModel)]
|
||||
#[proc_macro_derive(DeriveModel, attributes(sea_orm))]
|
||||
pub fn derive_model(input: TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||
|
||||
match derives::expand_derive_model(ident, data) {
|
||||
Ok(ts) => ts.into(),
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
}
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
derives::expand_derive_model(input)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DeriveActiveModel)]
|
||||
@ -85,10 +103,18 @@ pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DeriveRelation, attributes(sea_orm))]
|
||||
pub fn derive_relation(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
derives::expand_derive_relation(input)
|
||||
.unwrap_or_else(Error::into_compile_error)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[proc_macro_attribute]
|
||||
pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(input as syn::ItemFn);
|
||||
let input = parse_macro_input!(input as syn::ItemFn);
|
||||
|
||||
let ret = &input.sig.output;
|
||||
let name = &input.sig.ident;
|
||||
|
@ -248,7 +248,11 @@ impl ColumnDef {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn null(mut self) -> Self {
|
||||
pub fn null(self) -> Self {
|
||||
self.nullable()
|
||||
}
|
||||
|
||||
pub fn nullable(mut self) -> Self {
|
||||
self.null = true;
|
||||
self
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
pub use crate::{
|
||||
error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType,
|
||||
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
||||
DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, ForeignKeyAction, Iden,
|
||||
IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult,
|
||||
Related, RelationDef, RelationTrait, Select, Value,
|
||||
DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait,
|
||||
EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn,
|
||||
PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value,
|
||||
};
|
||||
|
||||
#[cfg(feature = "with-json")]
|
||||
|
@ -229,7 +229,7 @@ pub use schema::*;
|
||||
|
||||
pub use sea_orm_macros::{
|
||||
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
||||
DeriveModel, DerivePrimaryKey, FromQueryResult,
|
||||
DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, FromQueryResult,
|
||||
};
|
||||
|
||||
pub use sea_query;
|
||||
|
@ -1,64 +1,20 @@
|
||||
use crate as sea_orm;
|
||||
use crate::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)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: 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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||
Fruit,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -2,14 +2,9 @@ use crate as sea_orm;
|
||||
use crate::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
#[sea_orm(table_name = "filling")]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"filling"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
pub struct Model {
|
||||
pub id: i32,
|
||||
|
@ -1,70 +1,25 @@
|
||||
use crate as sea_orm;
|
||||
use crate::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"fruit"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "fruit")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub cake_id: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
CakeId,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::cake::Entity",
|
||||
from = "Column::CakeId",
|
||||
to = "super::cake::Column::Id"
|
||||
)]
|
||||
Cake,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::CakeId => ColumnType::Integer.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Cake => Entity::belongs_to(super::cake::Entity)
|
||||
.from(Column::CakeId)
|
||||
.to(super::cake::Column::Id)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::cake::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Cake.def()
|
||||
|
@ -2,7 +2,7 @@ pub mod common;
|
||||
|
||||
pub use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, Database, DbConn};
|
||||
|
||||
// DATABASE_URL="sqlite::memory:" cargo test --features sqlx-sqlit,runtime-async-std --test basic
|
||||
// DATABASE_URL="sqlite::memory:" cargo test --features sqlx-sqlite,runtime-async-std-native-tls --test basic
|
||||
#[sea_orm_macros::test]
|
||||
#[cfg(feature = "sqlx-sqlite")]
|
||||
async fn main() {
|
||||
|
@ -1,74 +1,27 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"baker"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "baker")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub contact_details: Json,
|
||||
pub bakery_id: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
ContactDetails,
|
||||
BakeryId,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::bakery::Entity",
|
||||
from = "Column::BakeryId",
|
||||
to = "super::bakery::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Bakery,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::ContactDetails => ColumnType::Json.def(),
|
||||
Self::BakeryId => ColumnType::Integer.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Bakery => Entity::belongs_to(super::bakery::Entity)
|
||||
.from(Column::BakeryId)
|
||||
.to(super::bakery::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
|
@ -1,70 +1,24 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"bakery"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "bakery")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub profit_margin: f64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
ProfitMargin,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::baker::Entity")]
|
||||
Baker,
|
||||
#[sea_orm(has_many = "super::order::Entity")]
|
||||
Order,
|
||||
#[sea_orm(has_many = "super::cake::Entity")]
|
||||
Cake,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::ProfitMargin => ColumnType::Double.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Baker => Entity::has_many(super::baker::Entity).into(),
|
||||
Self::Order => Entity::has_many(super::order::Entity).into(),
|
||||
Self::Cake => Entity::has_many(super::cake::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::baker::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Baker.def()
|
||||
|
@ -1,82 +1,32 @@
|
||||
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)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "cake")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||
pub price: Decimal,
|
||||
pub bakery_id: Option<i32>,
|
||||
pub gluten_free: bool,
|
||||
pub serial: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
Price,
|
||||
BakeryId,
|
||||
GlutenFree,
|
||||
Serial,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::bakery::Entity",
|
||||
from = "Column::BakeryId",
|
||||
to = "super::bakery::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Bakery,
|
||||
#[sea_orm(has_many = "super::lineitem::Entity")]
|
||||
Lineitem,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::Price => ColumnType::Decimal(Some((19, 4))).def(),
|
||||
Self::BakeryId => ColumnType::Integer.def().null(),
|
||||
Self::GlutenFree => ColumnType::Boolean.def(),
|
||||
Self::Serial => ColumnType::Uuid.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Bakery => Entity::belongs_to(super::bakery::Entity)
|
||||
.from(Column::BakeryId)
|
||||
.to(super::bakery::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
Self::Lineitem => Entity::has_many(super::lineitem::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
|
@ -1,74 +1,32 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"cakes_bakers"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "cakes_bakers")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub cake_id: i32,
|
||||
#[sea_orm(primary_key)]
|
||||
pub baker_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
CakeId,
|
||||
BakerId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
CakeId,
|
||||
BakerId,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = (i32, i32);
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::cake::Entity",
|
||||
from = "Column::CakeId",
|
||||
to = "super::cake::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Cake,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::baker::Entity",
|
||||
from = "Column::BakerId",
|
||||
to = "super::baker::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Baker,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::CakeId => ColumnType::Integer.def(),
|
||||
Self::BakerId => ColumnType::Integer.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Cake => Entity::belongs_to(super::cake::Entity)
|
||||
.from(Column::CakeId)
|
||||
.to(super::cake::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
Self::Baker => Entity::belongs_to(super::baker::Entity)
|
||||
.from(Column::BakerId)
|
||||
.to(super::baker::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
@ -1,66 +1,21 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"customer"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "customer")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
#[sea_orm(column_type = "Text", nullable)]
|
||||
pub notes: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Name,
|
||||
Notes,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(has_many = "super::order::Entity")]
|
||||
Order,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Name => ColumnType::String(None).def(),
|
||||
Self::Notes => ColumnType::Text.def().null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Order => Entity::has_many(super::order::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::order::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Order.def()
|
||||
|
@ -1,84 +1,37 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"lineitem"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "lineitem")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||
pub price: Decimal,
|
||||
pub quantity: i32,
|
||||
pub order_id: i32,
|
||||
pub cake_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Price,
|
||||
Quantity,
|
||||
OrderId,
|
||||
CakeId,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::order::Entity",
|
||||
from = "Column::OrderId",
|
||||
to = "super::order::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Order,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::cake::Entity",
|
||||
from = "Column::CakeId",
|
||||
to = "super::cake::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Cake,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Price => ColumnType::Decimal(Some((19, 4))).def(),
|
||||
Self::Quantity => ColumnType::Integer.def(),
|
||||
Self::OrderId => ColumnType::Integer.def(),
|
||||
Self::CakeId => ColumnType::Integer.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Order => Entity::belongs_to(super::order::Entity)
|
||||
.from(Column::OrderId)
|
||||
.to(super::order::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
Self::Cake => Entity::belongs_to(super::cake::Entity)
|
||||
.from(Column::CakeId)
|
||||
.to(super::cake::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::order::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Order.def()
|
||||
|
@ -1,57 +1,18 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"metadata"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "metadata")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub uuid: Uuid,
|
||||
pub key: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Uuid,
|
||||
Key,
|
||||
Value,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||
pub enum PrimaryKey {
|
||||
Uuid,
|
||||
}
|
||||
|
||||
impl PrimaryKeyTrait for PrimaryKey {
|
||||
type ValueType = Uuid;
|
||||
|
||||
fn auto_increment() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Uuid => ColumnType::Uuid.def(),
|
||||
Self::Key => ColumnType::String(None).def(),
|
||||
Self::Value => ColumnType::String(None).def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
unreachable!()
|
||||
|
@ -1,86 +1,39 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||
pub struct Entity;
|
||||
|
||||
impl EntityName for Entity {
|
||||
fn table_name(&self) -> &str {
|
||||
"order"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "order")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||
pub total: Decimal,
|
||||
pub bakery_id: i32,
|
||||
pub customer_id: i32,
|
||||
pub placed_at: DateTime,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
pub enum Column {
|
||||
Id,
|
||||
Total,
|
||||
BakeryId,
|
||||
CustomerId,
|
||||
PlacedAt,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::bakery::Entity",
|
||||
from = "Column::BakeryId",
|
||||
to = "super::bakery::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Bakery,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::customer::Entity",
|
||||
from = "Column::CustomerId",
|
||||
to = "super::customer::Column::Id",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Customer,
|
||||
#[sea_orm(has_many = "super::lineitem::Entity")]
|
||||
Lineitem,
|
||||
}
|
||||
|
||||
impl ColumnTrait for Column {
|
||||
type EntityName = Entity;
|
||||
|
||||
fn def(&self) -> ColumnDef {
|
||||
match self {
|
||||
Self::Id => ColumnType::Integer.def(),
|
||||
Self::Total => ColumnType::Decimal(Some((19, 4))).def(),
|
||||
Self::BakeryId => ColumnType::Integer.def(),
|
||||
Self::CustomerId => ColumnType::Integer.def(),
|
||||
Self::PlacedAt => ColumnType::DateTime.def(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RelationTrait for Relation {
|
||||
fn def(&self) -> RelationDef {
|
||||
match self {
|
||||
Self::Bakery => Entity::belongs_to(super::bakery::Entity)
|
||||
.from(Column::BakeryId)
|
||||
.to(super::bakery::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
Self::Customer => Entity::belongs_to(super::customer::Entity)
|
||||
.from(Column::CustomerId)
|
||||
.to(super::customer::Column::Id)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.into(),
|
||||
Self::Lineitem => Entity::has_many(super::lineitem::Entity).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::bakery::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Bakery.def()
|
||||
|
@ -6,8 +6,9 @@ pub use crud::*;
|
||||
use sea_orm::DatabaseConnection;
|
||||
|
||||
// Run the test locally:
|
||||
// DATABASE_URL="mysql://root:root@localhost" cargo test --features sqlx-mysql,runtime-async-std --test crud_tests
|
||||
// DATABASE_URL="postgres://root:root@localhost" cargo test --features sqlx-postgres,runtime-async-std --test crud_tests
|
||||
// DATABASE_URL="sqlite::memory:" cargo test --features sqlx-sqlite,runtime-async-std-native-tls --test crud_tests
|
||||
// DATABASE_URL="mysql://root:root@localhost" cargo test --features sqlx-mysql,runtime-async-std-native-tls --test crud_tests
|
||||
// DATABASE_URL="postgres://root:root@localhost" cargo test --features sqlx-postgres,runtime-async-std-native-tls --test crud_tests
|
||||
#[sea_orm_macros::test]
|
||||
#[cfg(any(
|
||||
feature = "sqlx-mysql",
|
||||
|
Loading…
x
Reference in New Issue
Block a user