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}