icydb_core/db/query/intent/
key_access.rs1use crate::{
2 db::query::plan::{AccessPath, AccessPlan, PlanError, canonical},
3 traits::{EntityKind, FieldValue},
4 value::Value,
5};
6
7#[derive(Clone, Debug, Eq, PartialEq)]
13pub enum KeyAccess<K> {
14 Single(K),
15 Many(Vec<K>),
16}
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub enum KeyAccessKind {
25 Single,
26 Many,
27 Only,
28}
29
30#[derive(Clone, Debug, Eq, PartialEq)]
36pub struct KeyAccessState<K> {
37 pub kind: KeyAccessKind,
38 pub access: KeyAccess<K>,
39}
40
41pub fn access_plan_from_keys_value<K>(access: &KeyAccess<K>) -> AccessPlan<Value>
43where
44 K: FieldValue,
45{
46 match access {
47 KeyAccess::Single(key) => AccessPlan::Path(AccessPath::ByKey(key.to_value())),
48 KeyAccess::Many(keys) => {
49 let mut values: Vec<Value> = keys.iter().map(FieldValue::to_value).collect();
50 canonical::canonicalize_key_values(&mut values);
51 if let Some(first) = values.first()
52 && values.len() == 1
53 {
54 return AccessPlan::Path(AccessPath::ByKey(first.clone()));
55 }
56
57 AccessPlan::Path(AccessPath::ByKeys(values))
58 }
59 }
60}
61
62pub fn access_plan_to_entity_keys<E: EntityKind>(
64 model: &crate::model::entity::EntityModel,
65 access: AccessPlan<Value>,
66) -> Result<AccessPlan<E::Key>, PlanError> {
67 let plan = match access {
68 AccessPlan::Path(path) => AccessPlan::Path(access_path_to_entity_keys::<E>(model, path)?),
69 AccessPlan::Union(children) => {
70 let mut out = Vec::with_capacity(children.len());
71 for child in children {
72 out.push(access_plan_to_entity_keys::<E>(model, child)?);
73 }
74 AccessPlan::Union(out)
75 }
76 AccessPlan::Intersection(children) => {
77 let mut out = Vec::with_capacity(children.len());
78 for child in children {
79 out.push(access_plan_to_entity_keys::<E>(model, child)?);
80 }
81 AccessPlan::Intersection(out)
82 }
83 };
84
85 Ok(plan)
86}
87
88pub fn access_path_to_entity_keys<E: EntityKind>(
90 model: &crate::model::entity::EntityModel,
91 path: AccessPath<Value>,
92) -> Result<AccessPath<E::Key>, PlanError> {
93 let path = match path {
94 AccessPath::ByKey(key) => AccessPath::ByKey(coerce_entity_key::<E>(model, &key)?),
95 AccessPath::ByKeys(keys) => {
96 let mut out = Vec::with_capacity(keys.len());
97 for key in keys {
98 out.push(coerce_entity_key::<E>(model, &key)?);
99 }
100 AccessPath::ByKeys(out)
101 }
102 AccessPath::KeyRange { start, end } => AccessPath::KeyRange {
103 start: coerce_entity_key::<E>(model, &start)?,
104 end: coerce_entity_key::<E>(model, &end)?,
105 },
106 AccessPath::IndexPrefix { index, values } => AccessPath::IndexPrefix { index, values },
107 AccessPath::FullScan => AccessPath::FullScan,
108 };
109
110 Ok(path)
111}
112
113pub fn coerce_entity_key<E: EntityKind>(
115 model: &crate::model::entity::EntityModel,
116 key: &Value,
117) -> Result<E::Key, PlanError> {
118 E::Key::from_value(key).ok_or_else(|| PlanError::PrimaryKeyMismatch {
119 field: model.primary_key.name.to_string(),
120 key: key.clone(),
121 })
122}