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 fn into_inner(self) -> AccessPlannedQuery {
369 *self.plan
370 }
371}
372
373#[derive(Debug)]
381pub struct PlannedQuery<E: EntityKind> {
382 plan: QueryPlanHandle,
383 _marker: PhantomData<E>,
384}
385
386impl<E: EntityKind> PlannedQuery<E> {
387 #[must_use]
388 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
389 Self {
390 plan: QueryPlanHandle::from_plan(plan),
391 _marker: PhantomData,
392 }
393 }
394
395 #[must_use]
396 pub fn explain(&self) -> ExplainPlan {
397 self.plan.logical_plan().explain()
398 }
399
400 #[must_use]
402 pub fn plan_hash_hex(&self) -> String {
403 self.plan.logical_plan().fingerprint().to_string()
404 }
405}
406
407#[derive(Clone, Debug)]
417pub struct CompiledQuery<E: EntityKind> {
418 plan: QueryPlanHandle,
419 _marker: PhantomData<E>,
420}
421
422impl<E: EntityKind> CompiledQuery<E> {
423 #[must_use]
424 pub(in crate::db) fn from_plan(plan: AccessPlannedQuery) -> Self {
425 Self {
426 plan: QueryPlanHandle::from_plan(plan),
427 _marker: PhantomData,
428 }
429 }
430
431 #[must_use]
432 pub fn explain(&self) -> ExplainPlan {
433 self.plan.logical_plan().explain()
434 }
435
436 #[must_use]
438 pub fn plan_hash_hex(&self) -> String {
439 self.plan.logical_plan().fingerprint().to_string()
440 }
441
442 #[must_use]
443 #[cfg(test)]
444 pub(in crate::db) fn projection_spec(&self) -> crate::db::query::plan::expr::ProjectionSpec {
445 self.plan.logical_plan().projection_spec(E::MODEL)
446 }
447
448 pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
450 self.plan.into_inner()
451 }
452
453 #[must_use]
454 #[cfg(test)]
455 pub(in crate::db) fn into_inner(self) -> AccessPlannedQuery {
456 self.plan.into_inner()
457 }
458}
459
460#[derive(Debug)]
472pub struct Query<E: EntityKind> {
473 inner: StructuralQuery,
474 _marker: PhantomData<E>,
475}
476
477impl<E: EntityKind> Query<E> {
478 pub(in crate::db) const fn from_inner(inner: StructuralQuery) -> Self {
480 Self {
481 inner,
482 _marker: PhantomData,
483 }
484 }
485
486 #[must_use]
490 pub const fn new(consistency: MissingRowPolicy) -> Self {
491 Self::from_inner(StructuralQuery::new(E::MODEL, consistency))
492 }
493
494 #[must_use]
496 pub const fn mode(&self) -> QueryMode {
497 self.inner.mode()
498 }
499
500 #[cfg(test)]
501 pub(in crate::db) fn explain_with_visible_indexes(
502 &self,
503 visible_indexes: &VisibleIndexes<'_>,
504 ) -> Result<ExplainPlan, QueryError> {
505 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
506
507 Ok(plan.explain())
508 }
509
510 #[cfg(test)]
511 pub(in crate::db) fn plan_hash_hex_with_visible_indexes(
512 &self,
513 visible_indexes: &VisibleIndexes<'_>,
514 ) -> Result<String, QueryError> {
515 let plan = self.build_plan_for_visibility(Some(visible_indexes))?;
516
517 Ok(plan.fingerprint().to_string())
518 }
519
520 fn build_plan_for_visibility(
523 &self,
524 visible_indexes: Option<&VisibleIndexes<'_>>,
525 ) -> Result<AccessPlannedQuery, QueryError> {
526 self.inner.build_plan_for_visibility(visible_indexes)
527 }
528
529 fn map_plan_for_visibility<T>(
533 &self,
534 visible_indexes: Option<&VisibleIndexes<'_>>,
535 map: impl FnOnce(AccessPlannedQuery) -> T,
536 ) -> Result<T, QueryError> {
537 let plan = self.build_plan_for_visibility(visible_indexes)?;
538
539 Ok(map(plan))
540 }
541
542 pub(in crate::db) fn planned_query_from_plan(plan: AccessPlannedQuery) -> PlannedQuery<E> {
544 PlannedQuery::from_plan(plan)
545 }
546
547 pub(in crate::db) fn compiled_query_from_plan(plan: AccessPlannedQuery) -> CompiledQuery<E> {
549 CompiledQuery::from_plan(plan)
550 }
551
552 #[must_use]
553 pub(in crate::db::query) fn has_explicit_order(&self) -> bool {
554 self.inner.has_explicit_order()
555 }
556
557 #[must_use]
558 pub(in crate::db) const fn structural(&self) -> &StructuralQuery {
559 &self.inner
560 }
561
562 #[must_use]
563 pub const fn has_grouping(&self) -> bool {
564 self.inner.has_grouping()
565 }
566
567 #[must_use]
568 pub(in crate::db::query) const fn load_spec(&self) -> Option<LoadSpec> {
569 self.inner.load_spec()
570 }
571
572 #[must_use]
574 pub fn filter(mut self, expr: impl Into<FilterExpr>) -> Self {
575 self.inner = self.inner.filter(expr);
576 self
577 }
578
579 #[cfg(test)]
583 #[must_use]
584 pub(in crate::db) fn filter_expr(mut self, expr: Expr) -> Self {
585 self.inner = self.inner.filter_expr(expr);
586 self
587 }
588
589 #[cfg(test)]
593 #[must_use]
594 pub(in crate::db) fn filter_predicate(mut self, predicate: Predicate) -> Self {
595 self.inner = self.inner.filter_predicate(predicate);
596 self
597 }
598
599 #[must_use]
601 pub fn order_term(mut self, term: FluentOrderTerm) -> Self {
602 self.inner = self.inner.order_term(term);
603 self
604 }
605
606 #[must_use]
608 pub fn order_terms<I>(mut self, terms: I) -> Self
609 where
610 I: IntoIterator<Item = FluentOrderTerm>,
611 {
612 for term in terms {
613 self.inner = self.inner.order_term(term);
614 }
615
616 self
617 }
618
619 #[must_use]
621 pub fn distinct(mut self) -> Self {
622 self.inner = self.inner.distinct();
623 self
624 }
625
626 #[cfg(all(test, feature = "sql"))]
629 #[must_use]
630 pub(in crate::db) fn select_fields<I, S>(mut self, fields: I) -> Self
631 where
632 I: IntoIterator<Item = S>,
633 S: Into<String>,
634 {
635 self.inner = self.inner.select_fields(fields);
636 self
637 }
638
639 pub fn group_by(self, field: impl AsRef<str>) -> Result<Self, QueryError> {
641 let Self { inner, .. } = self;
642 let inner = inner.group_by(field)?;
643
644 Ok(Self::from_inner(inner))
645 }
646
647 #[must_use]
649 pub fn aggregate(mut self, aggregate: AggregateExpr) -> Self {
650 self.inner = self.inner.aggregate(aggregate);
651 self
652 }
653
654 #[must_use]
656 pub fn grouped_limits(mut self, max_groups: u64, max_group_bytes: u64) -> Self {
657 self.inner = self.inner.grouped_limits(max_groups, max_group_bytes);
658 self
659 }
660
661 pub fn having_group(
663 self,
664 field: impl AsRef<str>,
665 op: CompareOp,
666 value: InputValue,
667 ) -> Result<Self, QueryError> {
668 let Self { inner, .. } = self;
669 let inner = inner.having_group(field, op, value.into())?;
670
671 Ok(Self::from_inner(inner))
672 }
673
674 pub fn having_aggregate(
676 self,
677 aggregate_index: usize,
678 op: CompareOp,
679 value: InputValue,
680 ) -> Result<Self, QueryError> {
681 let Self { inner, .. } = self;
682 let inner = inner.having_aggregate(aggregate_index, op, value.into())?;
683
684 Ok(Self::from_inner(inner))
685 }
686
687 #[cfg(test)]
691 pub(in crate::db) fn having_expr(self, expr: Expr) -> Result<Self, QueryError> {
692 let Self { inner, .. } = self;
693 let inner = inner.having_expr(expr)?;
694
695 Ok(Self::from_inner(inner))
696 }
697
698 pub(in crate::db) fn by_id(self, id: E::Key) -> Self {
700 let Self { inner, .. } = self;
701
702 Self::from_inner(inner.by_id(id.to_key_value()))
703 }
704
705 pub(in crate::db) fn by_ids<I>(self, ids: I) -> Self
707 where
708 I: IntoIterator<Item = E::Key>,
709 {
710 let Self { inner, .. } = self;
711
712 Self::from_inner(inner.by_ids(ids.into_iter().map(|id| id.to_key_value())))
713 }
714
715 #[must_use]
717 pub fn delete(mut self) -> Self {
718 self.inner = self.inner.delete();
719 self
720 }
721
722 #[must_use]
729 pub fn limit(mut self, limit: u32) -> Self {
730 self.inner = self.inner.limit(limit);
731 self
732 }
733
734 #[must_use]
740 pub fn offset(mut self, offset: u32) -> Self {
741 self.inner = self.inner.offset(offset);
742 self
743 }
744
745 pub fn explain(&self) -> Result<ExplainPlan, QueryError> {
747 let plan = self.planned()?;
748
749 Ok(plan.explain())
750 }
751
752 pub fn plan_hash_hex(&self) -> Result<String, QueryError> {
757 let plan = self.inner.build_plan()?;
758
759 Ok(plan.fingerprint().to_string())
760 }
761
762 pub fn planned(&self) -> Result<PlannedQuery<E>, QueryError> {
764 self.map_plan_for_visibility(None, Self::planned_query_from_plan)
765 }
766
767 pub fn plan(&self) -> Result<CompiledQuery<E>, QueryError> {
771 self.map_plan_for_visibility(None, Self::compiled_query_from_plan)
772 }
773
774 #[cfg(test)]
775 pub(in crate::db) fn plan_with_visible_indexes(
776 &self,
777 visible_indexes: &VisibleIndexes<'_>,
778 ) -> Result<CompiledQuery<E>, QueryError> {
779 self.map_plan_for_visibility(Some(visible_indexes), Self::compiled_query_from_plan)
780 }
781}
782
783impl<E> Query<E>
784where
785 E: EntityKind + SingletonEntity,
786 E::Key: Default,
787{
788 pub(in crate::db) fn only(self) -> Self {
790 let Self { inner, .. } = self;
791
792 Self::from_inner(inner.only(E::Key::default().to_key_value()))
793 }
794}