Skip to main content

icydb_core/db/query/intent/
key_access.rs

1use crate::{
2    db::query::plan::{AccessPath, AccessPlan, PlanError},
3    traits::{EntityKind, FieldValue},
4    value::Value,
5};
6
7///
8/// KeyAccess
9/// Primary-key-only access hints for query planning.
10///
11
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub enum KeyAccess<K> {
14    Single(K),
15    Many(Vec<K>),
16}
17
18///
19/// KeyAccessKind
20/// Identifies which key-only builder set the access path.
21///
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub enum KeyAccessKind {
25    Single,
26    Many,
27    Only,
28}
29
30///
31/// KeyAccessState
32/// Tracks key-only access plus its origin for intent validation.
33///
34
35#[derive(Clone, Debug, Eq, PartialEq)]
36pub struct KeyAccessState<K> {
37    pub kind: KeyAccessKind,
38    pub access: KeyAccess<K>,
39}
40
41// Build a key-only access plan without predicate-based planning.
42// Build a model-level access plan for key-only intents.
43// Build a model-level access plan for key-only intents.
44pub fn access_plan_from_keys_value<K>(access: &KeyAccess<K>) -> AccessPlan<Value>
45where
46    K: FieldValue,
47{
48    match access {
49        KeyAccess::Single(key) => AccessPlan::Path(AccessPath::ByKey(key.to_value())),
50        KeyAccess::Many(keys) => {
51            let values: Vec<Value> = keys.iter().map(FieldValue::to_value).collect();
52            if let Some(first) = values.first()
53                && values.len() == 1
54            {
55                return AccessPlan::Path(AccessPath::ByKey(first.clone()));
56            }
57
58            AccessPlan::Path(AccessPath::ByKeys(values))
59        }
60    }
61}
62
63// Convert model-level access plans into entity-keyed access plans.
64pub fn access_plan_to_entity_keys<E: EntityKind>(
65    model: &crate::model::entity::EntityModel,
66    access: AccessPlan<Value>,
67) -> Result<AccessPlan<E::Id>, PlanError> {
68    let plan = match access {
69        AccessPlan::Path(path) => AccessPlan::Path(access_path_to_entity_keys::<E>(model, path)?),
70        AccessPlan::Union(children) => {
71            let mut out = Vec::with_capacity(children.len());
72            for child in children {
73                out.push(access_plan_to_entity_keys::<E>(model, child)?);
74            }
75            AccessPlan::Union(out)
76        }
77        AccessPlan::Intersection(children) => {
78            let mut out = Vec::with_capacity(children.len());
79            for child in children {
80                out.push(access_plan_to_entity_keys::<E>(model, child)?);
81            }
82            AccessPlan::Intersection(out)
83        }
84    };
85
86    Ok(plan)
87}
88
89// Convert model-level access paths into entity-keyed access paths.
90pub fn access_path_to_entity_keys<E: EntityKind>(
91    model: &crate::model::entity::EntityModel,
92    path: AccessPath<Value>,
93) -> Result<AccessPath<E::Id>, PlanError> {
94    let path = match path {
95        AccessPath::ByKey(key) => AccessPath::ByKey(coerce_entity_key::<E>(model, &key)?),
96        AccessPath::ByKeys(keys) => {
97            let mut out = Vec::with_capacity(keys.len());
98            for key in keys {
99                out.push(coerce_entity_key::<E>(model, &key)?);
100            }
101            AccessPath::ByKeys(out)
102        }
103        AccessPath::KeyRange { start, end } => AccessPath::KeyRange {
104            start: coerce_entity_key::<E>(model, &start)?,
105            end: coerce_entity_key::<E>(model, &end)?,
106        },
107        AccessPath::IndexPrefix { index, values } => AccessPath::IndexPrefix { index, values },
108        AccessPath::FullScan => AccessPath::FullScan,
109    };
110
111    Ok(path)
112}
113
114// Convert model-level key values into typed entity keys.
115pub fn coerce_entity_key<E: EntityKind>(
116    model: &crate::model::entity::EntityModel,
117    key: &Value,
118) -> Result<E::Id, PlanError> {
119    E::Id::from_value(key).ok_or_else(|| PlanError::PrimaryKeyMismatch {
120        field: model.primary_key.name.to_string(),
121        key: key.clone(),
122    })
123}