reifydb_routine/procedure/set/
config.rs1use std::{str::FromStr, sync::LazyLock};
5
6use reifydb_catalog::error::CatalogError;
7use reifydb_core::{interface::catalog::config::ConfigKey, value::column::columns::Columns};
8use reifydb_transaction::transaction::Transaction;
9use reifydb_type::{
10 error::Error as TypeError,
11 fragment::Fragment,
12 params::Params,
13 value::{Value, r#type::Type},
14};
15
16use crate::routine::{Routine, RoutineInfo, context::ProcedureContext, error::RoutineError};
17
18static INFO: LazyLock<RoutineInfo> = LazyLock::new(|| RoutineInfo::new("system::config::set"));
19
20pub struct SetConfigProcedure;
24
25impl Default for SetConfigProcedure {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl SetConfigProcedure {
32 pub fn new() -> Self {
33 Self
34 }
35}
36
37impl<'a, 'tx> Routine<ProcedureContext<'a, 'tx>> for SetConfigProcedure {
38 fn info(&self) -> &RoutineInfo {
39 &INFO
40 }
41
42 fn return_type(&self, _input_types: &[Type]) -> Type {
43 Type::Any
44 }
45
46 fn execute(&self, ctx: &mut ProcedureContext<'a, 'tx>, _args: &Columns) -> Result<Columns, RoutineError> {
47 let (key, value) = match ctx.params {
48 Params::Positional(args) if args.len() == 2 => (args[0].clone(), args[1].clone()),
49 Params::Positional(args) => {
50 return Err(RoutineError::ProcedureArityMismatch {
51 procedure: Fragment::internal("system::config::set"),
52 expected: 2,
53 actual: args.len(),
54 });
55 }
56 _ => {
57 return Err(RoutineError::ProcedureArityMismatch {
58 procedure: Fragment::internal("system::config::set"),
59 expected: 2,
60 actual: 0,
61 });
62 }
63 };
64
65 let key_str = match &key {
66 Value::Utf8(s) => s.as_str().to_string(),
67 _ => {
68 return Err(RoutineError::ProcedureInvalidArgumentType {
69 procedure: Fragment::internal("system::config::set"),
70 argument_index: 0,
71 expected: vec![Type::Utf8],
72 actual: key.get_type(),
73 });
74 }
75 };
76
77 if matches!(value, Value::None { .. }) {
78 return Err(CatalogError::ConfigValueInvalid(key_str).into());
79 }
80
81 let config_key = match ConfigKey::from_str(&key_str) {
82 Ok(k) => k,
83 Err(_) => {
84 return Err(CatalogError::ConfigStorageKeyNotFound(key_str).into());
85 }
86 };
87
88 let coerced_value = config_key.accept(value).map_err(|e| {
89 RoutineError::Wrapped(Box::new(TypeError::from(CatalogError::from((config_key, e)))))
90 })?;
91
92 let value_clone = coerced_value.clone();
93
94 match ctx.tx {
95 Transaction::Admin(admin) => ctx.catalog.set_config(admin, config_key, coerced_value)?,
96 Transaction::Test(t) => ctx.catalog.set_config(t.inner, config_key, coerced_value)?,
97 _ => {
98 return Err(RoutineError::ProcedureExecutionFailed {
99 procedure: Fragment::internal("system::config::set"),
100 reason: "must run in an admin transaction".to_string(),
101 });
102 }
103 }
104
105 Ok(Columns::single_row([("key", Value::Utf8(key_str)), ("value", value_clone)]))
106 }
107}