Skip to main content

firestore/fluent_api/
select_order_builder.rs

1//! Builder for specifying the ordering of Firestore query and listing results.
2//!
3//! This module provides a fluent API to define, per field, the direction results should be
4//! sorted in.
5//!
6//! The main entry point is [`FirestoreQueryOrderBuilder`], passed into the closure given to
7//! `.order()` on a select or listing builder.
8//!
9//! [`FirestoreQueryOrderBuilder`]: crate::select_order_builder::FirestoreQueryOrderBuilder
10
11use crate::{FirestoreQueryDirection, FirestoreQueryOrder};
12
13/// A builder for constructing a list of orderings to apply to a query or listing.
14pub struct FirestoreQueryOrderBuilder {}
15
16impl FirestoreQueryOrderBuilder {
17    pub(crate) fn new() -> Self {
18        Self {}
19    }
20
21    /// Collects `order_field_expr` - typically built with [`FirestoreQueryOrderBuilder::field`]
22    /// and its chained methods - into the ordering for a query or listing, dropping `None`
23    /// entries.
24    #[inline]
25    pub fn fields<I>(&self, order_field_expr: I) -> Vec<FirestoreQueryOrder>
26    where
27        I: IntoIterator,
28        I::Item: FirestoreQueryOrderExpr,
29    {
30        order_field_expr
31            .into_iter()
32            .filter_map(|order| order.build_order())
33            .collect()
34    }
35
36    /// Targets `field_name` for an ordering.
37    #[inline]
38    pub fn field<S>(&self, field_name: S) -> FirestoreQueryOrderFieldExpr
39    where
40        S: AsRef<str>,
41    {
42        FirestoreQueryOrderFieldExpr::new(field_name.as_ref().to_string())
43    }
44}
45
46/// A trait for types that can be converted into a [`FirestoreQueryOrder`].
47///
48/// This is used by [`FirestoreQueryOrderBuilder::fields()`] to allow various ways of defining
49/// orderings, including optional ones.
50pub trait FirestoreQueryOrderExpr {
51    /// Builds the [`FirestoreQueryOrder`].
52    /// Returns `None` if the expression represents no ordering.
53    fn build_order(self) -> Option<FirestoreQueryOrder>;
54}
55
56/// Represents a specific field targeted for an ordering.
57///
58/// This struct provides methods to define the direction to sort the field by.
59pub struct FirestoreQueryOrderFieldExpr {
60    field_name: String,
61}
62
63impl FirestoreQueryOrderFieldExpr {
64    pub(crate) fn new(field_name: String) -> Self {
65        Self { field_name }
66    }
67
68    /// Orders by this field ascending.
69    /// Alias for [`ascending()`](#method.ascending).
70    #[inline]
71    pub fn asc(self) -> Option<FirestoreQueryOrder> {
72        self.ascending()
73    }
74
75    /// Orders by this field descending.
76    /// Alias for [`descending()`](#method.descending).
77    #[inline]
78    pub fn desc(self) -> Option<FirestoreQueryOrder> {
79        self.descending()
80    }
81
82    /// Orders by this field ascending.
83    #[inline]
84    pub fn ascending(self) -> Option<FirestoreQueryOrder> {
85        self.direction(FirestoreQueryDirection::Ascending)
86    }
87
88    /// Orders by this field descending.
89    #[inline]
90    pub fn descending(self) -> Option<FirestoreQueryOrder> {
91        self.direction(FirestoreQueryDirection::Descending)
92    }
93
94    /// Orders by this field using a direction chosen at runtime.
95    #[inline]
96    pub fn direction(self, direction: FirestoreQueryDirection) -> Option<FirestoreQueryOrder> {
97        Some(FirestoreQueryOrder::new(self.field_name, direction))
98    }
99}
100
101impl FirestoreQueryOrderExpr for FirestoreQueryOrder {
102    #[inline]
103    fn build_order(self) -> Option<FirestoreQueryOrder> {
104        Some(self)
105    }
106}
107
108// Allows using Option<FirestoreQueryOrder> in the fields array,
109// filtering out None values.
110impl<F> FirestoreQueryOrderExpr for Option<F>
111where
112    F: FirestoreQueryOrderExpr,
113{
114    #[inline]
115    fn build_order(self) -> Option<FirestoreQueryOrder> {
116        self.and_then(|expr| expr.build_order())
117    }
118}