Merge pull request #135 from SeaQL/entity-format

Entity format
This commit is contained in:
Chris Tsang 2021-09-10 12:55:05 +08:00 committed by GitHub
commit eca3949ea9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 884 additions and 734 deletions

View File

@ -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 {

View File

@ -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"

View 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>,
}
}

View File

@ -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)),*

View File

@ -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())
}

View 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
})
}

View File

@ -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::*;

View File

@ -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),
}
}

View 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),
}
}

View File

@ -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;

View File

@ -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
}

View File

@ -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")]

View File

@ -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;

View File

@ -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()

View File

@ -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,

View File

@ -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()

View File

@ -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() {

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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 {}

View File

@ -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()

View File

@ -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()

View File

@ -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!()

View File

@ -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()

View File

@ -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",