lorm_macros/lib.rs
1use proc_macro::TokenStream;
2use syn::{DeriveInput, parse_macro_input};
3
4mod models;
5mod orm;
6mod utils;
7
8/// `#[derive(ToLOrm)]`
9/// generate methods for Object Relational Mapping.
10///
11/// attributes:
12///
13/// `#[lorm(pk)]`
14/// Annotated field is marked as being the primary key and can only be generated at insertion time.
15/// This field is also automatically considered as a `#[lorm(by)]` field.
16/// - If `#[lorm(new)]` is specified, it will use its struct method to generate a new pk at insertion time
17/// - If `#[lorm(is_set)]` is specified, it will use its instance method against `self` to check if the pk is set. Otherwise it compares the pk value with its <struct>::default() (assuming the Default trait is set)
18/// - If `#[lorm(readonly)]` is specified, it will ignore is_set `#[lorm(new)]` and `#[lorm(is_set)]` and let the database handles the field
19///
20/// `#[lorm(rename="name")]`
21/// - at struct level to rename at table name
22/// - at field level to rename at column name
23///
24/// by default, a table name is the struct name pluralized and converted to table case: UserDetail => user_details.
25/// by default, a field name is converted to snake_case: UserDetail => user_detail.
26///
27/// `#[lorm(transient)]`
28/// ignore field. using sqlx::FromRow, skip need `#[lorm(transient)]` and `#[sqlx(skip)]`
29///
30/// `#[lorm(readonly)]`
31/// readonly attribute. Cannot be updated not inserted.
32/// Special cases to consider:
33/// - If applied to the primary key, key generation is left to the database. No update possible as it is the primary key.
34/// - If applied to create_at or updated_at field, timestamp generation is left to the database. No update possible.
35///
36/// `#[lorm(by)]`
37/// generate by_<field>, delete_by_<field> and select with its order_by_<field>, group_by_<field>,
38/// limit and offset methods.
39///
40/// `#[lorm(fk="module::path::class")]`
41/// Add the `#[lorm(fk="module::path::class")]` annotation to a foreign key field to generate the get_<field>() method which returns an instance of `module::path::class`.
42/// The generated method removes the trailing _id if present in the field name.
43///
44/// `#[lorm(created_at)]`
45/// Add the `#[lorm(created_at)]` annotation to mark the field as the `created_at` field.
46/// - If `#[lorm(new)]` is specified, it will use its method to update the time upon insertion
47/// - If `#[lorm(readonly)]` is specified, it will ignore is_set `#[lorm(new)]` and let the database handles the field
48///
49/// `#[lorm(updated_at)]`
50/// Add the `#[lorm(updated_at)]` annotation to mark the field as the `updated_at` field.
51/// - If `#[lorm(new)]` is specified, it will use its method to update the time upon insertion and update
52/// - If `#[lorm(readonly)]` is specified, it will ignore is_set `#[lorm(new)]` and let the database handles the field
53///
54/// `#[lorm(new="module::path::class::new_custom()")]`
55/// Add the `#[lorm(new="module::path::class::new_custom()")]` annotation to use a custom creation method.
56/// - The function call is expected to return an instance
57/// - When not provided, the type::new() method is called
58///
59/// `#[lorm(is_set="is_nil()")]`
60/// Uses a specific function call to check if the returned value if the default value.
61/// The function call is expected to return bool.
62/// Defaults to class_type::default() which assumes both the Default and PartialEq trait are implemented.
63///
64#[proc_macro_derive(ToLOrm,
65 attributes(
66 lorm,
67 // lorm(pk),
68 // lorm(by),
69 // lorm(transient),
70 // lorm(readonly),
71 // lorm(fk="module::path::class"),
72 // lorm(new="module::path::class::new_custom()"),
73 // lorm(is_set="is_nil()"),
74 // lorm(rename="name"),
75 // lorm(created_at),
76 // lorm(updated_at),
77 )
78)]
79pub fn sql_derive_to_orm(input: TokenStream) -> TokenStream {
80 let input = parse_macro_input!(input as DeriveInput);
81 match orm::expand_derive_to_orm(&input) {
82 Ok(ts) => ts,
83 Err(e) => e.to_compile_error().into(),
84 }
85}