quokka_macros/
lib.rs

1use darling::FromMeta;
2use proc_macro::{Span, TokenStream};
3use query::{build_sqlx_query, VisibleTraitItemFn};
4use syn::{parse_macro_input, Ident};
5
6mod from_state;
7mod provide_state;
8mod query;
9mod state;
10
11#[derive(darling::FromMeta, Default)]
12#[darling(default)]
13struct QueryAttrs {
14    query: String,
15    write: bool,
16    #[darling(default)]
17    db_field: Option<String>,
18}
19
20#[proc_macro_attribute]
21pub fn repository_query_one(attrs: TokenStream, input: TokenStream) -> TokenStream {
22    let attrs = match darling::ast::NestedMeta::parse_meta_list(attrs.into()) {
23        Ok(attrs) => attrs,
24        Err(e) => {
25            return TokenStream::from(darling::Error::from(e).write_errors());
26        }
27    };
28    let attrs = match QueryAttrs::from_list(&attrs) {
29        Ok(v) => v,
30        Err(e) => {
31            return TokenStream::from(e.write_errors());
32        }
33    };
34    let input = parse_macro_input!(input as VisibleTraitItemFn);
35
36    build_sqlx_query(
37        Ident::new("fetch_one", Span::call_site().into()),
38        attrs,
39        input,
40        quote::quote! {
41            Ok(sqlx::FromRow::from_row(&result)?)
42        }
43        .into(),
44    )
45}
46
47#[proc_macro_attribute]
48pub fn repository_query_optional(attrs: TokenStream, input: TokenStream) -> TokenStream {
49    let attrs = match darling::ast::NestedMeta::parse_meta_list(attrs.into()) {
50        Ok(attrs) => attrs,
51        Err(e) => {
52            return TokenStream::from(darling::Error::from(e).write_errors());
53        }
54    };
55
56    let attrs = match QueryAttrs::from_list(&attrs) {
57        Ok(v) => v,
58        Err(e) => {
59            return TokenStream::from(e.write_errors());
60        }
61    };
62    let input = parse_macro_input!(input as VisibleTraitItemFn);
63
64    build_sqlx_query(
65        Ident::new("fetch_optional", Span::call_site().into()),
66        attrs,
67        input,
68        quote::quote! {
69            Ok(result
70                .as_ref()
71                .map(sqlx::FromRow::from_row)
72                .transpose()?)
73        }
74        .into(),
75    )
76}
77
78#[proc_macro_attribute]
79pub fn repository_query_all(attrs: TokenStream, input: TokenStream) -> TokenStream {
80    let attrs = match darling::ast::NestedMeta::parse_meta_list(attrs.into()) {
81        Ok(attrs) => attrs,
82        Err(e) => {
83            return TokenStream::from(darling::Error::from(e).write_errors());
84        }
85    };
86
87    let attrs = match QueryAttrs::from_list(&attrs) {
88        Ok(v) => v,
89        Err(e) => {
90            return TokenStream::from(e.write_errors());
91        }
92    };
93    let input = parse_macro_input!(input as VisibleTraitItemFn);
94
95    build_sqlx_query(
96        Ident::new("fetch_all", Span::call_site().into()),
97        attrs,
98        input,
99        quote::quote! {
100            Ok(result.iter()
101                .map(sqlx::FromRow::from_row)
102                .collect::<sqlx::Result<_>>()?)
103        }
104        .into(),
105    )
106}
107
108#[proc_macro_attribute]
109pub fn repository_execute(attrs: TokenStream, input: TokenStream) -> TokenStream {
110    let attrs = match darling::ast::NestedMeta::parse_meta_list(attrs.into()) {
111        Ok(attrs) => attrs,
112        Err(e) => {
113            return TokenStream::from(darling::Error::from(e).write_errors());
114        }
115    };
116
117    let attrs = match QueryAttrs::from_list(&attrs) {
118        Ok(v) => v,
119        Err(e) => {
120            return TokenStream::from(e.write_errors());
121        }
122    };
123    let input = parse_macro_input!(input as VisibleTraitItemFn);
124
125    build_sqlx_query(
126        Ident::new("execute", Span::call_site().into()),
127        attrs,
128        input,
129        quote::quote! {
130            Ok(result.rows_affected())
131        }
132        .into(),
133    )
134}
135
136#[proc_macro_attribute]
137pub fn repository_query_paginated(attrs: TokenStream, input: TokenStream) -> TokenStream {
138    let attrs = match darling::ast::NestedMeta::parse_meta_list(attrs.into()) {
139        Ok(attrs) => attrs,
140        Err(e) => {
141            return TokenStream::from(darling::Error::from(e).write_errors());
142        }
143    };
144
145    let attrs = match QueryAttrs::from_list(&attrs) {
146        Ok(v) => v,
147        Err(e) => {
148            return TokenStream::from(e.write_errors());
149        }
150    };
151    let input = parse_macro_input!(input as VisibleTraitItemFn);
152
153    build_sqlx_query(
154        Ident::new("fetch_all", Span::call_site().into()),
155        attrs,
156        input,
157        quote::quote! {
158            Ok(result.iter()
159                .map(sqlx::FromRow::from_row)
160                .collect::<sqlx::Result<_>>()?)
161        }
162        .into(),
163    )
164}
165
166#[proc_macro_derive(FromState, attributes(from_state))]
167pub fn derive_from_state(input: TokenStream) -> TokenStream {
168    from_state::derive_from_state(parse_macro_input!(input as syn::DeriveInput)).into()
169}
170
171#[proc_macro_derive(ProvideState)]
172pub fn derive_provide_state(input: TokenStream) -> TokenStream {
173    provide_state::derive_provide_state(parse_macro_input!(input as syn::DeriveInput)).into()
174}
175
176#[proc_macro_derive(State, attributes(state))]
177pub fn derive_state(input: TokenStream) -> TokenStream {
178    state::derive_state(parse_macro_input!(input as syn::DeriveInput)).into()
179}