use radixdb_catalog::{CatalogName, ObjectId};
use radixdb_sql::{Expression, InfixOperator, ObjectName, ProceduralType, Statement};
use crate::{ProceduralResult, Program, RecordField, RuntimeType, SlotId};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TriggerReturnRecord {
Old,
New,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TriggerCompileContext {
pub record_fields: Vec<RecordField>,
pub old_available: bool,
pub new_available: bool,
pub new_writable: bool,
pub return_record: Option<TriggerReturnRecord>,
}
impl TriggerCompileContext {
pub fn validate(&self) -> ProceduralResult<()> {
RuntimeType::record(self.record_fields.clone())?;
if self.new_writable && !self.new_available {
return Err(crate::Diagnostic::new(
crate::DiagnosticKind::RuntimeInvalidIr,
"writable NEW requires an available NEW record",
));
}
if matches!(self.return_record, Some(TriggerReturnRecord::Old)) && !self.old_available {
return Err(crate::Diagnostic::new(
crate::DiagnosticKind::RuntimeInvalidIr,
"OLD trigger return requires an available OLD record",
));
}
if matches!(self.return_record, Some(TriggerReturnRecord::New)) && !self.new_available {
return Err(crate::Diagnostic::new(
crate::DiagnosticKind::RuntimeInvalidIr,
"NEW trigger return requires an available NEW record",
));
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CompileIdentity {
pub object_id: ObjectId,
pub definition_revision: u64,
pub display_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LocalBinding {
pub name: String,
pub slot: SlotId,
pub runtime_type: RuntimeType,
pub constant: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BoundExpression {
pub expression: Expression,
pub parameters: Vec<SlotId>,
pub result_type: RuntimeType,
pub dependencies: Vec<ObjectId>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BoundType {
pub runtime_type: RuntimeType,
pub dependencies: Vec<ObjectId>,
}
impl BoundType {
pub fn scalar(runtime_type: RuntimeType) -> Self {
Self {
runtime_type,
dependencies: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BoundResultColumn {
pub name: CatalogName,
pub runtime_type: RuntimeType,
}
impl BoundResultColumn {
pub const fn new(name: CatalogName, runtime_type: RuntimeType) -> Self {
Self { name, runtime_type }
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct BoundSqlStatement {
pub statement: Statement,
pub parameters: Vec<BoundSqlParameter>,
pub result_columns: Vec<BoundResultColumn>,
pub dependencies: Vec<ObjectId>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BoundSqlParameter {
Scalar(SlotId),
RecordField {
record: SlotId,
field: u32,
runtime_type: RuntimeType,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CallSiteArgument {
pub name: Option<String>,
pub value: CallSiteArgumentValue,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CallSiteArgumentValue {
Bound {
slot: SlotId,
runtime_type: RuntimeType,
assignable: bool,
},
UntypedNull,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BoundCallArgument {
Provided {
declared_name: String,
slot: SlotId,
},
Default {
declared_name: String,
expression: Expression,
runtime_type: RuntimeType,
},
ContextualExpression {
declared_name: String,
expression: BoundExpression,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct BoundRoutineCall {
pub routine: ObjectId,
pub arguments: Vec<BoundCallArgument>,
pub results: Vec<SlotId>,
pub dependencies: Vec<ObjectId>,
pub cost: u32,
}
pub trait SemanticResolver {
fn resolve_type(&mut self, syntax: &ProceduralType) -> ProceduralResult<BoundType>;
fn bind_expression(
&mut self,
expression: &Expression,
locals: &[LocalBinding],
expected: Option<&RuntimeType>,
) -> ProceduralResult<BoundExpression>;
fn bind_binary_operator(
&mut self,
operator: InfixOperator,
left: &RuntimeType,
right: &RuntimeType,
expected: Option<&RuntimeType>,
) -> ProceduralResult<RuntimeType>;
fn bind_statement(
&mut self,
statement: &Statement,
locals: &[LocalBinding],
) -> ProceduralResult<BoundSqlStatement>;
fn bind_procedure_call(
&mut self,
routine: &ObjectName,
arguments: &[CallSiteArgument],
) -> ProceduralResult<BoundRoutineCall>;
fn admit_transactional_side_effect(&mut self) -> ProceduralResult<()> {
Ok(())
}
fn is_observability_expression(&mut self, _expression: &Expression) -> bool {
false
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct CompiledRoutine {
pub program: Program,
pub dependencies: Vec<ObjectId>,
}