use reifydb_core::{
interface::catalog::{handler::Handler, id::NamespaceId},
key::{handler::HandlerKey, namespace_handler::NamespaceHandlerKey, variant_handler::VariantHandlerKey},
};
use reifydb_transaction::transaction::{Transaction, admin::AdminTransaction};
use reifydb_type::{fragment::Fragment, value::sumtype::VariantRef};
use crate::{
CatalogStore, Result,
error::{CatalogError, CatalogObjectKind},
store::{
handler::shape::{handler as handler_shape, handler_namespace},
sequence::system::SystemSequence,
},
};
#[derive(Debug, Clone)]
pub struct HandlerToCreate {
pub name: Fragment,
pub namespace: NamespaceId,
pub variant: VariantRef,
pub body_source: String,
}
impl CatalogStore {
pub(crate) fn create_handler(txn: &mut AdminTransaction, to_create: HandlerToCreate) -> Result<Handler> {
let namespace_id = to_create.namespace;
if let Some(_existing) = CatalogStore::find_handler_by_name(
&mut Transaction::Admin(&mut *txn),
namespace_id,
to_create.name.text(),
)? {
let namespace = CatalogStore::get_namespace(&mut Transaction::Admin(&mut *txn), namespace_id)?;
return Err(CatalogError::AlreadyExists {
kind: CatalogObjectKind::Handler,
namespace: namespace.name().to_string(),
name: to_create.name.text().to_string(),
fragment: to_create.name.clone(),
}
.into());
}
let handler_id = SystemSequence::next_handler_id(txn)?;
let mut row = handler_shape::SHAPE.allocate();
handler_shape::SHAPE.set_u64(&mut row, handler_shape::ID, handler_id);
handler_shape::SHAPE.set_u64(&mut row, handler_shape::NAMESPACE, namespace_id);
handler_shape::SHAPE.set_utf8(&mut row, handler_shape::NAME, to_create.name.text());
handler_shape::SHAPE.set_u64(&mut row, handler_shape::ON_SUMTYPE_ID, to_create.variant.sumtype_id);
handler_shape::SHAPE.set_u8(&mut row, handler_shape::ON_VARIANT_TAG, to_create.variant.variant_tag);
handler_shape::SHAPE.set_utf8(&mut row, handler_shape::BODY_SOURCE, &to_create.body_source);
txn.set(&HandlerKey::encoded(handler_id), row)?;
let mut ns_row = handler_namespace::SHAPE.allocate();
handler_namespace::SHAPE.set_u64(&mut ns_row, handler_namespace::ID, handler_id);
handler_namespace::SHAPE.set_utf8(&mut ns_row, handler_namespace::NAME, to_create.name.text());
txn.set(&NamespaceHandlerKey::encoded(namespace_id, handler_id), ns_row)?;
let mut var_row = handler_namespace::SHAPE.allocate();
handler_namespace::SHAPE.set_u64(&mut var_row, handler_namespace::ID, handler_id);
handler_namespace::SHAPE.set_utf8(&mut var_row, handler_namespace::NAME, to_create.name.text());
txn.set(
&VariantHandlerKey::encoded(
namespace_id,
to_create.variant.sumtype_id,
to_create.variant.variant_tag,
handler_id,
),
var_row,
)?;
Ok(Handler {
id: handler_id,
namespace: namespace_id,
name: to_create.name.text().to_string(),
variant: to_create.variant,
body_source: to_create.body_source,
})
}
}
#[cfg(test)]
pub mod tests {
use reifydb_core::{
interface::catalog::id::{HandlerId, NamespaceId},
key::namespace_handler::NamespaceHandlerKey,
};
use reifydb_engine::test_harness::create_test_admin_transaction;
use reifydb_type::{
fragment::Fragment,
value::sumtype::{SumTypeId, VariantRef},
};
use crate::{
CatalogStore,
store::handler::{create::HandlerToCreate, shape::handler_namespace},
test_utils::ensure_test_namespace,
};
#[test]
fn test_create_handler() {
let mut txn = create_test_admin_transaction();
let namespace = ensure_test_namespace(&mut txn);
let to_create = HandlerToCreate {
namespace: namespace.id(),
name: Fragment::internal("test_handler"),
variant: VariantRef {
sumtype_id: SumTypeId(0),
variant_tag: 1,
},
body_source: "return 42;".to_string(),
};
let result = CatalogStore::create_handler(&mut txn, to_create.clone()).unwrap();
assert_eq!(result.id, HandlerId(16385));
assert_eq!(result.namespace, NamespaceId(16385));
assert_eq!(result.name, "test_handler");
assert_eq!(result.variant.sumtype_id, SumTypeId(0));
assert_eq!(result.variant.variant_tag, 1);
assert_eq!(result.body_source, "return 42;");
let err = CatalogStore::create_handler(&mut txn, to_create).unwrap_err();
assert_eq!(err.diagnostic().code, "CA_003");
}
#[test]
fn test_handler_linked_to_namespace() {
let mut txn = create_test_admin_transaction();
let namespace = ensure_test_namespace(&mut txn);
let to_create = HandlerToCreate {
namespace: namespace.id(),
name: Fragment::internal("test_handler"),
variant: VariantRef {
sumtype_id: SumTypeId(0),
variant_tag: 0,
},
body_source: String::new(),
};
CatalogStore::create_handler(&mut txn, to_create).unwrap();
let to_create = HandlerToCreate {
namespace: namespace.id(),
name: Fragment::internal("another_handler"),
variant: VariantRef {
sumtype_id: SumTypeId(0),
variant_tag: 0,
},
body_source: String::new(),
};
CatalogStore::create_handler(&mut txn, to_create).unwrap();
let links: Vec<_> = txn
.range(NamespaceHandlerKey::full_scan(namespace.id()), 1024)
.unwrap()
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(links.len(), 2);
let link = &links[0];
let row = &link.row;
assert_eq!(handler_namespace::SHAPE.get_u64(row, handler_namespace::ID), 16386);
assert_eq!(handler_namespace::SHAPE.get_utf8(row, handler_namespace::NAME), "another_handler");
let link = &links[1];
let row = &link.row;
assert_eq!(handler_namespace::SHAPE.get_u64(row, handler_namespace::ID), 16385);
assert_eq!(handler_namespace::SHAPE.get_utf8(row, handler_namespace::NAME), "test_handler");
}
}