use revision::revisioned;
use surrealdb_strand::Strand;
use surrealdb_types::{SqlFormat, ToSql};
use crate::catalog::auth::AuthLimit;
use crate::expr::Expr;
use crate::expr::statements::info::InfoStructure;
use crate::kvs::impl_kv_value_revisioned;
use crate::sql::statements::define::DefineKind;
use crate::sql::{self};
use crate::val::{TableName, Value};
#[revisioned(revision = 3)]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub struct EventDefinition {
pub(crate) name: Strand,
pub(crate) target_table: TableName,
pub(crate) when: Expr,
pub(crate) then: Vec<Expr>,
pub(crate) comment: Option<String>,
#[revision(start = 2, default_fn = "default_auth_limit")]
pub(crate) auth_limit: AuthLimit,
#[revision(start = 3, default_fn = "default_event_kind")]
pub(crate) kind: EventKind,
}
#[revisioned(revision = 1)]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum EventKind {
Sync,
Async {
retry: u16,
max_depth: u16,
},
}
impl EventDefinition {
pub(crate) const DEFAULT_RETRY: u16 = 1;
pub(crate) const DEFAULT_MAX_DEPTH: u16 = 3;
fn default_auth_limit(_revision: u16) -> Result<AuthLimit, revision::Error> {
Ok(AuthLimit::new_no_limit())
}
fn default_event_kind(_revision: u16) -> Result<EventKind, revision::Error> {
Ok(EventKind::Sync)
}
}
impl_kv_value_revisioned!(EventDefinition);
impl EventDefinition {
pub(crate) fn is_async(&self) -> bool {
matches!(self.kind, EventKind::Async { .. })
}
pub(crate) fn to_sql_definition(&self) -> sql::DefineEventStatement {
sql::DefineEventStatement {
kind: DefineKind::Default,
name: sql::Expr::Idiom(sql::Idiom::field(self.name.clone())),
target_table: sql::Expr::Table(self.target_table.clone()),
when: self.when.clone().into(),
then: self.then.iter().cloned().map(Into::into).collect(),
comment: self
.comment
.clone()
.map(|v| sql::Expr::Literal(sql::Literal::String(v.into())))
.unwrap_or(sql::Expr::Literal(sql::Literal::None)),
event_kind: self.kind.clone(),
}
}
pub(crate) fn retry(&self) -> u16 {
match self.kind {
EventKind::Sync => 0,
EventKind::Async {
retry,
..
} => retry,
}
}
pub(crate) fn max_depth(&self) -> u16 {
match self.kind {
EventKind::Sync => 0,
EventKind::Async {
max_depth,
..
} => max_depth,
}
}
}
impl InfoStructure for EventDefinition {
fn structure(self) -> Value {
let mut map = map! {
"name" => self.name.into(),
"what" => self.target_table.into(),
"when" => self.when.structure(),
"then" => self.then.into_iter().map(|x| x.structure()).collect(),
"comment", if let Some(v) = self.comment => v.into(),
};
if let EventKind::Async {
retry,
max_depth,
} = &self.kind
{
map.insert("async", Value::Bool(true));
map.insert("retry", (*retry).into());
map.insert("maxdepth", (*max_depth).into());
}
Value::from(map)
}
}
impl ToSql for EventDefinition {
fn fmt_sql(&self, f: &mut String, fmt: SqlFormat) {
self.to_sql_definition().fmt_sql(f, fmt)
}
}