use uqa_core::Value;
use uqa_sql::SQLError;
pub use uqa_sql::ast::FunctionVolatility as SQLFunctionVolatility;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SQLFunctionOptions {
pub volatility: SQLFunctionVolatility,
pub may_mutate_engine: bool,
}
impl SQLFunctionOptions {
#[must_use]
pub const fn new(volatility: SQLFunctionVolatility, may_mutate_engine: bool) -> Self {
Self {
volatility,
may_mutate_engine,
}
}
#[must_use]
pub const fn read_only(volatility: SQLFunctionVolatility) -> Self {
Self::new(volatility, false)
}
}
impl Default for SQLFunctionOptions {
fn default() -> Self {
Self::new(SQLFunctionVolatility::Volatile, true)
}
}
pub(crate) struct RegisteredSQLFunction<F: ?Sized> {
pub(crate) function: std::sync::Arc<F>,
pub(crate) options: SQLFunctionOptions,
}
impl<F: ?Sized> RegisteredSQLFunction<F> {
pub(crate) fn new(function: std::sync::Arc<F>, options: SQLFunctionOptions) -> Self {
Self { function, options }
}
}
impl<F: ?Sized> Clone for RegisteredSQLFunction<F> {
fn clone(&self) -> Self {
Self {
function: self.function.clone(),
options: self.options,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct SQLTableFunctionResult {
pub columns: Vec<String>,
pub rows: Vec<Vec<Value>>,
}
impl SQLTableFunctionResult {
pub fn new(
columns: impl IntoIterator<Item = impl Into<String>>,
rows: Vec<Vec<Value>>,
) -> Self {
Self {
columns: columns.into_iter().map(Into::into).collect(),
rows,
}
}
}
pub struct SQLTableFunctionStream {
pub columns: Vec<String>,
pub rows: Box<dyn Iterator<Item = Result<Vec<Value>, SQLError>> + Send>,
}
impl SQLTableFunctionStream {
pub fn new<I>(columns: impl IntoIterator<Item = impl Into<String>>, rows: I) -> Self
where
I: Iterator<Item = Result<Vec<Value>, SQLError>> + Send + 'static,
{
Self {
columns: columns.into_iter().map(Into::into).collect(),
rows: Box::new(rows),
}
}
}
impl From<SQLTableFunctionResult> for SQLTableFunctionStream {
fn from(result: SQLTableFunctionResult) -> Self {
Self {
columns: result.columns,
rows: Box::new(result.rows.into_iter().map(Ok)),
}
}
}
pub trait SQLScalarFunction: Send + Sync {
fn call(&self, args: &[Value]) -> Result<Value, SQLError>;
}
impl<F> SQLScalarFunction for F
where
F: Fn(&[Value]) -> Result<Value, SQLError> + Send + Sync,
{
fn call(&self, args: &[Value]) -> Result<Value, SQLError> {
self(args)
}
}
pub trait SQLTableFunction: Send + Sync {
fn call(&self, _args: &[Value]) -> Result<SQLTableFunctionResult, SQLError> {
Err(SQLError::Unsupported(
"table function implements only the streaming call interface".into(),
))
}
fn call_stream(&self, args: &[Value]) -> Result<SQLTableFunctionStream, SQLError> {
self.call(args).map(Into::into)
}
}
impl<F> SQLTableFunction for F
where
F: Fn(&[Value]) -> Result<SQLTableFunctionResult, SQLError> + Send + Sync,
{
fn call(&self, args: &[Value]) -> Result<SQLTableFunctionResult, SQLError> {
self(args)
}
}
pub trait SQLAggregateFunction: Send + Sync {
fn create_state(&self) -> Box<dyn SQLAggregateState>;
}
impl<F, S> SQLAggregateFunction for F
where
F: Fn() -> S + Send + Sync,
S: SQLAggregateState + 'static,
{
fn create_state(&self) -> Box<dyn SQLAggregateState> {
Box::new(self())
}
}
pub trait SQLAggregateState: Send {
fn observe(&mut self, args: &[Value]) -> Result<(), SQLError>;
fn finish(&self) -> Result<Value, SQLError>;
}