diff --git a/README.md b/README.md index 35a75e17..1197a4ce 100644 --- a/README.md +++ b/README.md @@ -49,4 +49,4 @@ Balance between compile-time checking and compilation speed. 3. Avoid 'symbol soup' -Avoid procedural macro if possible, use derive macro where appropriate. \ No newline at end of file +Avoid function-like macros with DSL, use derive macros where appropriate. Be friendly with IDE tools. \ No newline at end of file diff --git a/examples/sqlx-mysql/src/example_cake.rs b/examples/sqlx-mysql/src/example_cake.rs index f987136e..3516908e 100644 --- a/examples/sqlx-mysql/src/example_cake.rs +++ b/examples/sqlx-mysql/src/example_cake.rs @@ -26,6 +26,16 @@ pub enum Relation { Fruit, } +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + impl ColumnTrait for Column { type EntityName = Entity; diff --git a/examples/sqlx-mysql/src/example_fruit.rs b/examples/sqlx-mysql/src/example_fruit.rs index b393e3d6..ee0c0c9b 100644 --- a/examples/sqlx-mysql/src/example_fruit.rs +++ b/examples/sqlx-mysql/src/example_fruit.rs @@ -26,6 +26,16 @@ pub enum PrimaryKey { #[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation {} +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + impl ColumnTrait for Column { type EntityName = Entity; diff --git a/examples/sqlx-mysql/src/main.rs b/examples/sqlx-mysql/src/main.rs index 205540d4..ce42bbf3 100644 --- a/examples/sqlx-mysql/src/main.rs +++ b/examples/sqlx-mysql/src/main.rs @@ -1,4 +1,4 @@ -use sea_orm::{ColumnTrait, Database, EntityTrait, QueryErr, QueryHelper}; +use sea_orm::{ColumnTrait, Database, EntityTrait, QueryErr, QueryHelper, FromQueryResult}; mod example_cake; mod example_fruit; @@ -104,26 +104,12 @@ async fn find_one(db: &Database) -> Result<(), QueryErr> { } async fn count_fruits_by_cake(db: &Database) -> Result<(), QueryErr> { - #[derive(Debug)] + #[derive(Debug, FromQueryResult)] struct SelectResult { name: String, num_of_fruits: i32, } - { - // TODO: implement with derive macro - use sea_orm::{FromQueryResult, QueryResult, TypeErr}; - - impl FromQueryResult for SelectResult { - fn from_query_result(row: &QueryResult, pre: &str) -> Result { - Ok(Self { - name: row.try_get(pre, "name")?, - num_of_fruits: row.try_get(pre, "num_of_fruits")?, - }) - } - } - } - print!("count fruits by cake: "); let select = cake::Entity::find() diff --git a/sea-orm-macros/src/derives/entity.rs b/sea-orm-macros/src/derives/entity.rs index 373a95f5..4f88b34c 100644 --- a/sea-orm-macros/src/derives/entity.rs +++ b/sea-orm-macros/src/derives/entity.rs @@ -39,15 +39,5 @@ pub fn expend_derive_entity(ident: Ident, attrs: Vec) -> syn::Result< write!(s, "{}", self.as_str()).unwrap(); } } - - impl EntityTrait for #ident { - type Model = Model; - - type Column = Column; - - type PrimaryKey = PrimaryKey; - - type Relation = Relation; - } )) } \ No newline at end of file diff --git a/sea-orm-macros/src/derives/from_query_result.rs b/sea-orm-macros/src/derives/from_query_result.rs new file mode 100644 index 00000000..1217ac2a --- /dev/null +++ b/sea-orm-macros/src/derives/from_query_result.rs @@ -0,0 +1,42 @@ +use proc_macro2::{Ident, TokenStream}; +use syn::{Data, DataStruct, Field, Fields}; +use quote::{format_ident, quote, quote_spanned}; + +pub fn expend_derive_from_query_result(ident: Ident, data: Data) -> syn::Result { + 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 = fields + .into_iter() + .map(|Field { ident, .. }| { + format_ident!("{}", ident.unwrap().to_string()) + }) + .collect(); + + let name: Vec = field + .iter() + .map(|f| { + let s = f.to_string(); + quote! { #s } + }) + .collect(); + + Ok(quote!( + impl sea_orm::FromQueryResult for #ident { + fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result { + Ok(Self { + #(#field: row.try_get(pre, #name)?),* + }) + } + } + )) +} \ No newline at end of file diff --git a/sea-orm-macros/src/derives/mod.rs b/sea-orm-macros/src/derives/mod.rs index e6139bcc..0d4a7b97 100644 --- a/sea-orm-macros/src/derives/mod.rs +++ b/sea-orm-macros/src/derives/mod.rs @@ -1,9 +1,11 @@ mod entity; +mod from_query_result; mod primary_key; mod column; mod model; pub use entity::*; +pub use from_query_result::*; pub use primary_key::*; pub use column::*; pub use model::*; \ No newline at end of file diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 07aa7cc6..d59e9e85 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -10,7 +10,7 @@ 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(), @@ -22,7 +22,7 @@ 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(), @@ -34,7 +34,7 @@ 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(), @@ -46,9 +46,21 @@ 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(), } +} + +#[proc_macro_derive(FromQueryResult)] +pub fn derive_from_query_result(input: TokenStream) -> TokenStream { + let DeriveInput { + ident, data, .. + } = parse_macro_input!(input); + + match derives::expend_derive_from_query_result(ident, data) { + Ok(ts) => ts.into(), + Err(e) => e.to_compile_error().into(), + } } \ No newline at end of file diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 878314cb..7a129752 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -1,5 +1,5 @@ pub use crate::{ ColumnTrait, ColumnType, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait, PrimaryKeyOfModel, PrimaryKeyTrait, QueryResult, Related, RelationDef, RelationTrait, Select, - TypeErr, Value, DeriveEntity, DerivePrimaryKey, DeriveColumn, DeriveModel, + TypeErr, Value, DeriveEntity, DerivePrimaryKey, DeriveColumn, DeriveModel }; diff --git a/src/lib.rs b/src/lib.rs index 7b3a9b8c..f421d8bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,4 +20,5 @@ pub use sea_orm_macros::{ DerivePrimaryKey, DeriveColumn, DeriveModel, + FromQueryResult, }; diff --git a/src/tests_cfg/cake.rs b/src/tests_cfg/cake.rs index 0221a672..e550a50a 100644 --- a/src/tests_cfg/cake.rs +++ b/src/tests_cfg/cake.rs @@ -26,6 +26,16 @@ pub enum Relation { Fruit, } +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + impl ColumnTrait for Column { type EntityName = Entity; diff --git a/src/tests_cfg/fruit.rs b/src/tests_cfg/fruit.rs index fa44183c..4c93d0b3 100644 --- a/src/tests_cfg/fruit.rs +++ b/src/tests_cfg/fruit.rs @@ -26,6 +26,16 @@ pub enum PrimaryKey { #[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation {} +impl EntityTrait for Entity { + type Model = Model; + + type Column = Column; + + type PrimaryKey = PrimaryKey; + + type Relation = Relation; +} + impl ColumnTrait for Column { type EntityName = Entity;