Skip to main content

reifydb_core/interface/catalog/
procedure.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::path::PathBuf;
5
6use reifydb_type::value::{constraint::TypeConstraint, sumtype::VariantRef};
7use serde::{Deserialize, Serialize};
8
9use crate::interface::catalog::id::{NamespaceId, ProcedureId};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
12pub enum RqlTrigger {
13	/// Invoked explicitly via CALL
14	#[default]
15	Call,
16	/// Triggered by DISPATCH on an event variant
17	Event {
18		variant: VariantRef,
19	},
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
23pub enum ProcedureKind {
24	Rql,
25	Test,
26	Native,
27	Ffi,
28	Wasm,
29}
30
31impl ProcedureKind {
32	pub fn as_str(&self) -> &'static str {
33		match self {
34			ProcedureKind::Rql => "rql",
35			ProcedureKind::Test => "test",
36			ProcedureKind::Native => "native",
37			ProcedureKind::Ffi => "ffi",
38			ProcedureKind::Wasm => "wasm",
39		}
40	}
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
44#[repr(transparent)]
45pub struct WasmModuleId(pub u64);
46
47#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
48pub struct ProcedureParam {
49	pub name: String,
50	pub param_type: TypeConstraint,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54pub enum Procedure {
55	/// User-defined RQL procedure. Persisted; transactional; addable/droppable via DDL.
56	Rql {
57		id: ProcedureId,
58		namespace: NamespaceId,
59		name: String,
60		params: Vec<ProcedureParam>,
61		return_type: Option<TypeConstraint>,
62		body: String,
63		trigger: RqlTrigger,
64	},
65	/// User-defined RQL test procedure. Persisted; only callable from test context.
66	Test {
67		id: ProcedureId,
68		namespace: NamespaceId,
69		name: String,
70		params: Vec<ProcedureParam>,
71		return_type: Option<TypeConstraint>,
72		body: String,
73	},
74	/// Built-in Rust procedure registered into the runtime registry. Ephemeral.
75	Native {
76		id: ProcedureId,
77		namespace: NamespaceId,
78		name: String,
79		params: Vec<ProcedureParam>,
80		return_type: Option<TypeConstraint>,
81		native_name: String,
82	},
83	/// Procedure loaded from an FFI shared library at boot. Ephemeral.
84	Ffi {
85		id: ProcedureId,
86		namespace: NamespaceId,
87		name: String,
88		params: Vec<ProcedureParam>,
89		return_type: Option<TypeConstraint>,
90		native_name: String,
91		library_path: PathBuf,
92		entry_symbol: String,
93	},
94	/// Procedure loaded from a WASM module at boot. Ephemeral.
95	Wasm {
96		id: ProcedureId,
97		namespace: NamespaceId,
98		name: String,
99		params: Vec<ProcedureParam>,
100		return_type: Option<TypeConstraint>,
101		native_name: String,
102		module_id: WasmModuleId,
103	},
104}
105
106impl Procedure {
107	pub fn id(&self) -> ProcedureId {
108		match self {
109			Procedure::Rql {
110				id,
111				..
112			}
113			| Procedure::Test {
114				id,
115				..
116			}
117			| Procedure::Native {
118				id,
119				..
120			}
121			| Procedure::Ffi {
122				id,
123				..
124			}
125			| Procedure::Wasm {
126				id,
127				..
128			} => *id,
129		}
130	}
131
132	pub fn namespace(&self) -> NamespaceId {
133		match self {
134			Procedure::Rql {
135				namespace,
136				..
137			}
138			| Procedure::Test {
139				namespace,
140				..
141			}
142			| Procedure::Native {
143				namespace,
144				..
145			}
146			| Procedure::Ffi {
147				namespace,
148				..
149			}
150			| Procedure::Wasm {
151				namespace,
152				..
153			} => *namespace,
154		}
155	}
156
157	pub fn name(&self) -> &str {
158		match self {
159			Procedure::Rql {
160				name,
161				..
162			}
163			| Procedure::Test {
164				name,
165				..
166			}
167			| Procedure::Native {
168				name,
169				..
170			}
171			| Procedure::Ffi {
172				name,
173				..
174			}
175			| Procedure::Wasm {
176				name,
177				..
178			} => name.as_str(),
179		}
180	}
181
182	pub fn params(&self) -> &[ProcedureParam] {
183		match self {
184			Procedure::Rql {
185				params,
186				..
187			}
188			| Procedure::Test {
189				params,
190				..
191			}
192			| Procedure::Native {
193				params,
194				..
195			}
196			| Procedure::Ffi {
197				params,
198				..
199			}
200			| Procedure::Wasm {
201				params,
202				..
203			} => params,
204		}
205	}
206
207	pub fn return_type(&self) -> Option<&TypeConstraint> {
208		match self {
209			Procedure::Rql {
210				return_type,
211				..
212			}
213			| Procedure::Test {
214				return_type,
215				..
216			}
217			| Procedure::Native {
218				return_type,
219				..
220			}
221			| Procedure::Ffi {
222				return_type,
223				..
224			}
225			| Procedure::Wasm {
226				return_type,
227				..
228			} => return_type.as_ref(),
229		}
230	}
231
232	pub fn kind(&self) -> ProcedureKind {
233		match self {
234			Procedure::Rql {
235				..
236			} => ProcedureKind::Rql,
237			Procedure::Test {
238				..
239			} => ProcedureKind::Test,
240			Procedure::Native {
241				..
242			} => ProcedureKind::Native,
243			Procedure::Ffi {
244				..
245			} => ProcedureKind::Ffi,
246			Procedure::Wasm {
247				..
248			} => ProcedureKind::Wasm,
249		}
250	}
251
252	/// True for variants that live in MVCC storage (Rql, Test).
253	/// False for Native/Ffi/Wasm which are repopulated from the runtime registry on every boot.
254	pub fn is_persistent(&self) -> bool {
255		matches!(self, Procedure::Rql { .. } | Procedure::Test { .. })
256	}
257
258	/// Event variant this procedure is bound to, if any. Only Rql procedures with `RqlTrigger::Event` return Some.
259	pub fn event_variant(&self) -> Option<VariantRef> {
260		match self {
261			Procedure::Rql {
262				trigger: RqlTrigger::Event {
263					variant,
264				},
265				..
266			} => Some(*variant),
267			_ => None,
268		}
269	}
270
271	/// Native registry lookup name for Native/Ffi/Wasm variants. None for Rql/Test.
272	pub fn native_name(&self) -> Option<&str> {
273		match self {
274			Procedure::Native {
275				native_name,
276				..
277			}
278			| Procedure::Ffi {
279				native_name,
280				..
281			}
282			| Procedure::Wasm {
283				native_name,
284				..
285			} => Some(native_name.as_str()),
286			_ => None,
287		}
288	}
289
290	/// RQL source body for Rql/Test variants. None for native-bound variants.
291	pub fn body(&self) -> Option<&str> {
292		match self {
293			Procedure::Rql {
294				body,
295				..
296			}
297			| Procedure::Test {
298				body,
299				..
300			} => Some(body.as_str()),
301			_ => None,
302		}
303	}
304}