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}