icydb_core/db/query/intent/
key_access.rs1use crate::{
2 db::query::plan::{AccessPath, AccessPlan, PlanError},
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 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
63pub 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
89pub 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
114pub 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}