gremlin_orm_macro/
lib.rs

1//! # `gremlin-orm-macro`
2
3use darling::{FromDeriveInput, FromField, ast::Data, util::Ignored};
4use proc_macro::TokenStream;
5use proc_macro_error2::abort;
6use syn::{DeriveInput, Ident, parse_macro_input};
7use thiserror::Error;
8
9mod delete;
10mod fetch;
11mod insert;
12mod stream;
13mod update;
14
15/// Generate the entity
16#[proc_macro_error2::proc_macro_error]
17#[proc_macro_derive(Entity, attributes(orm))]
18pub fn derive_response(input: TokenStream) -> TokenStream {
19    let args = parse_macro_input!(input as DeriveInput);
20
21    match generate(args) {
22        Ok(stream) => stream,
23        Err(err) => err.write_errors().into(),
24    }
25}
26
27fn generate(args: DeriveInput) -> Result<TokenStream, GeneratorError> {
28    let args: EntityArgs = EntityArgs::from_derive_input(&args)?;
29    let ident = args.ident.clone();
30
31    let args = if let Ok(v) = EntityCtx::try_from(args) {
32        v
33    } else {
34        abort!(
35            ident,
36            "The `Entity` macro can only be applied to a struct with named fields"
37        )
38    };
39
40    let insert_stream = insert::generate_insert(&args);
41    let update_stream = update::generate_update(&args);
42    let stream_stream = stream::generate_stream(&args);
43    let delete_stream = delete::generate_delete(&args);
44    let get_by_id_stream = fetch::generate_fetch(&args);
45
46    let stream = quote::quote! {
47        #insert_stream
48        #update_stream
49        #stream_stream
50        #delete_stream
51        #get_by_id_stream
52    };
53
54    Ok(stream.into())
55}
56
57#[derive(Debug, Clone)]
58struct EntityCtx {
59    ident: Ident,
60    vis: syn::Visibility,
61    data: Vec<EntityFieldCtx>,
62    table: String,
63}
64
65impl EntityCtx {
66    fn pks(&self) -> impl Iterator<Item = &EntityFieldCtx> {
67        self.data.iter().filter(|field| field.pk)
68    }
69}
70
71impl TryFrom<EntityArgs> for EntityCtx {
72    type Error = ();
73
74    fn try_from(value: EntityArgs) -> Result<Self, Self::Error> {
75        let mut data = vec![];
76
77        for row in value.data.take_struct().ok_or(())? {
78            data.push(row.try_into()?);
79        }
80
81        Ok(Self {
82            ident: value.ident,
83            vis: value.vis,
84            data,
85            table: value.table,
86        })
87    }
88}
89
90#[derive(Debug, Clone)]
91struct EntityFieldCtx {
92    ident: Ident,
93    vis: syn::Visibility,
94    ty: syn::Type,
95    pk: bool,
96    generated: bool,
97    deref: bool,
98    default: bool,
99}
100
101impl TryFrom<EntityField> for EntityFieldCtx {
102    type Error = ();
103
104    fn try_from(value: EntityField) -> Result<Self, Self::Error> {
105        Ok(Self {
106            ident: value.ident.ok_or(())?,
107            vis: value.vis,
108            ty: value.ty,
109            pk: value.pk,
110            generated: value.generated,
111            deref: value.deref,
112            default: value.default,
113        })
114    }
115}
116
117#[derive(Debug, FromDeriveInput)]
118#[darling(attributes(orm), forward_attrs(doc))]
119struct EntityArgs {
120    ident: Ident,
121    vis: syn::Visibility,
122    data: Data<Ignored, EntityField>,
123    table: String,
124}
125
126#[derive(Debug, Clone, FromField)]
127#[darling(attributes(orm), forward_attrs(doc))]
128struct EntityField {
129    ident: Option<Ident>,
130    vis: syn::Visibility,
131    ty: syn::Type,
132    #[darling(default)]
133    pk: bool,
134    #[darling(default)]
135    generated: bool,
136    #[darling(default)]
137    default: bool,
138    #[darling(default)]
139    deref: bool,
140}
141
142#[derive(Debug, Error)]
143pub(crate) enum GeneratorError {
144    #[error("{0}")]
145    Syn(
146        #[source]
147        #[from]
148        syn::Error,
149    ),
150    #[error("{0}")]
151    Darling(
152        #[source]
153        #[from]
154        darling::Error,
155    ),
156}
157
158impl GeneratorError {
159    pub(crate) fn write_errors(self) -> proc_macro2::TokenStream {
160        match self {
161            Self::Syn(err) => err.to_compile_error(),
162            Self::Darling(err) => err.write_errors(),
163        }
164    }
165}