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>
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 mut values: Vec<Value> = keys.iter().map(FieldValue::to_value).collect();
52 canonical::canonicalize_key_values(&mut values);
53 if let Some(first) = values.first()
54 && values.len() == 1
55 {
56 return AccessPlan::Path(AccessPath::ByKey(first.clone()));
57 }
58
59 AccessPlan::Path(AccessPath::ByKeys(values))
60 }
61 }
62}
63
64pub fn access_plan_to_entity_keys<E: EntityKind>(
66 model: &crate::model::entity::EntityModel,
67 access: AccessPlan<Value>,
68) -> Result<AccessPlan<E::Id>, PlanError> {
69 let plan = match access {
70 AccessPlan::Path(path) => AccessPlan::Path(access_path_to_entity_keys::<E>(model, path)?),
71 AccessPlan::Union(children) => {
72 let mut out = Vec::with_capacity(children.len());
73 for child in children {
74 out.push(access_plan_to_entity_keys::<E>(model, child)?);
75 }
76 AccessPlan::Union(out)
77 }
78 AccessPlan::Intersection(children) => {
79 let mut out = Vec::with_capacity(children.len());
80 for child in children {
81 out.push(access_plan_to_entity_keys::<E>(model, child)?);
82 }
83 AccessPlan::Intersection(out)
84 }
85 };
86
87 Ok(plan)
88}
89
90pub fn access_path_to_entity_keys<E: EntityKind>(
92 model: &crate::model::entity::EntityModel,
93 path: AccessPath<Value>,
94) -> Result<AccessPath<E::Id>, PlanError> {
95 let path = match path {
96 AccessPath::ByKey(key) => AccessPath::ByKey(coerce_entity_key::<E>(model, &key)?),
97 AccessPath::ByKeys(keys) => {
98 let mut out = Vec::with_capacity(keys.len());
99 for key in keys {
100 out.push(coerce_entity_key::<E>(model, &key)?);
101 }
102 AccessPath::ByKeys(out)
103 }
104 AccessPath::KeyRange { start, end } => AccessPath::KeyRange {
105 start: coerce_entity_key::<E>(model, &start)?,
106 end: coerce_entity_key::<E>(model, &end)?,
107 },
108 AccessPath::IndexPrefix { index, values } => AccessPath::IndexPrefix { index, values },
109 AccessPath::FullScan => AccessPath::FullScan,
110 };
111
112 Ok(path)
113}
114
115pub fn coerce_entity_key<E: EntityKind>(
117 model: &crate::model::entity::EntityModel,
118 key: &Value,
119) -> Result<E::Id, PlanError> {
120 E::Id::from_value(key).ok_or_else(|| PlanError::PrimaryKeyMismatch {
121 field: model.primary_key.name.to_string(),
122 key: key.clone(),
123 })
124}