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 Table,
100}
101
102#[derive(Debug, Clone)]
104pub enum Value {
105 Null,
106 Boolean(bool),
107 Int(i64),
108 Float(f64),
109 String(String),
110 Bytes(Vec<u8>),
111 Table(Vec<Vec<Value>>),
113}
114
115impl Value {
116 pub fn data_type(&self) -> DataType {
117 match self {
118 Value::Null => DataType::Null,
119 Value::Boolean(_) => DataType::Boolean,
120 Value::Int(_) => DataType::Int,
121 Value::Float(_) => DataType::Float,
122 Value::String(_) => DataType::String,
123 Value::Bytes(_) => DataType::Bytes,
124 Value::Table(_) => DataType::Table,
125 }
126 }
127
128 pub fn matches_type(&self, expected: &DataType) -> bool {
129 match (self, expected) {
130 (Value::Null, _) => true, _ => &self.data_type() == expected,
132 }
133 }
134
135 pub fn as_bool(&self) -> DbxResult<bool> {
137 match self {
138 Value::Boolean(b) => Ok(*b),
139 _ => Err(DbxError::TypeMismatch {
140 expected: "Boolean".to_string(),
141 actual: format!("{:?}", self.data_type()),
142 }),
143 }
144 }
145
146 pub fn as_i64(&self) -> DbxResult<i64> {
147 match self {
148 Value::Int(i) => Ok(*i),
149 _ => Err(DbxError::TypeMismatch {
150 expected: "Int".to_string(),
151 actual: format!("{:?}", self.data_type()),
152 }),
153 }
154 }
155
156 pub fn as_f64(&self) -> DbxResult<f64> {
157 match self {
158 Value::Float(f) => Ok(*f),
159 _ => Err(DbxError::TypeMismatch {
160 expected: "Float".to_string(),
161 actual: format!("{:?}", self.data_type()),
162 }),
163 }
164 }
165
166 pub fn as_str(&self) -> DbxResult<&str> {
167 match self {
168 Value::String(s) => Ok(s),
169 _ => Err(DbxError::TypeMismatch {
170 expected: "String".to_string(),
171 actual: format!("{:?}", self.data_type()),
172 }),
173 }
174 }
175
176 pub fn as_bytes(&self) -> DbxResult<&[u8]> {
177 match self {
178 Value::Bytes(b) => Ok(b),
179 _ => Err(DbxError::TypeMismatch {
180 expected: "Bytes".to_string(),
181 actual: format!("{:?}", self.data_type()),
182 }),
183 }
184 }
185
186 pub fn is_truthy(&self) -> bool {
188 match self {
189 Value::Null => false,
190 Value::Boolean(b) => *b,
191 Value::Int(i) => *i != 0,
192 Value::Float(f) => *f != 0.0,
193 Value::String(s) => !s.is_empty(),
194 Value::Bytes(b) => !b.is_empty(),
195 Value::Table(t) => !t.is_empty(),
196 }
197 }
198
199 pub fn as_table(&self) -> DbxResult<&Vec<Vec<Value>>> {
201 match self {
202 Value::Table(t) => Ok(t),
203 _ => Err(DbxError::TypeMismatch {
204 expected: "Table".to_string(),
205 actual: format!("{:?}", self.data_type()),
206 }),
207 }
208 }
209}