django_query_derive/lib.rs
1use proc_macro::{self, TokenStream};
2
3use proc_macro2 as pm2;
4
5mod attributes;
6mod filtering;
7mod persian_rug;
8mod row;
9mod sorting;
10
11/// Derive the `Filterable` trait, creating suitable `FilterClass`
12/// types.
13///
14/// This is only implemented for structs with named fields. All fields
15/// will be exposed, with a default operator of `exact` unless annotated
16/// to indicate otherwise. The annotations use the `django` attribute,
17/// which has the following options:
18///
19/// - `#[django(rename="new_name")]` Expose the annotated member for
20/// filtering as `new_name instead of using its name in the source
21/// code.
22///
23/// - `#[django(default_op=iexact)]` Set the default operator, which
24/// is applied when the field is referred to directly to be `iexact`,
25/// where `iexact` can be replaced with any of the built-in operators
26/// included in this crate.
27///
28/// - `#[django(default_fun=my_crate::MyOperatorClass)]` Set the
29/// default operator to be the custom type
30/// `my_crate::MyOperatorClass`, which must implement
31/// `OperatorClass`.]
32///
33/// - `#[django(exclude)]` Do not expose this field, it cannot be used
34/// in filtering.
35///
36/// - `#[django(traverse)]` This type of this field is itself `Filterable`
37/// and nested filters onto its members are permitted via the double
38/// underscore syntax that Django uses.
39///
40/// - `#[django(op(in, icontains))]` In addition to the default operator,
41/// this field can also be filtered on using `in` and `icontains`, using
42/// double underscores to separate the operator from the field name.
43///
44/// - `#[django(op(foo=my_crate::MyOperatorClass))]` This field has a
45/// custom filter operator `foo` which can be appended to its name
46/// with double underscores, and which when used, creates a filter
47/// using `my_crate::MyOperatorClass`, which must itself be an
48/// instance of `OperatorClass`.
49#[proc_macro_derive(Filterable, attributes(django))]
50pub fn filterable(input: TokenStream) -> TokenStream {
51 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
52
53 let res: pm2::TokenStream = filtering::derive_filterable(derive);
54
55 res.into()
56}
57
58/// Derive the `Sortable` trait, creating suitable `SorterClass` types.
59///
60/// This is only implemented for structs with named fields. No fields
61/// will be available to use as sort orders, unless there are
62/// annotations to indicate otherwise. The annotations use the
63/// `django` attribute, which has the following significant options
64/// here:
65///
66/// - `#[django(rename="new_name")]` Expose the annotated member for
67/// sorting as `new_name instead of using its name in the source
68/// code.
69///
70/// - `#[django(sort)]` The field, which must be [Ord], will be
71/// exposed as a sort order for the enclosing type. The ordering
72/// is taken directly from [Ord].
73///
74/// - `#[django(sort="name","age")]` The field has a type which is
75/// itself `Sortable`. Expose this field as defining a sort order of
76/// the same name, and When sorting by this field make the order
77/// defined by the field's own member `name`, and then by its own
78/// member `age` as a secondary sort.
79#[proc_macro_derive(Sortable, attributes(django))]
80pub fn sortable(input: TokenStream) -> TokenStream {
81 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
82
83 let res: pm2::TokenStream = sorting::derive_sortable(derive);
84
85 res.into()
86}
87
88/// Derive the `IntoRow` trait, determining the display of nested
89/// objects.
90///
91/// This is only implemented for structs with named fields. All fields
92/// will be included in the output by default, which means they must
93/// have types which implement `IntoCellValue`. The annotations for
94/// this derive macro use the `django` attribute, which has the
95/// following significant options here:
96///
97/// - `#[django(rename="new_name")]` Expose the annotated member in
98/// the output `new_name instead of using its name in the source code.
99///
100/// - `#[django(exclude)]` Do not include the annotated member in any
101/// output.
102///
103/// - `#[django(foreign_key="field_name")]` The field has a type which
104/// is itself `IntoRow`. Rather than requiring the field's type to
105/// implement `IntoCellValue`, instead take the value of the field
106/// from the cell called `field_name` in the field's own type's
107/// output row.
108#[proc_macro_derive(IntoRow, attributes(django))]
109pub fn into_row(input: TokenStream) -> TokenStream {
110 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
111
112 let res: pm2::TokenStream = row::derive_into_row(derive);
113
114 res.into()
115}
116
117/// Derive the `IntoRowWithContext` trait for `persian-rug` types.
118///
119/// This is only implemented for structs with named fields. All fields
120/// will be included in the output by default, which means they must
121/// have types which implement `IntoCellValue`. The annotations for
122/// this derive macro use the `django` attribute, which has the
123/// following significant options here:
124///
125/// - `#[django(rename="new_name")]` Expose the annotated member in
126/// the output `new_name instead of using its name in the source code.
127///
128/// - `#[django(exclude)]` Do not include the annotated member in any
129/// output.
130///
131/// - `#[django(foreign_key="field_name")]` The field has a type which
132/// is itself `IntoRow`. Rather than requiring the field's type to
133/// implement `IntoCellValue`, instead take the value of the field
134/// from the cell called `field_name` in the field's own type's
135/// output row.
136///
137/// The struct itself must also be annotated with the `django`
138/// attribute, which gives the `persian-rug` constraints to apply to
139/// to each derived `impl`:
140///
141/// - `#[django(persian_rug(context=Rug))]` The persian-rug
142/// context type for this type is `Rug`.
143///
144/// - `#[django(persian_rug(context=C, access(Foo<C>)))]` The
145/// persian-rug context type is the template parameter `C`. The
146/// context must provide access to `Foo<C>`.
147#[proc_macro_derive(IntoRowWithPersianRug, attributes(django))]
148pub fn into_row_with_persian_rug(input: TokenStream) -> TokenStream {
149 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
150
151 let res: pm2::TokenStream = persian_rug::derive_into_row_with_persian_rug(derive);
152
153 res.into()
154}
155
156/// Derive the `SortableWithContext` trait for `persian-rug` types.
157///
158/// This is only implemented for structs with named fields. No fields
159/// will be available to use as sort orders, unless there are
160/// annotations to indicate otherwise. The annotations use the
161/// `django` attribute, which has the following significant options
162/// here:
163///
164/// - `#[django(rename="new_name")]` Expose the annotated member for
165/// sorting as `new_name instead of using its name in the source
166/// code.
167///
168/// - `#[django(sort)]` The field, which must be [Ord], will be
169/// exposed as a sort order for the enclosing type. The ordering
170/// is taken directly from [Ord].
171///
172/// - `#[django(sort="name","age")]` The field has a type which is
173/// itself `Sortable`. Expose this field as defining a sort order of
174/// the same name, and When sorting by this field make the order
175/// defined by the field's own member `name`, and then by its own
176/// member `age` as a secondary sort.
177///
178/// The struct itself must also be annotated with the `django`
179/// attribute, which gives the `persian-rug` constraints to apply to
180/// to each derived `impl`:
181///
182/// - `#[django(persian_rug(context=Rug))]` The persian-rug
183/// context type for this type is `Rug`.
184///
185/// - `#[django(persian_rug(context=C, access(Foo<C>)))]` The
186/// persian-rug context type is the template parameter `C`. The
187/// context must provide access to `Foo<C>`.
188#[proc_macro_derive(SortableWithPersianRug, attributes(django))]
189pub fn sortable_with_persian_rug(input: TokenStream) -> TokenStream {
190 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
191
192 let res: pm2::TokenStream = persian_rug::derive_sortable_with_persian_rug(derive);
193
194 res.into()
195}
196
197/// Derive the `FilterableWithContext` trait for `persian-rug` types.
198///
199/// This is only implemented for structs with named fields. All fields
200/// will be exposed, with a default operator of `exact` unless annotated
201/// to indicate otherwise. The field annotations use the `django` attribute,
202/// which has the following options:
203///
204/// - `#[django(rename="new_name")]` Expose the annotated member for
205/// filtering as `new_name instead of using its name in the source
206/// code.
207///
208/// - `#[django(default_op=iexact)]` Set the default operator, which
209/// is applied when the field is referred to directly to be `iexact`,
210/// where `iexact` can be replaced with any of the built-in operators
211/// included in `django-query`.
212///
213/// - `#[django(default_fun=my_crate::MyOperatorClass)]` Set the
214/// default operator to be the custom type
215/// `my_crate::MyOperatorClass`, which must implement
216/// `OperatorClass`.
217///
218/// - `#[django(exclude)]` Do not expose this field, it cannot be used
219/// in filtering.
220///
221/// - `#[django(traverse)]` This type of this field is itself `Filterable`
222/// and nested filters onto its members are permitted via the double
223/// underscore syntax that Django uses.
224///
225/// - `#[django(op(in, icontains))]` In addition to the default operator,
226/// this field can also be filtered on using `in` and `icontains`, using
227/// double underscores to separate the operator from the field name.
228///
229/// - `#[django(op(foo=my_crate::MyOperatorClass))]` This field has a
230/// custom filter operator `foo` which can be appended to its name
231/// with double underscores, and which when used, creates a filter
232/// using `my_crate::MyOperatorClass`, which must itself be an
233/// instance of `OperatorClass`.
234///
235/// The struct itself must also be annotated with the `django`
236/// attribute, which gives the `persian-rug` constraints to apply to
237/// to each derived `impl`:
238///
239/// - `#[django(persian_rug(context=Rug))]` The persian-rug
240/// context type for this type is `Rug`.
241///
242/// - `#[django(persian_rug(context=C, access(Foo<C>)))]` The
243/// persian-rug context type is the template parameter `C`. The
244/// context must provide access to `Foo<C>`.
245#[proc_macro_derive(FilterableWithPersianRug, attributes(django))]
246pub fn filterable_with_persian_rug(input: TokenStream) -> TokenStream {
247 let derive: syn::DeriveInput = syn::parse_macro_input!(input);
248
249 let res: pm2::TokenStream = persian_rug::derive_filterable_with_persian_rug(derive);
250
251 res.into()
252}