miniorm_macros/
lib.rs

1#![warn(
2    missing_docs,
3    rustdoc::missing_crate_level_docs,
4    rustdoc::broken_intra_doc_links
5)]
6//! Helper crate for `miniorm` providing a device macro to easily
7//! implement the `Schema` and `Bind` trait.
8mod column;
9mod database;
10mod entity;
11
12use darling::FromDeriveInput;
13use database::Database;
14use entity::SchemaArgs;
15use proc_macro::TokenStream;
16use quote::quote;
17use strum::IntoEnumIterator;
18use syn::DeriveInput;
19
20/// Derive macro to automatically derive the `Schema` and `Bind` traits.
21///
22/// # The `column` directive
23///
24/// The schema for the column can provided using the `column` directive:
25///
26/// ```rust
27/// use miniorm::prelude::*;
28/// use sqlx::FromRow;
29///
30/// #[derive(Debug, Clone, Eq, PartialEq, FromRow, Entity)]
31/// struct Todo {
32///     #[column(TEXT NOT NULL)]
33///     description: String,
34///
35///     #[column(BOOLEAN NOT NULL DEFAULT false)]
36///     done: bool,
37/// }
38/// ```
39///
40/// in which case the `Schema` and `Bind` trait will be derived for all
41/// supported database types.
42/// <table>
43///     <tr>
44///         <td style="background-color:green;color:black;">
45///         Requires the <span style="color:blue">full</span> feature flag.
46///         </td>
47///     </tr>
48/// </table>
49///
50/// # The backend-specific directive
51///
52/// If only a specific backend is necessary, one of the dedicated backend-specific
53/// directive should be used instead. For instance, if `Schema` and `Bind` should
54/// only be derived for `postgres`:
55///
56/// ```rust
57/// use miniorm::prelude::*;
58/// use sqlx::FromRow;
59///
60/// #[derive(Debug, Clone, Eq, PartialEq, FromRow, Entity)]
61/// struct Todo {
62///     #[postgres(TEXT NOT NULL)]
63///     description: String,
64///
65///     #[postgres(BOOLEAN NOT NULL DEFAULT false)]
66///     done: bool,
67/// }
68/// ```
69/// <table>
70///     <tr>
71///         <td style="background-color:green;color:black;">
72///         This example requires the <span style="color:blue">postgres</span> feature flag.
73///         </td>
74///     </tr>
75/// </table>
76///
77/// # The `sqlx` directive
78///
79/// At the moment, only the following `sqlx` directives for `FromRow` are supported:
80/// - `skip`
81/// - `rename`
82/// - `json`
83///
84/// ```rust
85/// use miniorm::prelude::*;
86/// use sqlx::FromRow;
87///
88/// #[derive(Debug, Clone, Eq, PartialEq, FromRow, Entity)]
89/// struct Todo {
90///     #[postgres(TEXT NOT NULL)]
91///     description: String,
92///
93///     #[postgres(BOOLEAN NOT NULL DEFAULT false)]
94///     #[sqlx(rename = "DONE")]
95///     done: bool,
96///
97///     #[sqlx(skip)]
98///     metadata: String,
99/// }
100/// ```
101///
102#[proc_macro_derive(Entity, attributes(sqlx, column, postgres, sqlite, mysql))]
103pub fn derive_entity(input: TokenStream) -> TokenStream {
104    let input: DeriveInput = syn::parse(input).unwrap();
105    let args = SchemaArgs::from_derive_input(&input).expect("could not parse args");
106
107    let mut result = quote!();
108
109    for db in Database::iter() {
110        if args.columns().any(|col| col.supports_db(&db)) {
111            let schema_impl = args.generate_schema_impl(&db);
112            let bind_impl = args.generate_bind_col_impl(&db);
113            result = quote! {
114                #result
115                #schema_impl
116                #bind_impl
117            }
118        }
119    }
120
121    result.into()
122}