Charles Chege 497bdbe3dd Document the macros.
Add code examples for the macros
2021-10-28 15:46:38 +03:00

269 lines
7.9 KiB
Rust

extern crate proc_macro;
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput, Error};
mod attributes;
mod derives;
mod util;
/// Create an Entity
/// ### Usage
/// ```
/// use sea_orm::entity::prelude::*;
///
///#[derive(Copy, Clone, Default, Debug, DeriveEntity)]
///pub struct Entity;
/// ```
#[proc_macro_derive(DeriveEntity, attributes(sea_orm))]
pub fn derive_entity(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derives::expand_derive_entity(input)
.unwrap_or_else(Error::into_compile_error)
.into()
}
/// This derive macro is the 'almighty' macro which automatically generates
/// Entity, Column, and PrimaryKey from a given Model.
/// ### Usage
/// use sea_orm::entity::prelude::*;
///
/// #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Deserialize, Serialize, FromForm)]
/// #[sea_orm(table_name = "posts")]
/// pub struct Model {
/// #[sea_orm(primary_key)]
/// pub id: i32,
/// pub title: String,
/// #[sea_orm(column_type = "Text")]
/// pub text: String,
/// }
/// ```
#[proc_macro_derive(DeriveEntityModel, attributes(sea_orm))]
pub fn derive_entity_model(input: TokenStream) -> TokenStream {
let input_ts = input.clone();
let DeriveInput {
ident, data, attrs, ..
} = parse_macro_input!(input as DeriveInput);
if ident != "Model" {
panic!("Struct name must be Model");
}
let mut ts: TokenStream = derives::expand_derive_entity_model(data, attrs)
.unwrap_or_else(Error::into_compile_error)
.into();
ts.extend(vec![
derive_model(input_ts.clone()),
derive_active_model(input_ts),
]);
ts
}
/// The DerivePrimaryKey derive macro will implement [PrimaryKeyToColumn]
/// for PrimaryKey which defines tedious mappings between primary keys and columns.
/// The [EnumIter] is also derived, allowing iteration over all enum variants.
/// ### Usage
/// ```
/// use sea_orm::entity::prelude::*;
///
/// #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
/// pub enum PrimaryKey {
/// CakeId,
/// FillingId,
/// }
/// ```
#[proc_macro_derive(DerivePrimaryKey)]
pub fn derive_primary_key(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_primary_key(ident, data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// The DeriveColumn derive macro will implement [ColumnTrait] for Columns.
/// It defines the identifier of each column by implementing Iden and IdenStatic.
/// The EnumIter is also derived, allowing iteration over all enum variants.
/// ### Usage
/// ```
/// use sea_orm::entity::prelude::*;
///
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
/// pub enum Column {
/// CakeId,
/// FillingId,
/// }
/// ```
#[proc_macro_derive(DeriveColumn, attributes(sea_orm))]
pub fn derive_column(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_column(&ident, &data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// Derive a column if column names are not in snake-case
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveCustomColumn)]
/// pub enum Column {
/// Id,
/// Name,
/// VendorId,
/// }
#[proc_macro_derive(DeriveCustomColumn)]
pub fn derive_custom_column(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_custom_column(&ident, &data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// The DeriveModel derive macro will implement ModelTrait for Model,
/// which provides setters and getters for all attributes in the mod
/// It also implements FromQueryResult to convert a query result into the corresponding Model.
/// ### Usage
///
/// ```
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
/// pub struct Model {
/// pub id: i32,
/// pub name: String,
/// }
/// ```
#[proc_macro_derive(DeriveModel, attributes(sea_orm))]
pub fn derive_model(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derives::expand_derive_model(input)
.unwrap_or_else(Error::into_compile_error)
.into()
}
/// The DeriveActiveModel derive macro will implement ActiveModelTrait for ActiveModel
/// which provides setters and getters for all active values in the active model.
/// ### Usage
///
/// ```
///
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)]
/// pub struct Model {
/// pub id: i32,
/// pub name: String,
/// }
///
/// ```
#[proc_macro_derive(DeriveActiveModel, attributes(sea_orm))]
pub fn derive_active_model(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_active_model(ident, data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// FIXME Derive into an active model
#[proc_macro_derive(DeriveIntoActiveModel, attributes(sea_orm))]
pub fn derive_into_active_model(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derives::expand_into_active_model(input)
.unwrap_or_else(Error::into_compile_error)
.into()
}
/// Models that a user can override
/// ### Usage
///
/// ```
/// use sea_orm::entity::prelude::*;
///
/// #[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, DeriveActiveModelBehavior,)]
/// pub struct Model {
/// pub id: i32,
/// pub name: String,
/// }
/// ```
#[proc_macro_derive(DeriveActiveModelBehavior)]
pub fn derive_active_model_behavior(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_active_model_behavior(ident, data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// Convert a query result into the corresponding Model.
/// ### Usage
///
/// ```
/// #[derive(Debug, FromQueryResult)]
/// struct SelectResult {
/// name: String,
/// num_of_fruits: i32,
/// }
/// ```
#[proc_macro_derive(FromQueryResult)]
pub fn derive_from_query_result(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
match derives::expand_derive_from_query_result(ident, data) {
Ok(ts) => ts.into(),
Err(e) => e.to_compile_error().into(),
}
}
/// The DeriveRelation derive macro will implement RelationTrait for Relation.
/// ### Usage
/// ```
/// #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
/// pub enum Relation {
/// #[sea_orm(
/// belongs_to = "super::cake::Entity",
/// from = "Column::CakeId",
/// to = "super::cake::Column::Id"
/// )]
/// Cake,
/// #[sea_orm(
/// belongs_to = "super::cake_expanded::Entity",
/// from = "Column::CakeId",
/// to = "super::cake_expanded::Column::Id"
/// )]
/// CakeExpanded,
/// }
/// ```
#[proc_macro_derive(DeriveRelation, attributes(sea_orm))]
pub fn derive_relation(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
derives::expand_derive_relation(input)
.unwrap_or_else(Error::into_compile_error)
.into()
}
#[doc(hidden)]
#[proc_macro_attribute]
pub fn test(_: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::ItemFn);
let ret = &input.sig.output;
let name = &input.sig.ident;
let body = &input.block;
let attrs = &input.attrs;
quote::quote! (
#[test]
#(#attrs)*
fn #name() #ret {
let _ = ::env_logger::builder()
.filter_level(::log::LevelFilter::Debug)
.is_test(true)
.try_init();
crate::block_on!(async { #body })
}
)
.into()
}