1use crate::engine::Database;
6use crate::error::{DbxError, DbxResult};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10pub trait Callable: Send + Sync {
12 fn call(&self, ctx: &ExecutionContext, args: &[Value]) -> DbxResult<Value>;
14
15 fn name(&self) -> &str;
17
18 fn signature(&self) -> &Signature;
20}
21
22pub struct ExecutionContext {
24 pub dbx: Arc<Database>,
26 pub tx_id: Option<u64>,
28 pub metadata: HashMap<String, Value>,
30}
31
32impl ExecutionContext {
33 pub fn new(dbx: Arc<Database>) -> Self {
34 Self {
35 dbx,
36 tx_id: None,
37 metadata: HashMap::new(),
38 }
39 }
40
41 pub fn with_tx(mut self, tx_id: u64) -> Self {
42 self.tx_id = Some(tx_id);
43 self
44 }
45}
46
47#[derive(Debug, Clone)]
49pub struct Signature {
50 pub params: Vec<DataType>,
51 pub return_type: DataType,
52 pub is_variadic: bool,
53}
54
55impl Signature {
56 pub fn validate_args(&self, args: &[Value]) -> DbxResult<()> {
58 if !self.is_variadic && args.len() != self.params.len() {
59 return Err(DbxError::InvalidArguments(format!(
60 "Expected {} arguments, got {}",
61 self.params.len(),
62 args.len()
63 )));
64 }
65
66 if self.is_variadic && args.len() < self.params.len() {
67 return Err(DbxError::InvalidArguments(format!(
68 "Expected at least {} arguments, got {}",
69 self.params.len(),
70 args.len()
71 )));
72 }
73
74 for (expected, actual) in self.params.iter().zip(args.iter()) {
76 if !actual.matches_type(expected) {
77 return Err(DbxError::TypeMismatch {
78 expected: format!("{:?}", expected),
79 actual: format!("{:?}", actual.data_type()),
80 });
81 }
82 }
83
84 Ok(())
85 }
86}
87
88#[derive(Debug, Clone, PartialEq)]
90pub enum DataType {
91 Null,
92 Boolean,
93 Int,
94 Float,
95 String,
96 Bytes,
97 Row,
98 RecordBatch,
99 Array,
100 Table,
101}
102
103#[derive(Debug, Clone)]
105pub enum Value {
106 Null,
107 Boolean(bool),
108 Int(i64),
109 Float(f64),
110 String(String),
111 Bytes(Vec<u8>),
112 Array(Vec<Value>),
114 Table(Vec<Vec<Value>>),
116}
117
118impl Value {
119 pub fn data_type(&self) -> DataType {
120 match self {
121 Value::Null => DataType::Null,
122 Value::Boolean(_) => DataType::Boolean,
123 Value::Int(_) => DataType::Int,
124 Value::Float(_) => DataType::Float,
125 Value::String(_) => DataType::String,
126 Value::Bytes(_) => DataType::Bytes,
127 Value::Array(_) => DataType::Array,
128 Value::Table(_) => DataType::Table,
129 }
130 }
131
132 pub fn matches_type(&self, expected: &DataType) -> bool {
133 match (self, expected) {
134 (Value::Null, _) => true, _ => &self.data_type() == expected,
136 }
137 }
138
139 pub fn as_bool(&self) -> DbxResult<bool> {
141 match self {
142 Value::Boolean(b) => Ok(*b),
143 _ => Err(DbxError::TypeMismatch {
144 expected: "Boolean".to_string(),
145 actual: format!("{:?}", self.data_type()),
146 }),
147 }
148 }
149
150 pub fn as_i64(&self) -> DbxResult<i64> {
151 match self {
152 Value::Int(i) => Ok(*i),
153 _ => Err(DbxError::TypeMismatch {
154 expected: "Int".to_string(),
155 actual: format!("{:?}", self.data_type()),
156 }),
157 }
158 }
159
160 pub fn as_f64(&self) -> DbxResult<f64> {
161 match self {
162 Value::Float(f) => Ok(*f),
163 _ => Err(DbxError::TypeMismatch {
164 expected: "Float".to_string(),
165 actual: format!("{:?}", self.data_type()),
166 }),
167 }
168 }
169
170 pub fn as_str(&self) -> DbxResult<&str> {
171 match self {
172 Value::String(s) => Ok(s),
173 _ => Err(DbxError::TypeMismatch {
174 expected: "String".to_string(),
175 actual: format!("{:?}", self.data_type()),
176 }),
177 }
178 }
179
180 pub fn as_bytes(&self) -> DbxResult<&[u8]> {
181 match self {
182 Value::Bytes(b) => Ok(b),
183 _ => Err(DbxError::TypeMismatch {
184 expected: "Bytes".to_string(),
185 actual: format!("{:?}", self.data_type()),
186 }),
187 }
188 }
189
190 pub fn is_truthy(&self) -> bool {
192 match self {
193 Value::Null => false,
194 Value::Boolean(b) => *b,
195 Value::Int(i) => *i != 0,
196 Value::Float(f) => *f != 0.0,
197 Value::String(s) => !s.is_empty(),
198 Value::Bytes(b) => !b.is_empty(),
199 Value::Array(a) => !a.is_empty(),
200 Value::Table(t) => !t.is_empty(),
201 }
202 }
203
204 pub fn as_array(&self) -> DbxResult<&Vec<Value>> {
206 match self {
207 Value::Array(a) => Ok(a),
208 _ => Err(DbxError::TypeMismatch {
209 expected: "Array".to_string(),
210 actual: format!("{:?}", self.data_type()),
211 }),
212 }
213 }
214
215 pub fn as_table(&self) -> DbxResult<&Vec<Vec<Value>>> {
217 match self {
218 Value::Table(t) => Ok(t),
219 _ => Err(DbxError::TypeMismatch {
220 expected: "Table".to_string(),
221 actual: format!("{:?}", self.data_type()),
222 }),
223 }
224 }
225}