use reifydb_catalog::error::{CatalogError, CatalogObjectKind};
use reifydb_core::{
interface::catalog::{procedure::RqlTrigger, sumtype::SumTypeKind},
internal_error,
};
use reifydb_transaction::transaction::Transaction;
use reifydb_type::{fragment::Fragment, value::sumtype::VariantRef};
use crate::{
Result,
nodes::CreateProcedureNode,
plan::{
logical,
physical::{Compiler, PhysicalPlan},
},
};
impl<'bump> Compiler<'bump> {
pub(crate) fn compile_create_handler(
&mut self,
rx: &mut Transaction<'_>,
create: logical::CreateProcedureNode<'_>,
) -> Result<PhysicalPlan<'bump>> {
let on_event = create.on_event.expect("handler must have on_event");
let on_variant = create.on_variant.expect("handler must have on_variant");
let handler_ns_segments: Vec<&str> = create.procedure.namespace.iter().map(|n| n.text()).collect();
let Some(namespace) = self.catalog.find_namespace_by_segments(rx, &handler_ns_segments)? else {
let ns_fragment = if let Some(n) = create.procedure.namespace.first() {
let interned = self.interner.intern_fragment(n);
interned.with_text(handler_ns_segments.join("::"))
} else {
Fragment::internal("default".to_string())
};
return Err(CatalogError::NotFound {
kind: CatalogObjectKind::Namespace,
namespace: handler_ns_segments.join("::"),
name: String::new(),
fragment: ns_fragment,
}
.into());
};
let event_ns_segments: Vec<&str> = if on_event.namespace.is_empty() {
handler_ns_segments.clone()
} else {
on_event.namespace.iter().map(|n| n.text()).collect()
};
let Some(event_ns_def) = self.catalog.find_namespace_by_segments(rx, &event_ns_segments)? else {
let ns_fragment = Fragment::internal(event_ns_segments.join("::"));
return Err(CatalogError::NotFound {
kind: CatalogObjectKind::Namespace,
namespace: event_ns_segments.join("::"),
name: String::new(),
fragment: ns_fragment,
}
.into());
};
let event_name = on_event.name.text();
let Some(sumtype) = self.catalog.find_sumtype_by_name(rx, event_ns_def.id(), event_name)? else {
return Err(CatalogError::NotFound {
kind: CatalogObjectKind::Event,
namespace: event_ns_segments.join("::"),
name: event_name.to_string(),
fragment: Fragment::internal(event_name.to_string()),
}
.into());
};
if sumtype.kind != SumTypeKind::Event {
return Err(internal_error!(
"'{}' is not an EVENT type. Use CREATE EVENT to declare event types.",
event_name
));
}
let variant_name = on_variant.text().to_lowercase();
let Some(variant) = sumtype.variants.iter().find(|v| v.name == variant_name) else {
return Err(internal_error!(
"Variant '{}' not found in event type '{}'",
on_variant.text(),
event_name
));
};
Ok(PhysicalPlan::CreateProcedure(CreateProcedureNode {
namespace,
name: self.interner.intern_fragment(&create.procedure.name),
params: vec![],
body_source: create.body_source,
trigger: RqlTrigger::Event {
variant: VariantRef {
sumtype_id: sumtype.id,
variant_tag: variant.tag,
},
},
is_test: false,
}))
}
}