commit
eca3949ea9
@ -1,55 +1,18 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "cake")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"cake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
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)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
Fruit,
|
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 {
|
impl RelationTrait for Relation {
|
||||||
fn def(&self) -> RelationDef {
|
fn def(&self) -> RelationDef {
|
||||||
match self {
|
match self {
|
||||||
|
@ -16,7 +16,9 @@ path = "src/lib.rs"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
quote = "^1"
|
||||||
heck = "^0.3"
|
heck = "^0.3"
|
||||||
proc-macro2 = "^1"
|
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 {
|
fn default() -> Self {
|
||||||
<Self as sea_orm::ActiveModelBehavior>::new()
|
<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 {
|
fn from(m: <Entity as EntityTrait>::Model) -> Self {
|
||||||
Self {
|
Self {
|
||||||
#(#field: sea_orm::unchanged_active_value_not_intended_for_public_use(m.#field)),*
|
#(#field: sea_orm::unchanged_active_value_not_intended_for_public_use(m.#field)),*
|
||||||
|
@ -1,51 +1,135 @@
|
|||||||
use heck::SnakeCase;
|
use std::iter::FromIterator;
|
||||||
use proc_macro2::{Ident, TokenStream};
|
|
||||||
use quote::quote;
|
|
||||||
use syn::{Attribute, Meta};
|
|
||||||
|
|
||||||
fn get_entity_attr(attrs: &[Attribute]) -> Option<syn::Lit> {
|
use proc_macro2::TokenStream;
|
||||||
for attr in attrs {
|
use quote::{format_ident, quote};
|
||||||
let name_value = match attr.parse_meta() {
|
|
||||||
Ok(Meta::NameValue(nv)) => nv,
|
use crate::attributes::derive_attr;
|
||||||
_ => continue,
|
|
||||||
};
|
struct DeriveEntity {
|
||||||
if name_value.path.is_ident("table") {
|
column_ident: syn::Ident,
|
||||||
return Some(name_value.lit);
|
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> {
|
pub fn expand_derive_entity(input: syn::DeriveInput) -> syn::Result<TokenStream> {
|
||||||
let _entity_name = match get_entity_attr(&attrs) {
|
Ok(DeriveEntity::new(input)?.expand())
|
||||||
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;
|
|
||||||
}
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
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 active_model_behavior;
|
||||||
mod column;
|
mod column;
|
||||||
mod entity;
|
mod entity;
|
||||||
|
mod entity_model;
|
||||||
mod from_query_result;
|
mod from_query_result;
|
||||||
mod model;
|
mod model;
|
||||||
mod primary_key;
|
mod primary_key;
|
||||||
|
mod relation;
|
||||||
|
|
||||||
pub use active_model::*;
|
pub use active_model::*;
|
||||||
pub use active_model_behavior::*;
|
pub use active_model_behavior::*;
|
||||||
pub use column::*;
|
pub use column::*;
|
||||||
pub use entity::*;
|
pub use entity::*;
|
||||||
|
pub use entity_model::*;
|
||||||
pub use from_query_result::*;
|
pub use from_query_result::*;
|
||||||
pub use model::*;
|
pub use model::*;
|
||||||
pub use primary_key::*;
|
pub use primary_key::*;
|
||||||
|
pub use relation::*;
|
||||||
|
@ -1,57 +1,125 @@
|
|||||||
|
use crate::attributes::derive_attr;
|
||||||
use heck::CamelCase;
|
use heck::CamelCase;
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, quote_spanned};
|
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> {
|
enum Error {
|
||||||
let fields = match data {
|
InputNotStruct,
|
||||||
Data::Struct(DataStruct {
|
Syn(syn::Error),
|
||||||
fields: Fields::Named(named),
|
}
|
||||||
..
|
|
||||||
}) => named.named,
|
struct DeriveModel {
|
||||||
_ => {
|
column_idents: Vec<syn::Ident>,
|
||||||
return Ok(quote_spanned! {
|
entity_ident: syn::Ident,
|
||||||
ident.span() => compile_error!("you can only derive DeriveModel on structs");
|
field_idents: Vec<syn::Ident>,
|
||||||
})
|
ident: syn::Ident,
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
impl DeriveModel {
|
||||||
let field: Vec<Ident> = fields
|
fn new(input: syn::DeriveInput) -> Result<Self, Error> {
|
||||||
.clone()
|
let fields = match input.data {
|
||||||
.into_iter()
|
syn::Data::Struct(syn::DataStruct {
|
||||||
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string()))
|
fields: syn::Fields::Named(syn::FieldsNamed { named, .. }),
|
||||||
.collect();
|
..
|
||||||
|
}) => named,
|
||||||
let name: Vec<Ident> = fields
|
_ => return Err(Error::InputNotStruct),
|
||||||
.into_iter()
|
};
|
||||||
.map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string().to_camel_case()))
|
|
||||||
.collect();
|
let sea_attr = derive_attr::SeaOrm::try_from_attributes(&input.attrs)
|
||||||
|
.map_err(Error::Syn)?
|
||||||
Ok(quote!(
|
.unwrap_or_default();
|
||||||
impl sea_orm::ModelTrait for #ident {
|
|
||||||
type Entity = Entity;
|
let ident = input.ident;
|
||||||
|
let entity_ident = sea_attr.entity.unwrap_or_else(|| format_ident!("Entity"));
|
||||||
fn get(&self, c: <Self::Entity as EntityTrait>::Column) -> sea_orm::Value {
|
|
||||||
match c {
|
let field_idents = fields
|
||||||
#(<Self::Entity as EntityTrait>::Column::#name => self.#field.clone().into(),)*
|
.iter()
|
||||||
_ => panic!("This Model does not have this field"),
|
.map(|field| field.ident.as_ref().unwrap().clone())
|
||||||
}
|
.collect();
|
||||||
}
|
|
||||||
|
let column_idents = fields
|
||||||
fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: sea_orm::Value) {
|
.iter()
|
||||||
match c {
|
.map(|field| {
|
||||||
#(<Self::Entity as EntityTrait>::Column::#name => self.#field = v.unwrap(),)*
|
format_ident!(
|
||||||
_ => panic!("This Model does not have this field"),
|
"{}",
|
||||||
}
|
field.ident.as_ref().unwrap().to_string().to_camel_case()
|
||||||
}
|
)
|
||||||
}
|
})
|
||||||
|
.collect();
|
||||||
impl sea_orm::FromQueryResult for #ident {
|
|
||||||
fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result<Self, sea_orm::DbErr> {
|
Ok(DeriveModel {
|
||||||
Ok(Self {
|
column_idents,
|
||||||
#(#field: row.try_get(pre, <<Self as ModelTrait>::Entity as EntityTrait>::Column::#name.as_str().into())?),*
|
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;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use syn::{parse_macro_input, DeriveInput};
|
use syn::{parse_macro_input, DeriveInput, Error};
|
||||||
|
|
||||||
|
mod attributes;
|
||||||
mod derives;
|
mod derives;
|
||||||
|
|
||||||
#[proc_macro_derive(DeriveEntity, attributes(table))]
|
#[proc_macro_derive(DeriveEntity, attributes(sea_orm))]
|
||||||
pub fn derive_entity(input: TokenStream) -> TokenStream {
|
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) {
|
#[proc_macro_derive(DeriveEntityModel, attributes(sea_orm))]
|
||||||
Ok(ts) => ts.into(),
|
pub fn derive_entity_model(input: TokenStream) -> TokenStream {
|
||||||
Err(e) => e.to_compile_error().into(),
|
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)]
|
#[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 {
|
pub fn derive_model(input: TokenStream) -> TokenStream {
|
||||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
derives::expand_derive_model(input)
|
||||||
match derives::expand_derive_model(ident, data) {
|
.unwrap_or_else(Error::into_compile_error)
|
||||||
Ok(ts) => ts.into(),
|
.into()
|
||||||
Err(e) => e.to_compile_error().into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(DeriveActiveModel)]
|
#[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)]
|
#[doc(hidden)]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
|
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 ret = &input.sig.output;
|
||||||
let name = &input.sig.ident;
|
let name = &input.sig.ident;
|
||||||
|
@ -248,7 +248,11 @@ impl ColumnDef {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn null(mut self) -> Self {
|
pub fn null(self) -> Self {
|
||||||
|
self.nullable()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nullable(mut self) -> Self {
|
||||||
self.null = true;
|
self.null = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType,
|
error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType,
|
||||||
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
||||||
DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, ForeignKeyAction, Iden,
|
DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, EntityName, EntityTrait,
|
||||||
IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult,
|
EnumIter, ForeignKeyAction, Iden, IdenStatic, Linked, ModelTrait, PrimaryKeyToColumn,
|
||||||
Related, RelationDef, RelationTrait, Select, Value,
|
PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "with-json")]
|
#[cfg(feature = "with-json")]
|
||||||
|
@ -229,7 +229,7 @@ pub use schema::*;
|
|||||||
|
|
||||||
pub use sea_orm_macros::{
|
pub use sea_orm_macros::{
|
||||||
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity,
|
||||||
DeriveModel, DerivePrimaryKey, FromQueryResult,
|
DeriveEntityModel, DeriveModel, DerivePrimaryKey, DeriveRelation, FromQueryResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use sea_query;
|
pub use sea_query;
|
||||||
|
@ -1,64 +1,20 @@
|
|||||||
use crate as sea_orm;
|
use crate as sea_orm;
|
||||||
use crate::entity::prelude::*;
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "cake")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"cake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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 {
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::fruit::Entity")]
|
||||||
Fruit,
|
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 {
|
impl Related<super::fruit::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Fruit.def()
|
Relation::Fruit.def()
|
||||||
|
@ -2,14 +2,9 @@ use crate as sea_orm;
|
|||||||
use crate::entity::prelude::*;
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
#[sea_orm(table_name = "filling")]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"filling"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
@ -1,70 +1,25 @@
|
|||||||
use crate as sea_orm;
|
use crate as sea_orm;
|
||||||
use crate::entity::prelude::*;
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "fruit")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"fruit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cake_id: Option<i32>,
|
pub cake_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::cake::Entity",
|
||||||
|
from = "Column::CakeId",
|
||||||
|
to = "super::cake::Column::Id"
|
||||||
|
)]
|
||||||
Cake,
|
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 {
|
impl Related<super::cake::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Cake.def()
|
Relation::Cake.def()
|
||||||
|
@ -2,7 +2,7 @@ pub mod common;
|
|||||||
|
|
||||||
pub use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, Database, DbConn};
|
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]
|
#[sea_orm_macros::test]
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
@ -1,74 +1,27 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "baker")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"baker"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub contact_details: Json,
|
pub contact_details: Json,
|
||||||
pub bakery_id: Option<i32>,
|
pub bakery_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
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,
|
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 {
|
impl Related<super::bakery::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Bakery.def()
|
Relation::Bakery.def()
|
||||||
|
@ -1,70 +1,24 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "bakery")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"bakery"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub profit_margin: f64,
|
pub profit_margin: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::baker::Entity")]
|
||||||
Baker,
|
Baker,
|
||||||
|
#[sea_orm(has_many = "super::order::Entity")]
|
||||||
Order,
|
Order,
|
||||||
|
#[sea_orm(has_many = "super::cake::Entity")]
|
||||||
Cake,
|
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 {
|
impl Related<super::baker::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Baker.def()
|
Relation::Baker.def()
|
||||||
|
@ -1,82 +1,32 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "cake")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"cake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||||
pub price: Decimal,
|
pub price: Decimal,
|
||||||
pub bakery_id: Option<i32>,
|
pub bakery_id: Option<i32>,
|
||||||
pub gluten_free: bool,
|
pub gluten_free: bool,
|
||||||
pub serial: Uuid,
|
pub serial: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
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,
|
Bakery,
|
||||||
|
#[sea_orm(has_many = "super::lineitem::Entity")]
|
||||||
Lineitem,
|
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 {
|
impl Related<super::bakery::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Bakery.def()
|
Relation::Bakery.def()
|
||||||
|
@ -1,74 +1,32 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "cakes_bakers")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"cakes_bakers"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub cake_id: i32,
|
pub cake_id: i32,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub baker_id: i32,
|
pub baker_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
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,
|
Cake,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::baker::Entity",
|
||||||
|
from = "Column::BakerId",
|
||||||
|
to = "super::baker::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
Baker,
|
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 {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
@ -1,66 +1,21 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "customer")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"customer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[sea_orm(column_type = "Text", nullable)]
|
||||||
pub notes: Option<String>,
|
pub notes: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::order::Entity")]
|
||||||
Order,
|
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 {
|
impl Related<super::order::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Order.def()
|
Relation::Order.def()
|
||||||
|
@ -1,84 +1,37 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "lineitem")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"lineitem"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||||
pub price: Decimal,
|
pub price: Decimal,
|
||||||
pub quantity: i32,
|
pub quantity: i32,
|
||||||
pub order_id: i32,
|
pub order_id: i32,
|
||||||
pub cake_id: i32,
|
pub cake_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
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,
|
Order,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::cake::Entity",
|
||||||
|
from = "Column::CakeId",
|
||||||
|
to = "super::cake::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
Cake,
|
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 {
|
impl Related<super::order::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Order.def()
|
Relation::Order.def()
|
||||||
|
@ -1,57 +1,18 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "metadata")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"metadata"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
pub value: 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)]
|
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
pub enum Relation {}
|
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 {
|
impl RelationTrait for Relation {
|
||||||
fn def(&self) -> RelationDef {
|
fn def(&self) -> RelationDef {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -1,86 +1,39 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
pub struct Entity;
|
#[sea_orm(table_name = "order")]
|
||||||
|
|
||||||
impl EntityName for Entity {
|
|
||||||
fn table_name(&self) -> &str {
|
|
||||||
"order"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
#[sea_orm(column_type = "Decimal(Some((19, 4)))")]
|
||||||
pub total: Decimal,
|
pub total: Decimal,
|
||||||
pub bakery_id: i32,
|
pub bakery_id: i32,
|
||||||
pub customer_id: i32,
|
pub customer_id: i32,
|
||||||
pub placed_at: DateTime,
|
pub placed_at: DateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
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)]
|
|
||||||
pub enum Relation {
|
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,
|
Bakery,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::customer::Entity",
|
||||||
|
from = "Column::CustomerId",
|
||||||
|
to = "super::customer::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
Customer,
|
Customer,
|
||||||
|
#[sea_orm(has_many = "super::lineitem::Entity")]
|
||||||
Lineitem,
|
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 {
|
impl Related<super::bakery::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Bakery.def()
|
Relation::Bakery.def()
|
||||||
|
@ -6,8 +6,9 @@ pub use crud::*;
|
|||||||
use sea_orm::DatabaseConnection;
|
use sea_orm::DatabaseConnection;
|
||||||
|
|
||||||
// Run the test locally:
|
// Run the test locally:
|
||||||
// DATABASE_URL="mysql://root:root@localhost" cargo test --features sqlx-mysql,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="postgres://root:root@localhost" cargo test --features sqlx-postgres,runtime-async-std --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]
|
#[sea_orm_macros::test]
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "sqlx-mysql",
|
feature = "sqlx-mysql",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user