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}