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}