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(
296 &self,
297 ) -> Result<Option<AccessPlannedQuery>, QueryError> {
298 self.intent.try_build_trivial_scalar_load_plan()
299 }
300
301 #[must_use]
302 pub(in crate::db) fn trivial_scalar_load_fast_path_eligible(&self) -> bool {
303 self.intent.trivial_scalar_load_fast_path_eligible()
304 }
305
306 #[must_use]
307 #[cfg(test)]
308 pub(in crate::db) fn structural_cache_key(
309 &self,
310 ) -> crate::db::query::intent::StructuralQueryCacheKey {
311 crate::db::query::intent::StructuralQueryCacheKey::from_query_model(&self.intent)
312 }
313
314 #[must_use]
315 pub(in crate::db) fn structural_cache_key_with_normalized_predicate_fingerprint(
316 &self,
317 predicate_fingerprint: Option<[u8; 32]>,
318 ) -> crate::db::query::intent::StructuralQueryCacheKey {
319 self.intent
320 .structural_cache_key_with_normalized_predicate_fingerprint(predicate_fingerprint)
321 }
322
323 fn build_plan_for_visibility(
326 &self,
327 visible_indexes: Option<&VisibleIndexes<'_>>,
328 ) -> Result<AccessPlannedQuery, QueryError> {
329 match visible_indexes {
330 Some(visible_indexes) => self.build_plan_with_visible_indexes(visible_indexes),
331 None => self.build_plan(),
332 }
333 }
334
335 #[must_use]
336 pub(in crate::db) const fn model(&self) -> &'static crate::model::entity::EntityModel {
337 self.intent.model()
338 }
339}
340
341#[derive(Clone, Debug)]
350struct QueryPlanHandle {
351 plan: Box<AccessPlannedQuery>,
352}
353
354impl QueryPlanHandle {
355 #[must_use]
356 fn from_plan(plan: AccessPlannedQuery) -> Self {
357 Self {
358 plan: Box::new(plan),
359 }
360 }
361
362 #[must_use]
363 const fn logical_plan(&self) -> &AccessPlannedQuery {
364 &self.plan
365 }
366
367 #[must_use]
368 #[cfg(test)]
369 fn into_inner(self) -> AccessPlannedQuery {
370 *self.plan
371 }
372}
373
374#[derive(Debug)]
382pub struct PlannedQuery<E: EntityKind> {
383 plan: QueryPlanHandle,
384 _marker: PhantomData<E>,
385}
386
387impl<E: EntityKind> PlannedQuery<E> {
388 #[must_use]
389 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
390 Self {
391 plan: QueryPlanHandle::from_plan(plan),
392 _marker: PhantomData,
393 }
394 }
395
396 #[must_use]
397 pub fn explain(&self) -> ExplainPlan {
398 self.plan.logical_plan().explain()
399 }
400
401 #[must_use]
403 pub fn plan_hash_hex(&self) -> String {
404 self.plan.logical_plan().fingerprint().to_string()
405 }
406}
407
408#[derive(Clone, Debug)]
418pub struct CompiledQuery<E: EntityKind> {
419 plan: QueryPlanHandle,
420 _marker: PhantomData<E>,
421}
422
423impl<E: EntityKind> CompiledQuery<E> {
424 #[must_use]
425 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
426 Self {
427 plan: QueryPlanHandle::from_plan(plan),
428 _marker: PhantomData,
429 }
430 }
431
432 #[must_use]
433 pub fn explain(&self) -> ExplainPlan {
434 self.plan.logical_plan().explain()
435 }
436
437 #[must_use]
439 pub fn plan_hash_hex(&self) -> String {
440 self.plan.logical_plan().fingerprint().to_string()
441 }
442
443 #[must_use]
444 #[cfg(test)]
445 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
446 self.plan.logical_plan().projection_spec(E::MODEL)
447 }
448
449 #[cfg(test)]
451 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
452 self.plan.into_inner()
453 }
454
455 #[must_use]
456 #[cfg(test)]
457 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
458 self.plan.into_inner()
459 }
460}
461
462#[derive(Debug)]
474pub struct Query<E: EntityKind> {
475 inner: StructuralQuery,
476 _marker: PhantomData<E>,
477}
478
479impl<E: EntityKind> Query<E> {
480 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
482 Self {
483 inner,
484 _marker: PhantomData,
485 }
486 }
487
488 #[must_use]
492 pub const fn new(consistency: MissingRowPolicy) -> Self {
493 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
494 }
495
496 #[must_use]
498 pub const fn mode(&self) -> QueryMode {
499 self.inner.mode()
500 }
501
502 #[cfg(test)]
503 pub(in crate::db) fn explain_with_visible_indexes(
504 &self,
505 visible_indexes: &VisibleIndexes<'_>,
506 ) -> Result<ExplainPlan, QueryError> {
507 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
508
509 Ok(plan.explain())
510 }
511
512 #[cfg(test)]
513 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
514 &self,
515 visible_indexes: &VisibleIndexes<'_>,
516 ) -> Result<String, QueryError> {
517 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
518
519 Ok(plan.fingerprint().to_string())
520 }
521
522 fn build_plan_for_visibility(
525 &self,
526 visible_indexes: Option<&VisibleIndexes<'_>>,
527 ) -> Result<AccessPlannedQuery, QueryError> {
528 self.inner.build_plan_for_visibility(visible_indexes)
529 }
530
531 fn map_plan_for_visibility<T>(
535 &self,
536 visible_indexes: Option<&VisibleIndexes<'_>>,
537 map: impl FnOnce(AccessPlannedQuery) -> T,
538 ) -> Result<T, QueryError> {
539 let plan = self.build_plan_for_visibility(visible_indexes)?;
540
541 Ok(map(plan))
542 }
543
544 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
546 PlannedQuery::from_plan(plan)
547 }
548
549 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
551 CompiledQuery::from_plan(plan)
552 }
553
554 #[must_use]
555 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
556 self.inner.has_explicit_order()
557 }
558
559 #[must_use]
560 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
561 &self.inner
562 }
563
564 #[must_use]
565 pub const fn has_grouping(&self) -> bool {
566 self.inner.has_grouping()
567 }
568
569 #[must_use]
570 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
571 self.inner.load_spec()
572 }
573
574 #[must_use]
576 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
577 self.inner = self.inner.filter(expr);
578 self
579 }
580
581 #[cfg(test)]
585 #[must_use]
586 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
587 self.inner = self.inner.filter_expr(expr);
588 self
589 }
590
591 #[cfg(test)]
595 #[must_use]
596 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
597 self.inner = self.inner.filter_predicate(predicate);
598 self
599 }
600
601 #[must_use]
603 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
604 self.inner = self.inner.order_term(term);
605 self
606 }
607
608 #[must_use]
610 pub fn order_terms<I>(mut self, terms: I) -> Self
611 where
612 I: IntoIterator<Item = FluentOrderTerm>,
613 {
614 for term in terms {
615 self.inner = self.inner.order_term(term);
616 }
617
618 self
619 }
620
621 #[must_use]
623 pub fn distinct(mut self) -> Self {
624 self.inner = self.inner.distinct();
625 self
626 }
627
628 #[cfg(all(test, feature = "sql"))]
631 #[must_use]
632 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
633 where
634 I: IntoIterator<Item = S>,
635 S: Into<String>,
636 {
637 self.inner = self.inner.select_fields(fields);
638 self
639 }
640
641 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
643 let Self { inner, .. } = self;
644 let inner = inner.group_by(field)?;
645
646 Ok(Self::from_inner(inner))
647 }
648
649 #[must_use]
651 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
652 self.inner = self.inner.aggregate(aggregate);
653 self
654 }
655
656 #[must_use]
658 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
659 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
660 self
661 }
662
663 pub fn having_group(
665 self,
666 field: impl AsRef<str>,
667 op: CompareOp,
668 value: InputValue,
669 ) -> Result<Self, QueryError> {
670 let Self { inner, .. } = self;
671 let inner = inner.having_group(field, op, value.into())?;
672
673 Ok(Self::from_inner(inner))
674 }
675
676 pub fn having_aggregate(
678 self,
679 aggregate_index: usize,
680 op: CompareOp,
681 value: InputValue,
682 ) -> Result<Self, QueryError> {
683 let Self { inner, .. } = self;
684 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
685
686 Ok(Self::from_inner(inner))
687 }
688
689 #[cfg(test)]
693 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
694 let Self { inner, .. } = self;
695 let inner = inner.having_expr(expr)?;
696
697 Ok(Self::from_inner(inner))
698 }
699
700 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
702 let Self { inner, .. } = self;
703
704 Self::from_inner(inner.by_id(id.to_key_value()))
705 }
706
707 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
709 where
710 I: IntoIterator<Item = E::Key>,
711 {
712 let Self { inner, .. } = self;
713
714 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
715 }
716
717 #[must_use]
719 pub fn delete(mut self) -> Self {
720 self.inner = self.inner.delete();
721 self
722 }
723
724 #[must_use]
731 pub fn limit(mut self, limit: u32) -> Self {
732 self.inner = self.inner.limit(limit);
733 self
734 }
735
736 #[must_use]
742 pub fn offset(mut self, offset: u32) -> Self {
743 self.inner = self.inner.offset(offset);
744 self
745 }
746
747 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
749 let plan = self.planned()?;
750
751 Ok(plan.explain())
752 }
753
754 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
759 let plan = self.inner.build_plan()?;
760
761 Ok(plan.fingerprint().to_string())
762 }
763
764 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
766 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
767 }
768
769 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
773 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
774 }
775
776 #[cfg(test)]
777 pub(in crate::db) fn plan_with_visible_indexes(
778 &self,
779 visible_indexes: &VisibleIndexes<'_>,
780 ) -> Result<CompiledQuery<E>, QueryError> {
781 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
782 }
783}
784
785impl<E> Query<E>
786where
787 E: EntityKind + SingletonEntity,
788 E::Key: Default,
789{
790 pub(in crate::db) fn only(self) -> Self {
792 let Self { inner, .. } = self;
793
794 Self::from_inner(inner.only(E::Key::default().to_key_value()))
795 }
796}