meshdb_executor/
procedures.rs1use crate::value::Value;
2use meshdb_core::Property;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum ProcType {
12 String,
13 Integer,
14 Float,
15 Number,
16 Boolean,
17 Any,
18}
19
20impl ProcType {
21 pub fn parse(s: &str) -> Self {
22 let trimmed = s.trim().trim_end_matches('?').trim();
23 match trimmed.to_ascii_uppercase().as_str() {
24 "STRING" => ProcType::String,
25 "INTEGER" | "INT" => ProcType::Integer,
26 "FLOAT" => ProcType::Float,
27 "NUMBER" | "NUMERIC" => ProcType::Number,
28 "BOOLEAN" | "BOOL" => ProcType::Boolean,
29 _ => ProcType::Any,
30 }
31 }
32
33 pub fn accepts(&self, value: &Value) -> bool {
38 if matches!(value, Value::Null) {
39 return true;
40 }
41 match (self, value) {
42 (ProcType::Any, _) => true,
43 (ProcType::String, Value::Property(Property::String(_))) => true,
44 (ProcType::Integer, Value::Property(Property::Int64(_))) => true,
45 (ProcType::Float, Value::Property(Property::Float64(_))) => true,
46 (ProcType::Float, Value::Property(Property::Int64(_))) => true,
47 (ProcType::Number, Value::Property(Property::Int64(_))) => true,
48 (ProcType::Number, Value::Property(Property::Float64(_))) => true,
49 (ProcType::Boolean, Value::Property(Property::Bool(_))) => true,
50 _ => false,
51 }
52 }
53}
54
55#[derive(Debug, Clone)]
56pub struct ProcArgSpec {
57 pub name: String,
58 pub ty: ProcType,
59}
60
61#[derive(Debug, Clone)]
62pub struct ProcOutSpec {
63 pub name: String,
64 pub ty: ProcType,
65}
66
67#[derive(Debug, Clone)]
75pub struct Procedure {
76 pub qualified_name: Vec<String>,
77 pub inputs: Vec<ProcArgSpec>,
78 pub outputs: Vec<ProcOutSpec>,
79 pub rows: Vec<ProcRow>,
80}
81
82pub type ProcRow = HashMap<String, Value>;
87
88impl Procedure {
89 pub fn row_matches(&self, row: &ProcRow, args: &[Value]) -> bool {
96 for (spec, arg) in self.inputs.iter().zip(args.iter()) {
97 let cell = row.get(&spec.name).unwrap_or(&Value::Null);
98 if !values_equal_for_procedure(cell, arg) {
99 return false;
100 }
101 }
102 true
103 }
104}
105
106fn values_equal_for_procedure(a: &Value, b: &Value) -> bool {
107 match (a, b) {
108 (Value::Null, Value::Null) => true,
109 (Value::Null, _) | (_, Value::Null) => false,
110 (Value::Property(Property::Int64(x)), Value::Property(Property::Int64(y))) => x == y,
111 (Value::Property(Property::Float64(x)), Value::Property(Property::Float64(y))) => x == y,
112 (Value::Property(Property::Int64(i)), Value::Property(Property::Float64(f)))
113 | (Value::Property(Property::Float64(f)), Value::Property(Property::Int64(i))) => {
114 *f == (*i as f64)
115 }
116 (Value::Property(Property::String(x)), Value::Property(Property::String(y))) => x == y,
117 (Value::Property(Property::Bool(x)), Value::Property(Property::Bool(y))) => x == y,
118 _ => a == b,
119 }
120}
121
122#[derive(Debug, Clone, Default)]
129pub struct ProcedureRegistry {
130 procs: HashMap<String, Procedure>,
131}
132
133impl ProcedureRegistry {
134 pub fn new() -> Self {
135 Self::default()
136 }
137
138 pub fn register(&mut self, proc: Procedure) {
139 let key = proc.qualified_name.join(".");
140 self.procs.insert(key, proc);
141 }
142
143 pub fn get(&self, qualified_name: &[String]) -> Option<&Procedure> {
144 self.procs.get(&qualified_name.join("."))
145 }
146}