Experiments in applying Entity-Component-System patterns to durable data storage APIs.
at main 2.3 kB view raw
1use rusqlite::functions::FunctionFlags; 2use rusqlite::types::{Value, ValueRef}; 3use rusqlite::{Connection, Error, Result}; 4 5pub(crate) fn add_regexp_function(db: &Connection) -> Result<()> { 6 db.create_scalar_function( 7 "velodb_extract_data", 8 1, 9 FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC, 10 move |ctx| { 11 assert_eq!(ctx.len(), 1, "called with unexpected number of arguments"); 12 13 match ctx.get_raw(0) { 14 ValueRef::Null => Ok(Value::Null), 15 ValueRef::Integer(i) => Ok(Value::Integer(i)), 16 ValueRef::Real(r) => Ok(Value::Real(r)), 17 // Return NULL for BLOB - no JSON extraction possible 18 ValueRef::Blob(_blob) => Ok(Value::Null), 19 // JSON 20 ValueRef::Text(text) => { 21 let value: serde_json::Value = serde_json::from_slice(text) 22 .map_err(|e| Error::UserFunctionError(Box::new(e)))?; 23 24 let sqlite_value = match value { 25 serde_json::Value::Null => Value::Null, 26 serde_json::Value::Bool(true) => Value::Integer(1), 27 serde_json::Value::Bool(false) => Value::Integer(0), 28 serde_json::Value::Number(n) => n 29 .as_i64() 30 .map(Value::Integer) 31 .or(n.as_f64().map(Value::Real)) 32 .unwrap(), 33 serde_json::Value::String(s) => Value::Text(s), 34 array @ serde_json::Value::Array(_) => Value::Text(array.to_string()), 35 obj @ serde_json::Value::Object(_) => Value::Text(obj.to_string()), 36 }; 37 38 Ok(sqlite_value) 39 } 40 } 41 }, 42 ) 43} 44 45#[cfg(test)] 46mod tests { 47 #[test] 48 fn custom_fn_test() -> Result<(), anyhow::Error> { 49 let db = crate::Ecs::open_in_memory()?; 50 let result: bool = db.raw_sql().query_row( 51 "select velodb_extract_data(json_quote(10)) > velodb_extract_data(json_quote(2))", 52 [], 53 |row| row.get(0), 54 )?; 55 56 assert!(result); 57 58 Ok(()) 59 } 60}