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 #[must_use]
184 pub(in crate::db) fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
185 self.intent = self.intent.push_group_aggregate(aggregate);
186 self
187 }
188
189 #[must_use]
190 fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
191 self.intent = self.intent.grouped_limits(max_groups, max_group_bytes);
192 self
193 }
194
195 pub(in crate::db) fn having_group(
196 self,
197 field: impl AsRef<str>,
198 op: CompareOp,
199 value: Value,
200 ) -> Result<Self, QueryError> {
201 let field = field.as_ref().to_owned();
202 self.try_map_intent(|intent| intent.push_having_group_clause(&field, op, value))
203 }
204
205 pub(in crate::db) fn having_aggregate(
206 self,
207 aggregate_index: usize,
208 op: CompareOp,
209 value: Value,
210 ) -> Result<Self, QueryError> {
211 self.try_map_intent(|intent| {
212 intent.push_having_aggregate_clause(aggregate_index, op, value)
213 })
214 }
215
216 #[cfg(test)]
217 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
218 self.try_map_intent(|intent| intent.push_having_expr(expr))
219 }
220
221 pub(in crate::db) fn having_expr_preserving_shape(
222 self,
223 expr: Expr,
224 ) -> Result<Self, QueryError> {
225 self.try_map_intent(|intent| intent.push_having_expr_preserving_shape(expr))
226 }
227
228 #[must_use]
229 fn by_id(self, id: Value) -> Self {
230 self.map_intent(|intent| intent.by_id(id))
231 }
232
233 #[must_use]
234 fn by_ids<I>(self, ids: I) -> Self
235 where
236 I: IntoIterator<Item = Value>,
237 {
238 self.map_intent(|intent| intent.by_ids(ids))
239 }
240
241 #[must_use]
242 fn only(self, id: Value) -> Self {
243 self.map_intent(|intent| intent.only(id))
244 }
245
246 #[must_use]
247 pub(in crate::db) fn delete(mut self) -> Self {
248 self.intent = self.intent.delete();
249 self
250 }
251
252 #[must_use]
253 pub(in crate::db) fn limit(mut self, limit: u32) -> Self {
254 self.intent = self.intent.limit(limit);
255 self
256 }
257
258 #[must_use]
259 pub(in crate::db) fn offset(mut self, offset: u32) -> Self {
260 self.intent = self.intent.offset(offset);
261 self
262 }
263
264 pub(in crate::db) fn build_plan(&self) -> Result<AccessPlannedQuery, QueryError> {
265 self.intent.build_plan_model()
266 }
267
268 pub(in crate::db) fn build_plan_with_visible_indexes(
269 &self,
270 visible_indexes: &VisibleIndexes<'_>,
271 ) -> Result<AccessPlannedQuery, QueryError> {
272 self.intent.build_plan_model_with_indexes(visible_indexes)
273 }
274
275 pub(in crate::db) fn prepare_scalar_planning_state_with_schema_info(
276 &self,
277 schema_info: SchemaInfo,
278 ) -> Result<PreparedScalarPlanningState<'_>, QueryError> {
279 self.intent
280 .prepare_scalar_planning_state_with_schema_info(schema_info)
281 }
282
283 pub(in crate::db) fn build_plan_with_visible_indexes_from_scalar_planning_state(
284 &self,
285 visible_indexes: &VisibleIndexes<'_>,
286 planning_state: PreparedScalarPlanningState<'_>,
287 ) -> Result<AccessPlannedQuery, QueryError> {
288 self.intent
289 .build_plan_model_with_indexes_from_scalar_planning_state(
290 visible_indexes,
291 planning_state,
292 )
293 }
294
295 pub(in crate::db) fn try_build_trivial_scalar_load_plan_with_schema_info(
296 &self,
297 schema_info: SchemaInfo,
298 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
299 self.intent
300 .try_build_trivial_scalar_load_plan_with_schema_info(schema_info)
301 }
302
303 #[must_use]
304 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
305 self.intent.trivial_scalar_load_fast_path_eligible()
306 }
307
308 #[must_use]
309 #[cfg(test)]
310 pub(in crate::db) fn structural_cache_key(
311 &self,
312 ) -> crate::db::query::intent::StructuralQueryCacheKey {
313 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
314 }
315
316 #[must_use]
317 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
318 &self,
319 predicate_fingerprint: Option<[u8; 32]>,
320 ) -> crate::db::query::intent::StructuralQueryCacheKey {
321 self.intent
322 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
323 }
324
325 fn build_plan_for_visibility(
328 &self,
329 visible_indexes: Option<&VisibleIndexes<'_>>,
330 ) -> Result<AccessPlannedQuery, QueryError> {
331 match visible_indexes {
332 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
333 None => self.build_plan(),
334 }
335 }
336
337 #[must_use]
338 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
339 self.intent.model()
340 }
341}
342
343#[derive(Clone, Debug)]
352struct QueryPlanHandle {
353 plan: Box<AccessPlannedQuery>,
354}
355
356impl QueryPlanHandle {
357 #[must_use]
358 fn from_plan(plan: AccessPlannedQuery) -> Self {
359 Self {
360 plan: Box::new(plan),
361 }
362 }
363
364 #[must_use]
365 const fn logical_plan(&self) -> &AccessPlannedQuery {
366 &self.plan
367 }
368
369 #[must_use]
370 #[cfg(test)]
371 fn into_inner(self) -> AccessPlannedQuery {
372 *self.plan
373 }
374}
375
376#[derive(Debug)]
384pub struct PlannedQuery<E: EntityKind> {
385 plan: QueryPlanHandle,
386 _marker: PhantomData<E>,
387}
388
389impl<E: EntityKind> PlannedQuery<E> {
390 #[must_use]
391 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
392 Self {
393 plan: QueryPlanHandle::from_plan(plan),
394 _marker: PhantomData,
395 }
396 }
397
398 #[must_use]
399 pub fn explain(&self) -> ExplainPlan {
400 self.plan.logical_plan().explain()
401 }
402
403 #[must_use]
405 pub fn plan_hash_hex(&self) -> String {
406 self.plan.logical_plan().fingerprint().to_string()
407 }
408}
409
410#[derive(Clone, Debug)]
420pub struct CompiledQuery<E: EntityKind> {
421 plan: QueryPlanHandle,
422 _marker: PhantomData<E>,
423}
424
425impl<E: EntityKind> CompiledQuery<E> {
426 #[must_use]
427 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
428 Self {
429 plan: QueryPlanHandle::from_plan(plan),
430 _marker: PhantomData,
431 }
432 }
433
434 #[must_use]
435 pub fn explain(&self) -> ExplainPlan {
436 self.plan.logical_plan().explain()
437 }
438
439 #[must_use]
441 pub fn plan_hash_hex(&self) -> String {
442 self.plan.logical_plan().fingerprint().to_string()
443 }
444
445 #[must_use]
446 #[cfg(test)]
447 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
448 self.plan.logical_plan().projection_spec(E::MODEL)
449 }
450
451 #[cfg(test)]
453 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
454 self.plan.into_inner()
455 }
456
457 #[must_use]
458 #[cfg(test)]
459 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
460 self.plan.into_inner()
461 }
462}
463
464#[derive(Debug)]
476pub struct Query<E: EntityKind> {
477 inner: StructuralQuery,
478 _marker: PhantomData<E>,
479}
480
481impl<E: EntityKind> Query<E> {
482 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
484 Self {
485 inner,
486 _marker: PhantomData,
487 }
488 }
489
490 #[must_use]
494 pub const fn new(consistency: MissingRowPolicy) -> Self {
495 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
496 }
497
498 #[must_use]
500 pub const fn mode(&self) -> QueryMode {
501 self.inner.mode()
502 }
503
504 #[cfg(test)]
505 pub(in crate::db) fn explain_with_visible_indexes(
506 &self,
507 visible_indexes: &VisibleIndexes<'_>,
508 ) -> Result<ExplainPlan, QueryError> {
509 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
510
511 Ok(plan.explain())
512 }
513
514 #[cfg(test)]
515 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
516 &self,
517 visible_indexes: &VisibleIndexes<'_>,
518 ) -> Result<String, QueryError> {
519 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
520
521 Ok(plan.fingerprint().to_string())
522 }
523
524 fn build_plan_for_visibility(
527 &self,
528 visible_indexes: Option<&VisibleIndexes<'_>>,
529 ) -> Result<AccessPlannedQuery, QueryError> {
530 self.inner.build_plan_for_visibility(visible_indexes)
531 }
532
533 fn map_plan_for_visibility<T>(
537 &self,
538 visible_indexes: Option<&VisibleIndexes<'_>>,
539 map: impl FnOnce(AccessPlannedQuery) -> T,
540 ) -> Result<T, QueryError> {
541 let plan = self.build_plan_for_visibility(visible_indexes)?;
542
543 Ok(map(plan))
544 }
545
546 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
548 PlannedQuery::from_plan(plan)
549 }
550
551 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
553 CompiledQuery::from_plan(plan)
554 }
555
556 #[must_use]
557 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
558 self.inner.has_explicit_order()
559 }
560
561 #[must_use]
562 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
563 &self.inner
564 }
565
566 #[must_use]
567 pub const fn has_grouping(&self) -> bool {
568 self.inner.has_grouping()
569 }
570
571 #[must_use]
572 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
573 self.inner.load_spec()
574 }
575
576 #[must_use]
578 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
579 self.inner = self.inner.filter(expr);
580 self
581 }
582
583 #[cfg(test)]
587 #[must_use]
588 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
589 self.inner = self.inner.filter_expr(expr);
590 self
591 }
592
593 #[cfg(test)]
597 #[must_use]
598 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
599 self.inner = self.inner.filter_predicate(predicate);
600 self
601 }
602
603 #[must_use]
605 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
606 self.inner = self.inner.order_term(term);
607 self
608 }
609
610 #[must_use]
612 pub fn order_terms<I>(mut self, terms: I) -> Self
613 where
614 I: IntoIterator<Item = FluentOrderTerm>,
615 {
616 for term in terms {
617 self.inner = self.inner.order_term(term);
618 }
619
620 self
621 }
622
623 #[must_use]
625 pub fn distinct(mut self) -> Self {
626 self.inner = self.inner.distinct();
627 self
628 }
629
630 #[cfg(all(test, feature = "sql"))]
633 #[must_use]
634 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
635 where
636 I: IntoIterator<Item = S>,
637 S: Into<String>,
638 {
639 self.inner = self.inner.select_fields(fields);
640 self
641 }
642
643 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
645 let Self { inner, .. } = self;
646 let inner = inner.group_by(field)?;
647
648 Ok(Self::from_inner(inner))
649 }
650
651 #[must_use]
653 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
654 self.inner = self.inner.aggregate(aggregate);
655 self
656 }
657
658 #[must_use]
660 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
661 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
662 self
663 }
664
665 pub fn having_group(
667 self,
668 field: impl AsRef<str>,
669 op: CompareOp,
670 value: InputValue,
671 ) -> Result<Self, QueryError> {
672 let Self { inner, .. } = self;
673 let inner = inner.having_group(field, op, value.into())?;
674
675 Ok(Self::from_inner(inner))
676 }
677
678 pub fn having_aggregate(
680 self,
681 aggregate_index: usize,
682 op: CompareOp,
683 value: InputValue,
684 ) -> Result<Self, QueryError> {
685 let Self { inner, .. } = self;
686 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
687
688 Ok(Self::from_inner(inner))
689 }
690
691 #[cfg(test)]
695 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
696 let Self { inner, .. } = self;
697 let inner = inner.having_expr(expr)?;
698
699 Ok(Self::from_inner(inner))
700 }
701
702 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
704 let Self { inner, .. } = self;
705
706 Self::from_inner(inner.by_id(id.to_key_value()))
707 }
708
709 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
711 where
712 I: IntoIterator<Item = E::Key>,
713 {
714 let Self { inner, .. } = self;
715
716 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
717 }
718
719 #[must_use]
721 pub fn delete(mut self) -> Self {
722 self.inner = self.inner.delete();
723 self
724 }
725
726 #[must_use]
733 pub fn limit(mut self, limit: u32) -> Self {
734 self.inner = self.inner.limit(limit);
735 self
736 }
737
738 #[must_use]
744 pub fn offset(mut self, offset: u32) -> Self {
745 self.inner = self.inner.offset(offset);
746 self
747 }
748
749 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
751 let plan = self.planned()?;
752
753 Ok(plan.explain())
754 }
755
756 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
761 let plan = self.inner.build_plan()?;
762
763 Ok(plan.fingerprint().to_string())
764 }
765
766 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
768 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
769 }
770
771 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
775 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
776 }
777
778 #[cfg(test)]
779 pub(in crate::db) fn plan_with_visible_indexes(
780 &self,
781 visible_indexes: &VisibleIndexes<'_>,
782 ) -> Result<CompiledQuery<E>, QueryError> {
783 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
784 }
785}
786
787impl<E> Query<E>
788where
789 E: EntityKind + SingletonEntity,
790 E::Key: Default,
791{
792 pub(in crate::db) fn only(self) -> Self {
794 let Self { inner, .. } = self;
795
796 Self::from_inner(inner.only(E::Key::default().to_key_value()))
797 }
798}