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 schema::SchemaInfo,
23 },
24 traits::{EntityKind, KeyValueCodec, SingletonEntity},
25 value::{InputValue, Value},
26};
27use core::marker::PhantomData;
28
29#[derive(Clone, Debug)]
38pub(in crate::db) struct StructuralQuery {
39 intent: QueryModel<'static, Value>,
40}
41
42impl StructuralQuery {
43 #[must_use]
44 pub(in crate::db) const fn new(
45 model: &'static crate::model::entity::EntityModel,
46 consistency: MissingRowPolicy,
47 ) -> Self {
48 Self {
49 intent: QueryModel::new(model, consistency),
50 }
51 }
52
53 const fn from_intent(intent: QueryModel<'static, Value>) -> Self {
57 Self { intent }
58 }
59
60 fn map_intent(
63 self,
64 map: impl FnOnce(QueryModel<'static, Value>) -> QueryModel<'static, Value>,
65 ) -> Self {
66 Self::from_intent(map(self.intent))
67 }
68
69 fn try_map_intent(
72 self,
73 map: impl FnOnce(QueryModel<'static, Value>) -> Result<QueryModel<'static, Value>, QueryError>,
74 ) -> Result<Self, QueryError> {
75 map(self.intent).map(Self::from_intent)
76 }
77
78 #[must_use]
79 const fn mode(&self) -> QueryMode {
80 self.intent.mode()
81 }
82
83 #[must_use]
84 fn has_explicit_order(&self) -> bool {
85 self.intent.has_explicit_order()
86 }
87
88 #[must_use]
89 pub(in crate::db) const fn has_grouping(&self) -> bool {
90 self.intent.has_grouping()
91 }
92
93 #[must_use]
94 const fn load_spec(&self) -> Option<LoadSpec> {
95 match self.intent.mode() {
96 QueryMode::Load(spec) => Some(spec),
97 QueryMode::Delete(_) => None,
98 }
99 }
100
101 #[must_use]
102 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
103 self.intent = self.intent.filter_predicate(predicate);
104 self
105 }
106
107 #[must_use]
108 pub(in crate::db) fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
109 self.intent = self.intent.filter(expr.into());
110 self
111 }
112
113 #[must_use]
114 pub(in crate::db) fn filter_expr_with_normalized_predicate(
115 mut self,
116 expr: Expr,
117 predicate: Predicate,
118 ) -> Self {
119 self.intent = self
120 .intent
121 .filter_expr_with_normalized_predicate(expr, predicate);
122 self
123 }
124 pub(in crate::db) fn order_term(mut self, term: FluentOrderTerm) -> Self {
125 self.intent = self.intent.order_term(term);
126 self
127 }
128
129 #[must_use]
133 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
134 self.intent = self.intent.filter_expr(expr);
135 self
136 }
137
138 #[must_use]
139 pub(in crate::db) fn order_spec(mut self, order: OrderSpec) -> Self {
140 self.intent = self.intent.order_spec(order);
141 self
142 }
143
144 #[must_use]
145 pub(in crate::db) fn distinct(mut self) -> Self {
146 self.intent = self.intent.distinct();
147 self
148 }
149
150 #[cfg(all(test, feature = "sql"))]
151 #[must_use]
152 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
153 where
154 I: IntoIterator<Item = S>,
155 S: Into<String>,
156 {
157 self.intent = self.intent.select_fields(fields);
158 self
159 }
160
161 #[cfg(feature = "sql")]
162 #[must_use]
163 pub(in crate::db) fn projection_selection(mut self, selection: ProjectionSelection) -> Self {
164 self.intent = self.intent.projection_selection(selection);
165 self
166 }
167
168 #[cfg(feature = "sql")]
173 #[must_use]
174 pub(in crate::db) fn select_field_id(mut self, field: impl Into<String>) -> Self {
175 self.intent = self.intent.select_field_id(field);
176 self
177 }
178
179 pub(in crate::db) fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
180 self.try_map_intent(|intent| intent.push_group_field(field.as_ref()))
181 }
182
183 pub(in crate::db) fn group_by_with_schema(
184 self,
185 field: impl AsRef<str>,
186 schema: &SchemaInfo,
187 ) -> Result<Self, QueryError> {
188 self.try_map_intent(|intent| intent.push_group_field_with_schema(field.as_ref(), schema))
189 }
190
191 #[must_use]
192 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
193 self.intent = self.intent.push_group_aggregate(aggregate);
194 self
195 }
196
197 #[must_use]
198 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
199 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
200 self
201 }
202
203 pub(in crate::db) fn having_group(
204 self,
205 field: impl AsRef<str>,
206 op: CompareOp,
207 value: Value,
208 ) -> Result<Self, QueryError> {
209 let field = field.as_ref().to_owned();
210 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
211 }
212
213 pub(in crate::db) fn having_group_with_schema(
214 self,
215 field: impl AsRef<str>,
216 schema: &SchemaInfo,
217 op: CompareOp,
218 value: Value,
219 ) -> Result<Self, QueryError> {
220 let field = field.as_ref().to_owned();
221 self.try_map_intent(|intent| {
222 intent.push_having_group_clause_with_schema(&field, schema, op, value)
223 })
224 }
225
226 pub(in crate::db) fn having_aggregate(
227 self,
228 aggregate_index: usize,
229 op: CompareOp,
230 value: Value,
231 ) -> Result<Self, QueryError> {
232 self.try_map_intent(|intent| {
233 intent.push_having_aggregate_clause(aggregate_index, op, value)
234 })
235 }
236
237 #[cfg(test)]
238 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
239 self.try_map_intent(|intent| intent.push_having_expr(expr))
240 }
241
242 pub(in crate::db) fn having_expr_preserving_shape(
243 self,
244 expr: Expr,
245 ) -> Result<Self, QueryError> {
246 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
247 }
248
249 #[must_use]
250 fn by_id(self, id: Value) -> Self {
251 self.map_intent(|intent| intent.by_id(id))
252 }
253
254 #[must_use]
255 fn by_ids<I>(self, ids: I) -> Self
256 where
257 I: IntoIterator<Item = Value>,
258 {
259 self.map_intent(|intent| intent.by_ids(ids))
260 }
261
262 #[must_use]
263 fn only(self, id: Value) -> Self {
264 self.map_intent(|intent| intent.only(id))
265 }
266
267 #[must_use]
268 pub(in crate::db) fn delete(mut self) -> Self {
269 self.intent = self.intent.delete();
270 self
271 }
272
273 #[must_use]
274 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
275 self.intent = self.intent.limit(limit);
276 self
277 }
278
279 #[must_use]
280 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
281 self.intent = self.intent.offset(offset);
282 self
283 }
284
285 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
286 self.intent.build_plan_model()
287 }
288
289 pub(in crate::db) fn build_plan_with_visible_indexes(
290 &self,
291 visible_indexes: &VisibleIndexes<'_>,
292 ) -> Result<AccessPlannedQuery, QueryError> {
293 self.intent.build_plan_model_with_indexes(visible_indexes)
294 }
295
296 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
297 &self,
298 schema_info: SchemaInfo,
299 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
300 self.intent
301 .prepare_scalar_planning_state_with_schema_info(schema_info)
302 }
303
304 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
305 &self,
306 visible_indexes: &VisibleIndexes<'_>,
307 planning_state: PreparedScalarPlanningState<'_>,
308 ) -> Result<AccessPlannedQuery, QueryError> {
309 self.intent
310 .build_plan_model_with_indexes_from_scalar_planning_state(
311 visible_indexes,
312 planning_state,
313 )
314 }
315
316 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
317 &self,
318 schema_info: SchemaInfo,
319 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
320 self.intent
321 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)
322 }
323
324 #[must_use]
325 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
326 self.intent.trivial_scalar_load_fast_path_eligible()
327 }
328
329 #[must_use]
330 #[cfg(test)]
331 pub(in crate::db) fn structural_cache_key(
332 &self,
333 ) -> crate::db::query::intent::StructuralQueryCacheKey {
334 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
335 }
336
337 #[must_use]
338 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
339 &self,
340 predicate_fingerprint: Option<[u8; 32]>,
341 ) -> crate::db::query::intent::StructuralQueryCacheKey {
342 self.intent
343 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
344 }
345
346 fn build_plan_for_visibility(
349 &self,
350 visible_indexes: Option<&VisibleIndexes<'_>>,
351 ) -> Result<AccessPlannedQuery, QueryError> {
352 match visible_indexes {
353 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
354 None => self.build_plan(),
355 }
356 }
357
358 #[must_use]
359 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
360 self.intent.model()
361 }
362}
363
364#[derive(Clone, Debug)]
373struct QueryPlanHandle {
374 plan: Box<AccessPlannedQuery>,
375}
376
377impl QueryPlanHandle {
378 #[must_use]
379 fn from_plan(plan: AccessPlannedQuery) -> Self {
380 Self {
381 plan: Box::new(plan),
382 }
383 }
384
385 #[must_use]
386 const fn logical_plan(&self) -> &AccessPlannedQuery {
387 &self.plan
388 }
389
390 #[must_use]
391 #[cfg(test)]
392 fn into_inner(self) -> AccessPlannedQuery {
393 *self.plan
394 }
395}
396
397#[derive(Debug)]
405pub struct PlannedQuery<E: EntityKind> {
406 plan: QueryPlanHandle,
407 _marker: PhantomData<E>,
408}
409
410impl<E: EntityKind> PlannedQuery<E> {
411 #[must_use]
412 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
413 Self {
414 plan: QueryPlanHandle::from_plan(plan),
415 _marker: PhantomData,
416 }
417 }
418
419 #[must_use]
420 pub fn explain(&self) -> ExplainPlan {
421 self.plan.logical_plan().explain()
422 }
423
424 #[must_use]
426 pub fn plan_hash_hex(&self) -> String {
427 self.plan.logical_plan().fingerprint().to_string()
428 }
429}
430
431#[derive(Clone, Debug)]
441pub struct CompiledQuery<E: EntityKind> {
442 plan: QueryPlanHandle,
443 _marker: PhantomData<E>,
444}
445
446impl<E: EntityKind> CompiledQuery<E> {
447 #[must_use]
448 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
449 Self {
450 plan: QueryPlanHandle::from_plan(plan),
451 _marker: PhantomData,
452 }
453 }
454
455 #[must_use]
456 pub fn explain(&self) -> ExplainPlan {
457 self.plan.logical_plan().explain()
458 }
459
460 #[must_use]
462 pub fn plan_hash_hex(&self) -> String {
463 self.plan.logical_plan().fingerprint().to_string()
464 }
465
466 #[must_use]
467 #[cfg(test)]
468 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
469 self.plan.logical_plan().projection_spec(E::MODEL)
470 }
471
472 #[cfg(test)]
474 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
475 self.plan.into_inner()
476 }
477
478 #[must_use]
479 #[cfg(test)]
480 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
481 self.plan.into_inner()
482 }
483}
484
485#[derive(Debug)]
497pub struct Query<E: EntityKind> {
498 inner: StructuralQuery,
499 _marker: PhantomData<E>,
500}
501
502impl<E: EntityKind> Query<E> {
503 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
505 Self {
506 inner,
507 _marker: PhantomData,
508 }
509 }
510
511 #[must_use]
515 pub const fn new(consistency: MissingRowPolicy) -> Self {
516 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
517 }
518
519 #[must_use]
521 pub const fn mode(&self) -> QueryMode {
522 self.inner.mode()
523 }
524
525 #[cfg(test)]
526 pub(in crate::db) fn explain_with_visible_indexes(
527 &self,
528 visible_indexes: &VisibleIndexes<'_>,
529 ) -> Result<ExplainPlan, QueryError> {
530 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
531
532 Ok(plan.explain())
533 }
534
535 #[cfg(test)]
536 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
537 &self,
538 visible_indexes: &VisibleIndexes<'_>,
539 ) -> Result<String, QueryError> {
540 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
541
542 Ok(plan.fingerprint().to_string())
543 }
544
545 fn build_plan_for_visibility(
548 &self,
549 visible_indexes: Option<&VisibleIndexes<'_>>,
550 ) -> Result<AccessPlannedQuery, QueryError> {
551 self.inner.build_plan_for_visibility(visible_indexes)
552 }
553
554 fn map_plan_for_visibility<T>(
558 &self,
559 visible_indexes: Option<&VisibleIndexes<'_>>,
560 map: impl FnOnce(AccessPlannedQuery) -> T,
561 ) -> Result<T, QueryError> {
562 let plan = self.build_plan_for_visibility(visible_indexes)?;
563
564 Ok(map(plan))
565 }
566
567 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
569 PlannedQuery::from_plan(plan)
570 }
571
572 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
574 CompiledQuery::from_plan(plan)
575 }
576
577 #[must_use]
578 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
579 self.inner.has_explicit_order()
580 }
581
582 #[must_use]
583 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
584 &self.inner
585 }
586
587 #[must_use]
588 pub const fn has_grouping(&self) -> bool {
589 self.inner.has_grouping()
590 }
591
592 #[must_use]
593 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
594 self.inner.load_spec()
595 }
596
597 #[must_use]
599 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
600 self.inner = self.inner.filter(expr);
601 self
602 }
603
604 #[cfg(test)]
608 #[must_use]
609 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
610 self.inner = self.inner.filter_expr(expr);
611 self
612 }
613
614 #[cfg(test)]
618 #[must_use]
619 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
620 self.inner = self.inner.filter_predicate(predicate);
621 self
622 }
623
624 #[must_use]
626 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
627 self.inner = self.inner.order_term(term);
628 self
629 }
630
631 #[must_use]
633 pub fn order_terms<I>(mut self, terms: I) -> Self
634 where
635 I: IntoIterator<Item = FluentOrderTerm>,
636 {
637 for term in terms {
638 self.inner = self.inner.order_term(term);
639 }
640
641 self
642 }
643
644 #[must_use]
646 pub fn distinct(mut self) -> Self {
647 self.inner = self.inner.distinct();
648 self
649 }
650
651 #[cfg(all(test, feature = "sql"))]
654 #[must_use]
655 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
656 where
657 I: IntoIterator<Item = S>,
658 S: Into<String>,
659 {
660 self.inner = self.inner.select_fields(fields);
661 self
662 }
663
664 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
666 let Self { inner, .. } = self;
667 let inner = inner.group_by(field)?;
668
669 Ok(Self::from_inner(inner))
670 }
671
672 pub(in crate::db) fn group_by_with_schema(
673 self,
674 field: impl AsRef<str>,
675 schema: &SchemaInfo,
676 ) -> Result<Self, QueryError> {
677 let Self { inner, .. } = self;
678 let inner = inner.group_by_with_schema(field, schema)?;
679
680 Ok(Self::from_inner(inner))
681 }
682
683 #[must_use]
685 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
686 self.inner = self.inner.aggregate(aggregate);
687 self
688 }
689
690 #[must_use]
692 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
693 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
694 self
695 }
696
697 pub fn having_group(
699 self,
700 field: impl AsRef<str>,
701 op: CompareOp,
702 value: InputValue,
703 ) -> Result<Self, QueryError> {
704 let Self { inner, .. } = self;
705 let inner = inner.having_group(field, op, value.into())?;
706
707 Ok(Self::from_inner(inner))
708 }
709
710 pub(in crate::db) fn having_group_with_schema(
711 self,
712 field: impl AsRef<str>,
713 schema: &SchemaInfo,
714 op: CompareOp,
715 value: InputValue,
716 ) -> Result<Self, QueryError> {
717 let Self { inner, .. } = self;
718 let inner = inner.having_group_with_schema(field, schema, op, value.into())?;
719
720 Ok(Self::from_inner(inner))
721 }
722
723 pub fn having_aggregate(
725 self,
726 aggregate_index: usize,
727 op: CompareOp,
728 value: InputValue,
729 ) -> Result<Self, QueryError> {
730 let Self { inner, .. } = self;
731 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
732
733 Ok(Self::from_inner(inner))
734 }
735
736 #[cfg(test)]
740 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
741 let Self { inner, .. } = self;
742 let inner = inner.having_expr(expr)?;
743
744 Ok(Self::from_inner(inner))
745 }
746
747 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
749 let Self { inner, .. } = self;
750
751 Self::from_inner(inner.by_id(id.to_key_value()))
752 }
753
754 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
756 where
757 I: IntoIterator<Item = E::Key>,
758 {
759 let Self { inner, .. } = self;
760
761 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
762 }
763
764 #[must_use]
766 pub fn delete(mut self) -> Self {
767 self.inner = self.inner.delete();
768 self
769 }
770
771 #[must_use]
778 pub fn limit(mut self, limit: u32) -> Self {
779 self.inner = self.inner.limit(limit);
780 self
781 }
782
783 #[must_use]
789 pub fn offset(mut self, offset: u32) -> Self {
790 self.inner = self.inner.offset(offset);
791 self
792 }
793
794 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
796 let plan = self.planned()?;
797
798 Ok(plan.explain())
799 }
800
801 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
806 let plan = self.inner.build_plan()?;
807
808 Ok(plan.fingerprint().to_string())
809 }
810
811 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
813 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
814 }
815
816 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
820 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
821 }
822
823 #[cfg(test)]
824 pub(in crate::db) fn plan_with_visible_indexes(
825 &self,
826 visible_indexes: &VisibleIndexes<'_>,
827 ) -> Result<CompiledQuery<E>, QueryError> {
828 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
829 }
830}
831
832impl<E> Query<E>
833where
834 E: EntityKind + SingletonEntity,
835 E::Key: Default,
836{
837 pub(in crate::db) fn only(self) -> Self {
839 let Self { inner, .. } = self;
840
841 Self::from_inner(inner.only(E::Key::default().to_key_value()))
842 }
843}