1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3# crate.
18"##
19)]
20#![cfg_attr(
21 not(feature = "persian-rug"),
22 doc = r##"
23 - `"persian-rug"` - Support for types built with the `persian-rug` crate.
24"##
25)]
26# from the [`clone-replace`](::clone_replace) crate to provide data to mocks.
30"##
31)]
32#![cfg_attr(
33 not(feature = "clone-replace"),
34 doc = r##"
35 - `"clone-replace"` - Use a `CloneReplace` from the `clone-replace` crate to provide data to mocks.
36"##
37)]
38# trait, and its derive macro,
45which allow you to use attribute markup to automatically parse
46Django-style filter URLs into filter objects, when the `"filter"`
47feature is enabled.
48
49Example:
50```rust
51use django_query::filtering::{Filterable, OperatorSet};
52
53#[derive(Filterable)]
54struct Foo {
55 #[django(op(lt, gt))]
56 a: i32
57}
58
59let os = OperatorSet::<Foo>::new();
60let filter = os.create_filter_from_query("a__lt=4").unwrap();
61assert!(filter.filter_one(&Foo { a: 3}));
62```
63
64"##
65)]
66# trait, and its derive macro, which
72allow you to use attribute markup to automatically parse Django-style
73ordering URLs into sorter objects, when the `"sort"` feature is
74enabled.
75
76Example:
77```rust
78use core::cmp::Ordering;
79use django_query::sorting::{OrderingSet, Sortable};
80
81#[derive(Sortable)]
82struct Foo {
83 #[django(sort)]
84 a: i32
85}
86
87let os = OrderingSet::<Foo>::new();
88let sort = os.create_sort("-a").unwrap();
89assert_eq!(sort.compare(&Foo { a: 3}, &Foo {a: 4}), Ordering::Greater);
90```
91
92"##
93)]
94# trait, and its derive macro, which allow
101you to create Django-style JSON responses for your type; note that
102this isn't just standard serialization because complex objects are
103replaced by one of their fields, which functions as a foreign
104key. This is available when the `"row"` feature is enabled.
105
106Example:
107```rust
108use django_query::row::{IntoRow, Serializer};
109use serde_json::json;
110
111#[derive(IntoRow)]
112struct Foo {
113 a: Vec<i32>
114}
115
116let ser = Foo::get_serializer();
117let f = Foo { a: vec![2, 3]};
118assert_eq!(ser.to_json(&f), json! {
119 { "a": [2, 3] }
120});
121```
122
123"##
124)]
125# type, which implements
132[`wiremock::Respond`], and can provide a mock endpoint for a
133collection of objects whose type implements the preceding three
134traits. This is available when the `"wiremock"` feature is enabled.
135
136Example:
137```rust
138use django_query::{filtering::Filterable, mock::Endpoint, row::IntoRow, sorting::Sortable};
139use wiremock::{Mock, MockServer, matchers, http::Url};
140
141#[derive(Clone, IntoRow, Filterable, Sortable)]
142struct Foo {
143 name: String,
144}
145
146# tokio_test::block_on( async {
147let server = MockServer::start().await;
148let foos = vec![
149 Foo { name: "foo1".to_string() },
150 Foo { name: "foo2".to_string() }
151];
152
153Mock::given(matchers::method("GET"))
154 .respond_with(Endpoint::new(foos, Some(&server.uri())))
155 .mount(&server)
156 .await;
157
158let url = Url::parse(&server.uri()).expect("failed to parse MockServer URL");
159
160let body: serde_json::Value = reqwest::get(url)
161 .await
162 .expect("error getting response")
163 .json()
164 .await
165 .expect("error parsing response");
166
167assert_eq!(body, serde_json::json!{
168 {
169 "count": 2,
170 "next": null,
171 "previous": null,
172 "results": [
173 { "name": "foo1" },
174 { "name": "foo2" },
175 ]
176 }
177});
178
179# });
180```
181"##
182)]
183#![cfg_attr(
184 any(
185 feature = "row",
186 feature = "filter",
187 feature = "sort",
188 feature = "wiremock"
189 ),
190 doc = r##"
191
192## Context support
193
194There is support throughout this crate for types that require some
195context value in order to perform processing with them. Each module
196has an additional entry point with context support:
197"##
198)]
199# in [`filtering`].
203"##
204)]
205# in [`sorting`].
209"##
210)]
211# in [`row`].
215"##
216)]
217# in [`mock`].
221"##
222)]
223#![cfg_attr(
224 any(
225 feature = "row",
226 feature = "filter",
227 feature = "sort",
228 feature = "wiremock"
229 ),
230 doc = r##"
231
232The context support makes no more than basic assumptions about what the
233context value is, or how it behaves.
234"##
235)]
236#![cfg_attr(
237 any(feature = "row", feature = "filter", feature = "sort"),
238 doc = r##"
239However, corresponding
240derive macros for the traits are not provided, for the same reason.
241"##
242)]
243#![cfg_attr(
244 all(
245 feature = "persian-rug",
246 any(feature = "row", feature = "filter", feature = "sort")
247 ),
248 doc = r##"
249
250The `"persian-rug"` feature provides derive macros for using a [`persian_rug::Context`][::persian_rug::Context]:
251for types that require it:"##
252)]
253#,
257"##
258)]
259#
263"##
264)]
265#.
269"##
270)]
271#![cfg_attr(
272 all(
273 feature = "persian-rug",
274 any(feature = "row", feature = "filter", feature = "sort")
275 ),
276 doc = r##"
277
278Note that there is no corresponding `PersianRug` trait, only a derive
279macro which produces an implementation for the generic (`WithContext`)
280trait.
281"##
282)]
283# trait to
292represent something that:
293- Can be locked or queried to obtain a fixed view of the data.
294- For which references to that retrieved fixed view are iterable.
295
296This probably cannot be fully abstracted in stable Rust as it stands
297at the moment of writing, because of the lack of generic associated
298types.
299
300The standard [`RowSource`](mock::RowSource) implementations are for
301[`Arc<Vec<T>>`](::std::sync::Arc) and [`Vec<T>`], which clone
302themselves on each request (the latter being provided because it is
303convenient for small tests, even though it is expensive). Neither
304permits mutability.
305
306However, if the `"clone-replace"` feature is enabled, a
307[`CloneReplace`](::clone_replace::CloneReplace) from the
308[`clone-replace`](::clone_replace) crate can be used as a
309[`RowSource`](mock::RowSource). Note that in addition to the
310implementation for
311[`CloneReplace<Vec<T>>`](::clone_replace::CloneReplace), there is also
312a
313[`CloneReplaceFieldSource`](mock::clone_replace::CloneReplaceFieldSource)
314which allows you to extract a [`Vec`] field from a structure which is
315entirely contained within a
316[`CloneReplace`](::clone_replace::CloneReplace).
317
318"##
319)]
320# wrapped in a
331[`CloneReplace`](::clone_replace::CloneReplace) as data sources via
332[`CloneReplacePersianRugTableSource`](mock::clone_replace::persian_rug::CloneReplacePersianRugTableSource).
333
334"##
335)]
336
337#[cfg(feature = "filter")]
338#[cfg_attr(docsrs, doc(cfg(feature = "filter")))]
339pub mod filtering;
340
341#[cfg(feature = "wiremock")]
342#[cfg_attr(docsrs, doc(cfg(feature = "wiremock")))]
343pub mod mock;
344
345#[cfg(feature = "sort")]
346#[cfg_attr(docsrs, doc(cfg(feature = "sort")))]
347pub mod sorting;
348
349#[cfg(feature = "row")]
350#[cfg_attr(docsrs, doc(cfg(feature = "row")))]
351pub mod row;
352
353#[cfg(feature = "persian-rug")]
354#[doc(hidden)]
355pub mod persian_rug;