Add proc_macro
This commit is contained in:
parent
dc4bb3075f
commit
07b58551af
@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
".",
|
".",
|
||||||
|
"sea-orm-macros",
|
||||||
"examples/sqlx-mysql",
|
"examples/sqlx-mysql",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ path = "src/lib.rs"
|
|||||||
async-trait = "^0.1"
|
async-trait = "^0.1"
|
||||||
futures = { version = "^0.3" }
|
futures = { version = "^0.3" }
|
||||||
sea-query = { path = "../sea-query", version = "^0.10", features = [ "sqlx-mysql" ] }
|
sea-query = { path = "../sea-query", version = "^0.10", features = [ "sqlx-mysql" ] }
|
||||||
|
sea-orm-macros = { path = "sea-orm-macros", optional = true }
|
||||||
# sea-schema = { path = "../sea-schema" }
|
# sea-schema = { path = "../sea-schema" }
|
||||||
serde = { version = "^1.0", features = [ "derive" ] }
|
serde = { version = "^1.0", features = [ "derive" ] }
|
||||||
sqlx = { version = "^0.5", optional = true }
|
sqlx = { version = "^0.5", optional = true }
|
||||||
@ -32,7 +34,7 @@ strum = { version = "^0.20", features = [ "derive" ] }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug-print = []
|
debug-print = []
|
||||||
default = [ "sqlx-mysql", "runtime-async-std-native-tls" ]
|
default = [ "macros", "sqlx-mysql", "runtime-async-std-native-tls" ]
|
||||||
sqlx-dep = [ "sqlx" ]
|
sqlx-dep = [ "sqlx" ]
|
||||||
sqlx-mysql = [ "sqlx-dep", "sea-query/sqlx-mysql", "sqlx/mysql" ]
|
sqlx-mysql = [ "sqlx-dep", "sea-query/sqlx-mysql", "sqlx/mysql" ]
|
||||||
sqlx-postgres = [ "sqlx-dep", "sea-query/sqlx-postgres", "sqlx/postgres" ]
|
sqlx-postgres = [ "sqlx-dep", "sea-query/sqlx-postgres", "sqlx/postgres" ]
|
||||||
@ -42,3 +44,4 @@ runtime-tokio-native-tls = [ "sqlx/runtime-tokio-native-tls" ]
|
|||||||
runtime-actix-rustls = [ "sqlx/runtime-actix-rustls" ]
|
runtime-actix-rustls = [ "sqlx/runtime-actix-rustls" ]
|
||||||
runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls" ]
|
runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls" ]
|
||||||
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls" ]
|
runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls" ]
|
||||||
|
macros = [ "sea-orm-macros" ]
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
#[entity = "cake"]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq, DeriveModel)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
pub enum Column {
|
pub enum Column {
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
pub enum PrimaryKey {
|
pub enum PrimaryKey {
|
||||||
Id,
|
Id,
|
||||||
}
|
}
|
||||||
@ -25,16 +26,6 @@ pub enum Relation {
|
|||||||
Fruit,
|
Fruit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityTrait for Entity {
|
|
||||||
type Model = Model;
|
|
||||||
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
type PrimaryKey = PrimaryKey;
|
|
||||||
|
|
||||||
type Relation = Relation;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColumnTrait for Column {
|
impl ColumnTrait for Column {
|
||||||
type EntityName = Entity;
|
type EntityName = Entity;
|
||||||
|
|
||||||
@ -68,91 +59,3 @@ impl Model {
|
|||||||
Entity::find_related().belongs_to::<Entity>(self)
|
Entity::find_related().belongs_to::<Entity>(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl EntityName for Entity {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Entity {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
"cake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Entity {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl ModelTrait for Model {
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
fn get(&self, c: Self::Column) -> Value {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id.clone().into(),
|
|
||||||
Column::Name => self.name.clone().into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, c: Self::Column, v: Value) {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id = v.unwrap(),
|
|
||||||
Column::Name => self.name = v.unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query_result(row: &QueryResult, pre: &str) -> Result<Self, TypeErr> {
|
|
||||||
Ok(Self {
|
|
||||||
id: row.try_get(pre, Column::Id.as_str())?,
|
|
||||||
name: row.try_get(pre, Column::Name.as_str())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Column {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Column {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
Self::Name => "name",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for PrimaryKey {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for PrimaryKey {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyTrait for PrimaryKey {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyOfModel<Model> for PrimaryKey {
|
|
||||||
fn into_column(self) -> <Model as ModelTrait>::Column {
|
|
||||||
match self {
|
|
||||||
Self::Id => Column::Id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
#[entity = "fruit"]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq, DeriveModel)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
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)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
pub enum Column {
|
pub enum Column {
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
CakeId,
|
CakeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
pub enum PrimaryKey {
|
pub enum PrimaryKey {
|
||||||
Id,
|
Id,
|
||||||
}
|
}
|
||||||
@ -25,16 +26,6 @@ pub enum PrimaryKey {
|
|||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
impl EntityTrait for Entity {
|
|
||||||
type Model = Model;
|
|
||||||
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
type PrimaryKey = PrimaryKey;
|
|
||||||
|
|
||||||
type Relation = Relation;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColumnTrait for Column {
|
impl ColumnTrait for Column {
|
||||||
type EntityName = Entity;
|
type EntityName = Entity;
|
||||||
|
|
||||||
@ -52,95 +43,3 @@ impl RelationTrait for Relation {
|
|||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl EntityName for Entity {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Entity {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
"fruit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Entity {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl ModelTrait for Model {
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
fn get(&self, c: Self::Column) -> Value {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id.clone().into(),
|
|
||||||
Column::Name => self.name.clone().into(),
|
|
||||||
Column::CakeId => self.cake_id.clone().into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, c: Self::Column, v: Value) {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id = v.unwrap(),
|
|
||||||
Column::Name => self.name = v.unwrap(),
|
|
||||||
Column::CakeId => self.cake_id = v.unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query_result(row: &QueryResult, pre: &str) -> Result<Self, TypeErr> {
|
|
||||||
Ok(Self {
|
|
||||||
id: row.try_get(pre, Column::Id.as_str())?,
|
|
||||||
name: row.try_get(pre, Column::Name.as_str())?,
|
|
||||||
cake_id: row.try_get(pre, Column::CakeId.as_str())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Column {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Column {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
Self::Name => "name",
|
|
||||||
Self::CakeId => "cake_id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for PrimaryKey {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for PrimaryKey {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyTrait for PrimaryKey {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyOfModel<Model> for PrimaryKey {
|
|
||||||
fn into_column(self) -> <Model as ModelTrait>::Column {
|
|
||||||
match self {
|
|
||||||
Self::Id => Column::Id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
23
sea-orm-macros/Cargo.toml
Normal file
23
sea-orm-macros/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "sea-orm-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
||||||
|
edition = "2018"
|
||||||
|
description = ""
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
documentation = "https://docs.rs/sea-orm"
|
||||||
|
repository = "https://github.com/SeaQL/sea-orm"
|
||||||
|
categories = [ "database" ]
|
||||||
|
keywords = [ "orm", "database", "sql", "mysql", "postgres", "sqlite" ]
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "sea_orm_macros"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = { version = "1", default-features = false, features = [ "derive", "parsing", "proc-macro", "printing" ] }
|
||||||
|
quote = "1"
|
||||||
|
heck = "0.3"
|
||||||
|
proc-macro2 = "1"
|
48
sea-orm-macros/src/derives/column.rs
Normal file
48
sea-orm-macros/src/derives/column.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use heck::SnakeCase;
|
||||||
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
use syn::{Data, DataEnum, Fields, Variant};
|
||||||
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
|
pub fn expend_derive_column(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||||
|
let variants = match data {
|
||||||
|
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
||||||
|
_ => return Ok(quote_spanned! {
|
||||||
|
ident.span() => compile_error!("you can only derive DeriveColumn on enums");
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let variant: Vec<TokenStream> = variants
|
||||||
|
.iter()
|
||||||
|
.map(|Variant { ident, fields, .. }| {
|
||||||
|
match fields {
|
||||||
|
Fields::Named(_) => quote! { #ident{..} },
|
||||||
|
Fields::Unnamed(_) => quote! { #ident(..) },
|
||||||
|
Fields::Unit => quote! { #ident },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let name: Vec<TokenStream> = variants
|
||||||
|
.iter()
|
||||||
|
.map(|v| {
|
||||||
|
let ident = v.ident.to_string().to_snake_case();
|
||||||
|
quote! { #ident }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(quote!(
|
||||||
|
impl Iden for #ident {
|
||||||
|
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
||||||
|
write!(s, "{}", self.as_str()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdenStatic for #ident {
|
||||||
|
fn as_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
#(Self::#variant => #name),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
53
sea-orm-macros/src/derives/entity.rs
Normal file
53
sea-orm-macros/src/derives/entity.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use heck::SnakeCase;
|
||||||
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
use syn::{Attribute, Meta};
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
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("entity") {
|
||||||
|
return Some(name_value.lit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expend_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 EntityName for #ident {}
|
||||||
|
|
||||||
|
impl IdenStatic for #ident {
|
||||||
|
fn as_str(&self) -> &str {
|
||||||
|
#entity_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iden for #ident {
|
||||||
|
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
||||||
|
write!(s, "{}", self.as_str()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntityTrait for #ident {
|
||||||
|
type Model = Model;
|
||||||
|
|
||||||
|
type Column = Column;
|
||||||
|
|
||||||
|
type PrimaryKey = PrimaryKey;
|
||||||
|
|
||||||
|
type Relation = Relation;
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
9
sea-orm-macros/src/derives/mod.rs
Normal file
9
sea-orm-macros/src/derives/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
mod entity;
|
||||||
|
mod primary_key;
|
||||||
|
mod column;
|
||||||
|
mod model;
|
||||||
|
|
||||||
|
pub use entity::*;
|
||||||
|
pub use primary_key::*;
|
||||||
|
pub use column::*;
|
||||||
|
pub use model::*;
|
57
sea-orm-macros/src/derives/model.rs
Normal file
57
sea-orm-macros/src/derives/model.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use heck::CamelCase;
|
||||||
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
use syn::{Data, DataStruct, Field, Fields};
|
||||||
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
|
|
||||||
|
pub fn expend_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 ModelTrait for #ident {
|
||||||
|
type Column = Column;
|
||||||
|
|
||||||
|
fn get(&self, c: Self::Column) -> Value {
|
||||||
|
match c {
|
||||||
|
#(Self::Column::#name => self.#field.clone().into()),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, c: Self::Column, v: Value) {
|
||||||
|
match c {
|
||||||
|
#(Self::Column::#name => self.#field = v.unwrap()),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_query_result(row: &QueryResult, pre: &str) -> Result<Self, TypeErr> {
|
||||||
|
Ok(Self {
|
||||||
|
#(#field: row.try_get(pre, Self::Column::#name.as_str().into())?),*
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
58
sea-orm-macros/src/derives/primary_key.rs
Normal file
58
sea-orm-macros/src/derives/primary_key.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use heck::SnakeCase;
|
||||||
|
use proc_macro2::{Ident, TokenStream};
|
||||||
|
use syn::{Data, DataEnum, Fields, Variant};
|
||||||
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
|
pub fn expend_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
|
||||||
|
let variants = match data {
|
||||||
|
syn::Data::Enum(DataEnum { variants, .. }) => variants,
|
||||||
|
_ => return Ok(quote_spanned! {
|
||||||
|
ident.span() => compile_error!("you can only derive DerivePrimaryKey on enums");
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let variant: Vec<TokenStream> = variants
|
||||||
|
.iter()
|
||||||
|
.map(|Variant { ident, fields, .. }| {
|
||||||
|
match fields {
|
||||||
|
Fields::Named(_) => quote! { #ident{..} },
|
||||||
|
Fields::Unnamed(_) => quote! { #ident(..) },
|
||||||
|
Fields::Unit => quote! { #ident },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let name: Vec<TokenStream> = variants
|
||||||
|
.iter()
|
||||||
|
.map(|v| {
|
||||||
|
let ident = v.ident.to_string().to_snake_case();
|
||||||
|
quote! { #ident }
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(quote!(
|
||||||
|
impl Iden for #ident {
|
||||||
|
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
||||||
|
write!(s, "{}", self.as_str()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdenStatic for #ident {
|
||||||
|
fn as_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
#(Self::#variant => #name),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimaryKeyTrait for #ident {}
|
||||||
|
|
||||||
|
impl PrimaryKeyOfModel<Model> for #ident {
|
||||||
|
fn into_column(self) -> <Model as ModelTrait>::Column {
|
||||||
|
match self {
|
||||||
|
#(Self::#variant => Column::#variant),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
54
sea-orm-macros/src/lib.rs
Normal file
54
sea-orm-macros/src/lib.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use syn::{DeriveInput, parse_macro_input};
|
||||||
|
|
||||||
|
mod derives;
|
||||||
|
|
||||||
|
#[proc_macro_derive(DeriveEntity, attributes(entity))]
|
||||||
|
pub fn derive_entity(input: TokenStream) -> TokenStream {
|
||||||
|
let DeriveInput {
|
||||||
|
ident, attrs, ..
|
||||||
|
} = parse_macro_input!(input);
|
||||||
|
|
||||||
|
match derives::expend_derive_entity(ident, attrs) {
|
||||||
|
Ok(ts) => ts.into(),
|
||||||
|
Err(e) => e.to_compile_error().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(DerivePrimaryKey)]
|
||||||
|
pub fn derive_primary_key(input: TokenStream) -> TokenStream {
|
||||||
|
let DeriveInput {
|
||||||
|
ident, data, ..
|
||||||
|
} = parse_macro_input!(input);
|
||||||
|
|
||||||
|
match derives::expend_derive_primary_key(ident, data) {
|
||||||
|
Ok(ts) => ts.into(),
|
||||||
|
Err(e) => e.to_compile_error().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(DeriveColumn)]
|
||||||
|
pub fn derive_column(input: TokenStream) -> TokenStream {
|
||||||
|
let DeriveInput {
|
||||||
|
ident, data, ..
|
||||||
|
} = parse_macro_input!(input);
|
||||||
|
|
||||||
|
match derives::expend_derive_column(ident, data) {
|
||||||
|
Ok(ts) => ts.into(),
|
||||||
|
Err(e) => e.to_compile_error().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(DeriveModel)]
|
||||||
|
pub fn derive_model(input: TokenStream) -> TokenStream {
|
||||||
|
let DeriveInput {
|
||||||
|
ident, data, ..
|
||||||
|
} = parse_macro_input!(input);
|
||||||
|
|
||||||
|
match derives::expend_derive_model(ident, data) {
|
||||||
|
Ok(ts) => ts.into(),
|
||||||
|
Err(e) => e.to_compile_error().into(),
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
ColumnTrait, ColumnType, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait,
|
ColumnTrait, ColumnType, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait,
|
||||||
PrimaryKeyOfModel, PrimaryKeyTrait, QueryResult, Related, RelationDef, RelationTrait, Select,
|
PrimaryKeyOfModel, PrimaryKeyTrait, QueryResult, Related, RelationDef, RelationTrait, Select,
|
||||||
TypeErr, Value,
|
TypeErr, Value, DeriveEntity, DerivePrimaryKey, DeriveColumn, DeriveModel,
|
||||||
};
|
};
|
||||||
|
@ -15,3 +15,9 @@ pub use query::*;
|
|||||||
pub use sea_query;
|
pub use sea_query;
|
||||||
pub use sea_query::Iden;
|
pub use sea_query::Iden;
|
||||||
pub use strum::EnumIter;
|
pub use strum::EnumIter;
|
||||||
|
pub use sea_orm_macros::{
|
||||||
|
DeriveEntity,
|
||||||
|
DerivePrimaryKey,
|
||||||
|
DeriveColumn,
|
||||||
|
DeriveModel,
|
||||||
|
};
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
use crate::entity::prelude::*;
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
#[entity = "cake"]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq, DeriveModel)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
pub enum Column {
|
pub enum Column {
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
pub enum PrimaryKey {
|
pub enum PrimaryKey {
|
||||||
Id,
|
Id,
|
||||||
}
|
}
|
||||||
@ -25,16 +26,6 @@ pub enum Relation {
|
|||||||
Fruit,
|
Fruit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityTrait for Entity {
|
|
||||||
type Model = Model;
|
|
||||||
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
type PrimaryKey = PrimaryKey;
|
|
||||||
|
|
||||||
type Relation = Relation;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColumnTrait for Column {
|
impl ColumnTrait for Column {
|
||||||
type EntityName = Entity;
|
type EntityName = Entity;
|
||||||
|
|
||||||
@ -68,91 +59,3 @@ impl Model {
|
|||||||
Entity::find_related().belongs_to::<Entity>(self)
|
Entity::find_related().belongs_to::<Entity>(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl EntityName for Entity {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Entity {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
"cake"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Entity {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl ModelTrait for Model {
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
fn get(&self, c: Self::Column) -> Value {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id.clone().into(),
|
|
||||||
Column::Name => self.name.clone().into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, c: Self::Column, v: Value) {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id = v.unwrap(),
|
|
||||||
Column::Name => self.name = v.unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query_result(row: &QueryResult, pre: &str) -> Result<Self, TypeErr> {
|
|
||||||
Ok(Self {
|
|
||||||
id: row.try_get(pre, Column::Id.as_str())?,
|
|
||||||
name: row.try_get(pre, Column::Name.as_str())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Column {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Column {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
Self::Name => "name",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for PrimaryKey {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for PrimaryKey {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyTrait for PrimaryKey {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyOfModel<Model> for PrimaryKey {
|
|
||||||
fn into_column(self) -> <Model as ModelTrait>::Column {
|
|
||||||
match self {
|
|
||||||
Self::Id => Column::Id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
use crate::entity::prelude::*;
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
|
||||||
|
#[entity = "fruit"]
|
||||||
pub struct Entity;
|
pub struct Entity;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq, DeriveModel)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
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)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
pub enum Column {
|
pub enum Column {
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
CakeId,
|
CakeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
|
||||||
pub enum PrimaryKey {
|
pub enum PrimaryKey {
|
||||||
Id,
|
Id,
|
||||||
}
|
}
|
||||||
@ -25,16 +26,6 @@ pub enum PrimaryKey {
|
|||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
impl EntityTrait for Entity {
|
|
||||||
type Model = Model;
|
|
||||||
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
type PrimaryKey = PrimaryKey;
|
|
||||||
|
|
||||||
type Relation = Relation;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColumnTrait for Column {
|
impl ColumnTrait for Column {
|
||||||
type EntityName = Entity;
|
type EntityName = Entity;
|
||||||
|
|
||||||
@ -52,95 +43,3 @@ impl RelationTrait for Relation {
|
|||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl EntityName for Entity {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Entity {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
"fruit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Entity {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl ModelTrait for Model {
|
|
||||||
type Column = Column;
|
|
||||||
|
|
||||||
fn get(&self, c: Self::Column) -> Value {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id.clone().into(),
|
|
||||||
Column::Name => self.name.clone().into(),
|
|
||||||
Column::CakeId => self.cake_id.clone().into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, c: Self::Column, v: Value) {
|
|
||||||
match c {
|
|
||||||
Column::Id => self.id = v.unwrap(),
|
|
||||||
Column::Name => self.name = v.unwrap(),
|
|
||||||
Column::CakeId => self.cake_id = v.unwrap(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_query_result(row: &QueryResult, pre: &str) -> Result<Self, TypeErr> {
|
|
||||||
Ok(Self {
|
|
||||||
id: row.try_get(pre, Column::Id.as_str())?,
|
|
||||||
name: row.try_get(pre, Column::Name.as_str())?,
|
|
||||||
cake_id: row.try_get(pre, Column::CakeId.as_str())?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for Column {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for Column {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
Self::Name => "name",
|
|
||||||
Self::CakeId => "cake_id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl Iden for PrimaryKey {
|
|
||||||
fn unquoted(&self, s: &mut dyn std::fmt::Write) {
|
|
||||||
write!(s, "{}", self.as_str()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl IdenStatic for PrimaryKey {
|
|
||||||
fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Id => "id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyTrait for PrimaryKey {}
|
|
||||||
|
|
||||||
// TODO: implement with derive macro
|
|
||||||
impl PrimaryKeyOfModel<Model> for PrimaryKey {
|
|
||||||
fn into_column(self) -> <Model as ModelTrait>::Column {
|
|
||||||
match self {
|
|
||||||
Self::Id => Column::Id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user