helios_persistence/sof/sqlite_udfs.rs
1//! SQLite scalar UDFs registered for the in-DB SOF runner.
2//!
3//! These functions cover SQL operations that the SoF v2 conformance suite
4//! exercises but that don't have a clean built-in equivalent in SQLite's JSON1
5//! /core dialect (no regex, no `split_part`, no `last_value`-of-string). The
6//! UDFs are registered on every pooled connection at acquire time via the
7//! `SqliteConnectionManager::with_init` callback wired in
8//! `backends::sqlite::backend`.
9
10use rusqlite::Connection;
11use rusqlite::functions::FunctionFlags;
12
13/// Registers the SOF helper UDFs on `conn`.
14///
15/// Currently:
16/// - `fhir_last_segment(text) -> text` — substring of the input after the
17/// last `/`, used by `getReferenceKey()` to extract the id portion of a
18/// `Reference.reference` like `Patient/123`. Returns the input unchanged
19/// when no `/` is present, and NULL when the input is NULL.
20pub fn register(conn: &Connection) -> rusqlite::Result<()> {
21 conn.create_scalar_function(
22 "fhir_last_segment",
23 1,
24 FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
25 |ctx| {
26 let arg = ctx.get_raw(0);
27 let s = match arg {
28 rusqlite::types::ValueRef::Null => return Ok(None::<String>),
29 rusqlite::types::ValueRef::Text(t) => std::str::from_utf8(t)
30 .map_err(|e| rusqlite::Error::UserFunctionError(Box::new(e)))?,
31 _ => {
32 return Err(rusqlite::Error::UserFunctionError(
33 "fhir_last_segment expects a text argument".into(),
34 ));
35 }
36 };
37 Ok(Some(match s.rfind('/') {
38 Some(idx) => s[idx + 1..].to_string(),
39 None => s.to_string(),
40 }))
41 },
42 )?;
43 Ok(())
44}