Skip to main content

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}