Skip to main content

teaql_core/
query.rs

1use std::collections::BTreeMap;
2
3use crate::{Expr, Value};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum SortDirection {
7    Asc,
8    Desc,
9}
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct NamedExpr {
13    pub alias: String,
14    pub expr: Expr,
15}
16
17impl NamedExpr {
18    pub fn new(alias: impl Into<String>, expr: Expr) -> Self {
19        Self {
20            alias: alias.into(),
21            expr,
22        }
23    }
24}
25
26#[derive(Debug, Clone, PartialEq)]
27pub struct OrderBy {
28    pub field: String,
29    pub expr: Option<Expr>,
30    pub direction: SortDirection,
31}
32
33impl OrderBy {
34    pub fn new(field: impl Into<String>, direction: SortDirection) -> Self {
35        Self {
36            field: field.into(),
37            expr: None,
38            direction,
39        }
40    }
41
42    pub fn expr(expr: Expr, direction: SortDirection) -> Self {
43        Self {
44            field: String::new(),
45            expr: Some(expr),
46            direction,
47        }
48    }
49
50    pub fn asc(field: impl Into<String>) -> Self {
51        Self::new(field, SortDirection::Asc)
52    }
53
54    pub fn desc(field: impl Into<String>) -> Self {
55        Self::new(field, SortDirection::Desc)
56    }
57
58    pub fn asc_expr(expr: Expr) -> Self {
59        Self::expr(expr, SortDirection::Asc)
60    }
61
62    pub fn desc_expr(expr: Expr) -> Self {
63        Self::expr(expr, SortDirection::Desc)
64    }
65
66    pub fn asc_gbk(field: impl Into<String>) -> Self {
67        Self::asc_expr(Expr::gbk(Expr::column(field)))
68    }
69
70    pub fn desc_gbk(field: impl Into<String>) -> Self {
71        Self::desc_expr(Expr::gbk(Expr::column(field)))
72    }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub enum AggregateFunction {
77    Count,
78    Sum,
79    Avg,
80    Min,
81    Max,
82    Stddev,
83    StddevPop,
84    VarSamp,
85    VarPop,
86    BitAnd,
87    BitOr,
88    BitXor,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct Aggregate {
93    pub function: AggregateFunction,
94    pub field: String,
95    pub alias: String,
96}
97
98impl Aggregate {
99    pub fn new(
100        function: AggregateFunction,
101        field: impl Into<String>,
102        alias: impl Into<String>,
103    ) -> Self {
104        Self {
105            function,
106            field: field.into(),
107            alias: alias.into(),
108        }
109    }
110
111    pub fn count(alias: impl Into<String>) -> Self {
112        Self::new(AggregateFunction::Count, "*", alias)
113    }
114
115    pub fn count_field(field: impl Into<String>, alias: impl Into<String>) -> Self {
116        Self::new(AggregateFunction::Count, field, alias)
117    }
118
119    pub fn sum(field: impl Into<String>, alias: impl Into<String>) -> Self {
120        Self::new(AggregateFunction::Sum, field, alias)
121    }
122
123    pub fn avg(field: impl Into<String>, alias: impl Into<String>) -> Self {
124        Self::new(AggregateFunction::Avg, field, alias)
125    }
126
127    pub fn min(field: impl Into<String>, alias: impl Into<String>) -> Self {
128        Self::new(AggregateFunction::Min, field, alias)
129    }
130
131    pub fn max(field: impl Into<String>, alias: impl Into<String>) -> Self {
132        Self::new(AggregateFunction::Max, field, alias)
133    }
134
135    pub fn stddev(field: impl Into<String>, alias: impl Into<String>) -> Self {
136        Self::new(AggregateFunction::Stddev, field, alias)
137    }
138
139    pub fn stddev_pop(field: impl Into<String>, alias: impl Into<String>) -> Self {
140        Self::new(AggregateFunction::StddevPop, field, alias)
141    }
142
143    pub fn var_samp(field: impl Into<String>, alias: impl Into<String>) -> Self {
144        Self::new(AggregateFunction::VarSamp, field, alias)
145    }
146
147    pub fn var_pop(field: impl Into<String>, alias: impl Into<String>) -> Self {
148        Self::new(AggregateFunction::VarPop, field, alias)
149    }
150
151    pub fn bit_and(field: impl Into<String>, alias: impl Into<String>) -> Self {
152        Self::new(AggregateFunction::BitAnd, field, alias)
153    }
154
155    pub fn bit_or(field: impl Into<String>, alias: impl Into<String>) -> Self {
156        Self::new(AggregateFunction::BitOr, field, alias)
157    }
158
159    pub fn bit_xor(field: impl Into<String>, alias: impl Into<String>) -> Self {
160        Self::new(AggregateFunction::BitXor, field, alias)
161    }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
165pub struct Slice {
166    pub limit: Option<u64>,
167    pub offset: u64,
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub struct RelationLoad {
172    pub name: String,
173    pub query: Option<Box<SelectQuery>>,
174}
175
176impl RelationLoad {
177    pub fn new(name: impl Into<String>) -> Self {
178        Self {
179            name: name.into(),
180            query: None,
181        }
182    }
183
184    pub fn with_query(name: impl Into<String>, query: SelectQuery) -> Self {
185        Self {
186            name: name.into(),
187            query: Some(Box::new(query)),
188        }
189    }
190}
191
192#[derive(Debug, Clone, PartialEq)]
193pub struct RelationAggregate {
194    pub relation_name: String,
195    pub alias: String,
196    pub query: SelectQuery,
197    pub single_result: bool,
198}
199
200impl RelationAggregate {
201    pub fn new(
202        relation_name: impl Into<String>,
203        alias: impl Into<String>,
204        query: SelectQuery,
205        single_result: bool,
206    ) -> Self {
207        Self {
208            relation_name: relation_name.into(),
209            alias: alias.into(),
210            query,
211            single_result,
212        }
213    }
214}
215
216#[derive(Debug, Clone, PartialEq, Eq)]
217pub struct RawSqlProjection {
218    pub property_name: String,
219    pub raw_sql_segment: String,
220}
221
222impl RawSqlProjection {
223    pub fn new(property_name: impl Into<String>, raw_sql_segment: impl Into<String>) -> Self {
224        Self {
225            property_name: property_name.into(),
226            raw_sql_segment: raw_sql_segment.into(),
227        }
228    }
229}
230
231#[derive(Debug, Clone, PartialEq)]
232pub struct ObjectGroupBy {
233    pub property_name: String,
234    pub storage_field: String,
235    pub query: SelectQuery,
236}
237
238impl ObjectGroupBy {
239    pub fn new(
240        property_name: impl Into<String>,
241        storage_field: impl Into<String>,
242        query: SelectQuery,
243    ) -> Self {
244        Self {
245            property_name: property_name.into(),
246            storage_field: storage_field.into(),
247            query,
248        }
249    }
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub struct AggregationCacheOptions {
254    pub enabled: bool,
255    pub cache_expired_millis: u64,
256    pub propagate: bool,
257    pub propagate_cache_expired_millis: u64,
258}
259
260impl AggregationCacheOptions {
261    pub fn enabled(cache_expired_millis: u64) -> Self {
262        Self {
263            enabled: true,
264            cache_expired_millis,
265            propagate: false,
266            propagate_cache_expired_millis: 0,
267        }
268    }
269
270    pub fn propagate(mut self, cache_expired_millis: u64) -> Self {
271        self.propagate = true;
272        self.propagate_cache_expired_millis = cache_expired_millis;
273        self
274    }
275}
276
277#[derive(Debug, Clone, PartialEq)]
278pub struct SelectQuery {
279    pub entity: String,
280    pub projection: Vec<String>,
281    pub expr_projection: Vec<NamedExpr>,
282    pub filter: Option<Expr>,
283    pub having: Option<Expr>,
284    pub order_by: Vec<OrderBy>,
285    pub slice: Option<Slice>,
286    pub aggregates: Vec<Aggregate>,
287    pub group_by: Vec<String>,
288    pub relations: Vec<RelationLoad>,
289    pub aggregation_cache: Option<AggregationCacheOptions>,
290    pub comment: Option<String>,
291    pub raw_sql: Option<String>,
292    pub raw_sql_search_criteria: Vec<String>,
293    pub dynamic_properties: Vec<RawSqlProjection>,
294    pub raw_projections: Vec<RawSqlProjection>,
295    pub object_group_bys: Vec<ObjectGroupBy>,
296    pub child_enhancements: Vec<SelectQuery>,
297}
298
299impl SelectQuery {
300    pub fn new(entity: impl Into<String>) -> Self {
301        Self {
302            entity: entity.into(),
303            projection: Vec::new(),
304            expr_projection: Vec::new(),
305            filter: None,
306            having: None,
307            order_by: Vec::new(),
308            slice: None,
309            aggregates: Vec::new(),
310            group_by: Vec::new(),
311            relations: Vec::new(),
312            aggregation_cache: None,
313            comment: None,
314            raw_sql: None,
315            raw_sql_search_criteria: Vec::new(),
316            dynamic_properties: Vec::new(),
317            raw_projections: Vec::new(),
318            object_group_bys: Vec::new(),
319            child_enhancements: Vec::new(),
320        }
321    }
322
323    pub fn project(mut self, field: impl Into<String>) -> Self {
324        self.projection.push(field.into());
325        self
326    }
327
328    pub fn projects(mut self, fields: impl IntoIterator<Item = impl Into<String>>) -> Self {
329        self.projection.extend(fields.into_iter().map(Into::into));
330        self
331    }
332
333    pub fn project_expr(mut self, alias: impl Into<String>, expr: Expr) -> Self {
334        self.expr_projection.push(NamedExpr::new(alias, expr));
335        self
336    }
337
338    pub fn project_raw(
339        mut self,
340        alias: impl Into<String>,
341        raw_sql_segment: impl Into<String>,
342    ) -> Self {
343        self.raw_projections
344            .push(RawSqlProjection::new(alias, raw_sql_segment));
345        self
346    }
347
348    pub fn dynamic_property_raw(
349        mut self,
350        alias: impl Into<String>,
351        raw_sql_segment: impl Into<String>,
352    ) -> Self {
353        self.dynamic_properties
354            .push(RawSqlProjection::new(alias, raw_sql_segment));
355        self
356    }
357
358    pub fn filter(mut self, filter: Expr) -> Self {
359        self.filter = Some(filter);
360        self
361    }
362
363    pub fn and_filter(mut self, filter: Expr) -> Self {
364        self.filter = Some(match self.filter.take() {
365            Some(existing) => existing.and_expr(filter),
366            None => filter,
367        });
368        self
369    }
370
371    pub fn or_filter(mut self, filter: Expr) -> Self {
372        self.filter = Some(match self.filter.take() {
373            Some(existing) => existing.or_expr(filter),
374            None => filter,
375        });
376        self
377    }
378
379    pub fn having(mut self, having: Expr) -> Self {
380        self.having = Some(having);
381        self
382    }
383
384    pub fn and_having(mut self, having: Expr) -> Self {
385        self.having = Some(match self.having.take() {
386            Some(existing) => existing.and_expr(having),
387            None => having,
388        });
389        self
390    }
391
392    pub fn or_having(mut self, having: Expr) -> Self {
393        self.having = Some(match self.having.take() {
394            Some(existing) => existing.or_expr(having),
395            None => having,
396        });
397        self
398    }
399
400    pub fn order_by(mut self, order: OrderBy) -> Self {
401        self.order_by.push(order);
402        self
403    }
404
405    pub fn order_asc(self, field: impl Into<String>) -> Self {
406        self.order_by(OrderBy::asc(field))
407    }
408
409    pub fn order_desc(self, field: impl Into<String>) -> Self {
410        self.order_by(OrderBy::desc(field))
411    }
412
413    pub fn order_expr_asc(self, expr: Expr) -> Self {
414        self.order_by(OrderBy::asc_expr(expr))
415    }
416
417    pub fn order_expr_desc(self, expr: Expr) -> Self {
418        self.order_by(OrderBy::desc_expr(expr))
419    }
420
421    pub fn order_gbk_asc(self, field: impl Into<String>) -> Self {
422        self.order_by(OrderBy::asc_gbk(field))
423    }
424
425    pub fn order_gbk_desc(self, field: impl Into<String>) -> Self {
426        self.order_by(OrderBy::desc_gbk(field))
427    }
428
429    pub fn group_by(mut self, field: impl Into<String>) -> Self {
430        self.group_by.push(field.into());
431        self
432    }
433
434    pub fn aggregate(mut self, aggregate: Aggregate) -> Self {
435        self.aggregates.push(aggregate);
436        self
437    }
438
439    pub fn count(self, alias: impl Into<String>) -> Self {
440        self.aggregate(Aggregate::count(alias))
441    }
442
443    pub fn count_field(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
444        self.aggregate(Aggregate::count_field(field, alias))
445    }
446
447    pub fn sum(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
448        self.aggregate(Aggregate::sum(field, alias))
449    }
450
451    pub fn avg(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
452        self.aggregate(Aggregate::avg(field, alias))
453    }
454
455    pub fn min(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
456        self.aggregate(Aggregate::min(field, alias))
457    }
458
459    pub fn max(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
460        self.aggregate(Aggregate::max(field, alias))
461    }
462
463    pub fn stddev(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
464        self.aggregate(Aggregate::stddev(field, alias))
465    }
466
467    pub fn stddev_pop(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
468        self.aggregate(Aggregate::stddev_pop(field, alias))
469    }
470
471    pub fn var_samp(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
472        self.aggregate(Aggregate::var_samp(field, alias))
473    }
474
475    pub fn var_pop(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
476        self.aggregate(Aggregate::var_pop(field, alias))
477    }
478
479    pub fn bit_and(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
480        self.aggregate(Aggregate::bit_and(field, alias))
481    }
482
483    pub fn bit_or(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
484        self.aggregate(Aggregate::bit_or(field, alias))
485    }
486
487    pub fn bit_xor(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
488        self.aggregate(Aggregate::bit_xor(field, alias))
489    }
490
491    pub fn enable_aggregation_cache(self) -> Self {
492        self.enable_aggregation_cache_for(0)
493    }
494
495    pub fn enable_aggregation_cache_for(mut self, cache_expired_millis: u64) -> Self {
496        self.aggregation_cache = Some(AggregationCacheOptions::enabled(cache_expired_millis));
497        self
498    }
499
500    pub fn propagate_aggregation_cache(mut self, cache_expired_millis: u64) -> Self {
501        self.aggregation_cache = Some(
502            self.aggregation_cache
503                .unwrap_or_else(|| AggregationCacheOptions::enabled(0))
504                .propagate(cache_expired_millis),
505        );
506        self
507    }
508
509    pub fn comment(mut self, comment: impl Into<String>) -> Self {
510        self.comment = Some(comment.into());
511        self
512    }
513
514    pub fn raw_sql(mut self, raw_sql: impl Into<String>) -> Self {
515        self.raw_sql = Some(raw_sql.into());
516        self
517    }
518
519    pub fn raw_sql_search_criteria(mut self, raw_sql: impl Into<String>) -> Self {
520        self.raw_sql_search_criteria.push(raw_sql.into());
521        self
522    }
523
524    pub fn object_group_by(
525        mut self,
526        property_name: impl Into<String>,
527        storage_field: impl Into<String>,
528        query: SelectQuery,
529    ) -> Self {
530        self.object_group_bys
531            .push(ObjectGroupBy::new(property_name, storage_field, query));
532        self
533    }
534
535    pub fn child_enhancement(mut self, query: SelectQuery) -> Self {
536        self.child_enhancements.push(query);
537        self
538    }
539
540    pub fn relation(mut self, name: impl Into<String>) -> Self {
541        self.relations.push(RelationLoad::new(name));
542        self
543    }
544
545    pub fn relation_query(mut self, name: impl Into<String>, query: SelectQuery) -> Self {
546        self.relations.push(RelationLoad::with_query(name, query));
547        self
548    }
549
550    pub fn limit(mut self, limit: u64) -> Self {
551        let slice = self.slice.get_or_insert(Slice {
552            limit: None,
553            offset: 0,
554        });
555        slice.limit = Some(limit);
556        self
557    }
558
559    pub fn offset(mut self, offset: u64) -> Self {
560        let slice = self.slice.get_or_insert(Slice {
561            limit: None,
562            offset: 0,
563        });
564        slice.offset = offset;
565        self
566    }
567
568    pub fn page(self, offset: u64, limit: u64) -> Self {
569        self.offset(offset).limit(limit)
570    }
571}
572
573pub type Record = BTreeMap<String, Value>;
574
575pub fn record_to_json_value(record: &Record) -> serde_json::Value {
576    serde_json::Value::Object(
577        record
578            .iter()
579            .map(|(key, value)| (key.clone(), value.to_json_value()))
580            .collect(),
581    )
582}