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}