Skip to main content

icydb_core/db/executor/
executable_plan.rs

1//! Module: db::executor::executable_plan
2//! Responsibility: bind validated access-planned queries to executor-ready contracts.
3//! Does not own: logical plan semantics or route policy decisions.
4//! Boundary: shared plan container for load/delete/aggregate runtime entrypoints.
5
6#[cfg(test)]
7use crate::db::executor::route::LoadTerminalFastPathContract;
8use crate::{
9    db::{
10        access::AccessPlan,
11        cursor::{ContinuationSignature, CursorPlanError, GroupedPlannedCursor, PlannedCursor},
12        executor::{
13            EntityAuthority, ExecutionPreparation, ExecutorPlanError, GroupedPaginationWindow,
14            LoweredIndexPrefixSpec, LoweredIndexRangeSpec,
15            explain::assemble_load_execution_node_descriptor, lower_index_prefix_specs,
16            lower_index_range_specs, preparation::slot_map_for_model_plan,
17            traversal::row_read_consistency_for_plan,
18        },
19        predicate::MissingRowPolicy,
20        query::explain::ExplainExecutionNodeDescriptor,
21        query::plan::{
22            AccessPlannedQuery, ContinuationContract, ExecutionOrdering, GroupSpec, OrderSpec,
23            QueryMode, constant_covering_projection_value_from_access,
24            covering_index_projection_context,
25        },
26    },
27    error::InternalError,
28    traits::{EntityKind, EntityValue},
29};
30use std::marker::PhantomData;
31#[cfg(test)]
32use std::ops::Bound;
33///
34/// ExecutionStrategy
35///
36/// Executor-facing execution shape contract derived from planner ordering.
37/// Session and runtime entrypoints consume this strategy and must not
38/// re-derive grouped/scalar routing shape from boolean flags.
39///
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub enum ExecutionStrategy {
42    PrimaryKey,
43    Ordered,
44    Grouped,
45}
46
47///
48/// BytesByProjectionMode
49///
50/// Canonical `bytes_by(field)` projection mode classification used by execution
51/// and explain surfaces.
52///
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub(in crate::db) enum BytesByProjectionMode {
56    Materialized,
57    CoveringIndex,
58    CoveringConstant,
59}
60
61/// Classify canonical `bytes_by(field)` execution mode from one neutral access context.
62#[must_use]
63pub(in crate::db::executor) fn classify_bytes_by_projection_mode(
64    access: &AccessPlan<crate::value::Value>,
65    order_spec: Option<&OrderSpec>,
66    consistency: MissingRowPolicy,
67    has_predicate: bool,
68    target_field: &str,
69    primary_key_name: &'static str,
70) -> BytesByProjectionMode {
71    if !matches!(consistency, MissingRowPolicy::Ignore) {
72        return BytesByProjectionMode::Materialized;
73    }
74
75    if constant_covering_projection_value_from_access(access, target_field).is_some() {
76        return BytesByProjectionMode::CoveringConstant;
77    }
78
79    if has_predicate {
80        return BytesByProjectionMode::Materialized;
81    }
82
83    if covering_index_projection_context(access, order_spec, target_field, primary_key_name)
84        .is_some()
85    {
86        return BytesByProjectionMode::CoveringIndex;
87    }
88
89    BytesByProjectionMode::Materialized
90}
91
92/// ExecutablePlanCore
93///
94/// Generic-free executable-plan payload shared by typed `ExecutablePlan<E>`
95/// wrappers. This keeps cursor, ordering, and lowered structural plan state
96/// monomorphic while typed access and model-driven behavior remain at the
97/// outer executor boundary.
98///
99
100#[derive(Debug)]
101struct ExecutablePlanCore {
102    plan: AccessPlannedQuery,
103    continuation: Option<ContinuationContract>,
104    index_prefix_specs: Vec<LoweredIndexPrefixSpec>,
105    index_prefix_spec_invalid: bool,
106    index_range_specs: Vec<LoweredIndexRangeSpec>,
107    index_range_spec_invalid: bool,
108}
109
110impl ExecutablePlanCore {
111    #[must_use]
112    const fn new(
113        plan: AccessPlannedQuery,
114        continuation: Option<ContinuationContract>,
115        index_prefix_specs: Vec<LoweredIndexPrefixSpec>,
116        index_prefix_spec_invalid: bool,
117        index_range_specs: Vec<LoweredIndexRangeSpec>,
118        index_range_spec_invalid: bool,
119    ) -> Self {
120        Self {
121            plan,
122            continuation,
123            index_prefix_specs,
124            index_prefix_spec_invalid,
125            index_range_specs,
126            index_range_spec_invalid,
127        }
128    }
129
130    #[must_use]
131    const fn plan(&self) -> &AccessPlannedQuery {
132        &self.plan
133    }
134
135    #[must_use]
136    const fn mode(&self) -> QueryMode {
137        self.plan.scalar_plan().mode
138    }
139
140    #[must_use]
141    const fn is_grouped(&self) -> bool {
142        match self.continuation {
143            Some(ref contract) => contract.is_grouped(),
144            None => false,
145        }
146    }
147
148    fn execution_ordering(&self) -> Result<ExecutionOrdering, InternalError> {
149        let contract = self.continuation_contract()?;
150        Ok(contract.order_contract().ordering().clone())
151    }
152
153    fn execution_strategy(&self) -> Result<ExecutionStrategy, InternalError> {
154        let ordering = self.execution_ordering()?;
155
156        Ok(match ordering {
157            ExecutionOrdering::PrimaryKey => ExecutionStrategy::PrimaryKey,
158            ExecutionOrdering::Explicit(_) => ExecutionStrategy::Ordered,
159            ExecutionOrdering::Grouped(_) => ExecutionStrategy::Grouped,
160        })
161    }
162
163    #[must_use]
164    const fn consistency(&self) -> MissingRowPolicy {
165        row_read_consistency_for_plan(&self.plan)
166    }
167
168    #[must_use]
169    const fn order_spec(&self) -> Option<&OrderSpec> {
170        self.plan.scalar_plan().order.as_ref()
171    }
172
173    #[must_use]
174    fn has_predicate(&self) -> bool {
175        self.plan.has_residual_predicate()
176    }
177
178    fn index_prefix_specs(&self) -> Result<&[LoweredIndexPrefixSpec], InternalError> {
179        if self.index_prefix_spec_invalid {
180            return Err(
181                ExecutorPlanError::lowered_index_prefix_spec_invalid().into_internal_error()
182            );
183        }
184
185        Ok(self.index_prefix_specs.as_slice())
186    }
187
188    fn index_range_specs(&self) -> Result<&[LoweredIndexRangeSpec], InternalError> {
189        if self.index_range_spec_invalid {
190            return Err(ExecutorPlanError::lowered_index_range_spec_invalid().into_internal_error());
191        }
192
193        Ok(self.index_range_specs.as_slice())
194    }
195
196    #[must_use]
197    fn into_inner(self) -> AccessPlannedQuery {
198        self.plan
199    }
200
201    fn prepare_cursor(
202        &self,
203        authority: EntityAuthority,
204        cursor: Option<&[u8]>,
205    ) -> Result<PlannedCursor, ExecutorPlanError> {
206        let Some(contract) = self.continuation.as_ref() else {
207            return Err(ExecutorPlanError::continuation_cursor_requires_load_plan());
208        };
209
210        authority
211            .prepare_scalar_cursor(contract, cursor)
212            .map_err(ExecutorPlanError::from)
213    }
214
215    fn revalidate_cursor(
216        &self,
217        authority: EntityAuthority,
218        cursor: PlannedCursor,
219    ) -> Result<PlannedCursor, InternalError> {
220        let Some(contract) = self.continuation.as_ref() else {
221            return Err(
222                ExecutorPlanError::continuation_cursor_requires_load_plan().into_internal_error()
223            );
224        };
225
226        authority
227            .revalidate_scalar_cursor(contract, cursor)
228            .map_err(CursorPlanError::into_internal_error)
229    }
230
231    fn revalidate_grouped_cursor(
232        &self,
233        cursor: GroupedPlannedCursor,
234    ) -> Result<GroupedPlannedCursor, InternalError> {
235        let Some(contract) = self.continuation.as_ref() else {
236            return Err(
237                ExecutorPlanError::grouped_cursor_revalidation_requires_grouped_plan()
238                    .into_internal_error(),
239            );
240        };
241
242        contract
243            .revalidate_grouped_cursor(cursor)
244            .map_err(CursorPlanError::into_internal_error)
245    }
246
247    fn continuation_signature_for_runtime(&self) -> Result<ContinuationSignature, InternalError> {
248        let contract = self.continuation_contract()?;
249        Ok(contract.continuation_signature())
250    }
251
252    fn grouped_cursor_boundary_arity(&self) -> Result<usize, InternalError> {
253        let contract = self.continuation_contract()?;
254        if !contract.is_grouped() {
255            return Err(
256                ExecutorPlanError::grouped_cursor_boundary_arity_requires_grouped_plan()
257                    .into_internal_error(),
258            );
259        }
260
261        Ok(contract.boundary_arity())
262    }
263
264    fn grouped_pagination_window(
265        &self,
266        cursor: &GroupedPlannedCursor,
267    ) -> Result<GroupedPaginationWindow, InternalError> {
268        let contract = self.continuation_contract()?;
269        let window = contract
270            .grouped_paging_window(cursor)
271            .map_err(CursorPlanError::into_internal_error)?;
272        let (
273            limit,
274            initial_offset_for_page,
275            selection_bound,
276            resume_initial_offset,
277            resume_boundary,
278        ) = window.into_parts();
279
280        Ok(GroupedPaginationWindow::new(
281            limit,
282            initial_offset_for_page,
283            selection_bound,
284            resume_initial_offset,
285            resume_boundary,
286        ))
287    }
288
289    // Borrow immutable continuation contract for load-mode plans.
290    fn continuation_contract(&self) -> Result<&ContinuationContract, InternalError> {
291        self.continuation.as_ref().ok_or_else(|| {
292            ExecutorPlanError::continuation_contract_requires_load_plan().into_internal_error()
293        })
294    }
295}
296
297// Build one canonical lowered executable-plan core from resolved authority
298// plus one logical plan, regardless of whether the caller started from a typed
299// `ExecutablePlan<E>` shell or a structural follow-on rewrite.
300fn build_executable_plan_core(
301    authority: EntityAuthority,
302    mut plan: AccessPlannedQuery,
303) -> ExecutablePlanCore {
304    authority.finalize_static_planning_shape(&mut plan);
305
306    // Phase 0: derive immutable continuation contract once from planner semantics.
307    let continuation = plan.continuation_contract(authority.entity_path());
308
309    // Phase 1: lower index-prefix specs once and retain invariant state.
310    let (index_prefix_specs, index_prefix_spec_invalid) =
311        match lower_index_prefix_specs(authority.entity_tag(), &plan.access) {
312            Ok(specs) => (specs, false),
313            Err(_) => (Vec::new(), true),
314        };
315
316    // Phase 2: lower index-range specs once and retain invariant state.
317    let (index_range_specs, index_range_spec_invalid) =
318        match lower_index_range_specs(authority.entity_tag(), &plan.access) {
319            Ok(specs) => (specs, false),
320            Err(_) => (Vec::new(), true),
321        };
322
323    ExecutablePlanCore::new(
324        plan,
325        continuation,
326        index_prefix_specs,
327        index_prefix_spec_invalid,
328        index_range_specs,
329        index_range_spec_invalid,
330    )
331}
332
333///
334/// ExecutablePlan
335///
336/// Executor-ready plan bound to a specific entity type.
337///
338
339#[derive(Debug)]
340pub(in crate::db) struct ExecutablePlan<E: EntityKind> {
341    core: ExecutablePlanCore,
342    marker: PhantomData<fn() -> E>,
343}
344
345///
346/// PreparedLoadPlan
347///
348/// Generic-free load-plan boundary consumed by continuation resolution and
349/// load pipeline preparation after the typed `ExecutablePlan<E>` shell is no
350/// longer needed.
351///
352
353#[derive(Debug)]
354pub(in crate::db::executor) struct PreparedLoadPlan {
355    authority: EntityAuthority,
356    core: ExecutablePlanCore,
357}
358
359impl PreparedLoadPlan {
360    #[must_use]
361    pub(in crate::db::executor) fn from_plan(
362        authority: EntityAuthority,
363        plan: AccessPlannedQuery,
364    ) -> Self {
365        Self {
366            authority,
367            core: build_executable_plan_core(authority, plan),
368        }
369    }
370
371    #[must_use]
372    pub(in crate::db::executor) const fn authority(&self) -> EntityAuthority {
373        self.authority
374    }
375
376    #[must_use]
377    pub(in crate::db::executor) const fn mode(&self) -> QueryMode {
378        self.core.mode()
379    }
380
381    #[must_use]
382    pub(in crate::db::executor) const fn logical_plan(&self) -> &AccessPlannedQuery {
383        self.core.plan()
384    }
385
386    pub(in crate::db::executor) fn execution_ordering(
387        &self,
388    ) -> Result<ExecutionOrdering, InternalError> {
389        self.core.execution_ordering()
390    }
391
392    pub(in crate::db::executor) fn revalidate_cursor(
393        &self,
394        cursor: PlannedCursor,
395    ) -> Result<PlannedCursor, InternalError> {
396        self.core.revalidate_cursor(self.authority, cursor)
397    }
398
399    pub(in crate::db::executor) fn revalidate_grouped_cursor(
400        &self,
401        cursor: GroupedPlannedCursor,
402    ) -> Result<GroupedPlannedCursor, InternalError> {
403        self.core.revalidate_grouped_cursor(cursor)
404    }
405
406    pub(in crate::db::executor) fn continuation_signature_for_runtime(
407        &self,
408    ) -> Result<ContinuationSignature, InternalError> {
409        self.core.continuation_signature_for_runtime()
410    }
411
412    pub(in crate::db::executor) fn grouped_cursor_boundary_arity(
413        &self,
414    ) -> Result<usize, InternalError> {
415        self.core.grouped_cursor_boundary_arity()
416    }
417
418    pub(in crate::db::executor) fn grouped_pagination_window(
419        &self,
420        cursor: &GroupedPlannedCursor,
421    ) -> Result<GroupedPaginationWindow, InternalError> {
422        self.core.grouped_pagination_window(cursor)
423    }
424
425    pub(in crate::db::executor) fn index_prefix_specs(
426        &self,
427    ) -> Result<&[LoweredIndexPrefixSpec], InternalError> {
428        self.core.index_prefix_specs()
429    }
430
431    pub(in crate::db::executor) fn index_range_specs(
432        &self,
433    ) -> Result<&[LoweredIndexRangeSpec], InternalError> {
434        self.core.index_range_specs()
435    }
436
437    #[must_use]
438    pub(in crate::db::executor) fn into_plan(self) -> AccessPlannedQuery {
439        self.core.into_inner()
440    }
441}
442
443///
444/// PreparedAggregatePlan
445///
446/// Generic-free aggregate-plan boundary consumed by aggregate terminal and
447/// runtime preparation after the typed `ExecutablePlan<E>` shell is no longer
448/// needed.
449///
450
451#[derive(Debug)]
452pub(in crate::db::executor) struct PreparedAggregatePlan {
453    authority: EntityAuthority,
454    core: ExecutablePlanCore,
455}
456
457impl PreparedAggregatePlan {
458    #[must_use]
459    pub(in crate::db::executor) fn execution_preparation(&self) -> ExecutionPreparation {
460        ExecutionPreparation::from_plan(self.core.plan(), slot_map_for_model_plan(self.core.plan()))
461    }
462
463    pub(in crate::db::executor) fn into_streaming_parts(
464        self,
465    ) -> Result<
466        (
467            EntityAuthority,
468            AccessPlannedQuery,
469            Vec<LoweredIndexPrefixSpec>,
470            Vec<LoweredIndexRangeSpec>,
471        ),
472        InternalError,
473    > {
474        let Self { authority, core } = self;
475        if core.index_prefix_spec_invalid {
476            return Err(
477                ExecutorPlanError::lowered_index_prefix_spec_invalid().into_internal_error()
478            );
479        }
480        if core.index_range_spec_invalid {
481            return Err(ExecutorPlanError::lowered_index_range_spec_invalid().into_internal_error());
482        }
483
484        Ok((
485            authority,
486            core.plan,
487            core.index_prefix_specs,
488            core.index_range_specs,
489        ))
490    }
491
492    /// Re-shape one prepared aggregate plan into one grouped prepared load plan
493    /// without reconstructing a typed `ExecutablePlan<E>` shell.
494    #[must_use]
495    pub(in crate::db::executor) fn into_grouped_load_plan(
496        self,
497        group: GroupSpec,
498    ) -> PreparedLoadPlan {
499        PreparedLoadPlan::from_plan(self.authority, self.core.into_inner().into_grouped(group))
500    }
501}
502
503impl<E: EntityKind> ExecutablePlan<E> {
504    pub(in crate::db) fn new(plan: AccessPlannedQuery) -> Self {
505        Self::build(plan)
506    }
507
508    fn build(mut plan: AccessPlannedQuery) -> Self {
509        let authority = EntityAuthority::for_type::<E>();
510        authority.finalize_static_planning_shape(&mut plan);
511        authority.finalize_planner_route_profile(&mut plan);
512
513        Self {
514            core: build_executable_plan_core(authority, plan),
515            marker: PhantomData,
516        }
517    }
518
519    /// Explain scalar load execution shape as one canonical execution-node descriptor tree.
520    pub(in crate::db) fn explain_load_execution_node_descriptor(
521        &self,
522    ) -> Result<ExplainExecutionNodeDescriptor, InternalError>
523    where
524        E: EntityValue,
525    {
526        if !self.mode().is_load() {
527            return Err(
528                ExecutorPlanError::load_execution_descriptor_requires_load_plan()
529                    .into_internal_error(),
530            );
531        }
532
533        assemble_load_execution_node_descriptor(
534            E::MODEL.fields(),
535            E::MODEL.primary_key().name(),
536            self.core.plan(),
537        )
538    }
539
540    /// Validate and decode a continuation cursor into executor-ready cursor state.
541    pub(in crate::db) fn prepare_cursor(
542        &self,
543        cursor: Option<&[u8]>,
544    ) -> Result<PlannedCursor, ExecutorPlanError> {
545        self.core
546            .prepare_cursor(EntityAuthority::for_type::<E>(), cursor)
547    }
548
549    /// Return the plan mode (load vs delete).
550    #[must_use]
551    pub(in crate::db) const fn mode(&self) -> QueryMode {
552        self.core.mode()
553    }
554
555    /// Return whether this executable plan carries grouped logical shape.
556    #[must_use]
557    pub(in crate::db) const fn is_grouped(&self) -> bool {
558        self.core.is_grouped()
559    }
560
561    /// Return planner-projected execution strategy for entrypoint dispatch.
562    pub(in crate::db) fn execution_strategy(&self) -> Result<ExecutionStrategy, InternalError> {
563        self.core.execution_strategy()
564    }
565
566    /// Borrow the structural logical plan for executor-owned tests.
567    #[must_use]
568    #[cfg(test)]
569    pub(in crate::db) const fn logical_plan(&self) -> &AccessPlannedQuery {
570        self.core.plan()
571    }
572
573    /// Expose planner-projected execution ordering for executor/lowering tests.
574    #[cfg(test)]
575    pub(in crate::db) fn execution_ordering(&self) -> Result<ExecutionOrdering, InternalError> {
576        self.core.execution_ordering()
577    }
578
579    pub(in crate::db) const fn access(
580        &self,
581    ) -> &crate::db::access::AccessPlan<crate::value::Value> {
582        &self.core.plan().access
583    }
584
585    /// Borrow scalar row-consistency policy for runtime row reads.
586    #[must_use]
587    pub(in crate::db) const fn consistency(&self) -> MissingRowPolicy {
588        self.core.consistency()
589    }
590
591    /// Classify canonical `bytes_by(field)` execution mode for this plan/field.
592    #[must_use]
593    pub(in crate::db) fn bytes_by_projection_mode(
594        &self,
595        target_field: &str,
596    ) -> BytesByProjectionMode {
597        let authority = EntityAuthority::for_type::<E>();
598
599        classify_bytes_by_projection_mode(
600            self.access(),
601            self.order_spec(),
602            self.consistency(),
603            self.has_predicate(),
604            target_field,
605            authority.primary_key_name(),
606        )
607    }
608
609    /// Return a stable explain/diagnostic label for one bytes-by mode.
610    #[must_use]
611    pub(in crate::db) const fn bytes_by_projection_mode_label(
612        mode: BytesByProjectionMode,
613    ) -> &'static str {
614        match mode {
615            BytesByProjectionMode::Materialized => "field_materialized",
616            BytesByProjectionMode::CoveringIndex => "field_covering_index",
617            BytesByProjectionMode::CoveringConstant => "field_covering_constant",
618        }
619    }
620
621    /// Borrow scalar ORDER BY contract for this executable plan, if any.
622    #[must_use]
623    pub(in crate::db::executor) const fn order_spec(&self) -> Option<&OrderSpec> {
624        self.core.order_spec()
625    }
626
627    /// Return whether this executable plan has a residual predicate.
628    #[must_use]
629    pub(in crate::db::executor) fn has_predicate(&self) -> bool {
630        self.core.has_predicate()
631    }
632
633    pub(in crate::db) fn index_prefix_specs(
634        &self,
635    ) -> Result<&[LoweredIndexPrefixSpec], InternalError> {
636        self.core.index_prefix_specs()
637    }
638
639    pub(in crate::db) fn index_range_specs(
640        &self,
641    ) -> Result<&[LoweredIndexRangeSpec], InternalError> {
642        self.core.index_range_specs()
643    }
644
645    /// Render one canonical executor snapshot for test-only planner/executor
646    /// contract checks.
647    #[cfg(test)]
648    pub(in crate::db) fn render_snapshot_canonical(&self) -> Result<String, InternalError>
649    where
650        E: EntityValue,
651    {
652        // Phase 1: project all executor-owned summary fields from the logical plan.
653        let plan = self.core.plan();
654        let authority = EntityAuthority::for_type::<E>();
655        let projection_spec = plan.frozen_projection_spec();
656        let projection_selection = if plan.grouped_plan().is_some()
657            || projection_spec.len() != authority.row_layout().field_count()
658        {
659            "Declared"
660        } else {
661            "All"
662        };
663        let projection_coverage_flag = plan.grouped_plan().is_some();
664        let continuation_signature = self.core.continuation_signature_for_runtime()?;
665        let ordering_direction = self
666            .core
667            .continuation_contract()?
668            .order_contract()
669            .direction();
670        let load_terminal_fast_path =
671            crate::db::executor::route::derive_load_terminal_fast_path_contract_for_plan(
672                authority, plan,
673            );
674
675        // Phase 2: lower index-bound summaries into stable compact text.
676        let index_prefix_specs = render_index_prefix_specs(self.core.index_prefix_specs()?);
677        let index_range_specs = render_index_range_specs(self.core.index_range_specs()?);
678        let explain_plan = plan.explain_with_model(E::MODEL);
679
680        // Phase 3: join the canonical snapshot payload in one stable line order.
681        Ok([
682            "snapshot_version=1".to_string(),
683            format!("plan_hash={}", plan.fingerprint()),
684            format!("mode={:?}", self.core.mode()),
685            format!("is_grouped={}", self.core.is_grouped()),
686            format!("execution_strategy={:?}", self.core.execution_strategy()?),
687            format!(
688                "load_terminal_fast_path={}",
689                render_load_terminal_fast_path_label(load_terminal_fast_path.as_ref())
690            ),
691            format!("ordering_direction={ordering_direction:?}"),
692            format!(
693                "distinct_execution_strategy={:?}",
694                plan.distinct_execution_strategy()
695            ),
696            format!("projection_selection={projection_selection}"),
697            format!("projection_spec={projection_spec:?}"),
698            format!("order_spec={:?}", plan.scalar_plan().order),
699            format!("page_spec={:?}", plan.scalar_plan().page),
700            format!("projection_coverage_flag={projection_coverage_flag}"),
701            format!("continuation_signature={continuation_signature}"),
702            format!("index_prefix_specs={index_prefix_specs}"),
703            format!("index_range_specs={index_range_specs}"),
704            format!("explain_plan={explain_plan:?}"),
705        ]
706        .join("\n"))
707    }
708
709    /// Split the executable plan into its canonical structural logical plan.
710    ///
711    /// Aggregate/scalar prepared boundaries should prefer this helper when they
712    /// no longer need the typed `ExecutablePlan<E>` shell after entering
713    /// structural execution preparation.
714    pub(in crate::db) fn into_plan(self) -> AccessPlannedQuery {
715        self.core.into_inner()
716    }
717
718    /// Validate and decode grouped continuation cursor state for grouped plans.
719    #[cfg(test)]
720    pub(in crate::db) fn prepare_grouped_cursor(
721        &self,
722        cursor: Option<&[u8]>,
723    ) -> Result<GroupedPlannedCursor, ExecutorPlanError> {
724        let Some(contract) = self.core.continuation.as_ref() else {
725            return Err(ExecutorPlanError::grouped_cursor_preparation_requires_grouped_plan());
726        };
727
728        contract
729            .prepare_grouped_cursor(EntityAuthority::for_type::<E>().entity_path(), cursor)
730            .map_err(ExecutorPlanError::from)
731    }
732
733    /// Validate one already-decoded grouped continuation token for grouped plans.
734    pub(in crate::db) fn prepare_grouped_cursor_token(
735        &self,
736        cursor: Option<crate::db::cursor::GroupedContinuationToken>,
737    ) -> Result<GroupedPlannedCursor, ExecutorPlanError> {
738        let Some(contract) = self.core.continuation.as_ref() else {
739            return Err(ExecutorPlanError::grouped_cursor_preparation_requires_grouped_plan());
740        };
741
742        contract
743            .prepare_grouped_cursor_token(EntityAuthority::for_type::<E>().entity_path(), cursor)
744            .map_err(ExecutorPlanError::from)
745    }
746
747    /// Consume one typed load executable plan into one generic-free boundary
748    /// payload for continuation and load-pipeline preparation.
749    #[must_use]
750    pub(in crate::db::executor) fn into_prepared_load_plan(self) -> PreparedLoadPlan {
751        PreparedLoadPlan {
752            authority: EntityAuthority::for_type::<E>(),
753            core: self.core,
754        }
755    }
756
757    /// Consume one typed aggregate executable plan into one generic-free
758    /// boundary payload for aggregate terminal and runtime preparation.
759    #[must_use]
760    pub(in crate::db::executor) fn into_prepared_aggregate_plan(self) -> PreparedAggregatePlan {
761        PreparedAggregatePlan {
762            authority: EntityAuthority::for_type::<E>(),
763            core: self.core,
764        }
765    }
766}
767
768#[cfg(test)]
769const fn render_load_terminal_fast_path_label(
770    contract: Option<&LoadTerminalFastPathContract>,
771) -> &'static str {
772    match contract {
773        Some(LoadTerminalFastPathContract::CoveringRead(_)) => "CoveringRead",
774        None => "Materialized",
775    }
776}
777
778#[cfg(test)]
779fn render_index_prefix_specs(specs: &[LoweredIndexPrefixSpec]) -> String {
780    let rendered = specs
781        .iter()
782        .map(|spec| {
783            format!(
784                "{{index:{},bound_type:equality,lower:{},upper:{}}}",
785                spec.index().name(),
786                render_lowered_bound(spec.lower()),
787                render_lowered_bound(spec.upper()),
788            )
789        })
790        .collect::<Vec<_>>();
791
792    format!("[{}]", rendered.join(","))
793}
794
795#[cfg(test)]
796fn render_index_range_specs(specs: &[LoweredIndexRangeSpec]) -> String {
797    let rendered = specs
798        .iter()
799        .map(|spec| {
800            format!(
801                "{{index:{},lower:{},upper:{}}}",
802                spec.index().name(),
803                render_lowered_bound(spec.lower()),
804                render_lowered_bound(spec.upper()),
805            )
806        })
807        .collect::<Vec<_>>();
808
809    format!("[{}]", rendered.join(","))
810}
811
812#[cfg(test)]
813fn render_lowered_bound(bound: &Bound<crate::db::access::LoweredKey>) -> String {
814    match bound {
815        Bound::Included(key) => format!("included({})", render_lowered_key_summary(key)),
816        Bound::Excluded(key) => format!("excluded({})", render_lowered_key_summary(key)),
817        Bound::Unbounded => "unbounded".to_string(),
818    }
819}
820
821#[cfg(test)]
822fn render_lowered_key_summary(key: &crate::db::access::LoweredKey) -> String {
823    let bytes = key.as_bytes();
824    let head_len = bytes.len().min(8);
825    let tail_len = bytes.len().min(8);
826    let head = crate::db::codec::cursor::encode_cursor(&bytes[..head_len]);
827    let tail = crate::db::codec::cursor::encode_cursor(&bytes[bytes.len() - tail_len..]);
828
829    format!("len:{}:head:{head}:tail:{tail}", bytes.len())
830}