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 entity;
8mod entity_config;
9mod linq;
10
11use proc_macro::TokenStream;
12
13#[proc_macro_derive(
14 EntityType,
15 attributes(
16 table,
17 primary_key,
18 auto_increment,
19 sequence,
20 required,
21 max_length,
22 column,
23 foreign_key,
24 navigation,
25 not_mapped,
26 index,
27 unique,
28 through,
29 concurrency_check,
30 on_delete,
31 context
32 )
33)]
34pub fn derive_entity_type(input: TokenStream) -> TokenStream {
35 entity::expand_entity_type(input)
36}
37
38#[proc_macro]
39pub fn column(input: TokenStream) -> TokenStream {
40 column_macro::expand_column(input)
41}
42
43/// Derive a typed keyed-`DbContext` key.
44///
45/// The enum's variants become `IDbContextKey::name()` values (snake-case by
46/// default, overridable with `#[key("...")]`) and the type implements
47/// `From<Key> for rust_dix::ServiceKey`. This makes
48/// `#[inject(owned, key = Key::Read)]` and `add_dbcontext_keyed(Key::Read, ...)`
49/// share the same typed key.
50///
51/// ```ignore
52/// #[derive(DbContextKey, Debug, Clone, Copy, PartialEq, Eq, Hash)]
53/// enum Db {
54/// Read,
55/// Write,
56/// #[key("audit-log")]
57/// Audit,
58/// }
59/// ```
60///
61/// The enum must derive `Debug + Clone + Copy + PartialEq + Eq + Hash` (the
62/// bounds required by `rust_dix::ServiceKey::new`).
63#[proc_macro_derive(DbContextKey, attributes(key))]
64pub fn derive_db_context_key(input: TokenStream) -> TokenStream {
65 db_context_key::expand(syn::parse_macro_input!(input as syn::DeriveInput)).into()
66}
67
68/// Compile-time LINQ-to-SQL.
69///
70/// ```ignore
71/// linq!(ctx.set::<Blog>(), |b: Blog| b.rating > 5).to_list().await?;
72///
73/// let expr = linq!(|b: Blog| b.rating > min);
74/// ctx.set::<Blog>().filter(expr).to_list().await?;
75/// ```
76#[proc_macro]
77pub fn linq(input: TokenStream) -> TokenStream {
78 linq::expand_linq(input)
79}
80
81/// Attribute macro for `impl IEntityTypeConfiguration<T>` blocks.
82///
83/// Emits an `inventory::submit!` registering the configuration for automatic
84/// discovery by `DbContext::from_options()`. The first argument is the entity
85/// type `T`; the config type is taken from the `impl`'s `Self` type. An
86/// optional second argument specifies the DbContext key for multi-database
87/// scenarios.
88///
89/// # Examples
90///
91/// ```ignore
92/// #[derive(Default)]
93/// pub struct BlogConfig;
94///
95/// // Default context
96/// #[entity(Blog)]
97/// impl IEntityTypeConfiguration<Blog> for BlogConfig {
98/// fn configure(&self, entity: &mut EntityTypeBuilder<'_, Blog>) {
99/// entity.to_table("blogs_renamed");
100/// }
101/// }
102///
103/// // Keyed context ("logs" database)
104/// #[entity(LogEntry, "logs")]
105/// impl LogEntryConfig for IEntityTypeConfiguration<LogEntry> {
106/// fn configure(&self, entity: &mut EntityTypeBuilder<'_, LogEntry>) {
107/// entity.to_table("app_logs");
108/// }
109/// }
110/// ```
111#[proc_macro_attribute]
112pub fn entity(args: TokenStream, input: TokenStream) -> TokenStream {
113 entity_config::expand_entity_config(args, input)
114}