Skip to main content

rust_ef_macros/
lib.rs

1//! Procedural macros for Rust Entity Framework (rust-ef).
2
3#![forbid(unsafe_code)]
4
5mod column_macro;
6mod db_context_key;
7mod db_enum;
8mod entity;
9mod entity_config;
10mod linq;
11
12use proc_macro::TokenStream;
13
14#[proc_macro_derive(
15    EntityType,
16    attributes(
17        table,
18        primary_key,
19        auto_increment,
20        sequence,
21        required,
22        max_length,
23        column,
24        foreign_key,
25        navigation,
26        not_mapped,
27        index,
28        unique,
29        through,
30        concurrency_check,
31        on_delete,
32        context,
33        keyless,
34        column_type,
35        precision,
36        fixed_length,
37        collation,
38        comment,
39        computed
40    )
41)]
42pub fn derive_entity_type(input: TokenStream) -> TokenStream {
43    entity::expand_entity_type(input)
44}
45
46#[proc_macro]
47pub fn column(input: TokenStream) -> TokenStream {
48    column_macro::expand_column(input)
49}
50
51/// Derive a typed keyed-`DbContext` key.
52///
53/// The enum's variants become `IDbContextKey::name()` values (snake-case by
54/// default, overridable with `#[key("...")]`) and the type implements
55/// `From<Key> for rust_dix::ServiceKey`. This makes
56/// `#[inject(owned, key = Key::Read)]` and `add_dbcontext_keyed(Key::Read, ...)`
57/// share the same typed key.
58///
59/// ```ignore
60/// #[derive(DbContextKey, Debug, Clone, Copy, PartialEq, Eq, Hash)]
61/// enum Db {
62///     Read,
63///     Write,
64///     #[key("audit-log")]
65///     Audit,
66/// }
67/// ```
68///
69/// The enum must derive `Debug + Clone + Copy + PartialEq + Eq + Hash` (the
70/// bounds required by `rust_dix::ServiceKey::new`).
71#[proc_macro_derive(DbContextKey, attributes(key))]
72pub fn derive_db_context_key(input: TokenStream) -> TokenStream {
73    db_context_key::expand(syn::parse_macro_input!(input as syn::DeriveInput)).into()
74}
75
76/// Derive string-backed database mapping for a unit-only enum.
77///
78/// Generates `From<Enum> for DbValue`, `TryFrom<DbValue> for Enum`,
79/// `as_str()` and `from_db_str()`. Variant names default to the Rust variant
80/// identifier; override with `#[db_value("...")]`.
81///
82/// ```ignore
83/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, DbEnum)]
84/// enum Status {
85///     #[default]
86///     Pending,
87///     #[db_value("PAID")]
88///     Paid,
89/// }
90/// ```
91#[proc_macro_derive(DbEnum, attributes(db_value))]
92pub fn derive_db_enum(input: TokenStream) -> TokenStream {
93    db_enum::expand_db_enum(input)
94}
95
96/// Compile-time LINQ-to-SQL.
97///
98/// ```ignore
99/// linq!(ctx.set::<Blog>(), |b: Blog| b.rating > 5).to_list().await?;
100///
101/// let expr = linq!(|b: Blog| b.rating > min);
102/// ctx.set::<Blog>().filter(expr).to_list().await?;
103/// ```
104#[proc_macro]
105pub fn linq(input: TokenStream) -> TokenStream {
106    linq::expand_linq(input)
107}
108
109/// Attribute macro for `impl IEntityTypeConfiguration<T>` blocks.
110///
111/// Emits an `inventory::submit!` registering the configuration for automatic
112/// discovery by `DbContext::from_options()`. The first argument is the entity
113/// type `T`; the config type is taken from the `impl`'s `Self` type. An
114/// optional second argument specifies the DbContext key for multi-database
115/// scenarios.
116///
117/// # Examples
118///
119/// ```ignore
120/// #[derive(Default)]
121/// pub struct BlogConfig;
122///
123/// // Default context
124/// #[entity(Blog)]
125/// impl IEntityTypeConfiguration<Blog> for BlogConfig {
126///     fn configure(&self, entity: &mut EntityTypeBuilder<'_, Blog>) {
127///         entity.to_table("blogs_renamed");
128///     }
129/// }
130///
131/// // Keyed context ("logs" database)
132/// #[entity(LogEntry, "logs")]
133/// impl LogEntryConfig for IEntityTypeConfiguration<LogEntry> {
134///     fn configure(&self, entity: &mut EntityTypeBuilder<'_, LogEntry>) {
135///         entity.to_table("app_logs");
136///     }
137/// }
138/// ```
139#[proc_macro_attribute]
140pub fn entity(args: TokenStream, input: TokenStream) -> TokenStream {
141    entity_config::expand_entity_config(args, input)
142}