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 trace_chain: Vec<crate::TraceNode>,
292    pub raw_sql: Option<String>,
293    pub raw_sql_search_criteria: Vec<String>,
294    pub dynamic_properties: Vec<RawSqlProjection>,
295    pub raw_projections: Vec<RawSqlProjection>,
296    pub object_group_bys: Vec<ObjectGroupBy>,
297    pub child_enhancements: Vec<SelectQuery>,
298}
299
300impl SelectQuery {
301    pub fn new(entity: impl Into<String>) -> Self {
302        Self {
303            entity: entity.into(),
304            projection: Vec::new(),
305            expr_projection: Vec::new(),
306            filter: None,
307            having: None,
308            order_by: Vec::new(),
309            slice: None,
310            aggregates: Vec::new(),
311            group_by: Vec::new(),
312            relations: Vec::new(),
313            aggregation_cache: None,
314            comment: None,
315            trace_chain: Vec::new(),
316            raw_sql: None,
317            raw_sql_search_criteria: Vec::new(),
318            dynamic_properties: Vec::new(),
319            raw_projections: Vec::new(),
320            object_group_bys: Vec::new(),
321            child_enhancements: Vec::new(),
322        }
323    }
324
325    pub fn project(mut self, field: impl Into<String>) -> Self {
326        self.projection.push(field.into());
327        self
328    }
329
330    pub fn projects(mut self, fields: impl IntoIterator<Item = impl Into<String>>) -> Self {
331        self.projection.extend(fields.into_iter().map(Into::into));
332        self
333    }
334
335    pub fn project_expr(mut self, alias: impl Into<String>, expr: Expr) -> Self {
336        self.expr_projection.push(NamedExpr::new(alias, expr));
337        self
338    }
339
340    pub fn project_raw(
341        mut self,
342        alias: impl Into<String>,
343        raw_sql_segment: impl Into<String>,
344    ) -> Self {
345        self.raw_projections
346            .push(RawSqlProjection::new(alias, raw_sql_segment));
347        self
348    }
349
350    pub fn dynamic_property_raw(
351        mut self,
352        alias: impl Into<String>,
353        raw_sql_segment: impl Into<String>,
354    ) -> Self {
355        self.dynamic_properties
356            .push(RawSqlProjection::new(alias, raw_sql_segment));
357        self
358    }
359
360    pub fn filter(mut self, filter: Expr) -> Self {
361        self.filter = Some(filter);
362        self
363    }
364
365    pub fn and_filter(mut self, filter: Expr) -> Self {
366        self.filter = Some(match self.filter.take() {
367            Some(existing) => existing.and_expr(filter),
368            None => filter,
369        });
370        self
371    }
372
373    pub fn or_filter(mut self, filter: Expr) -> Self {
374        self.filter = Some(match self.filter.take() {
375            Some(existing) => existing.or_expr(filter),
376            None => filter,
377        });
378        self
379    }
380
381    pub fn having(mut self, having: Expr) -> Self {
382        self.having = Some(having);
383        self
384    }
385
386    pub fn and_having(mut self, having: Expr) -> Self {
387        self.having = Some(match self.having.take() {
388            Some(existing) => existing.and_expr(having),
389            None => having,
390        });
391        self
392    }
393
394    pub fn or_having(mut self, having: Expr) -> Self {
395        self.having = Some(match self.having.take() {
396            Some(existing) => existing.or_expr(having),
397            None => having,
398        });
399        self
400    }
401
402    pub fn order_by(mut self, order: OrderBy) -> Self {
403        self.order_by.push(order);
404        self
405    }
406
407    pub fn order_asc(self, field: impl Into<String>) -> Self {
408        self.order_by(OrderBy::asc(field))
409    }
410
411    pub fn order_desc(self, field: impl Into<String>) -> Self {
412        self.order_by(OrderBy::desc(field))
413    }
414
415    pub fn order_expr_asc(self, expr: Expr) -> Self {
416        self.order_by(OrderBy::asc_expr(expr))
417    }
418
419    pub fn order_expr_desc(self, expr: Expr) -> Self {
420        self.order_by(OrderBy::desc_expr(expr))
421    }
422
423    pub fn order_gbk_asc(self, field: impl Into<String>) -> Self {
424        self.order_by(OrderBy::asc_gbk(field))
425    }
426
427    pub fn order_gbk_desc(self, field: impl Into<String>) -> Self {
428        self.order_by(OrderBy::desc_gbk(field))
429    }
430
431    pub fn group_by(mut self, field: impl Into<String>) -> Self {
432        self.group_by.push(field.into());
433        self
434    }
435
436    pub fn aggregate(mut self, aggregate: Aggregate) -> Self {
437        self.aggregates.push(aggregate);
438        self
439    }
440
441    pub fn count(self, alias: impl Into<String>) -> Self {
442        self.aggregate(Aggregate::count(alias))
443    }
444
445    pub fn count_field(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
446        self.aggregate(Aggregate::count_field(field, alias))
447    }
448
449    pub fn sum(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
450        self.aggregate(Aggregate::sum(field, alias))
451    }
452
453    pub fn avg(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
454        self.aggregate(Aggregate::avg(field, alias))
455    }
456
457    pub fn min(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
458        self.aggregate(Aggregate::min(field, alias))
459    }
460
461    pub fn max(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
462        self.aggregate(Aggregate::max(field, alias))
463    }
464
465    pub fn stddev(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
466        self.aggregate(Aggregate::stddev(field, alias))
467    }
468
469    pub fn stddev_pop(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
470        self.aggregate(Aggregate::stddev_pop(field, alias))
471    }
472
473    pub fn var_samp(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
474        self.aggregate(Aggregate::var_samp(field, alias))
475    }
476
477    pub fn var_pop(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
478        self.aggregate(Aggregate::var_pop(field, alias))
479    }
480
481    pub fn bit_and(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
482        self.aggregate(Aggregate::bit_and(field, alias))
483    }
484
485    pub fn bit_or(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
486        self.aggregate(Aggregate::bit_or(field, alias))
487    }
488
489    pub fn bit_xor(self, field: impl Into<String>, alias: impl Into<String>) -> Self {
490        self.aggregate(Aggregate::bit_xor(field, alias))
491    }
492
493    pub fn enable_aggregation_cache(self) -> Self {
494        self.enable_aggregation_cache_for(0)
495    }
496
497    pub fn enable_aggregation_cache_for(mut self, cache_expired_millis: u64) -> Self {
498        self.aggregation_cache = Some(AggregationCacheOptions::enabled(cache_expired_millis));
499        self
500    }
501
502    pub fn propagate_aggregation_cache(mut self, cache_expired_millis: u64) -> Self {
503        self.aggregation_cache = Some(
504            self.aggregation_cache
505                .unwrap_or_else(|| AggregationCacheOptions::enabled(0))
506                .propagate(cache_expired_millis),
507        );
508        self
509    }
510
511    pub fn comment(mut self, comment: impl Into<String>) -> Self {
512        let comment_str = comment.into();
513        self.comment = Some(comment_str.clone());
514        self.trace_chain.push(crate::TraceNode {
515            entity_type: self.entity.clone(),
516            entity_id: None,
517            comment: comment_str,
518        });
519        self
520    }
521
522    pub fn raw_sql(mut self, raw_sql: impl Into<String>) -> Self {
523        self.raw_sql = Some(raw_sql.into());
524        self
525    }
526
527    pub fn raw_sql_search_criteria(mut self, raw_sql: impl Into<String>) -> Self {
528        self.raw_sql_search_criteria.push(raw_sql.into());
529        self
530    }
531
532    pub fn object_group_by(
533        mut self,
534        property_name: impl Into<String>,
535        storage_field: impl Into<String>,
536        query: SelectQuery,
537    ) -> Self {
538        self.object_group_bys
539            .push(ObjectGroupBy::new(property_name, storage_field, query));
540        self
541    }
542
543    pub fn child_enhancement(mut self, query: SelectQuery) -> Self {
544        self.child_enhancements.push(query);
545        self
546    }
547
548    pub fn relation(mut self, name: impl Into<String>) -> Self {
549        self.relations.push(RelationLoad::new(name));
550        self
551    }
552
553    pub fn relation_query(mut self, name: impl Into<String>, query: SelectQuery) -> Self {
554        self.relations.push(RelationLoad::with_query(name, query));
555        self
556    }
557
558    pub fn limit(mut self, limit: u64) -> Self {
559        let slice = self.slice.get_or_insert(Slice {
560            limit: None,
561            offset: 0,
562        });
563        slice.limit = Some(limit);
564        self
565    }
566
567    pub fn offset(mut self, offset: u64) -> Self {
568        let slice = self.slice.get_or_insert(Slice {
569            limit: None,
570            offset: 0,
571        });
572        slice.offset = offset;
573        self
574    }
575
576    pub fn page(self, offset: u64, limit: u64) -> Self {
577        self.offset(offset).limit(limit)
578    }
579}
580
581pub type Record = BTreeMap<String, Value>;
582
583pub fn record_to_json_value(record: &Record) -> serde_json::Value {
584    serde_json::Value::Object(
585        record
586            .iter()
587            .map(|(key, value)| (key.clone(), value.to_json_value()))
588            .collect(),
589    )
590}