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}