Skip to main content

vantage_mongodb/select/impls/
selectable.rs

1//! Selectable<AnyMongoType, MongoCondition> implementation for MongoSelect.
2
3use vantage_expressions::traits::selectable::SourceRef;
4use vantage_expressions::{Expression, Expressive, ExpressiveEnum, Order, Selectable};
5
6use crate::condition::MongoCondition;
7use crate::select::MongoSelect;
8use crate::types::AnyMongoType;
9
10impl Selectable<AnyMongoType, MongoCondition> for MongoSelect {
11    fn add_source(&mut self, source: impl Into<SourceRef<AnyMongoType>>, _alias: Option<String>) {
12        let source_ref = source.into().into_expressive_enum();
13        if let ExpressiveEnum::Scalar(val) = source_ref
14            && let Some(name) = val.try_get::<String>()
15        {
16            self.collection = Some(name);
17        }
18    }
19
20    fn add_field(&mut self, field: impl Into<String>) {
21        self.fields.push(field.into());
22    }
23
24    fn add_expression(&mut self, _expression: impl Expressive<AnyMongoType>) {
25        // MongoDB projections don't support arbitrary expressions in find().
26    }
27
28    fn add_where_condition(&mut self, condition: impl Into<MongoCondition>) {
29        self.conditions.push(condition.into());
30    }
31
32    fn set_distinct(&mut self, distinct: bool) {
33        self.distinct = distinct;
34    }
35
36    fn add_order_by(&mut self, order: impl Into<MongoCondition>, direction: Order) {
37        // Convention: a MongoCondition::Doc with a single key → use that key.
38        // The direction from the Order param overrides whatever value is in the doc.
39        let cond = order.into();
40        if let MongoCondition::Doc(doc) = &cond
41            && let Some((key, _)) = doc.iter().next()
42        {
43            let dir = if direction.ascending { 1 } else { -1 };
44            self.sort.push((key.to_string(), dir));
45        }
46    }
47
48    fn add_group_by(&mut self, expression: impl Expressive<AnyMongoType>) {
49        let preview = expression.preview();
50        self.group_by.push(preview);
51    }
52
53    fn set_limit(&mut self, limit: Option<i64>, skip: Option<i64>) {
54        self.limit = limit;
55        self.skip = skip;
56    }
57
58    fn clear_fields(&mut self) {
59        self.fields.clear();
60    }
61
62    fn clear_where_conditions(&mut self) {
63        self.conditions.clear();
64    }
65
66    fn clear_order_by(&mut self) {
67        self.sort.clear();
68    }
69
70    fn clear_group_by(&mut self) {
71        self.group_by.clear();
72    }
73
74    fn has_fields(&self) -> bool {
75        !self.fields.is_empty()
76    }
77
78    fn has_where_conditions(&self) -> bool {
79        !self.conditions.is_empty()
80    }
81
82    fn has_order_by(&self) -> bool {
83        !self.sort.is_empty()
84    }
85
86    fn has_group_by(&self) -> bool {
87        !self.group_by.is_empty()
88    }
89
90    fn is_distinct(&self) -> bool {
91        self.distinct
92    }
93
94    fn get_limit(&self) -> Option<i64> {
95        self.limit
96    }
97
98    fn get_skip(&self) -> Option<i64> {
99        self.skip
100    }
101
102    fn as_field(&self, field: impl Into<String>) -> Expression<AnyMongoType> {
103        let coll = self.collection.as_deref().unwrap_or("?");
104        let filter = if self.conditions.is_empty() {
105            "<no conditions>".to_string()
106        } else if self.conditions.len() == 1 {
107            "<1 condition>".to_string()
108        } else {
109            format!("<{} conditions>", self.conditions.len())
110        };
111        // Braces are left out: `Expression` templates treat `{}` as a placeholder.
112        Expression::new(
113            format!("db.{}.find({}).project({})", coll, filter, field.into()),
114            vec![],
115        )
116    }
117
118    fn as_count(&self) -> Expression<AnyMongoType> {
119        let coll = self.collection.as_deref().unwrap_or("?");
120        Expression::new(format!("db.{}.countDocuments()", coll), vec![])
121    }
122
123    fn as_sum(&self, column: impl Expressive<AnyMongoType>) -> Expression<AnyMongoType> {
124        let coll = self.collection.as_deref().unwrap_or("?");
125        Expression::new(
126            format!("db.{}.aggregate($sum: {})", coll, column.preview()),
127            vec![],
128        )
129    }
130
131    fn as_max(&self, column: impl Expressive<AnyMongoType>) -> Expression<AnyMongoType> {
132        let coll = self.collection.as_deref().unwrap_or("?");
133        Expression::new(
134            format!("db.{}.aggregate($max: {})", coll, column.preview()),
135            vec![],
136        )
137    }
138
139    fn as_min(&self, column: impl Expressive<AnyMongoType>) -> Expression<AnyMongoType> {
140        let coll = self.collection.as_deref().unwrap_or("?");
141        Expression::new(
142            format!("db.{}.aggregate($min: {})", coll, column.preview()),
143            vec![],
144        )
145    }
146}
147
148/// A select names its query for display only; MongoDB runs selects through
149/// the driver, never as expression text.
150impl Expressive<AnyMongoType> for MongoSelect {
151    fn expr(&self) -> Expression<AnyMongoType> {
152        self.as_field(self.fields.join(", "))
153    }
154}