django_query/
row.rs

1//! # Convert Rust structs with named fields into tables of output
2//!
3//! Django produces JSON encoded tabular output in response to queries,
4//! where each row of the output is a JSON object, and those objects do not
5//! contain any nested objects. Instead, nested objects are represented
6//! by a pre-selected foreign key.
7//!
8//! # Overview
9//!
10//! The [`IntoRow`] trait in this module allows the type to produce a [`Serializer`] that
11//! can convert an instance into a row within a table of JSON output.
12//! The [`macro@IntoRow`] derive macro for this
13//! trait will produce everything necessary for structs with
14//! named fields.
15//!
16//! The value of a cell within the table cannot itself be JSON
17//! object-typed, in line with Django's database origins. However, it
18//! is possible to return multiple values in an array inside one
19//! cell. The [`CellValue`] type captures the subset of permitted JSON
20//! [`Value`](serde_json::Value)s that are permitted.
21//!
22//! A type which can directly be the value in a given cell of output
23//! should implement [`IntoCellValue`]. If the type implements
24//! [`Display`], and if the desired JSON representation is a string,
25//! you can derive the marker trait [`StringCellValue`] to benefit
26//! from a blanket derivation of [`IntoCellValue`] for string
27//! values. Otherwise [`IntoCellValue`] must be implemented directly.
28//!
29//! Since Django results do not contain nested objects, fields with
30//! structured types must be handled differently. Here, one field of
31//! the nested type is chosen to represent that value, as what is in
32//! effect a foreign key. The [`AsForeignKey`] trait captures this
33//! idea, and is blanket implemented for [`IntoRow`] types.
34//!
35//! Example:
36//! ```rust
37//! use django_query::row::{Serializer, IntoRow};
38//! use serde_json::json;
39//! use std::sync::Arc;
40//!
41//! #[derive(IntoRow)]
42//! struct Foo {
43//!   a: i32,
44//!   #[django(foreign_key="a")]
45//!   b: Option<Arc<Foo>>
46//! }
47//!
48//! let f1 = Arc::new(Foo { a: 1, b: None });
49//! let f2 = Arc::new(Foo { a: 2, b: Some(f1.clone()) });
50//! let f3 = Arc::new(Foo { a: 3, b: Some(f2.clone()) });
51//!
52//! let ser = Arc::<Foo>::get_serializer();
53//!
54//! assert_eq!(ser.to_json(&f1), json! {
55//!   { "a": 1i32, "b": null }
56//! });
57//! assert_eq!(ser.to_json(&f2), json! {
58//!   { "a": 2i32, "b": 1i32 }
59//! });
60//! assert_eq!(ser.to_json(&f3), json! {
61//!   { "a": 3i32, "b": 2i32 }
62//! });
63//! ```
64
65use std::collections::BTreeMap;
66use std::fmt::Display;
67use std::sync::Arc;
68
69use chrono::DateTime;
70use serde_json::value::Value;
71use serde_json::Number;
72
73/// The JSON types Django permits in cells - everything except object.
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub enum CellValue {
76    /// A null
77    Null,
78    /// A Boolean
79    Bool(bool),
80    /// A number
81    Number(Number),
82    /// A string
83    String(String),
84    /// An array of non-object values
85    Array(Vec<CellValue>),
86}
87
88/// Convert a value into a JSON [`CellValue`].
89///
90/// [`CellValue`] captures the types that can appear within a cell of
91/// the output table.
92pub trait IntoCellValue {
93    fn to_cell_value(&self) -> CellValue;
94}
95
96/// Use [`Display`] to convert the type into a [`CellValue`]
97pub trait StringCellValue {}
98
99impl StringCellValue for String {}
100
101impl<T> IntoCellValue for T
102where
103    T: StringCellValue + Display,
104{
105    fn to_cell_value(&self) -> CellValue {
106        CellValue::String(self.to_string())
107    }
108}
109
110impl IntoCellValue for i8 {
111    fn to_cell_value(&self) -> CellValue {
112        CellValue::Number(serde_json::Number::from(*self))
113    }
114}
115
116impl IntoCellValue for u8 {
117    fn to_cell_value(&self) -> CellValue {
118        CellValue::Number(serde_json::Number::from(*self))
119    }
120}
121
122impl IntoCellValue for i16 {
123    fn to_cell_value(&self) -> CellValue {
124        CellValue::Number(serde_json::Number::from(*self))
125    }
126}
127
128impl IntoCellValue for u16 {
129    fn to_cell_value(&self) -> CellValue {
130        CellValue::Number(serde_json::Number::from(*self))
131    }
132}
133
134impl IntoCellValue for i32 {
135    fn to_cell_value(&self) -> CellValue {
136        CellValue::Number(serde_json::Number::from(*self))
137    }
138}
139
140impl IntoCellValue for u32 {
141    fn to_cell_value(&self) -> CellValue {
142        CellValue::Number(serde_json::Number::from(*self))
143    }
144}
145
146impl IntoCellValue for i64 {
147    fn to_cell_value(&self) -> CellValue {
148        CellValue::Number(serde_json::Number::from(*self))
149    }
150}
151
152impl IntoCellValue for u64 {
153    fn to_cell_value(&self) -> CellValue {
154        CellValue::Number(serde_json::Number::from(*self))
155    }
156}
157
158impl IntoCellValue for isize {
159    fn to_cell_value(&self) -> CellValue {
160        CellValue::Number(serde_json::Number::from(*self))
161    }
162}
163
164impl IntoCellValue for usize {
165    fn to_cell_value(&self) -> CellValue {
166        CellValue::Number(serde_json::Number::from(*self))
167    }
168}
169
170impl IntoCellValue for f32 {
171    fn to_cell_value(&self) -> CellValue {
172        serde_json::Number::from_f64((*self).into())
173            .map(CellValue::Number)
174            .unwrap_or_else(|| CellValue::Null)
175    }
176}
177
178impl IntoCellValue for f64 {
179    fn to_cell_value(&self) -> CellValue {
180        serde_json::Number::from_f64(*self)
181            .map(CellValue::Number)
182            .unwrap_or_else(|| CellValue::Null)
183    }
184}
185
186impl IntoCellValue for bool {
187    fn to_cell_value(&self) -> CellValue {
188        CellValue::Bool(*self)
189    }
190}
191
192impl<T> IntoCellValue for DateTime<T>
193where
194    T: chrono::TimeZone,
195    <T as chrono::TimeZone>::Offset: Display,
196{
197    fn to_cell_value(&self) -> CellValue {
198        CellValue::String(self.to_rfc3339_opts(chrono::SecondsFormat::Micros, true))
199    }
200}
201
202impl<T> IntoCellValue for Option<T>
203where
204    T: IntoCellValue,
205{
206    fn to_cell_value(&self) -> CellValue {
207        if let Some(ref x) = self {
208            x.to_cell_value()
209        } else {
210            CellValue::Null
211        }
212    }
213}
214
215impl<T> IntoCellValue for Vec<T>
216where
217    T: IntoCellValue,
218{
219    fn to_cell_value(&self) -> CellValue {
220        CellValue::Array(self.iter().map(|item| item.to_cell_value()).collect())
221    }
222}
223
224/// Visit the values in the Django output row for a given value.
225pub trait CellVisitor {
226    /// Visit a value in the row, where:
227    /// - `name` is the name of the column
228    /// - `v` is the value in that column for this row
229    fn visit_value(&mut self, name: &str, v: CellValue);
230}
231
232/// Visit the columns that a Django output row for a given type will contain.
233pub trait ColumnVisitor {
234    /// Visit a column in the row where:
235    /// - `name` is the name of the column
236    fn visit_column(&mut self, name: &str);
237}
238
239/// Produce a [`Serializer`] to convert values of this type into rows
240/// of output.
241pub trait IntoRow<'s>: Sized {
242    type Serializer: Serializer<'s, Self>;
243    fn get_serializer() -> Self::Serializer;
244}
245
246/// A converter that visits rows of Django output for a given type.
247///
248/// This is suitable for the top level of Django output; i.e. things
249/// whose collection has its own endpoint.
250pub trait Serializer<'a, T>
251where
252    Self: 'a,
253{
254    /// Visit the values in a row of output for this type using
255    /// `visitor`.
256    fn accept_cell_visitor<V: CellVisitor>(&self, value: &T, visitor: &mut V);
257
258    /// Visit the columns in a row using `visitor`; note that this
259    /// does not require an instance of the type.
260    fn accept_column_visitor<V: ColumnVisitor>(&self, visitor: &mut V);
261
262    /// Convert an instance of this type into a [`BTreeMap`].
263    fn to_row(&self, value: &T) -> BTreeMap<String, CellValue> {
264        let mut r = RowVisitor {
265            values: BTreeMap::new(),
266        };
267        self.accept_cell_visitor(value, &mut r);
268        r.values
269    }
270
271    /// Convert an instance of this type into a [`serde_json::Value`]
272    fn to_json(&self, value: &T) -> Value {
273        let mut j = JsonVisitor {
274            value: serde_json::map::Map::new(),
275        };
276        self.accept_cell_visitor(value, &mut j);
277        Value::Object(j.value)
278    }
279
280    /// Collect the columns for a table of this type into an ordered
281    /// sequence.
282    fn columns(&self) -> Vec<String> {
283        let mut c = ColumnListVisitor { value: Vec::new() };
284        self.accept_column_visitor(&mut c);
285        c.value
286    }
287}
288
289#[doc(hidden)]
290pub trait SelfSerializer<'a>
291where
292    Self: 'a,
293{
294    /// Visit the values in a row of output for this type using
295    /// `visitor`.
296    fn accept_cell_visitor<V: CellVisitor>(&self, visitor: &mut V);
297
298    /// Visit the columns in a row using `visitor`; note that this
299    /// does not require an instance of the type.
300    fn accept_column_visitor<V: ColumnVisitor>(visitor: &mut V);
301}
302
303// Note the presence of the marker is to prevent type annotations
304// elsewhere, otherwise even though we have a constraint on some other
305// type that the serializer is for Self rust cannot rule out that we
306// wanted to use it for some other type.
307#[doc(hidden)]
308pub struct DefaultSelfSerializer<T> {
309    _marker: core::marker::PhantomData<T>,
310}
311
312impl<'a, T> IntoRow<'a> for T
313where
314    T: SelfSerializer<'a>,
315{
316    type Serializer = DefaultSelfSerializer<Self>;
317    fn get_serializer() -> Self::Serializer {
318        DefaultSelfSerializer {
319            _marker: Default::default(),
320        }
321    }
322}
323
324impl<'a, T> Serializer<'a, T> for DefaultSelfSerializer<T>
325where
326    T: SelfSerializer<'a>,
327{
328    fn accept_cell_visitor<V: CellVisitor>(&self, value: &T, visitor: &mut V) {
329        value.accept_cell_visitor(visitor)
330    }
331
332    fn accept_column_visitor<V: ColumnVisitor>(&self, visitor: &mut V) {
333        T::accept_column_visitor(visitor)
334    }
335}
336
337impl<'s, T> IntoRow<'s> for Option<T>
338where
339    T: IntoRow<'s>,
340{
341    type Serializer = OptionSerializer;
342    fn get_serializer() -> Self::Serializer {
343        OptionSerializer
344    }
345}
346
347#[doc(hidden)]
348pub struct OptionSerializer;
349
350impl<'s, T> Serializer<'s, Option<T>> for OptionSerializer
351where
352    T: IntoRow<'s>,
353{
354    fn accept_cell_visitor<V: CellVisitor>(&self, value: &Option<T>, visitor: &mut V) {
355        if let Some(item) = value.as_ref() {
356            T::get_serializer().accept_cell_visitor(item, visitor);
357        } else {
358            let mut n = NullColumnVisitor { parent: visitor };
359            T::get_serializer().accept_column_visitor(&mut n);
360        }
361    }
362
363    fn accept_column_visitor<V: ColumnVisitor>(&self, visitor: &mut V) {
364        T::get_serializer().accept_column_visitor(visitor);
365    }
366}
367
368impl<'s, T> IntoRow<'s> for Arc<T>
369where
370    T: IntoRow<'s>,
371{
372    type Serializer = ArcSerializer;
373    fn get_serializer() -> Self::Serializer {
374        ArcSerializer
375    }
376}
377
378#[doc(hidden)]
379pub struct ArcSerializer;
380
381impl<'r, T> Serializer<'r, Arc<T>> for ArcSerializer
382where
383    T: IntoRow<'r>,
384{
385    fn accept_cell_visitor<V: CellVisitor>(&self, value: &Arc<T>, visitor: &mut V) {
386        T::get_serializer().accept_cell_visitor(&*value, visitor);
387    }
388
389    fn accept_column_visitor<V: ColumnVisitor>(&self, visitor: &mut V) {
390        T::get_serializer().accept_column_visitor(visitor);
391    }
392}
393
394/// Convert a structured value into a single representative [`CellValue`]
395///
396/// The conversion takes a `key`, so that different consumers can choose
397/// different foreign keys to represent this type in their output.
398pub trait AsForeignKey<'a, 'r>: Sized {
399    type CellReducer: CellReducer<'a, 'r, Self>;
400    fn get_cell_reducer(key: &'a str) -> Self::CellReducer;
401}
402
403impl<'a, 'r, T> AsForeignKey<'a, 'r> for T
404where
405    T: IntoRow<'r>,
406{
407    type CellReducer = SerializerCellReducer<'a, <T as IntoRow<'r>>::Serializer>;
408
409    fn get_cell_reducer(key: &'a str) -> Self::CellReducer {
410        SerializerCellReducer::new(T::get_serializer(), key)
411    }
412}
413
414impl<'a, 'r, T> AsForeignKey<'a, 'r> for Vec<T>
415where
416    T: AsForeignKey<'a, 'r>,
417{
418    type CellReducer = VecCellReducer<<T as AsForeignKey<'a, 'r>>::CellReducer>;
419    fn get_cell_reducer(key: &'a str) -> Self::CellReducer {
420        VecCellReducer {
421            nested: T::get_cell_reducer(key),
422        }
423    }
424}
425
426#[doc(hidden)]
427pub trait CellReducer<'a, 'r, T> {
428    /// Return the representation of the object if the column `name`
429    /// of its own table is used to stand in for it.
430    fn reduce_to_cell(&self, value: &T) -> CellValue;
431}
432
433#[doc(hidden)]
434pub struct SerializerCellReducer<'a, S> {
435    serializer: S,
436    key: &'a str,
437}
438
439impl<'a, S> SerializerCellReducer<'a, S> {
440    pub fn new(serializer: S, key: &'a str) -> Self {
441        Self { serializer, key }
442    }
443}
444
445impl<'a, 'r, S, T> CellReducer<'a, 'r, T> for SerializerCellReducer<'a, S>
446where
447    S: Serializer<'r, T>,
448{
449    fn reduce_to_cell(&self, value: &T) -> CellValue {
450        let mut k = ForeignKeyVisitor {
451            target: self.key,
452            value: None,
453        };
454        self.serializer.accept_cell_visitor(value, &mut k);
455        k.value.unwrap_or(CellValue::Null)
456    }
457}
458
459#[doc(hidden)]
460pub struct VecCellReducer<C> {
461    nested: C,
462}
463
464impl<'a, 'r, T, C> CellReducer<'a, 'r, Vec<T>> for VecCellReducer<C>
465where
466    C: CellReducer<'a, 'r, T>,
467{
468    fn reduce_to_cell(&self, value: &Vec<T>) -> CellValue {
469        CellValue::Array(
470            value
471                .iter()
472                .map(|item| self.nested.reduce_to_cell(item))
473                .collect(),
474        )
475    }
476}
477
478#[doc(hidden)]
479pub struct ForeignKeyVisitor<'a> {
480    pub target: &'a str,
481    pub value: Option<CellValue>,
482}
483
484impl<'a> CellVisitor for ForeignKeyVisitor<'a> {
485    fn visit_value(&mut self, name: &str, v: CellValue) {
486        if name == self.target {
487            self.value = Some(v);
488        }
489    }
490}
491
492struct RowVisitor {
493    pub values: BTreeMap<String, CellValue>,
494}
495
496impl CellVisitor for RowVisitor {
497    fn visit_value(&mut self, name: &str, v: CellValue) {
498        self.values.insert(name.to_string(), v);
499    }
500}
501
502impl From<CellValue> for Value {
503    fn from(v: CellValue) -> Self {
504        match v {
505            CellValue::Null => Value::Null,
506            CellValue::Bool(b) => Value::Bool(b),
507            CellValue::Number(n) => Value::Number(n),
508            CellValue::String(s) => Value::String(s),
509            CellValue::Array(a) => Value::Array(a.into_iter().map(|x| x.into()).collect()),
510        }
511    }
512}
513
514struct JsonVisitor {
515    pub value: serde_json::map::Map<String, Value>,
516}
517
518impl CellVisitor for JsonVisitor {
519    fn visit_value(&mut self, name: &str, v: CellValue) {
520        self.value.insert(name.to_string(), v.into());
521    }
522}
523
524struct ColumnListVisitor {
525    pub value: Vec<String>,
526}
527
528impl ColumnVisitor for ColumnListVisitor {
529    fn visit_column(&mut self, name: &str) {
530        self.value.push(name.to_string())
531    }
532}
533
534struct NullColumnVisitor<'a, V> {
535    parent: &'a mut V,
536}
537
538impl<'a, V> ColumnVisitor for NullColumnVisitor<'a, V>
539where
540    V: CellVisitor,
541{
542    fn visit_column(&mut self, name: &str) {
543        self.parent.visit_value(name, CellValue::Null);
544    }
545}
546
547// Generic state support
548
549/// Produce a [`Serializer`] to convert values of this type, which
550/// requires a context value, into rows of output.
551///
552#[cfg_attr(
553    feature = "persian-rug",
554    doc = r##"
555This can be derived via the
556[`IntoRowWithPersianRug`](IntoRowWithPersianRug)
557derive macro for the case of a [`persian-rug`](::persian_rug)
558type.
559"##
560)]
561pub trait IntoRowWithContext<'a, A: 'a>: Sized {
562    type Serializer: Serializer<'a, Self>;
563    /// `accessor` is some context value
564    fn get_serializer(accessor: A) -> Self::Serializer;
565}
566
567/// Convert a structured value into a single representative
568/// [`CellValue`] using a context value
569///
570/// The conversion takes a `key`, so that different consumers can choose
571/// different foreign keys to represent this type in their output.
572pub trait AsForeignKeyWithContext<'a, 'r, A: 'r>: Sized {
573    type CellReducer: CellReducer<'a, 'r, Self>;
574    fn get_cell_reducer(accessor: A, key: &'a str) -> Self::CellReducer;
575}
576
577impl<'a, 'r, A, T> AsForeignKeyWithContext<'a, 'r, A> for Vec<T>
578where
579    T: AsForeignKeyWithContext<'a, 'r, A>,
580    A: 'r,
581{
582    type CellReducer = VecCellReducer<<T as AsForeignKeyWithContext<'a, 'r, A>>::CellReducer>;
583    fn get_cell_reducer(accessor: A, key: &'a str) -> Self::CellReducer {
584        VecCellReducer {
585            nested: T::get_cell_reducer(accessor, key),
586        }
587    }
588}
589
590impl<'s, T, A> IntoRowWithContext<'s, A> for Option<T>
591where
592    T: IntoRowWithContext<'s, A>,
593    A: 's + Clone,
594{
595    type Serializer = OptionSerializerWithContext<A>;
596    fn get_serializer(access: A) -> Self::Serializer {
597        OptionSerializerWithContext { access }
598    }
599}
600
601impl<'a, 's, T, A> AsForeignKeyWithContext<'a, 's, A> for Option<T>
602where
603    T: IntoRowWithContext<'s, A>,
604    A: 's + Clone,
605{
606    type CellReducer = SerializerCellReducer<'a, OptionSerializerWithContext<A>>;
607    fn get_cell_reducer(access: A, key: &'a str) -> Self::CellReducer {
608        SerializerCellReducer::new(OptionSerializerWithContext { access }, key)
609    }
610}
611
612#[doc(hidden)]
613pub struct OptionSerializerWithContext<A> {
614    access: A,
615}
616
617impl<'s, T, A> Serializer<'s, Option<T>> for OptionSerializerWithContext<A>
618where
619    T: IntoRowWithContext<'s, A>,
620    A: 's + Clone,
621{
622    fn accept_cell_visitor<V: CellVisitor>(&self, value: &Option<T>, visitor: &mut V) {
623        if let Some(item) = value.as_ref() {
624            T::get_serializer(self.access.clone()).accept_cell_visitor(item, visitor);
625        } else {
626            let mut n = NullColumnVisitor { parent: visitor };
627            T::get_serializer(self.access.clone()).accept_column_visitor(&mut n);
628        }
629    }
630
631    fn accept_column_visitor<V: ColumnVisitor>(&self, visitor: &mut V) {
632        T::get_serializer(self.access.clone()).accept_column_visitor(visitor);
633    }
634}
635
636pub use django_query_derive::IntoRow;
637
638#[cfg(feature = "persian-rug")]
639#[cfg_attr(docsrs, doc(cfg(feature = "persian-rug")))]
640pub use crate::persian_rug::IntoRowWithPersianRug;