1#[cfg(feature = "sql")]
7use crate::db::query::plan::expr::ProjectionSelection;
8use crate::{
9 db::{
10 predicate::{CompareOp, MissingRowPolicy, Predicate},
11 query::{
12 builder::AggregateExpr,
13 explain::ExplainPlan,
14 expr::FilterExpr,
15 expr::OrderTerm as FluentOrderTerm,
16 intent::{QueryError, QueryModel},
17 plan::{
18 AccessPlannedQuery, LoadSpec, OrderSpec, PreparedScalarPlanningState, QueryMode,
19 VisibleIndexes, expr::Expr,
20 },
21 },
22 },
23 traits::{EntityKind, KeyValueCodec, SingletonEntity},
24 value::{InputValue, Value},
25};
26use core::marker::PhantomData;
27
28#[derive(Clone, Debug)]
37pub(in crate::db) struct StructuralQuery {
38 intent: QueryModel<'static, Value>,
39}
40
41impl StructuralQuery {
42 #[must_use]
43 pub(in crate::db) const fn new(
44 model: &'static crate::model::entity::EntityModel,
45 consistency: MissingRowPolicy,
46 ) -> Self {
47 Self {
48 intent: QueryModel::new(model, consistency),
49 }
50 }
51
52 const fn from_intent(intent: QueryModel<'static, Value>) -> Self {
56 Self { intent }
57 }
58
59 fn map_intent(
62 self,
63 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
64 ) -> Self {
65 Self::from_intent(map(self.intent))
66 }
67
68 fn try_map_intent(
71 self,
72 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
73 ) -> Result<Self, QueryError> {
74 map(self.intent).map(Self::from_intent)
75 }
76
77 #[must_use]
78 const fn mode(&self) -> QueryMode {
79 self.intent.mode()
80 }
81
82 #[must_use]
83 fn has_explicit_order(&self) -> bool {
84 self.intent.has_explicit_order()
85 }
86
87 #[must_use]
88 pub(in crate::db) const fn has_grouping(&self) -> bool {
89 self.intent.has_grouping()
90 }
91
92 #[must_use]
93 const fn load_spec(&self) -> Option<LoadSpec> {
94 match self.intent.mode() {
95 QueryMode::Load(spec) => Some(spec),
96 QueryMode::Delete(_) => None,
97 }
98 }
99
100 #[must_use]
101 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
102 self.intent = self.intent.filter_predicate(predicate);
103 self
104 }
105
106 #[must_use]
107 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
108 self.intent = self.intent.filter(expr.into());
109 self
110 }
111
112 #[must_use]
113 pub(in crate::db) fn filter_expr_with_normalized_predicate(
114 mut self,
115 expr: Expr,
116 predicate: Predicate,
117 ) -> Self {
118 self.intent = self
119 .intent
120 .filter_expr_with_normalized_predicate(expr, predicate);
121 self
122 }
123 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
124 self.intent = self.intent.order_term(term);
125 self
126 }
127
128 #[must_use]
132 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
133 self.intent = self.intent.filter_expr(expr);
134 self
135 }
136
137 #[must_use]
138 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
139 self.intent = self.intent.order_spec(order);
140 self
141 }
142
143 #[must_use]
144 pub(in crate::db) fn distinct(mut self) -> Self {
145 self.intent = self.intent.distinct();
146 self
147 }
148
149 #[cfg(all(test, feature = "sql"))]
150 #[must_use]
151 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
152 where
153 I: IntoIterator<Item = S>,
154 S: Into<String>,
155 {
156 self.intent = self.intent.select_fields(fields);
157 self
158 }
159
160 #[cfg(feature = "sql")]
161 #[must_use]
162 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
163 self.intent = self.intent.projection_selection(selection);
164 self
165 }
166
167 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
168 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
169 }
170
171 #[must_use]
172 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
173 self.intent = self.intent.push_group_aggregate(aggregate);
174 self
175 }
176
177 #[must_use]
178 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
179 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
180 self
181 }
182
183 pub(in crate::db) fn having_group(
184 self,
185 field: impl AsRef<str>,
186 op: CompareOp,
187 value: Value,
188 ) -> Result<Self, QueryError> {
189 let field = field.as_ref().to_owned();
190 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
191 }
192
193 pub(in crate::db) fn having_aggregate(
194 self,
195 aggregate_index: usize,
196 op: CompareOp,
197 value: Value,
198 ) -> Result<Self, QueryError> {
199 self.try_map_intent(|intent| {
200 intent.push_having_aggregate_clause(aggregate_index, op, value)
201 })
202 }
203
204 #[cfg(test)]
205 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
206 self.try_map_intent(|intent| intent.push_having_expr(expr))
207 }
208
209 pub(in crate::db) fn having_expr_preserving_shape(
210 self,
211 expr: Expr,
212 ) -> Result<Self, QueryError> {
213 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
214 }
215
216 #[must_use]
217 fn by_id(self, id: Value) -> Self {
218 self.map_intent(|intent| intent.by_id(id))
219 }
220
221 #[must_use]
222 fn by_ids<I>(self, ids: I) -> Self
223 where
224 I: IntoIterator<Item = Value>,
225 {
226 self.map_intent(|intent| intent.by_ids(ids))
227 }
228
229 #[must_use]
230 fn only(self, id: Value) -> Self {
231 self.map_intent(|intent| intent.only(id))
232 }
233
234 #[must_use]
235 pub(in crate::db) fn delete(mut self) -> Self {
236 self.intent = self.intent.delete();
237 self
238 }
239
240 #[must_use]
241 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
242 self.intent = self.intent.limit(limit);
243 self
244 }
245
246 #[must_use]
247 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
248 self.intent = self.intent.offset(offset);
249 self
250 }
251
252 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
253 self.intent.build_plan_model()
254 }
255
256 pub(in crate::db) fn build_plan_with_visible_indexes(
257 &self,
258 visible_indexes: &VisibleIndexes<'_>,
259 ) -> Result<AccessPlannedQuery, QueryError> {
260 self.intent.build_plan_model_with_indexes(visible_indexes)
261 }
262
263 pub(in crate::db) fn prepare_scalar_planning_state(
264 &self,
265 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
266 self.intent.prepare_scalar_planning_state()
267 }
268
269 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
270 &self,
271 visible_indexes: &VisibleIndexes<'_>,
272 planning_state: PreparedScalarPlanningState<'_>,
273 ) -> Result<AccessPlannedQuery, QueryError> {
274 self.intent
275 .build_plan_model_with_indexes_from_scalar_planning_state(
276 visible_indexes,
277 planning_state,
278 )
279 }
280
281 pub(in crate::db) fn try_build_trivial_scalar_load_plan(
282 &self,
283 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
284 self.intent.try_build_trivial_scalar_load_plan()
285 }
286
287 #[must_use]
288 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
289 self.intent.trivial_scalar_load_fast_path_eligible()
290 }
291
292 #[must_use]
293 #[cfg(test)]
294 pub(in crate::db) fn structural_cache_key(
295 &self,
296 ) -> crate::db::query::intent::StructuralQueryCacheKey {
297 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
298 }
299
300 #[must_use]
301 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
302 &self,
303 predicate_fingerprint: Option<[u8; 32]>,
304 ) -> crate::db::query::intent::StructuralQueryCacheKey {
305 self.intent
306 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
307 }
308
309 fn build_plan_for_visibility(
312 &self,
313 visible_indexes: Option<&VisibleIndexes<'_>>,
314 ) -> Result<AccessPlannedQuery, QueryError> {
315 match visible_indexes {
316 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
317 None => self.build_plan(),
318 }
319 }
320
321 #[must_use]
322 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
323 self.intent.model()
324 }
325}
326
327#[derive(Clone, Debug)]
336struct QueryPlanHandle {
337 plan: Box<AccessPlannedQuery>,
338}
339
340impl QueryPlanHandle {
341 #[must_use]
342 fn from_plan(plan: AccessPlannedQuery) -> Self {
343 Self {
344 plan: Box::new(plan),
345 }
346 }
347
348 #[must_use]
349 const fn logical_plan(&self) -> &AccessPlannedQuery {
350 &self.plan
351 }
352
353 #[must_use]
354 fn into_inner(self) -> AccessPlannedQuery {
355 *self.plan
356 }
357}
358
359#[derive(Debug)]
367pub struct PlannedQuery<E: EntityKind> {
368 plan: QueryPlanHandle,
369 _marker: PhantomData<E>,
370}
371
372impl<E: EntityKind> PlannedQuery<E> {
373 #[must_use]
374 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
375 Self {
376 plan: QueryPlanHandle::from_plan(plan),
377 _marker: PhantomData,
378 }
379 }
380
381 #[must_use]
382 pub fn explain(&self) -> ExplainPlan {
383 self.plan.logical_plan().explain()
384 }
385
386 #[must_use]
388 pub fn plan_hash_hex(&self) -> String {
389 self.plan.logical_plan().fingerprint().to_string()
390 }
391}
392
393#[derive(Clone, Debug)]
403pub struct CompiledQuery<E: EntityKind> {
404 plan: QueryPlanHandle,
405 _marker: PhantomData<E>,
406}
407
408impl<E: EntityKind> CompiledQuery<E> {
409 #[must_use]
410 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
411 Self {
412 plan: QueryPlanHandle::from_plan(plan),
413 _marker: PhantomData,
414 }
415 }
416
417 #[must_use]
418 pub fn explain(&self) -> ExplainPlan {
419 self.plan.logical_plan().explain()
420 }
421
422 #[must_use]
424 pub fn plan_hash_hex(&self) -> String {
425 self.plan.logical_plan().fingerprint().to_string()
426 }
427
428 #[must_use]
429 #[cfg(test)]
430 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
431 self.plan.logical_plan().projection_spec(E::MODEL)
432 }
433
434 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
436 self.plan.into_inner()
437 }
438
439 #[must_use]
440 #[cfg(test)]
441 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
442 self.plan.into_inner()
443 }
444}
445
446#[derive(Debug)]
458pub struct Query<E: EntityKind> {
459 inner: StructuralQuery,
460 _marker: PhantomData<E>,
461}
462
463impl<E: EntityKind> Query<E> {
464 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
466 Self {
467 inner,
468 _marker: PhantomData,
469 }
470 }
471
472 #[must_use]
476 pub const fn new(consistency: MissingRowPolicy) -> Self {
477 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
478 }
479
480 #[must_use]
482 pub const fn mode(&self) -> QueryMode {
483 self.inner.mode()
484 }
485
486 #[cfg(test)]
487 pub(in crate::db) fn explain_with_visible_indexes(
488 &self,
489 visible_indexes: &VisibleIndexes<'_>,
490 ) -> Result<ExplainPlan, QueryError> {
491 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
492
493 Ok(plan.explain())
494 }
495
496 #[cfg(test)]
497 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
498 &self,
499 visible_indexes: &VisibleIndexes<'_>,
500 ) -> Result<String, QueryError> {
501 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
502
503 Ok(plan.fingerprint().to_string())
504 }
505
506 fn build_plan_for_visibility(
509 &self,
510 visible_indexes: Option<&VisibleIndexes<'_>>,
511 ) -> Result<AccessPlannedQuery, QueryError> {
512 self.inner.build_plan_for_visibility(visible_indexes)
513 }
514
515 fn map_plan_for_visibility<T>(
519 &self,
520 visible_indexes: Option<&VisibleIndexes<'_>>,
521 map: impl FnOnce(AccessPlannedQuery) -> T,
522 ) -> Result<T, QueryError> {
523 let plan = self.build_plan_for_visibility(visible_indexes)?;
524
525 Ok(map(plan))
526 }
527
528 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
530 PlannedQuery::from_plan(plan)
531 }
532
533 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
535 CompiledQuery::from_plan(plan)
536 }
537
538 #[must_use]
539 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
540 self.inner.has_explicit_order()
541 }
542
543 #[must_use]
544 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
545 &self.inner
546 }
547
548 #[must_use]
549 pub const fn has_grouping(&self) -> bool {
550 self.inner.has_grouping()
551 }
552
553 #[must_use]
554 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
555 self.inner.load_spec()
556 }
557
558 #[must_use]
560 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
561 self.inner = self.inner.filter(expr);
562 self
563 }
564
565 #[cfg(test)]
569 #[must_use]
570 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
571 self.inner = self.inner.filter_expr(expr);
572 self
573 }
574
575 #[cfg(test)]
579 #[must_use]
580 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
581 self.inner = self.inner.filter_predicate(predicate);
582 self
583 }
584
585 #[must_use]
587 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
588 self.inner = self.inner.order_term(term);
589 self
590 }
591
592 #[must_use]
594 pub fn order_terms<I>(mut self, terms: I) -> Self
595 where
596 I: IntoIterator<Item = FluentOrderTerm>,
597 {
598 for term in terms {
599 self.inner = self.inner.order_term(term);
600 }
601
602 self
603 }
604
605 #[must_use]
607 pub fn distinct(mut self) -> Self {
608 self.inner = self.inner.distinct();
609 self
610 }
611
612 #[cfg(all(test, feature = "sql"))]
615 #[must_use]
616 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
617 where
618 I: IntoIterator<Item = S>,
619 S: Into<String>,
620 {
621 self.inner = self.inner.select_fields(fields);
622 self
623 }
624
625 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
627 let Self { inner, .. } = self;
628 let inner = inner.group_by(field)?;
629
630 Ok(Self::from_inner(inner))
631 }
632
633 #[must_use]
635 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
636 self.inner = self.inner.aggregate(aggregate);
637 self
638 }
639
640 #[must_use]
642 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
643 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
644 self
645 }
646
647 pub fn having_group(
649 self,
650 field: impl AsRef<str>,
651 op: CompareOp,
652 value: InputValue,
653 ) -> Result<Self, QueryError> {
654 let Self { inner, .. } = self;
655 let inner = inner.having_group(field, op, value.into())?;
656
657 Ok(Self::from_inner(inner))
658 }
659
660 pub fn having_aggregate(
662 self,
663 aggregate_index: usize,
664 op: CompareOp,
665 value: InputValue,
666 ) -> Result<Self, QueryError> {
667 let Self { inner, .. } = self;
668 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
669
670 Ok(Self::from_inner(inner))
671 }
672
673 #[cfg(test)]
677 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
678 let Self { inner, .. } = self;
679 let inner = inner.having_expr(expr)?;
680
681 Ok(Self::from_inner(inner))
682 }
683
684 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
686 let Self { inner, .. } = self;
687
688 Self::from_inner(inner.by_id(id.to_key_value()))
689 }
690
691 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
693 where
694 I: IntoIterator<Item = E::Key>,
695 {
696 let Self { inner, .. } = self;
697
698 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
699 }
700
701 #[must_use]
703 pub fn delete(mut self) -> Self {
704 self.inner = self.inner.delete();
705 self
706 }
707
708 #[must_use]
715 pub fn limit(mut self, limit: u32) -> Self {
716 self.inner = self.inner.limit(limit);
717 self
718 }
719
720 #[must_use]
726 pub fn offset(mut self, offset: u32) -> Self {
727 self.inner = self.inner.offset(offset);
728 self
729 }
730
731 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
733 let plan = self.planned()?;
734
735 Ok(plan.explain())
736 }
737
738 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
743 let plan = self.inner.build_plan()?;
744
745 Ok(plan.fingerprint().to_string())
746 }
747
748 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
750 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
751 }
752
753 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
757 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
758 }
759
760 #[cfg(test)]
761 pub(in crate::db) fn plan_with_visible_indexes(
762 &self,
763 visible_indexes: &VisibleIndexes<'_>,
764 ) -> Result<CompiledQuery<E>, QueryError> {
765 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
766 }
767}
768
769impl<E> Query<E>
770where
771 E: EntityKind + SingletonEntity,
772 E::Key: Default,
773{
774 pub(in crate::db) fn only(self) -> Self {
776 let Self { inner, .. } = self;
777
778 Self::from_inner(inner.only(E::Key::default().to_key_value()))
779 }
780}