Skip to main content

icydb_core/db/predicate/
coercion.rs

1use crate::value::CoercionFamily;
2use std::collections::BTreeMap;
3
4///
5/// CoercionId
6///
7/// Identifier for an explicit comparison coercion policy.
8///
9/// Coercions express *how* values may be compared, not whether a comparison
10/// is valid for a given field. Validation and planning enforce legality.
11///
12
13#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub enum CoercionId {
15    Strict,
16    NumericWiden,
17    TextCasefold,
18    CollectionElement,
19}
20
21impl CoercionId {
22    /// Stable tag used by plan hash encodings (fingerprint/continuation).
23    #[must_use]
24    pub const fn plan_hash_tag(self) -> u8 {
25        match self {
26            Self::Strict => 0x01,
27            Self::NumericWiden => 0x02,
28            Self::TextCasefold => 0x04,
29            Self::CollectionElement => 0x05,
30        }
31    }
32}
33
34///
35/// CoercionSpec
36///
37/// Fully-specified coercion policy for predicate comparisons.
38///
39
40#[derive(Clone, Debug, Eq, PartialEq)]
41pub struct CoercionSpec {
42    pub id: CoercionId,
43    pub params: BTreeMap<String, String>,
44}
45
46impl CoercionSpec {
47    #[must_use]
48    pub const fn new(id: CoercionId) -> Self {
49        Self {
50            id,
51            params: BTreeMap::new(),
52        }
53    }
54}
55
56impl Default for CoercionSpec {
57    fn default() -> Self {
58        Self::new(CoercionId::Strict)
59    }
60}
61
62///
63/// CoercionRuleFamily
64///
65/// Rule-side matcher for coercion routing families.
66///
67
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub(crate) enum CoercionRuleFamily {
70    Any,
71    Family(CoercionFamily),
72}
73
74///
75/// CoercionRule
76///
77/// Declarative coercion routing rule between value families.
78///
79
80#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81pub(crate) struct CoercionRule {
82    pub left: CoercionRuleFamily,
83    pub right: CoercionRuleFamily,
84    pub id: CoercionId,
85}
86
87pub(crate) const COERCION_TABLE: &[CoercionRule] = &[
88    CoercionRule {
89        left: CoercionRuleFamily::Any,
90        right: CoercionRuleFamily::Any,
91        id: CoercionId::Strict,
92    },
93    CoercionRule {
94        left: CoercionRuleFamily::Family(CoercionFamily::Numeric),
95        right: CoercionRuleFamily::Family(CoercionFamily::Numeric),
96        id: CoercionId::NumericWiden,
97    },
98    CoercionRule {
99        left: CoercionRuleFamily::Family(CoercionFamily::Textual),
100        right: CoercionRuleFamily::Family(CoercionFamily::Textual),
101        id: CoercionId::TextCasefold,
102    },
103    CoercionRule {
104        left: CoercionRuleFamily::Any,
105        right: CoercionRuleFamily::Any,
106        id: CoercionId::CollectionElement,
107    },
108];
109
110/// Returns whether a coercion rule exists for the provided routing families.
111#[must_use]
112pub(in crate::db) fn supports_coercion(
113    left: CoercionFamily,
114    right: CoercionFamily,
115    id: CoercionId,
116) -> bool {
117    COERCION_TABLE.iter().any(|rule| {
118        rule.id == id && family_matches(rule.left, left) && family_matches(rule.right, right)
119    })
120}
121
122fn family_matches(rule: CoercionRuleFamily, value: CoercionFamily) -> bool {
123    match rule {
124        CoercionRuleFamily::Any => true,
125        CoercionRuleFamily::Family(expected) => expected == value,
126    }
127}