use anyhow::{Result, anyhow};
use futures::Stream;
use serde_json::Value;
use std::pin::Pin;
#[derive(Debug, Clone)]
pub struct ProcedureSignature {
pub args: Vec<(&'static str, ValueType)>,
pub optional_args: Vec<(&'static str, ValueType, Value)>,
pub yields: Vec<(&'static str, ValueType)>,
}
impl ProcedureSignature {
pub fn validate_args(&self, mut args: Vec<Value>) -> Result<Vec<Value>> {
let req_count = self.args.len();
let total_count = req_count + self.optional_args.len();
if args.len() < req_count {
return Err(anyhow!(
"Too few arguments. Expected at least {}, got {}",
req_count,
args.len()
));
}
if args.len() > total_count {
return Err(anyhow!(
"Too many arguments. Expected at most {}, got {}",
total_count,
args.len()
));
}
for (i, (name, ty)) in self.args.iter().enumerate() {
if !ty.matches(&args[i]) {
return Err(anyhow!(
"Invalid type for argument '{}'. Expected {:?}, got {:?}",
name,
ty,
args[i]
));
}
}
for i in 0..self.optional_args.len() {
let idx = req_count + i;
let (name, ty, default) = &self.optional_args[i];
if idx < args.len() {
if !ty.matches(&args[idx]) {
return Err(anyhow!(
"Invalid type for optional argument '{}'. Expected {:?}, got {:?}",
name,
ty,
args[idx]
));
}
} else {
args.push(default.clone());
}
}
Ok(args)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueType {
Int,
Float,
String,
Bool,
List,
Map,
Node,
Relationship,
Path,
Any,
}
impl ValueType {
pub fn matches(&self, val: &Value) -> bool {
match self {
ValueType::Int => val.is_i64() || val.is_u64(),
ValueType::Float => val.is_f64() || val.is_i64() || val.is_u64(),
ValueType::String => val.is_string(),
ValueType::Bool => val.is_boolean(),
ValueType::List => val.is_array(),
ValueType::Map => val.is_object(),
ValueType::Node => val.is_string() || val.is_u64(), ValueType::Relationship => val.is_u64() || val.is_object(),
ValueType::Path => val.is_object(), ValueType::Any => true,
}
}
}
#[derive(Debug, Clone)]
pub struct AlgoResultRow {
pub values: Vec<Value>,
}
pub trait AlgoProcedure: Send + Sync {
fn name(&self) -> &str;
fn signature(&self) -> ProcedureSignature;
fn execute(
&self,
ctx: AlgoContext,
args: Vec<Value>,
) -> Pin<Box<dyn Stream<Item = Result<AlgoResultRow>> + Send + 'static>>;
}
use std::sync::Arc;
use uni_store::runtime::L0Manager;
use uni_store::storage::manager::StorageManager;
pub struct AlgoContext {
pub storage: Arc<StorageManager>,
pub l0_manager: Option<Arc<L0Manager>>,
}
impl AlgoContext {
pub fn new(storage: Arc<StorageManager>, l0_manager: Option<Arc<L0Manager>>) -> Self {
Self {
storage,
l0_manager,
}
}
}