MCPcopy Create free account
hub / github.com/erans/pgsqlite / register_jsonb_object_agg

Function register_jsonb_object_agg

src/functions/json_functions.rs:1076–1147  ·  view source on GitHub ↗

jsonb_object_agg(key, value) - Aggregate key-value pairs into a JSON object

(conn: &Connection)

Source from the content-addressed store, hash-verified

1074
1075/// jsonb_object_agg(key, value) - Aggregate key-value pairs into a JSON object
1076fn register_jsonb_object_agg(conn: &Connection) -> Result<()> {
1077 use rusqlite::functions::Aggregate;
1078 use std::collections::HashMap;
1079
1080 #[derive(Default)]
1081 struct JsonbObjectAgg;
1082
1083 impl Aggregate<HashMap<String, JsonValue>, Option<String>> for JsonbObjectAgg {
1084 fn init(&self, _: &mut rusqlite::functions::Context<'_>) -> Result<HashMap<String, JsonValue>> {
1085 Ok(HashMap::new())
1086 }
1087
1088 fn step(&self, ctx: &mut rusqlite::functions::Context<'_>, agg: &mut HashMap<String, JsonValue>) -> Result<()> {
1089 // Get the key (first argument)
1090 let key_value = ctx.get_raw(0);
1091 let key = match key_value {
1092 rusqlite::types::ValueRef::Text(s) => std::str::from_utf8(s).unwrap_or("").to_string(),
1093 rusqlite::types::ValueRef::Integer(i) => i.to_string(),
1094 rusqlite::types::ValueRef::Real(f) => f.to_string(),
1095 rusqlite::types::ValueRef::Null => "null".to_string(),
1096 rusqlite::types::ValueRef::Blob(_) => return Ok(()), // Skip blob keys
1097 };
1098
1099 // Get the value (second argument)
1100 let value_raw = ctx.get_raw(1);
1101 let json_value = match value_raw {
1102 rusqlite::types::ValueRef::Null => JsonValue::Null,
1103 rusqlite::types::ValueRef::Integer(i) => JsonValue::Number(serde_json::Number::from(i)),
1104 rusqlite::types::ValueRef::Real(f) => {
1105 if let Some(num) = serde_json::Number::from_f64(f) {
1106 JsonValue::Number(num)
1107 } else {
1108 JsonValue::Null
1109 }
1110 }
1111 rusqlite::types::ValueRef::Text(s) => {
1112 let text = std::str::from_utf8(s).unwrap_or("");
1113 // For jsonb_object_agg, try to parse as JSON first, if it fails treat as string
1114 serde_json::from_str(text)
1115 .unwrap_or_else(|_| JsonValue::String(text.to_string()))
1116 }
1117 rusqlite::types::ValueRef::Blob(b) => {
1118 // Convert blob to hex string
1119 JsonValue::String(format!("\\x{}", hex::encode(b)))
1120 }
1121 };
1122
1123 agg.insert(key, json_value);
1124 Ok(())
1125 }
1126
1127 fn finalize(&self, _: &mut rusqlite::functions::Context<'_>, agg: Option<HashMap<String, JsonValue>>) -> Result<Option<String>> {
1128 match agg {
1129 Some(map) => {
1130 let json_map: serde_json::Map<String, JsonValue> = map.into_iter().collect();
1131 let json_object = JsonValue::Object(json_map);
1132 Ok(Some(serde_json::to_string(&json_object).unwrap_or_else(|_| "{}".to_string())))
1133 }

Callers 1

register_json_functionsFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected