1use fsqlite_error::{FrankenError, Result};
22use fsqlite_func::{
23 ColumnContext, FunctionRegistry, IndexInfo, ScalarFunction, VirtualTable, VirtualTableCursor,
24};
25use fsqlite_types::{SqliteValue, cx::Cx};
26use serde_json::{Map, Number, Value};
27
28const JSON_VALID_DEFAULT_FLAGS: u8 = 0x01;
29const JSON_VALID_RFC_8259_FLAG: u8 = 0x01;
30const JSON_VALID_JSON5_FLAG: u8 = 0x02;
31const JSON_VALID_JSONB_SUPERFICIAL_FLAG: u8 = 0x04;
32const JSON_VALID_JSONB_STRICT_FLAG: u8 = 0x08;
33const JSON_PRETTY_DEFAULT_INDENT_WIDTH: usize = 4;
34
35const JSONB_NULL_TYPE: u8 = 0x0;
36const JSONB_TRUE_TYPE: u8 = 0x1;
37const JSONB_FALSE_TYPE: u8 = 0x2;
38const JSONB_INT_TYPE: u8 = 0x3;
39const JSONB_FLOAT_TYPE: u8 = 0x5;
40const JSONB_TEXT_TYPE: u8 = 0x7;
41const JSONB_TEXT_JSON_TYPE: u8 = 0x8;
42const JSONB_ARRAY_TYPE: u8 = 0xB;
43const JSONB_OBJECT_TYPE: u8 = 0xC;
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46enum PathSegment {
47 Key(String),
48 Index(usize),
49 Append,
50 FromEnd(usize),
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54enum EditMode {
55 Set,
56 Insert,
57 Replace,
58}
59
60pub fn json(input: &str) -> Result<String> {
64 let value = parse_json_text(input)?;
65 serde_json::to_string(&value)
66 .map_err(|error| FrankenError::function_error(format!("json serialize failed: {error}")))
67}
68
69#[must_use]
77pub fn json_valid(input: &str, flags: Option<u8>) -> i64 {
78 json_valid_blob(input.as_bytes(), flags)
79}
80
81#[must_use]
83pub fn json_valid_blob(input: &[u8], flags: Option<u8>) -> i64 {
84 let effective_flags = flags.unwrap_or(JSON_VALID_DEFAULT_FLAGS);
85 if effective_flags == 0 {
86 return 0;
87 }
88
89 let allow_json = effective_flags & JSON_VALID_RFC_8259_FLAG != 0;
90 let allow_json5 = effective_flags & JSON_VALID_JSON5_FLAG != 0;
91 let allow_jsonb_superficial = effective_flags & JSON_VALID_JSONB_SUPERFICIAL_FLAG != 0;
92 let allow_jsonb_strict = effective_flags & JSON_VALID_JSONB_STRICT_FLAG != 0;
93
94 if allow_json || allow_json5 {
95 if let Ok(text) = std::str::from_utf8(input) {
96 if allow_json && parse_json_text(text).is_ok() {
97 return 1;
98 }
99 if allow_json5 && parse_json5_text(text).is_ok() {
100 return 1;
101 }
102 }
103 }
104
105 if allow_jsonb_strict && decode_jsonb_root(input).is_ok() {
106 return 1;
107 }
108 if allow_jsonb_superficial && is_superficially_valid_jsonb(input) {
109 return 1;
110 }
111
112 0
113}
114
115pub fn jsonb(input: &str) -> Result<Vec<u8>> {
117 let value = parse_json_text(input)?;
118 encode_jsonb_root(&value)
119}
120
121pub fn json_from_jsonb(input: &[u8]) -> Result<String> {
123 let value = decode_jsonb_root(input)?;
124 serde_json::to_string(&value).map_err(|error| {
125 FrankenError::function_error(format!("json_from_jsonb encode failed: {error}"))
126 })
127}
128
129pub fn json_type(input: &str, path: Option<&str>) -> Result<Option<&'static str>> {
133 let root = parse_json_text(input)?;
134 let target = match path {
135 Some(path_expr) => resolve_path(&root, path_expr)?,
136 None => Some(&root),
137 };
138 Ok(target.map(json_type_name))
139}
140
141pub fn json_extract(input: &str, paths: &[&str]) -> Result<SqliteValue> {
146 if paths.is_empty() {
147 return Err(FrankenError::function_error(
148 "json_extract requires at least one path",
149 ));
150 }
151
152 let root = parse_json_text(input)?;
153
154 if paths.len() == 1 {
155 let selected = resolve_path(&root, paths[0])?;
156 return Ok(selected.map_or(SqliteValue::Null, json_to_sqlite_scalar));
157 }
158
159 let mut out = Vec::with_capacity(paths.len());
160 for path_expr in paths {
161 let selected = resolve_path(&root, path_expr)?;
162 out.push(selected.cloned().unwrap_or(Value::Null));
163 }
164
165 let encoded = serde_json::to_string(&Value::Array(out)).map_err(|error| {
166 FrankenError::function_error(format!("json_extract array encode failed: {error}"))
167 })?;
168 Ok(SqliteValue::Text(encoded))
169}
170
171pub fn jsonb_extract(input: &str, paths: &[&str]) -> Result<Vec<u8>> {
175 if paths.is_empty() {
176 return Err(FrankenError::function_error(
177 "jsonb_extract requires at least one path",
178 ));
179 }
180
181 let root = parse_json_text(input)?;
182 let output = if paths.len() == 1 {
183 resolve_path(&root, paths[0])?
184 .cloned()
185 .unwrap_or(Value::Null)
186 } else {
187 let mut values = Vec::with_capacity(paths.len());
188 for path_expr in paths {
189 values.push(
190 resolve_path(&root, path_expr)?
191 .cloned()
192 .unwrap_or(Value::Null),
193 );
194 }
195 Value::Array(values)
196 };
197
198 encode_jsonb_root(&output)
199}
200
201pub fn json_arrow(input: &str, path: &str) -> Result<SqliteValue> {
205 let root = parse_json_text(input)?;
206 let selected = resolve_path(&root, path)?;
207 let Some(value) = selected else {
208 return Ok(SqliteValue::Null);
209 };
210 let encoded = serde_json::to_string(value).map_err(|error| {
211 FrankenError::function_error(format!("json_arrow encode failed: {error}"))
212 })?;
213 Ok(SqliteValue::Text(encoded))
214}
215
216pub fn json_double_arrow(input: &str, path: &str) -> Result<SqliteValue> {
218 json_extract(input, &[path])
219}
220
221pub fn json_array_length(input: &str, path: Option<&str>) -> Result<Option<usize>> {
223 let root = parse_json_text(input)?;
224 let target = match path {
225 Some(path_expr) => resolve_path(&root, path_expr)?,
226 None => Some(&root),
227 };
228 Ok(target.and_then(Value::as_array).map(Vec::len))
229}
230
231#[must_use]
233pub fn json_error_position(input: &str) -> usize {
234 match serde_json::from_str::<Value>(input) {
235 Ok(_) => 0,
236 Err(error) => {
237 let line = error.line();
238 let column = error.column();
239 if line == 0 || column == 0 {
240 return 1;
241 }
242
243 let mut current_line = 1usize;
244 let mut current_col = 1usize;
245 let mut char_pos = 1usize;
246 for (_idx, ch) in input.char_indices() {
247 if current_line == line && current_col == column {
248 return char_pos;
249 }
250 if ch == '\n' {
251 current_line += 1;
252 current_col = 1;
253 } else {
254 current_col += ch.len_utf8();
255 }
256 char_pos += 1;
257 }
258 char_pos
259 }
260 }
261}
262
263pub fn json_pretty(input: &str, indent: Option<&str>) -> Result<String> {
265 let root = parse_json_text(input)?;
266 let indent_unit = match indent {
267 Some(indent) => indent.to_owned(),
268 None => " ".repeat(JSON_PRETTY_DEFAULT_INDENT_WIDTH),
269 };
270 let mut out = String::new();
271 write_pretty_value(&root, &indent_unit, 0, &mut out)?;
272 Ok(out)
273}
274
275#[must_use]
277pub fn json_quote(value: &SqliteValue) -> String {
278 match value {
279 SqliteValue::Null => "null".to_owned(),
280 SqliteValue::Integer(i) => i.to_string(),
281 SqliteValue::Float(f) => {
282 if f.is_finite() {
283 format!("{f}")
284 } else {
285 "null".to_owned()
286 }
287 }
288 SqliteValue::Text(text) => {
289 serde_json::to_string(text).unwrap_or_else(|_| "\"\"".to_owned())
290 }
291 SqliteValue::Blob(bytes) => {
292 let mut hex = String::with_capacity(bytes.len() * 2);
293 for byte in bytes {
294 use std::fmt::Write;
295 let _ = write!(hex, "{byte:02x}");
296 }
297 serde_json::to_string(&hex).unwrap_or_else(|_| "\"\"".to_owned())
298 }
299 }
300}
301
302pub fn json_array(values: &[SqliteValue]) -> Result<String> {
304 let mut out = Vec::with_capacity(values.len());
305 for value in values {
306 out.push(sqlite_to_json(value)?);
307 }
308 serde_json::to_string(&Value::Array(out))
309 .map_err(|error| FrankenError::function_error(format!("json_array encode failed: {error}")))
310}
311
312pub fn json_object(args: &[SqliteValue]) -> Result<String> {
316 if args.len() % 2 != 0 {
317 return Err(FrankenError::function_error(
318 "json_object requires an even number of arguments",
319 ));
320 }
321
322 let mut map = Map::with_capacity(args.len() / 2);
323 let mut idx = 0;
324 while idx < args.len() {
325 let key = match &args[idx] {
326 SqliteValue::Text(text) => text.clone(),
327 _ => {
328 return Err(FrankenError::function_error(
329 "json_object keys must be text",
330 ));
331 }
332 };
333 let value = sqlite_to_json(&args[idx + 1])?;
334 map.insert(key, value);
335 idx += 2;
336 }
337
338 serde_json::to_string(&Value::Object(map)).map_err(|error| {
339 FrankenError::function_error(format!("json_object encode failed: {error}"))
340 })
341}
342
343pub fn jsonb_array(values: &[SqliteValue]) -> Result<Vec<u8>> {
345 let json_text = json_array(values)?;
346 jsonb(&json_text)
347}
348
349pub fn jsonb_object(args: &[SqliteValue]) -> Result<Vec<u8>> {
351 let json_text = json_object(args)?;
352 jsonb(&json_text)
353}
354
355pub fn json_group_array(values: &[SqliteValue]) -> Result<String> {
357 json_array(values)
358}
359
360pub fn jsonb_group_array(values: &[SqliteValue]) -> Result<Vec<u8>> {
362 let json_text = json_group_array(values)?;
363 jsonb(&json_text)
364}
365
366pub fn json_group_object(entries: &[(SqliteValue, SqliteValue)]) -> Result<String> {
370 let mut map = Map::with_capacity(entries.len());
371 for (key_value, value) in entries {
372 let key = match key_value {
373 SqliteValue::Text(text) => text.clone(),
374 _ => {
375 return Err(FrankenError::function_error(
376 "json_group_object keys must be text",
377 ));
378 }
379 };
380 map.insert(key, sqlite_to_json(value)?);
381 }
382 serde_json::to_string(&Value::Object(map)).map_err(|error| {
383 FrankenError::function_error(format!("json_group_object encode failed: {error}"))
384 })
385}
386
387pub fn jsonb_group_object(entries: &[(SqliteValue, SqliteValue)]) -> Result<Vec<u8>> {
389 let json_text = json_group_object(entries)?;
390 jsonb(&json_text)
391}
392
393pub fn json_set(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<String> {
395 edit_json_paths(input, pairs, EditMode::Set)
396}
397
398pub fn jsonb_set(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<Vec<u8>> {
400 let json_text = json_set(input, pairs)?;
401 jsonb(&json_text)
402}
403
404pub fn json_insert(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<String> {
406 edit_json_paths(input, pairs, EditMode::Insert)
407}
408
409pub fn jsonb_insert(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<Vec<u8>> {
411 let json_text = json_insert(input, pairs)?;
412 jsonb(&json_text)
413}
414
415pub fn json_replace(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<String> {
417 edit_json_paths(input, pairs, EditMode::Replace)
418}
419
420pub fn jsonb_replace(input: &str, pairs: &[(&str, SqliteValue)]) -> Result<Vec<u8>> {
422 let json_text = json_replace(input, pairs)?;
423 jsonb(&json_text)
424}
425
426pub fn json_remove(input: &str, paths: &[&str]) -> Result<String> {
428 let mut root = parse_json_text(input)?;
429 for path in paths {
430 let segments = parse_path(path)?;
431 remove_at_path(&mut root, &segments);
432 }
433 serde_json::to_string(&root).map_err(|error| {
434 FrankenError::function_error(format!("json_remove encode failed: {error}"))
435 })
436}
437
438pub fn jsonb_remove(input: &str, paths: &[&str]) -> Result<Vec<u8>> {
440 let json_text = json_remove(input, paths)?;
441 jsonb(&json_text)
442}
443
444pub fn json_patch(input: &str, patch: &str) -> Result<String> {
446 let root = parse_json_text(input)?;
447 let patch_value = parse_json_text(patch)?;
448 let merged = merge_patch(root, patch_value);
449 serde_json::to_string(&merged)
450 .map_err(|error| FrankenError::function_error(format!("json_patch encode failed: {error}")))
451}
452
453pub fn jsonb_patch(input: &str, patch: &str) -> Result<Vec<u8>> {
455 let json_text = json_patch(input, patch)?;
456 jsonb(&json_text)
457}
458
459#[derive(Debug, Clone, PartialEq)]
461pub struct JsonTableRow {
462 pub key: SqliteValue,
464 pub value: SqliteValue,
466 pub type_name: &'static str,
468 pub atom: SqliteValue,
470 pub id: i64,
472 pub parent: SqliteValue,
474 pub fullkey: String,
476 pub path: String,
478}
479
480pub fn json_each(input: &str, path: Option<&str>) -> Result<Vec<JsonTableRow>> {
482 let root = parse_json_text(input)?;
483 let base_path = path.unwrap_or("$");
484 let target = match path {
485 Some(path_expr) => resolve_path(&root, path_expr)?,
486 None => Some(&root),
487 };
488 let Some(target) = target else {
489 return Ok(Vec::new());
490 };
491
492 let mut rows = Vec::new();
493 let mut next_id = 1_i64;
494
495 match target {
496 Value::Array(array) => {
497 for (index, item) in array.iter().enumerate() {
498 let index_i64 = i64::try_from(index).map_err(|error| {
499 FrankenError::function_error(format!("json_each index overflow: {error}"))
500 })?;
501 let fullkey = append_array_path(base_path, index);
502 rows.push(JsonTableRow {
503 key: SqliteValue::Integer(index_i64),
504 value: json_value_column(item)?,
505 type_name: json_type_name(item),
506 atom: json_atom_column(item),
507 id: next_id,
508 parent: SqliteValue::Null,
509 fullkey,
510 path: base_path.to_owned(),
511 });
512 next_id += 1;
513 }
514 }
515 Value::Object(object) => {
516 for (key, item) in object {
517 let fullkey = append_object_path(base_path, key);
518 rows.push(JsonTableRow {
519 key: SqliteValue::Text(key.clone()),
520 value: json_value_column(item)?,
521 type_name: json_type_name(item),
522 atom: json_atom_column(item),
523 id: next_id,
524 parent: SqliteValue::Null,
525 fullkey,
526 path: base_path.to_owned(),
527 });
528 next_id += 1;
529 }
530 }
531 scalar => {
532 rows.push(JsonTableRow {
533 key: SqliteValue::Null,
534 value: json_value_column(scalar)?,
535 type_name: json_type_name(scalar),
536 atom: json_atom_column(scalar),
537 id: next_id,
538 parent: SqliteValue::Null,
539 fullkey: base_path.to_owned(),
540 path: base_path.to_owned(),
541 });
542 }
543 }
544
545 Ok(rows)
546}
547
548pub fn json_tree(input: &str, path: Option<&str>) -> Result<Vec<JsonTableRow>> {
550 let root = parse_json_text(input)?;
551 let base_path = path.unwrap_or("$");
552 let target = match path {
553 Some(path_expr) => resolve_path(&root, path_expr)?,
554 None => Some(&root),
555 };
556 let Some(target) = target else {
557 return Ok(Vec::new());
558 };
559
560 let mut rows = Vec::new();
561 let mut next_id = 1_i64;
562 append_tree_rows(
563 &mut rows,
564 target,
565 SqliteValue::Null,
566 None,
567 base_path,
568 base_path,
569 &mut next_id,
570 )?;
571 Ok(rows)
572}
573
574pub struct JsonEachVtab;
576
577#[derive(Default)]
579pub struct JsonEachCursor {
580 rows: Vec<JsonTableRow>,
581 pos: usize,
582}
583
584impl VirtualTable for JsonEachVtab {
585 type Cursor = JsonEachCursor;
586
587 fn connect(_cx: &Cx, _args: &[&str]) -> Result<Self> {
588 Ok(Self)
589 }
590
591 fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
592 info.estimated_cost = 100.0;
593 info.estimated_rows = 100;
594 Ok(())
595 }
596
597 fn open(&self) -> Result<Self::Cursor> {
598 Ok(JsonEachCursor::default())
599 }
600}
601
602impl VirtualTableCursor for JsonEachCursor {
603 fn filter(
604 &mut self,
605 _cx: &Cx,
606 _idx_num: i32,
607 _idx_str: Option<&str>,
608 args: &[SqliteValue],
609 ) -> Result<()> {
610 let (input, path) = parse_json_table_filter_args(args)?;
611 self.rows = json_each(input, path)?;
612 self.pos = 0;
613 Ok(())
614 }
615
616 fn next(&mut self, _cx: &Cx) -> Result<()> {
617 if self.pos < self.rows.len() {
618 self.pos += 1;
619 }
620 Ok(())
621 }
622
623 fn eof(&self) -> bool {
624 self.pos >= self.rows.len()
625 }
626
627 fn column(&self, ctx: &mut ColumnContext, col: i32) -> Result<()> {
628 let row = self.rows.get(self.pos).ok_or_else(|| {
629 FrankenError::function_error("json_each cursor is out of bounds for column read")
630 })?;
631 write_json_table_column(row, ctx, col)
632 }
633
634 fn rowid(&self) -> Result<i64> {
635 self.rows.get(self.pos).map(|row| row.id).ok_or_else(|| {
636 FrankenError::function_error("json_each cursor is out of bounds for rowid")
637 })
638 }
639}
640
641pub struct JsonTreeVtab;
643
644#[derive(Default)]
646pub struct JsonTreeCursor {
647 rows: Vec<JsonTableRow>,
648 pos: usize,
649}
650
651impl VirtualTable for JsonTreeVtab {
652 type Cursor = JsonTreeCursor;
653
654 fn connect(_cx: &Cx, _args: &[&str]) -> Result<Self> {
655 Ok(Self)
656 }
657
658 fn best_index(&self, info: &mut IndexInfo) -> Result<()> {
659 info.estimated_cost = 200.0;
660 info.estimated_rows = 1_000;
661 Ok(())
662 }
663
664 fn open(&self) -> Result<Self::Cursor> {
665 Ok(JsonTreeCursor::default())
666 }
667}
668
669impl VirtualTableCursor for JsonTreeCursor {
670 fn filter(
671 &mut self,
672 _cx: &Cx,
673 _idx_num: i32,
674 _idx_str: Option<&str>,
675 args: &[SqliteValue],
676 ) -> Result<()> {
677 let (input, path) = parse_json_table_filter_args(args)?;
678 self.rows = json_tree(input, path)?;
679 self.pos = 0;
680 Ok(())
681 }
682
683 fn next(&mut self, _cx: &Cx) -> Result<()> {
684 if self.pos < self.rows.len() {
685 self.pos += 1;
686 }
687 Ok(())
688 }
689
690 fn eof(&self) -> bool {
691 self.pos >= self.rows.len()
692 }
693
694 fn column(&self, ctx: &mut ColumnContext, col: i32) -> Result<()> {
695 let row = self.rows.get(self.pos).ok_or_else(|| {
696 FrankenError::function_error("json_tree cursor is out of bounds for column read")
697 })?;
698 write_json_table_column(row, ctx, col)
699 }
700
701 fn rowid(&self) -> Result<i64> {
702 self.rows.get(self.pos).map(|row| row.id).ok_or_else(|| {
703 FrankenError::function_error("json_tree cursor is out of bounds for rowid")
704 })
705 }
706}
707
708fn parse_json_text(input: &str) -> Result<Value> {
709 serde_json::from_str::<Value>(input)
710 .map_err(|error| FrankenError::function_error(format!("invalid JSON input: {error}")))
711}
712
713fn parse_json5_text(input: &str) -> Result<Value> {
714 json5::from_str::<Value>(input)
715 .map_err(|error| FrankenError::function_error(format!("invalid JSON5 input: {error}")))
716}
717
718fn encode_jsonb_root(value: &Value) -> Result<Vec<u8>> {
719 let mut out = Vec::new();
720 encode_jsonb_value(value, &mut out)?;
721 Ok(out)
722}
723
724fn encode_jsonb_value(value: &Value, out: &mut Vec<u8>) -> Result<()> {
725 match value {
726 Value::Null => append_jsonb_node(JSONB_NULL_TYPE, &[], out),
727 Value::Bool(true) => append_jsonb_node(JSONB_TRUE_TYPE, &[], out),
728 Value::Bool(false) => append_jsonb_node(JSONB_FALSE_TYPE, &[], out),
729 Value::Number(number) => {
730 if let Some(i) = number.as_i64() {
731 append_jsonb_node(JSONB_INT_TYPE, &i.to_be_bytes(), out)
732 } else if let Some(u) = number.as_u64() {
733 if let Ok(i) = i64::try_from(u) {
734 append_jsonb_node(JSONB_INT_TYPE, &i.to_be_bytes(), out)
735 } else {
736 let float = u as f64;
737 append_jsonb_node(JSONB_FLOAT_TYPE, &float.to_bits().to_be_bytes(), out)
738 }
739 } else {
740 let float = number.as_f64().ok_or_else(|| {
741 FrankenError::function_error("failed to encode non-finite JSON number")
742 })?;
743 append_jsonb_node(JSONB_FLOAT_TYPE, &float.to_bits().to_be_bytes(), out)
744 }
745 }
746 Value::String(text) => append_jsonb_node(JSONB_TEXT_TYPE, text.as_bytes(), out),
747 Value::Array(array) => {
748 let mut payload = Vec::new();
749 for item in array {
750 encode_jsonb_value(item, &mut payload)?;
751 }
752 append_jsonb_node(JSONB_ARRAY_TYPE, &payload, out)
753 }
754 Value::Object(object) => {
755 let mut payload = Vec::new();
756 for (key, item) in object {
757 append_jsonb_node(JSONB_TEXT_JSON_TYPE, key.as_bytes(), &mut payload)?;
758 encode_jsonb_value(item, &mut payload)?;
759 }
760 append_jsonb_node(JSONB_OBJECT_TYPE, &payload, out)
761 }
762 }
763}
764
765fn append_jsonb_node(node_type: u8, payload: &[u8], out: &mut Vec<u8>) -> Result<()> {
766 let (len_size, len_bytes) = encode_jsonb_payload_len(payload.len())?;
767 let len_size_u8 = u8::try_from(len_size).map_err(|error| {
768 FrankenError::function_error(format!("jsonb length-size conversion failed: {error}"))
769 })?;
770 let header = (node_type << 4) | len_size_u8;
771 out.push(header);
772 out.extend_from_slice(&len_bytes[..len_size]);
773 out.extend_from_slice(payload);
774 Ok(())
775}
776
777fn encode_jsonb_payload_len(payload_len: usize) -> Result<(usize, [u8; 8])> {
778 if payload_len == 0 {
779 return Ok((0, [0; 8]));
780 }
781
782 let payload_u64 = u64::try_from(payload_len).map_err(|error| {
783 FrankenError::function_error(format!("jsonb payload too large: {error}"))
784 })?;
785 let len_size = if u8::try_from(payload_u64).is_ok() {
786 1
787 } else if u16::try_from(payload_u64).is_ok() {
788 2
789 } else if u32::try_from(payload_u64).is_ok() {
790 4
791 } else {
792 8
793 };
794
795 let raw = payload_u64.to_be_bytes();
796 let mut out = [0u8; 8];
797 out[..len_size].copy_from_slice(&raw[8 - len_size..]);
798 Ok((len_size, out))
799}
800
801fn decode_jsonb_root(input: &[u8]) -> Result<Value> {
802 let (value, consumed) = decode_jsonb_value(input)?;
803 if consumed != input.len() {
804 return Err(FrankenError::function_error(
805 "invalid JSONB: trailing bytes",
806 ));
807 }
808 Ok(value)
809}
810
811fn decode_jsonb_value(input: &[u8]) -> Result<(Value, usize)> {
812 let (node_type, payload, consumed) = decode_jsonb_node(input)?;
813 let value = match node_type {
814 JSONB_NULL_TYPE => {
815 if !payload.is_empty() {
816 return Err(FrankenError::function_error("invalid JSONB null payload"));
817 }
818 Value::Null
819 }
820 JSONB_TRUE_TYPE => {
821 if !payload.is_empty() {
822 return Err(FrankenError::function_error("invalid JSONB true payload"));
823 }
824 Value::Bool(true)
825 }
826 JSONB_FALSE_TYPE => {
827 if !payload.is_empty() {
828 return Err(FrankenError::function_error("invalid JSONB false payload"));
829 }
830 Value::Bool(false)
831 }
832 JSONB_INT_TYPE => {
833 if payload.len() != 8 {
834 return Err(FrankenError::function_error(
835 "invalid JSONB integer payload size",
836 ));
837 }
838 let mut raw = [0u8; 8];
839 raw.copy_from_slice(payload);
840 Value::Number(Number::from(i64::from_be_bytes(raw)))
841 }
842 JSONB_FLOAT_TYPE => {
843 if payload.len() != 8 {
844 return Err(FrankenError::function_error(
845 "invalid JSONB float payload size",
846 ));
847 }
848 let mut raw = [0u8; 8];
849 raw.copy_from_slice(payload);
850 let float = f64::from_bits(u64::from_be_bytes(raw));
851 let number = Number::from_f64(float).ok_or_else(|| {
852 FrankenError::function_error("invalid non-finite JSONB float payload")
853 })?;
854 Value::Number(number)
855 }
856 JSONB_TEXT_TYPE | JSONB_TEXT_JSON_TYPE => {
857 let text = String::from_utf8(payload.to_vec()).map_err(|error| {
858 FrankenError::function_error(format!("invalid JSONB text payload: {error}"))
859 })?;
860 Value::String(text)
861 }
862 JSONB_ARRAY_TYPE => {
863 let mut cursor = 0usize;
864 let mut values = Vec::new();
865 while cursor < payload.len() {
866 let (item, used) = decode_jsonb_value(&payload[cursor..])?;
867 values.push(item);
868 cursor += used;
869 }
870 Value::Array(values)
871 }
872 JSONB_OBJECT_TYPE => {
873 let mut cursor = 0usize;
874 let mut map = Map::new();
875 while cursor < payload.len() {
876 let (key_node, key_used) = decode_jsonb_value(&payload[cursor..])?;
877 cursor += key_used;
878 let Value::String(key) = key_node else {
879 return Err(FrankenError::function_error(
880 "invalid JSONB object key payload",
881 ));
882 };
883 if cursor >= payload.len() {
884 return Err(FrankenError::function_error(
885 "invalid JSONB object missing value",
886 ));
887 }
888 let (item, used) = decode_jsonb_value(&payload[cursor..])?;
889 cursor += used;
890 map.insert(key, item);
891 }
892 Value::Object(map)
893 }
894 _ => {
895 return Err(FrankenError::function_error("invalid JSONB node type"));
896 }
897 };
898
899 Ok((value, consumed))
900}
901
902fn decode_jsonb_node(input: &[u8]) -> Result<(u8, &[u8], usize)> {
903 if input.is_empty() {
904 return Err(FrankenError::function_error("invalid JSONB: empty payload"));
905 }
906
907 let header = input[0];
908 let node_type = header >> 4;
909 let len_size = usize::from(header & 0x0f);
910 if !matches!(len_size, 0 | 1 | 2 | 4 | 8) {
911 return Err(FrankenError::function_error(
912 "invalid JSONB length-size nibble",
913 ));
914 }
915 if !matches!(
916 node_type,
917 JSONB_NULL_TYPE
918 | JSONB_TRUE_TYPE
919 | JSONB_FALSE_TYPE
920 | JSONB_INT_TYPE
921 | JSONB_FLOAT_TYPE
922 | JSONB_TEXT_TYPE
923 | JSONB_TEXT_JSON_TYPE
924 | JSONB_ARRAY_TYPE
925 | JSONB_OBJECT_TYPE
926 ) {
927 return Err(FrankenError::function_error("invalid JSONB node type"));
928 }
929
930 if input.len() < 1 + len_size {
931 return Err(FrankenError::function_error(
932 "invalid JSONB: truncated payload length",
933 ));
934 }
935
936 let len_end = 1 + len_size;
937 let payload_len = decode_jsonb_payload_len(&input[1..len_end])?;
938 let total = 1 + len_size + payload_len;
939 if input.len() < total {
940 return Err(FrankenError::function_error(
941 "invalid JSONB: truncated payload",
942 ));
943 }
944
945 Ok((node_type, &input[1 + len_size..total], total))
946}
947
948fn decode_jsonb_payload_len(bytes: &[u8]) -> Result<usize> {
949 if bytes.is_empty() {
950 return Ok(0);
951 }
952 if !matches!(bytes.len(), 1 | 2 | 4 | 8) {
953 return Err(FrankenError::function_error(
954 "invalid JSONB length encoding size",
955 ));
956 }
957
958 let mut raw = [0u8; 8];
959 raw[8 - bytes.len()..].copy_from_slice(bytes);
960 let payload_len = u64::from_be_bytes(raw);
961 usize::try_from(payload_len).map_err(|error| {
962 FrankenError::function_error(format!("JSONB payload length overflow: {error}"))
963 })
964}
965
966fn is_superficially_valid_jsonb(input: &[u8]) -> bool {
967 if input.is_empty() {
968 return false;
969 }
970 let header = input[0];
971 let node_type = header >> 4;
972 let len_size = usize::from(header & 0x0f);
973 if !matches!(len_size, 0 | 1 | 2 | 4 | 8) {
974 return false;
975 }
976 if !matches!(
977 node_type,
978 JSONB_NULL_TYPE
979 | JSONB_TRUE_TYPE
980 | JSONB_FALSE_TYPE
981 | JSONB_INT_TYPE
982 | JSONB_FLOAT_TYPE
983 | JSONB_TEXT_TYPE
984 | JSONB_TEXT_JSON_TYPE
985 | JSONB_ARRAY_TYPE
986 | JSONB_OBJECT_TYPE
987 ) {
988 return false;
989 }
990 if input.len() < 1 + len_size {
991 return false;
992 }
993 let len_end = 1 + len_size;
994 let Ok(payload_len) = decode_jsonb_payload_len(&input[1..len_end]) else {
995 return false;
996 };
997 1 + len_size + payload_len <= input.len()
998}
999
1000#[allow(clippy::too_many_lines)]
1001fn parse_path(path: &str) -> Result<Vec<PathSegment>> {
1002 let bytes = path.as_bytes();
1003 if bytes.first().copied() != Some(b'$') {
1004 return Err(FrankenError::function_error(format!(
1005 "invalid json path `{path}`: must start with `$`"
1006 )));
1007 }
1008
1009 let mut idx = 1;
1010 let mut segments = Vec::new();
1011 while idx < bytes.len() {
1012 match bytes[idx] {
1013 b'.' => {
1014 idx += 1;
1015 if idx >= bytes.len() {
1016 return Err(FrankenError::function_error(format!(
1017 "invalid json path `{path}`: empty key segment"
1018 )));
1019 }
1020
1021 if bytes[idx] == b'"' {
1022 let quoted_start = idx;
1023 idx += 1;
1024 let mut escaped = false;
1025 while idx < bytes.len() {
1026 let byte = bytes[idx];
1027 if escaped {
1028 escaped = false;
1029 idx += 1;
1030 continue;
1031 }
1032 if byte == b'\\' {
1033 escaped = true;
1034 idx += 1;
1035 continue;
1036 }
1037 if byte == b'"' {
1038 break;
1039 }
1040 idx += 1;
1041 }
1042 if idx >= bytes.len() {
1043 return Err(FrankenError::function_error(format!(
1044 "invalid json path `{path}`: missing closing quote in key segment"
1045 )));
1046 }
1047 let quoted_key = &path[quoted_start..=idx];
1048 let key = serde_json::from_str::<String>(quoted_key).map_err(|error| {
1049 FrankenError::function_error(format!(
1050 "invalid json path `{path}` quoted key `{quoted_key}`: {error}"
1051 ))
1052 })?;
1053 idx += 1; segments.push(PathSegment::Key(key));
1055 } else {
1056 let start = idx;
1057 while idx < bytes.len() && bytes[idx] != b'.' && bytes[idx] != b'[' {
1058 idx += 1;
1059 }
1060 if start == idx {
1061 return Err(FrankenError::function_error(format!(
1062 "invalid json path `{path}`: empty key segment"
1063 )));
1064 }
1065 segments.push(PathSegment::Key(path[start..idx].to_owned()));
1066 }
1067 }
1068 b'[' => {
1069 idx += 1;
1070 let start = idx;
1071 while idx < bytes.len() && bytes[idx] != b']' {
1072 idx += 1;
1073 }
1074 if idx >= bytes.len() {
1075 return Err(FrankenError::function_error(format!(
1076 "invalid json path `{path}`: missing closing `]`"
1077 )));
1078 }
1079 let segment_text = &path[start..idx];
1080 idx += 1;
1081
1082 if segment_text == "#" {
1083 segments.push(PathSegment::Append);
1084 } else if let Some(rest) = segment_text.strip_prefix("#-") {
1085 let from_end = rest.parse::<usize>().map_err(|error| {
1086 FrankenError::function_error(format!(
1087 "invalid json path `{path}` from-end index `{segment_text}`: {error}"
1088 ))
1089 })?;
1090 if from_end == 0 {
1091 return Err(FrankenError::function_error(format!(
1092 "invalid json path `{path}`: from-end index must be >= 1"
1093 )));
1094 }
1095 segments.push(PathSegment::FromEnd(from_end));
1096 } else {
1097 let index = segment_text.parse::<usize>().map_err(|error| {
1098 FrankenError::function_error(format!(
1099 "invalid json path `{path}` array index `{segment_text}`: {error}"
1100 ))
1101 })?;
1102 segments.push(PathSegment::Index(index));
1103 }
1104 }
1105 _ => {
1106 return Err(FrankenError::function_error(format!(
1107 "invalid json path `{path}` at byte offset {idx}"
1108 )));
1109 }
1110 }
1111 }
1112
1113 Ok(segments)
1114}
1115
1116fn resolve_path<'a>(root: &'a Value, path: &str) -> Result<Option<&'a Value>> {
1117 let segments = parse_path(path)?;
1118 let mut cursor = root;
1119
1120 for segment in segments {
1121 match segment {
1122 PathSegment::Key(key) => {
1123 let Some(next) = cursor.get(&key) else {
1124 return Ok(None);
1125 };
1126 cursor = next;
1127 }
1128 PathSegment::Index(index) => {
1129 let Some(array) = cursor.as_array() else {
1130 return Ok(None);
1131 };
1132 let Some(next) = array.get(index) else {
1133 return Ok(None);
1134 };
1135 cursor = next;
1136 }
1137 PathSegment::FromEnd(from_end) => {
1138 let Some(array) = cursor.as_array() else {
1139 return Ok(None);
1140 };
1141 if from_end > array.len() {
1142 return Ok(None);
1143 }
1144 let index = array.len() - from_end;
1145 cursor = &array[index];
1146 }
1147 PathSegment::Append => return Ok(None),
1148 }
1149 }
1150
1151 Ok(Some(cursor))
1152}
1153
1154fn append_object_path(base: &str, key: &str) -> String {
1155 format!("{base}.{key}")
1156}
1157
1158fn append_array_path(base: &str, index: usize) -> String {
1159 format!("{base}[{index}]")
1160}
1161
1162fn json_value_column(value: &Value) -> Result<SqliteValue> {
1163 match value {
1164 Value::Array(_) | Value::Object(_) => serde_json::to_string(value)
1165 .map(SqliteValue::Text)
1166 .map_err(|error| {
1167 FrankenError::function_error(format!("json table value encode failed: {error}"))
1168 }),
1169 _ => Ok(json_to_sqlite_scalar(value)),
1170 }
1171}
1172
1173fn json_atom_column(value: &Value) -> SqliteValue {
1174 match value {
1175 Value::Array(_) | Value::Object(_) => SqliteValue::Null,
1176 _ => json_to_sqlite_scalar(value),
1177 }
1178}
1179
1180fn append_tree_rows(
1181 rows: &mut Vec<JsonTableRow>,
1182 value: &Value,
1183 key: SqliteValue,
1184 parent_id: Option<i64>,
1185 fullkey: &str,
1186 path: &str,
1187 next_id: &mut i64,
1188) -> Result<()> {
1189 let current_id = *next_id;
1190 *next_id += 1;
1191
1192 rows.push(JsonTableRow {
1193 key,
1194 value: json_value_column(value)?,
1195 type_name: json_type_name(value),
1196 atom: json_atom_column(value),
1197 id: current_id,
1198 parent: parent_id.map_or(SqliteValue::Null, SqliteValue::Integer),
1199 fullkey: fullkey.to_owned(),
1200 path: path.to_owned(),
1201 });
1202
1203 match value {
1204 Value::Array(array) => {
1205 for (index, item) in array.iter().enumerate() {
1206 let index_i64 = i64::try_from(index).map_err(|error| {
1207 FrankenError::function_error(format!("json_tree index overflow: {error}"))
1208 })?;
1209 let child_fullkey = append_array_path(fullkey, index);
1210 append_tree_rows(
1211 rows,
1212 item,
1213 SqliteValue::Integer(index_i64),
1214 Some(current_id),
1215 &child_fullkey,
1216 fullkey,
1217 next_id,
1218 )?;
1219 }
1220 }
1221 Value::Object(object) => {
1222 for (child_key, item) in object {
1223 let child_fullkey = append_object_path(fullkey, child_key);
1224 append_tree_rows(
1225 rows,
1226 item,
1227 SqliteValue::Text(child_key.clone()),
1228 Some(current_id),
1229 &child_fullkey,
1230 fullkey,
1231 next_id,
1232 )?;
1233 }
1234 }
1235 _ => {}
1236 }
1237
1238 Ok(())
1239}
1240
1241fn parse_json_table_filter_args(args: &[SqliteValue]) -> Result<(&str, Option<&str>)> {
1242 let Some(input_arg) = args.first() else {
1243 return Err(FrankenError::function_error(
1244 "json table-valued functions require JSON input argument",
1245 ));
1246 };
1247 let SqliteValue::Text(input_text) = input_arg else {
1248 return Err(FrankenError::function_error(
1249 "json table-valued input must be TEXT JSON",
1250 ));
1251 };
1252
1253 let path = match args.get(1) {
1254 None | Some(SqliteValue::Null) => None,
1255 Some(SqliteValue::Text(path)) => Some(path.as_str()),
1256 Some(_) => {
1257 return Err(FrankenError::function_error(
1258 "json table-valued PATH argument must be TEXT or NULL",
1259 ));
1260 }
1261 };
1262
1263 Ok((input_text.as_str(), path))
1264}
1265
1266fn write_json_table_column(row: &JsonTableRow, ctx: &mut ColumnContext, col: i32) -> Result<()> {
1267 let value = match col {
1268 0 => row.key.clone(),
1269 1 => row.value.clone(),
1270 2 => SqliteValue::Text(row.type_name.to_owned()),
1271 3 => row.atom.clone(),
1272 4 => SqliteValue::Integer(row.id),
1273 5 => row.parent.clone(),
1274 6 => SqliteValue::Text(row.fullkey.clone()),
1275 7 => SqliteValue::Text(row.path.clone()),
1276 _ => {
1277 return Err(FrankenError::function_error(format!(
1278 "json table-valued invalid column index {col}"
1279 )));
1280 }
1281 };
1282 ctx.set_value(value);
1283 Ok(())
1284}
1285
1286fn json_type_name(value: &Value) -> &'static str {
1287 match value {
1288 Value::Null => "null",
1289 Value::Bool(true) => "true",
1290 Value::Bool(false) => "false",
1291 Value::Number(number) => {
1292 if number.is_i64() || number.is_u64() {
1293 "integer"
1294 } else {
1295 "real"
1296 }
1297 }
1298 Value::String(_) => "text",
1299 Value::Array(_) => "array",
1300 Value::Object(_) => "object",
1301 }
1302}
1303
1304fn json_to_sqlite_scalar(value: &Value) -> SqliteValue {
1305 match value {
1306 Value::Null => SqliteValue::Null,
1307 Value::Bool(true) => SqliteValue::Integer(1),
1308 Value::Bool(false) => SqliteValue::Integer(0),
1309 Value::Number(number) => {
1310 if let Some(i) = number.as_i64() {
1311 SqliteValue::Integer(i)
1312 } else if let Some(u) = number.as_u64() {
1313 if let Ok(i) = i64::try_from(u) {
1314 SqliteValue::Integer(i)
1315 } else {
1316 SqliteValue::Float(u as f64)
1317 }
1318 } else {
1319 SqliteValue::Float(number.as_f64().unwrap_or(0.0))
1320 }
1321 }
1322 Value::String(text) => SqliteValue::Text(text.clone()),
1323 Value::Array(_) | Value::Object(_) => {
1324 let encoded = serde_json::to_string(value).unwrap_or_else(|_| "null".to_owned());
1325 SqliteValue::Text(encoded)
1326 }
1327 }
1328}
1329
1330fn sqlite_to_json(value: &SqliteValue) -> Result<Value> {
1331 match value {
1332 SqliteValue::Null => Ok(Value::Null),
1333 SqliteValue::Integer(i) => Ok(Value::Number(Number::from(*i))),
1334 SqliteValue::Float(f) => {
1335 if !f.is_finite() {
1336 return Err(FrankenError::function_error(
1337 "non-finite float is not representable in JSON",
1338 ));
1339 }
1340 let number = Number::from_f64(*f).ok_or_else(|| {
1341 FrankenError::function_error("failed to convert floating-point value to JSON")
1342 })?;
1343 Ok(Value::Number(number))
1344 }
1345 SqliteValue::Text(text) => Ok(Value::String(text.clone())),
1346 SqliteValue::Blob(bytes) => {
1347 let mut hex = String::with_capacity(bytes.len() * 2);
1348 for byte in bytes {
1349 use std::fmt::Write;
1350 let _ = write!(hex, "{byte:02x}");
1351 }
1352 Ok(Value::String(hex))
1353 }
1354 }
1355}
1356
1357fn write_pretty_value(value: &Value, indent: &str, depth: usize, out: &mut String) -> Result<()> {
1358 match value {
1359 Value::Array(array) => {
1360 if array.is_empty() {
1361 out.push_str("[]");
1362 return Ok(());
1363 }
1364
1365 out.push('[');
1366 out.push('\n');
1367 for (idx, item) in array.iter().enumerate() {
1368 out.push_str(&indent.repeat(depth + 1));
1369 write_pretty_value(item, indent, depth + 1, out)?;
1370 if idx + 1 < array.len() {
1371 out.push(',');
1372 }
1373 out.push('\n');
1374 }
1375 out.push_str(&indent.repeat(depth));
1376 out.push(']');
1377 Ok(())
1378 }
1379 Value::Object(object) => {
1380 if object.is_empty() {
1381 out.push_str("{}");
1382 return Ok(());
1383 }
1384
1385 out.push('{');
1386 out.push('\n');
1387 for (idx, (key, item)) in object.iter().enumerate() {
1388 out.push_str(&indent.repeat(depth + 1));
1389 let key_quoted = serde_json::to_string(key).map_err(|error| {
1390 FrankenError::function_error(format!(
1391 "json_pretty key-encode failed for `{key}`: {error}"
1392 ))
1393 })?;
1394 out.push_str(&key_quoted);
1395 out.push_str(": ");
1396 write_pretty_value(item, indent, depth + 1, out)?;
1397 if idx + 1 < object.len() {
1398 out.push(',');
1399 }
1400 out.push('\n');
1401 }
1402 out.push_str(&indent.repeat(depth));
1403 out.push('}');
1404 Ok(())
1405 }
1406 _ => {
1407 let encoded = serde_json::to_string(value).map_err(|error| {
1408 FrankenError::function_error(format!("json_pretty value-encode failed: {error}"))
1409 })?;
1410 out.push_str(&encoded);
1411 Ok(())
1412 }
1413 }
1414}
1415
1416fn edit_json_paths(input: &str, pairs: &[(&str, SqliteValue)], mode: EditMode) -> Result<String> {
1417 let mut root = parse_json_text(input)?;
1418 for (path, value) in pairs {
1419 let segments = parse_path(path)?;
1420 let replacement = sqlite_to_json(value)?;
1421 apply_edit(&mut root, &segments, replacement, mode);
1422 }
1423
1424 serde_json::to_string(&root)
1425 .map_err(|error| FrankenError::function_error(format!("json edit encode failed: {error}")))
1426}
1427
1428fn apply_edit(root: &mut Value, segments: &[PathSegment], new_value: Value, mode: EditMode) {
1429 if segments.is_empty() {
1430 match mode {
1431 EditMode::Set | EditMode::Replace => *root = new_value,
1432 EditMode::Insert => {}
1433 }
1434 return;
1435 }
1436 if !matches!(root, Value::Object(_) | Value::Array(_)) {
1437 return;
1440 }
1441
1442 let original = root.clone();
1443 let (parent_segments, last) = segments.split_at(segments.len() - 1);
1444 let Some(last_segment) = last.first() else {
1445 return;
1446 };
1447 let Some(parent) = resolve_parent_for_edit(root, parent_segments, Some(last_segment), mode)
1448 else {
1449 *root = original;
1450 return;
1451 };
1452
1453 let applied = match (parent, last_segment) {
1454 (Value::Object(object), PathSegment::Key(key)) => {
1455 let exists = object.contains_key(key);
1456 match mode {
1457 EditMode::Set => {
1458 object.insert(key.clone(), new_value);
1459 true
1460 }
1461 EditMode::Insert => {
1462 if exists {
1463 false
1464 } else {
1465 object.insert(key.clone(), new_value);
1466 true
1467 }
1468 }
1469 EditMode::Replace => {
1470 if exists {
1471 object.insert(key.clone(), new_value);
1472 true
1473 } else {
1474 false
1475 }
1476 }
1477 }
1478 }
1479 (Value::Array(array), PathSegment::Index(index)) => {
1480 apply_array_edit(array, *index, new_value, mode)
1481 }
1482 (Value::Array(array), PathSegment::Append) => {
1483 if matches!(mode, EditMode::Set | EditMode::Insert) {
1484 array.push(new_value);
1485 true
1486 } else {
1487 false
1488 }
1489 }
1490 (Value::Array(array), PathSegment::FromEnd(from_end)) => {
1491 if *from_end == 0 || *from_end > array.len() {
1492 false
1493 } else {
1494 let index = array.len() - *from_end;
1495 apply_array_edit(array, index, new_value, mode)
1496 }
1497 }
1498 _ => false,
1499 };
1500
1501 if !applied {
1502 *root = original;
1503 }
1504}
1505
1506fn apply_array_edit(
1507 array: &mut Vec<Value>,
1508 index: usize,
1509 new_value: Value,
1510 mode: EditMode,
1511) -> bool {
1512 if index > array.len() {
1513 return false;
1514 }
1515
1516 if index == array.len() {
1517 if matches!(mode, EditMode::Set | EditMode::Insert) {
1518 array.push(new_value);
1519 return true;
1520 }
1521 return false;
1522 }
1523
1524 match mode {
1525 EditMode::Set | EditMode::Replace => {
1526 array[index] = new_value;
1527 true
1528 }
1529 EditMode::Insert => false,
1530 }
1531}
1532
1533fn remove_at_path(root: &mut Value, segments: &[PathSegment]) {
1534 if segments.is_empty() {
1535 *root = Value::Null;
1536 return;
1537 }
1538
1539 let (parent_segments, last) = segments.split_at(segments.len() - 1);
1540 let Some(last_segment) = last.first() else {
1541 return;
1542 };
1543 let Some(parent) = resolve_path_mut(root, parent_segments) else {
1544 return;
1545 };
1546
1547 match (parent, last_segment) {
1548 (Value::Object(object), PathSegment::Key(key)) => {
1549 object.remove(key);
1550 }
1551 (Value::Array(array), PathSegment::Index(index)) => {
1552 if *index < array.len() {
1553 array.remove(*index);
1554 }
1555 }
1556 (Value::Array(array), PathSegment::FromEnd(from_end)) => {
1557 if *from_end == 0 || *from_end > array.len() {
1558 return;
1559 }
1560 let index = array.len() - *from_end;
1561 array.remove(index);
1562 }
1563 _ => {}
1564 }
1565}
1566
1567fn resolve_path_mut<'a>(root: &'a mut Value, segments: &[PathSegment]) -> Option<&'a mut Value> {
1568 let mut cursor = root;
1569
1570 for segment in segments {
1571 match segment {
1572 PathSegment::Key(key) => {
1573 let next = cursor.as_object_mut()?.get_mut(key)?;
1574 cursor = next;
1575 }
1576 PathSegment::Index(index) => {
1577 let next = cursor.as_array_mut()?.get_mut(*index)?;
1578 cursor = next;
1579 }
1580 PathSegment::FromEnd(from_end) => {
1581 let array = cursor.as_array_mut()?;
1582 if *from_end == 0 || *from_end > array.len() {
1583 return None;
1584 }
1585 let index = array.len() - *from_end;
1586 let next = array.get_mut(index)?;
1587 cursor = next;
1588 }
1589 PathSegment::Append => return None,
1590 }
1591 }
1592
1593 Some(cursor)
1594}
1595
1596fn resolve_parent_for_edit<'a>(
1597 root: &'a mut Value,
1598 segments: &[PathSegment],
1599 tail_hint: Option<&PathSegment>,
1600 mode: EditMode,
1601) -> Option<&'a mut Value> {
1602 fn scaffold_for_next_segment(next: Option<&PathSegment>) -> Value {
1603 match next {
1604 Some(PathSegment::Index(_) | PathSegment::Append | PathSegment::FromEnd(_)) => {
1605 Value::Array(Vec::new())
1606 }
1607 _ => Value::Object(Map::new()),
1608 }
1609 }
1610
1611 let mut cursor = root;
1612
1613 for (idx, segment) in segments.iter().enumerate() {
1614 let next_segment = segments.get(idx + 1).or_else(|| {
1615 if idx + 1 == segments.len() {
1616 tail_hint
1617 } else {
1618 None
1619 }
1620 });
1621 match segment {
1622 PathSegment::Key(key) => {
1623 if cursor.is_null() && matches!(mode, EditMode::Set | EditMode::Insert) {
1624 *cursor = Value::Object(Map::new());
1625 }
1626
1627 let object = cursor.as_object_mut()?;
1628 if !object.contains_key(key) {
1629 if !matches!(mode, EditMode::Set | EditMode::Insert) {
1630 return None;
1631 }
1632 object.insert(key.clone(), scaffold_for_next_segment(next_segment));
1633 }
1634 let next = object.get_mut(key)?;
1635 cursor = next;
1636 }
1637 PathSegment::Index(index) => {
1638 if cursor.is_null() && matches!(mode, EditMode::Set | EditMode::Insert) {
1639 *cursor = Value::Array(Vec::new());
1640 }
1641 let array = cursor.as_array_mut()?;
1642 if *index > array.len() {
1643 return None;
1644 }
1645 if *index == array.len() {
1646 if !matches!(mode, EditMode::Set | EditMode::Insert) {
1647 return None;
1648 }
1649 array.push(scaffold_for_next_segment(next_segment));
1650 }
1651 let next = array.get_mut(*index)?;
1652 cursor = next;
1653 }
1654 PathSegment::Append => {
1655 if cursor.is_null() && matches!(mode, EditMode::Set | EditMode::Insert) {
1656 *cursor = Value::Array(Vec::new());
1657 }
1658 let array = cursor.as_array_mut()?;
1659 if !matches!(mode, EditMode::Set | EditMode::Insert) {
1660 return None;
1661 }
1662 array.push(scaffold_for_next_segment(next_segment));
1663 cursor = array.last_mut()?;
1664 }
1665 PathSegment::FromEnd(from_end) => {
1666 let array = cursor.as_array_mut()?;
1667 if *from_end == 0 || *from_end > array.len() {
1668 return None;
1669 }
1670 let index = array.len() - *from_end;
1671 let next = array.get_mut(index)?;
1672 cursor = next;
1673 }
1674 }
1675 }
1676
1677 Some(cursor)
1678}
1679
1680fn merge_patch(target: Value, patch: Value) -> Value {
1681 match patch {
1682 Value::Object(patch_map) => {
1683 let mut target_map = match target {
1684 Value::Object(map) => map,
1685 _ => Map::new(),
1686 };
1687
1688 for (key, patch_value) in patch_map {
1689 if patch_value.is_null() {
1690 target_map.remove(&key);
1691 continue;
1692 }
1693 let prior = target_map.remove(&key).unwrap_or(Value::Null);
1694 target_map.insert(key, merge_patch(prior, patch_value));
1695 }
1696
1697 Value::Object(target_map)
1698 }
1699 other => other,
1700 }
1701}
1702
1703fn invalid_arity(name: &str, expected: &str, got: usize) -> FrankenError {
1708 FrankenError::function_error(format!("{name} expects {expected}; got {got} argument(s)"))
1709}
1710
1711fn text_arg<'a>(name: &str, args: &'a [SqliteValue], index: usize) -> Result<&'a str> {
1712 match args.get(index) {
1713 Some(SqliteValue::Text(text)) => Ok(text.as_str()),
1714 Some(other) => Err(FrankenError::function_error(format!(
1715 "{name} argument {} must be TEXT, got {}",
1716 index + 1,
1717 other.typeof_str()
1718 ))),
1719 None => Err(FrankenError::function_error(format!(
1720 "{name} missing argument {}",
1721 index + 1
1722 ))),
1723 }
1724}
1725
1726fn optional_flags_arg(name: &str, args: &[SqliteValue], index: usize) -> Result<Option<u8>> {
1727 let Some(value) = args.get(index) else {
1728 return Ok(None);
1729 };
1730 let raw = value.to_integer();
1731 let flags = u8::try_from(raw).map_err(|_| {
1732 FrankenError::function_error(format!("{name} flags out of range for u8: {raw}"))
1733 })?;
1734 Ok(Some(flags))
1735}
1736
1737fn usize_to_i64(name: &str, value: usize) -> Result<i64> {
1738 i64::try_from(value).map_err(|_| {
1739 FrankenError::function_error(format!("{name} result does not fit in i64: {value}"))
1740 })
1741}
1742
1743fn collect_path_args<'a>(
1744 name: &str,
1745 args: &'a [SqliteValue],
1746 start: usize,
1747) -> Result<Vec<&'a str>> {
1748 let mut out = Vec::with_capacity(args.len().saturating_sub(start));
1749 for idx in start..args.len() {
1750 out.push(text_arg(name, args, idx)?);
1751 }
1752 Ok(out)
1753}
1754
1755fn collect_path_value_pairs(
1756 name: &str,
1757 args: &[SqliteValue],
1758 start: usize,
1759) -> Result<Vec<(String, SqliteValue)>> {
1760 let mut pairs = Vec::with_capacity((args.len().saturating_sub(start)) / 2);
1761 let mut idx = start;
1762 while idx < args.len() {
1763 let path = text_arg(name, args, idx)?.to_owned();
1764 let value = args[idx + 1].clone();
1765 pairs.push((path, value));
1766 idx += 2;
1767 }
1768 Ok(pairs)
1769}
1770
1771pub struct JsonFunc;
1772
1773impl ScalarFunction for JsonFunc {
1774 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1775 if args.len() != 1 {
1776 return Err(invalid_arity(self.name(), "exactly 1 argument", args.len()));
1777 }
1778 let input = text_arg(self.name(), args, 0)?;
1779 Ok(SqliteValue::Text(json(input)?))
1780 }
1781
1782 fn num_args(&self) -> i32 {
1783 1
1784 }
1785
1786 fn name(&self) -> &'static str {
1787 "json"
1788 }
1789}
1790
1791pub struct JsonValidFunc;
1792
1793impl ScalarFunction for JsonValidFunc {
1794 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1795 if !(1..=2).contains(&args.len()) {
1796 return Err(invalid_arity(self.name(), "1 or 2 arguments", args.len()));
1797 }
1798 let flags = optional_flags_arg(self.name(), args, 1)?;
1799 let value = match &args[0] {
1800 SqliteValue::Text(text) => json_valid(text, flags),
1801 SqliteValue::Blob(bytes) => json_valid_blob(bytes, flags),
1802 _ => 0,
1803 };
1804 Ok(SqliteValue::Integer(value))
1805 }
1806
1807 fn num_args(&self) -> i32 {
1808 -1
1809 }
1810
1811 fn name(&self) -> &'static str {
1812 "json_valid"
1813 }
1814}
1815
1816pub struct JsonTypeFunc;
1817
1818impl ScalarFunction for JsonTypeFunc {
1819 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1820 if !(1..=2).contains(&args.len()) {
1821 return Err(invalid_arity(self.name(), "1 or 2 arguments", args.len()));
1822 }
1823 let input = text_arg(self.name(), args, 0)?;
1824 let path = if args.len() == 2 {
1825 if matches!(args[1], SqliteValue::Null) {
1826 return Ok(SqliteValue::Null);
1827 }
1828 Some(text_arg(self.name(), args, 1)?)
1829 } else {
1830 None
1831 };
1832 Ok(match json_type(input, path)? {
1833 Some(kind) => SqliteValue::Text(kind.to_owned()),
1834 None => SqliteValue::Null,
1835 })
1836 }
1837
1838 fn num_args(&self) -> i32 {
1839 -1
1840 }
1841
1842 fn name(&self) -> &'static str {
1843 "json_type"
1844 }
1845}
1846
1847pub struct JsonExtractFunc;
1848
1849impl ScalarFunction for JsonExtractFunc {
1850 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1851 if args.len() < 2 {
1852 return Err(invalid_arity(
1853 self.name(),
1854 "at least 2 arguments (json, path...)",
1855 args.len(),
1856 ));
1857 }
1858 let input = text_arg(self.name(), args, 0)?;
1859 let paths = collect_path_args(self.name(), args, 1)?;
1860 json_extract(input, &paths)
1861 }
1862
1863 fn num_args(&self) -> i32 {
1864 -1
1865 }
1866
1867 fn name(&self) -> &'static str {
1868 "json_extract"
1869 }
1870}
1871
1872pub struct JsonArrayFunc;
1873
1874impl ScalarFunction for JsonArrayFunc {
1875 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1876 Ok(SqliteValue::Text(json_array(args)?))
1877 }
1878
1879 fn num_args(&self) -> i32 {
1880 -1
1881 }
1882
1883 fn name(&self) -> &'static str {
1884 "json_array"
1885 }
1886}
1887
1888pub struct JsonObjectFunc;
1889
1890impl ScalarFunction for JsonObjectFunc {
1891 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1892 Ok(SqliteValue::Text(json_object(args)?))
1893 }
1894
1895 fn num_args(&self) -> i32 {
1896 -1
1897 }
1898
1899 fn name(&self) -> &'static str {
1900 "json_object"
1901 }
1902}
1903
1904pub struct JsonQuoteFunc;
1905
1906impl ScalarFunction for JsonQuoteFunc {
1907 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1908 if args.len() != 1 {
1909 return Err(invalid_arity(self.name(), "exactly 1 argument", args.len()));
1910 }
1911 Ok(SqliteValue::Text(json_quote(&args[0])))
1912 }
1913
1914 fn num_args(&self) -> i32 {
1915 1
1916 }
1917
1918 fn name(&self) -> &'static str {
1919 "json_quote"
1920 }
1921}
1922
1923pub struct JsonSetFunc;
1924
1925impl ScalarFunction for JsonSetFunc {
1926 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1927 if args.len() < 3 || args.len() % 2 == 0 {
1928 return Err(invalid_arity(
1929 self.name(),
1930 "an odd argument count >= 3 (json, path, value, ...)",
1931 args.len(),
1932 ));
1933 }
1934 let input = text_arg(self.name(), args, 0)?;
1935 let pairs_owned = collect_path_value_pairs(self.name(), args, 1)?;
1936 let pairs = pairs_owned
1937 .iter()
1938 .map(|(path, value)| (path.as_str(), value.clone()))
1939 .collect::<Vec<_>>();
1940 Ok(SqliteValue::Text(json_set(input, &pairs)?))
1941 }
1942
1943 fn num_args(&self) -> i32 {
1944 -1
1945 }
1946
1947 fn name(&self) -> &'static str {
1948 "json_set"
1949 }
1950}
1951
1952pub struct JsonInsertFunc;
1953
1954impl ScalarFunction for JsonInsertFunc {
1955 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1956 if args.len() < 3 || args.len() % 2 == 0 {
1957 return Err(invalid_arity(
1958 self.name(),
1959 "an odd argument count >= 3 (json, path, value, ...)",
1960 args.len(),
1961 ));
1962 }
1963 let input = text_arg(self.name(), args, 0)?;
1964 let pairs_owned = collect_path_value_pairs(self.name(), args, 1)?;
1965 let pairs = pairs_owned
1966 .iter()
1967 .map(|(path, value)| (path.as_str(), value.clone()))
1968 .collect::<Vec<_>>();
1969 Ok(SqliteValue::Text(json_insert(input, &pairs)?))
1970 }
1971
1972 fn num_args(&self) -> i32 {
1973 -1
1974 }
1975
1976 fn name(&self) -> &'static str {
1977 "json_insert"
1978 }
1979}
1980
1981pub struct JsonReplaceFunc;
1982
1983impl ScalarFunction for JsonReplaceFunc {
1984 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
1985 if args.len() < 3 || args.len() % 2 == 0 {
1986 return Err(invalid_arity(
1987 self.name(),
1988 "an odd argument count >= 3 (json, path, value, ...)",
1989 args.len(),
1990 ));
1991 }
1992 let input = text_arg(self.name(), args, 0)?;
1993 let pairs_owned = collect_path_value_pairs(self.name(), args, 1)?;
1994 let pairs = pairs_owned
1995 .iter()
1996 .map(|(path, value)| (path.as_str(), value.clone()))
1997 .collect::<Vec<_>>();
1998 Ok(SqliteValue::Text(json_replace(input, &pairs)?))
1999 }
2000
2001 fn num_args(&self) -> i32 {
2002 -1
2003 }
2004
2005 fn name(&self) -> &'static str {
2006 "json_replace"
2007 }
2008}
2009
2010pub struct JsonRemoveFunc;
2011
2012impl ScalarFunction for JsonRemoveFunc {
2013 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
2014 if args.len() < 2 {
2015 return Err(invalid_arity(
2016 self.name(),
2017 "at least 2 arguments (json, path...)",
2018 args.len(),
2019 ));
2020 }
2021 let input = text_arg(self.name(), args, 0)?;
2022 let paths = collect_path_args(self.name(), args, 1)?;
2023 Ok(SqliteValue::Text(json_remove(input, &paths)?))
2024 }
2025
2026 fn num_args(&self) -> i32 {
2027 -1
2028 }
2029
2030 fn name(&self) -> &'static str {
2031 "json_remove"
2032 }
2033}
2034
2035pub struct JsonPatchFunc;
2036
2037impl ScalarFunction for JsonPatchFunc {
2038 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
2039 if args.len() != 2 {
2040 return Err(invalid_arity(
2041 self.name(),
2042 "exactly 2 arguments",
2043 args.len(),
2044 ));
2045 }
2046 let input = text_arg(self.name(), args, 0)?;
2047 let patch = text_arg(self.name(), args, 1)?;
2048 Ok(SqliteValue::Text(json_patch(input, patch)?))
2049 }
2050
2051 fn num_args(&self) -> i32 {
2052 2
2053 }
2054
2055 fn name(&self) -> &'static str {
2056 "json_patch"
2057 }
2058}
2059
2060pub struct JsonArrayLengthFunc;
2061
2062impl ScalarFunction for JsonArrayLengthFunc {
2063 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
2064 if !(1..=2).contains(&args.len()) {
2065 return Err(invalid_arity(self.name(), "1 or 2 arguments", args.len()));
2066 }
2067 let input = text_arg(self.name(), args, 0)?;
2068 let path = if args.len() == 2 {
2069 if matches!(args[1], SqliteValue::Null) {
2070 return Ok(SqliteValue::Null);
2071 }
2072 Some(text_arg(self.name(), args, 1)?)
2073 } else {
2074 None
2075 };
2076 Ok(match json_array_length(input, path)? {
2077 Some(len) => SqliteValue::Integer(usize_to_i64(self.name(), len)?),
2078 None => SqliteValue::Null,
2079 })
2080 }
2081
2082 fn num_args(&self) -> i32 {
2083 -1
2084 }
2085
2086 fn name(&self) -> &'static str {
2087 "json_array_length"
2088 }
2089}
2090
2091pub struct JsonErrorPositionFunc;
2092
2093impl ScalarFunction for JsonErrorPositionFunc {
2094 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
2095 if args.len() != 1 {
2096 return Err(invalid_arity(self.name(), "exactly 1 argument", args.len()));
2097 }
2098 let input = text_arg(self.name(), args, 0)?;
2099 Ok(SqliteValue::Integer(usize_to_i64(
2100 self.name(),
2101 json_error_position(input),
2102 )?))
2103 }
2104
2105 fn num_args(&self) -> i32 {
2106 1
2107 }
2108
2109 fn name(&self) -> &'static str {
2110 "json_error_position"
2111 }
2112}
2113
2114pub struct JsonPrettyFunc;
2115
2116impl ScalarFunction for JsonPrettyFunc {
2117 fn invoke(&self, args: &[SqliteValue]) -> Result<SqliteValue> {
2118 if !(1..=2).contains(&args.len()) {
2119 return Err(invalid_arity(self.name(), "1 or 2 arguments", args.len()));
2120 }
2121 let input = text_arg(self.name(), args, 0)?;
2122 let indent = if args.len() == 2 {
2123 if matches!(args[1], SqliteValue::Null) {
2124 None
2125 } else {
2126 Some(text_arg(self.name(), args, 1)?)
2127 }
2128 } else {
2129 None
2130 };
2131 Ok(SqliteValue::Text(json_pretty(input, indent)?))
2132 }
2133
2134 fn num_args(&self) -> i32 {
2135 -1
2136 }
2137
2138 fn name(&self) -> &'static str {
2139 "json_pretty"
2140 }
2141}
2142
2143pub fn register_json_scalars(registry: &mut FunctionRegistry) {
2145 registry.register_scalar(JsonFunc);
2146 registry.register_scalar(JsonValidFunc);
2147 registry.register_scalar(JsonTypeFunc);
2148 registry.register_scalar(JsonExtractFunc);
2149 registry.register_scalar(JsonArrayFunc);
2150 registry.register_scalar(JsonObjectFunc);
2151 registry.register_scalar(JsonQuoteFunc);
2152 registry.register_scalar(JsonSetFunc);
2153 registry.register_scalar(JsonInsertFunc);
2154 registry.register_scalar(JsonReplaceFunc);
2155 registry.register_scalar(JsonRemoveFunc);
2156 registry.register_scalar(JsonPatchFunc);
2157 registry.register_scalar(JsonArrayLengthFunc);
2158 registry.register_scalar(JsonErrorPositionFunc);
2159 registry.register_scalar(JsonPrettyFunc);
2160}
2161
2162#[cfg(test)]
2163mod tests {
2164 use super::*;
2165 use fsqlite_func::FunctionRegistry;
2166
2167 #[test]
2168 fn test_register_json_scalars_registers_core_functions() {
2169 let mut registry = FunctionRegistry::new();
2170 register_json_scalars(&mut registry);
2171
2172 for name in [
2173 "json",
2174 "json_valid",
2175 "json_type",
2176 "json_extract",
2177 "json_set",
2178 "json_remove",
2179 "json_array",
2180 "json_object",
2181 "json_quote",
2182 "json_patch",
2183 ] {
2184 assert!(
2185 registry.contains_scalar(name),
2186 "missing registration for {name}"
2187 );
2188 }
2189 }
2190
2191 #[test]
2192 fn test_registered_json_extract_scalar_executes() {
2193 let mut registry = FunctionRegistry::new();
2194 register_json_scalars(&mut registry);
2195 let func = registry
2196 .find_scalar("json_extract", 2)
2197 .expect("json_extract should be registered");
2198 let out = func
2199 .invoke(&[
2200 SqliteValue::Text(r#"{"a":1,"b":[2,3]}"#.to_owned()),
2201 SqliteValue::Text("$.b[1]".to_owned()),
2202 ])
2203 .unwrap();
2204 assert_eq!(out, SqliteValue::Integer(3));
2205 }
2206
2207 #[test]
2208 fn test_registered_json_set_scalar_executes() {
2209 let mut registry = FunctionRegistry::new();
2210 register_json_scalars(&mut registry);
2211 let func = registry
2212 .find_scalar("json_set", 3)
2213 .expect("json_set should be registered");
2214 let out = func
2215 .invoke(&[
2216 SqliteValue::Text(r#"{"a":1}"#.to_owned()),
2217 SqliteValue::Text("$.b".to_owned()),
2218 SqliteValue::Integer(2),
2219 ])
2220 .unwrap();
2221 assert_eq!(out, SqliteValue::Text(r#"{"a":1,"b":2}"#.to_owned()));
2222 }
2223
2224 #[test]
2225 fn test_json_valid_text() {
2226 assert_eq!(json(r#"{"a":1}"#).unwrap(), r#"{"a":1}"#);
2227 }
2228
2229 #[test]
2230 fn test_json_invalid_error() {
2231 let err = json("not json").unwrap_err();
2232 assert!(matches!(err, FrankenError::FunctionError(_)));
2233 }
2234
2235 #[test]
2236 fn test_json_valid_flags_default() {
2237 assert_eq!(json_valid(r#"{"a":1}"#, None), 1);
2238 assert_eq!(json_valid("not json", None), 0);
2239 }
2240
2241 #[test]
2242 fn test_json_valid_flags_json5() {
2243 let json5_text = concat!("{", "a:1", "}");
2244 assert_eq!(json_valid(json5_text, Some(JSON_VALID_JSON5_FLAG)), 1);
2245 assert_eq!(json_valid(json5_text, Some(JSON_VALID_RFC_8259_FLAG)), 0);
2246 }
2247
2248 #[test]
2249 fn test_json_valid_flags_strict() {
2250 assert_eq!(json_valid("invalid", Some(JSON_VALID_RFC_8259_FLAG)), 0);
2251 }
2252
2253 #[test]
2254 fn test_json_valid_flags_jsonb() {
2255 let payload = jsonb(r#"{"a":[1,2,3]}"#).unwrap();
2256 assert_eq!(
2257 json_valid_blob(&payload, Some(JSON_VALID_JSONB_SUPERFICIAL_FLAG)),
2258 1
2259 );
2260 assert_eq!(
2261 json_valid_blob(&payload, Some(JSON_VALID_JSONB_STRICT_FLAG)),
2262 1
2263 );
2264 let mut broken = payload;
2265 broken.push(0xFF);
2266 assert_eq!(
2267 json_valid_blob(&broken, Some(JSON_VALID_JSONB_SUPERFICIAL_FLAG)),
2268 1
2269 );
2270 assert_eq!(
2271 json_valid_blob(&broken, Some(JSON_VALID_JSONB_STRICT_FLAG)),
2272 0
2273 );
2274 }
2275
2276 #[test]
2277 fn test_json_type_object() {
2278 assert_eq!(json_type(r#"{"a":1}"#, None).unwrap(), Some("object"));
2279 }
2280
2281 #[test]
2282 fn test_json_type_path() {
2283 assert_eq!(
2284 json_type(r#"{"a":1}"#, Some("$.a")).unwrap(),
2285 Some("integer")
2286 );
2287 }
2288
2289 #[test]
2290 fn test_json_type_missing_path() {
2291 assert_eq!(json_type(r#"{"a":1}"#, Some("$.b")).unwrap(), None);
2292 }
2293
2294 #[test]
2295 fn test_json_extract_single() {
2296 let result = json_extract(r#"{"a":1}"#, &["$.a"]).unwrap();
2297 assert_eq!(result, SqliteValue::Integer(1));
2298 }
2299
2300 #[test]
2301 fn test_json_extract_multiple() {
2302 let result = json_extract(r#"{"a":1,"b":2}"#, &["$.a", "$.b"]).unwrap();
2303 assert_eq!(result, SqliteValue::Text("[1,2]".to_owned()));
2304 }
2305
2306 #[test]
2307 fn test_json_extract_string_unwrap() {
2308 let result = json_extract(r#"{"a":"hello"}"#, &["$.a"]).unwrap();
2309 assert_eq!(result, SqliteValue::Text("hello".to_owned()));
2310 }
2311
2312 #[test]
2313 fn test_arrow_preserves_json() {
2314 let result = json_arrow(r#"{"a":"hello"}"#, "$.a").unwrap();
2315 assert_eq!(result, SqliteValue::Text(r#""hello""#.to_owned()));
2316 }
2317
2318 #[test]
2319 fn test_double_arrow_unwraps() {
2320 let result = json_double_arrow(r#"{"a":"hello"}"#, "$.a").unwrap();
2321 assert_eq!(result, SqliteValue::Text("hello".to_owned()));
2322 }
2323
2324 #[test]
2325 fn test_json_extract_array_index() {
2326 let result = json_extract("[10,20,30]", &["$[1]"]).unwrap();
2327 assert_eq!(result, SqliteValue::Integer(20));
2328 }
2329
2330 #[test]
2331 fn test_json_extract_quoted_key_segment() {
2332 let result = json_extract(r#"{"a.b":1}"#, &["$.\"a.b\""]).unwrap();
2333 assert_eq!(result, SqliteValue::Integer(1));
2334 }
2335
2336 #[test]
2337 fn test_json_extract_from_end() {
2338 let result = json_extract("[10,20,30]", &["$[#-1]"]).unwrap();
2339 assert_eq!(result, SqliteValue::Integer(30));
2340 }
2341
2342 #[test]
2343 fn test_jsonb_extract_returns_blob() {
2344 let blob = jsonb_extract(r#"{"a":"hello"}"#, &["$.a"]).unwrap();
2345 let text = json_from_jsonb(&blob).unwrap();
2346 assert_eq!(text, r#""hello""#);
2347 }
2348
2349 #[test]
2350 fn test_json_quote_text() {
2351 assert_eq!(
2352 json_quote(&SqliteValue::Text("hello".to_owned())),
2353 r#""hello""#
2354 );
2355 }
2356
2357 #[test]
2358 fn test_json_quote_null() {
2359 assert_eq!(json_quote(&SqliteValue::Null), "null");
2360 }
2361
2362 #[test]
2363 fn test_json_array_basic() {
2364 let out = json_array(&[
2365 SqliteValue::Integer(1),
2366 SqliteValue::Text("two".to_owned()),
2367 SqliteValue::Null,
2368 ])
2369 .unwrap();
2370 assert_eq!(out, r#"[1,"two",null]"#);
2371 }
2372
2373 #[test]
2374 fn test_json_object_basic() {
2375 let out = json_object(&[
2376 SqliteValue::Text("a".to_owned()),
2377 SqliteValue::Integer(1),
2378 SqliteValue::Text("b".to_owned()),
2379 SqliteValue::Text("two".to_owned()),
2380 ])
2381 .unwrap();
2382 assert_eq!(out, r#"{"a":1,"b":"two"}"#);
2383 }
2384
2385 #[test]
2386 fn test_jsonb_roundtrip() {
2387 let blob = jsonb(r#"{"a":1,"b":[2,3]}"#).unwrap();
2388 let text = json_from_jsonb(&blob).unwrap();
2389 assert_eq!(text, r#"{"a":1,"b":[2,3]}"#);
2390 }
2391
2392 #[test]
2393 fn test_jsonb_array_variant() {
2394 let blob = jsonb_array(&[
2395 SqliteValue::Integer(1),
2396 SqliteValue::Text("two".to_owned()),
2397 SqliteValue::Null,
2398 ])
2399 .unwrap();
2400 assert_eq!(json_from_jsonb(&blob).unwrap(), r#"[1,"two",null]"#);
2401 }
2402
2403 #[test]
2404 fn test_jsonb_object_variant() {
2405 let blob = jsonb_object(&[
2406 SqliteValue::Text("a".to_owned()),
2407 SqliteValue::Integer(1),
2408 SqliteValue::Text("b".to_owned()),
2409 SqliteValue::Text("two".to_owned()),
2410 ])
2411 .unwrap();
2412 assert_eq!(json_from_jsonb(&blob).unwrap(), r#"{"a":1,"b":"two"}"#);
2413 }
2414
2415 #[test]
2416 fn test_json_array_length() {
2417 assert_eq!(json_array_length("[1,2,3]", None).unwrap(), Some(3));
2418 assert_eq!(json_array_length("[]", None).unwrap(), Some(0));
2419 assert_eq!(json_array_length(r#"{"a":1}"#, None).unwrap(), None);
2420 }
2421
2422 #[test]
2423 fn test_json_array_length_path() {
2424 assert_eq!(
2425 json_array_length(r#"{"a":[1,2,3]}"#, Some("$.a")).unwrap(),
2426 Some(3)
2427 );
2428 }
2429
2430 #[test]
2431 fn test_json_array_length_not_array() {
2432 assert_eq!(json_array_length(r#"{"a":1}"#, Some("$.a")).unwrap(), None);
2433 assert_eq!(json_array_length(r#""text""#, None).unwrap(), None);
2434 }
2435
2436 #[test]
2437 fn test_json_error_position_valid() {
2438 assert_eq!(json_error_position(r#"{"a":1}"#), 0);
2439 }
2440
2441 #[test]
2442 fn test_json_error_position_invalid() {
2443 assert!(json_error_position(r#"{"a":}"#) > 0);
2444 }
2445
2446 #[test]
2447 fn test_json_pretty_default() {
2448 let output = json_pretty(r#"{"a":1}"#, None).unwrap();
2449 assert!(output.contains('\n'));
2450 assert!(output.contains(" \"a\""));
2451 }
2452
2453 #[test]
2454 fn test_json_pretty_custom_indent() {
2455 let output = json_pretty(r#"{"a":1}"#, Some("\t")).unwrap();
2456 assert!(output.contains("\n\t\"a\""));
2457 }
2458
2459 #[test]
2460 fn test_json_set_create() {
2461 let out = json_set(r#"{"a":1}"#, &[("$.b", SqliteValue::Integer(2))]).unwrap();
2462 assert_eq!(out, r#"{"a":1,"b":2}"#);
2463 }
2464
2465 #[test]
2466 fn test_json_set_nested_path_create() {
2467 let out = json_set("{}", &[("$.a.b", SqliteValue::Integer(1))]).unwrap();
2468 assert_eq!(out, r#"{"a":{"b":1}}"#);
2469 }
2470
2471 #[test]
2472 fn test_json_set_nested_array_path_create() {
2473 let out = json_set("{}", &[("$.a[0]", SqliteValue::Integer(1))]).unwrap();
2474 assert_eq!(out, r#"{"a":[1]}"#);
2475 }
2476
2477 #[test]
2478 fn test_json_set_nested_append_path_create() {
2479 let out = json_set("{}", &[("$.a[#]", SqliteValue::Integer(1))]).unwrap();
2480 assert_eq!(out, r#"{"a":[1]}"#);
2481 }
2482
2483 #[test]
2484 fn test_json_set_nested_array_object_create() {
2485 let out = json_set("{}", &[("$.a[0].b", SqliteValue::Integer(1))]).unwrap();
2486 assert_eq!(out, r#"{"a":[{"b":1}]}"#);
2487 }
2488
2489 #[test]
2490 fn test_json_set_nested_array_index_out_of_range_does_not_scaffold() {
2491 let out = json_set("{}", &[("$.a[1]", SqliteValue::Integer(1))]).unwrap();
2492 assert_eq!(out, "{}");
2493 }
2494
2495 #[test]
2496 fn test_json_set_nested_from_end_does_not_scaffold() {
2497 let out = json_set("{}", &[("$.a[#-1]", SqliteValue::Integer(1))]).unwrap();
2498 assert_eq!(out, "{}");
2499 }
2500
2501 #[test]
2502 fn test_json_set_scalar_root_with_array_path_is_noop() {
2503 let out = json_set("null", &[("$.a[0]", SqliteValue::Integer(1))]).unwrap();
2504 assert_eq!(out, "null");
2505 }
2506
2507 #[test]
2508 fn test_json_set_existing_null_value_with_array_path_is_noop() {
2509 let out = json_set(r#"{"a":null}"#, &[("$.a[1]", SqliteValue::Integer(1))]).unwrap();
2510 assert_eq!(out, r#"{"a":null}"#);
2511 }
2512
2513 #[test]
2514 fn test_json_set_overwrite() {
2515 let out = json_set(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(2))]).unwrap();
2516 assert_eq!(out, r#"{"a":2}"#);
2517 }
2518
2519 #[test]
2520 fn test_json_insert_no_overwrite() {
2521 let out = json_insert(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(2))]).unwrap();
2522 assert_eq!(out, r#"{"a":1}"#);
2523 }
2524
2525 #[test]
2526 fn test_json_insert_create() {
2527 let out = json_insert(r#"{"a":1}"#, &[("$.b", SqliteValue::Integer(2))]).unwrap();
2528 assert_eq!(out, r#"{"a":1,"b":2}"#);
2529 }
2530
2531 #[test]
2532 fn test_json_insert_nested_path_create() {
2533 let out = json_insert("{}", &[("$.a.b", SqliteValue::Integer(1))]).unwrap();
2534 assert_eq!(out, r#"{"a":{"b":1}}"#);
2535 }
2536
2537 #[test]
2538 fn test_json_insert_nested_array_path_create() {
2539 let out = json_insert("{}", &[("$.a[0]", SqliteValue::Integer(1))]).unwrap();
2540 assert_eq!(out, r#"{"a":[1]}"#);
2541 }
2542
2543 #[test]
2544 fn test_json_replace_overwrite() {
2545 let out = json_replace(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(2))]).unwrap();
2546 assert_eq!(out, r#"{"a":2}"#);
2547 }
2548
2549 #[test]
2550 fn test_json_replace_no_create() {
2551 let out = json_replace(r#"{"a":1}"#, &[("$.b", SqliteValue::Integer(2))]).unwrap();
2552 assert_eq!(out, r#"{"a":1}"#);
2553 }
2554
2555 #[test]
2556 fn test_json_remove_key() {
2557 let out = json_remove(r#"{"a":1,"b":2}"#, &["$.a"]).unwrap();
2558 assert_eq!(out, r#"{"b":2}"#);
2559 }
2560
2561 #[test]
2562 fn test_json_remove_array_compact() {
2563 let out = json_remove("[1,2,3]", &["$[1]"]).unwrap();
2564 assert_eq!(out, "[1,3]");
2565 }
2566
2567 #[test]
2568 fn test_json_patch_merge() {
2569 let out = json_patch(r#"{"a":1,"b":2}"#, r#"{"b":3,"c":4}"#).unwrap();
2570 assert_eq!(out, r#"{"a":1,"b":3,"c":4}"#);
2571 }
2572
2573 #[test]
2574 fn test_json_patch_delete() {
2575 let out = json_patch(r#"{"a":1,"b":2}"#, r#"{"b":null}"#).unwrap();
2576 assert_eq!(out, r#"{"a":1}"#);
2577 }
2578
2579 #[test]
2580 fn test_jsonb_set_variant() {
2581 let blob = jsonb_set(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(9))]).unwrap();
2582 let text = json_from_jsonb(&blob).unwrap();
2583 assert_eq!(text, r#"{"a":9}"#);
2584 }
2585
2586 #[test]
2587 fn test_jsonb_insert_variant() {
2588 let blob = jsonb_insert(r#"{"a":1}"#, &[("$.b", SqliteValue::Integer(2))]).unwrap();
2589 let text = json_from_jsonb(&blob).unwrap();
2590 assert_eq!(text, r#"{"a":1,"b":2}"#);
2591 }
2592
2593 #[test]
2594 fn test_jsonb_replace_variant() {
2595 let blob = jsonb_replace(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(5))]).unwrap();
2596 let text = json_from_jsonb(&blob).unwrap();
2597 assert_eq!(text, r#"{"a":5}"#);
2598 }
2599
2600 #[test]
2601 fn test_jsonb_remove_variant() {
2602 let blob = jsonb_remove(r#"{"a":1,"b":2}"#, &["$.a"]).unwrap();
2603 let text = json_from_jsonb(&blob).unwrap();
2604 assert_eq!(text, r#"{"b":2}"#);
2605 }
2606
2607 #[test]
2608 fn test_jsonb_patch_variant() {
2609 let blob = jsonb_patch(r#"{"a":1,"b":2}"#, r#"{"b":7}"#).unwrap();
2610 let text = json_from_jsonb(&blob).unwrap();
2611 assert_eq!(text, r#"{"a":1,"b":7}"#);
2612 }
2613
2614 #[test]
2615 fn test_json_group_array_includes_nulls() {
2616 let out = json_group_array(&[
2617 SqliteValue::Integer(1),
2618 SqliteValue::Null,
2619 SqliteValue::Integer(3),
2620 ])
2621 .unwrap();
2622 assert_eq!(out, "[1,null,3]");
2623 }
2624
2625 #[test]
2626 fn test_json_group_array_basic() {
2627 let out = json_group_array(&[
2628 SqliteValue::Integer(1),
2629 SqliteValue::Integer(2),
2630 SqliteValue::Integer(3),
2631 ])
2632 .unwrap();
2633 assert_eq!(out, "[1,2,3]");
2634 }
2635
2636 #[test]
2637 fn test_json_group_object_basic() {
2638 let out = json_group_object(&[
2639 (SqliteValue::Text("a".to_owned()), SqliteValue::Integer(1)),
2640 (SqliteValue::Text("b".to_owned()), SqliteValue::Integer(2)),
2641 ])
2642 .unwrap();
2643 assert_eq!(out, r#"{"a":1,"b":2}"#);
2644 }
2645
2646 #[test]
2647 fn test_json_group_object_duplicate_keys_last_wins() {
2648 let out = json_group_object(&[
2649 (SqliteValue::Text("k".to_owned()), SqliteValue::Integer(1)),
2650 (SqliteValue::Text("k".to_owned()), SqliteValue::Integer(2)),
2651 ])
2652 .unwrap();
2653 assert_eq!(out, r#"{"k":2}"#);
2654 }
2655
2656 #[test]
2657 fn test_jsonb_group_array_and_object_variants() {
2658 let array_blob = jsonb_group_array(&[SqliteValue::Integer(1), SqliteValue::Null]).unwrap();
2659 assert_eq!(json_from_jsonb(&array_blob).unwrap(), "[1,null]");
2660
2661 let object_blob =
2662 jsonb_group_object(&[(SqliteValue::Text("a".to_owned()), SqliteValue::Integer(7))])
2663 .unwrap();
2664 assert_eq!(json_from_jsonb(&object_blob).unwrap(), r#"{"a":7}"#);
2665 }
2666
2667 #[test]
2668 fn test_json_each_array() {
2669 let rows = json_each("[10,20]", None).unwrap();
2670 assert_eq!(rows.len(), 2);
2671 assert_eq!(rows[0].key, SqliteValue::Integer(0));
2672 assert_eq!(rows[1].key, SqliteValue::Integer(1));
2673 assert_eq!(rows[0].value, SqliteValue::Integer(10));
2674 assert_eq!(rows[1].value, SqliteValue::Integer(20));
2675 }
2676
2677 #[test]
2678 fn test_json_each_object() {
2679 let rows = json_each(r#"{"a":1,"b":2}"#, None).unwrap();
2680 assert_eq!(rows.len(), 2);
2681 assert_eq!(rows[0].key, SqliteValue::Text("a".to_owned()));
2682 assert_eq!(rows[1].key, SqliteValue::Text("b".to_owned()));
2683 assert_eq!(rows[0].value, SqliteValue::Integer(1));
2684 assert_eq!(rows[1].value, SqliteValue::Integer(2));
2685 }
2686
2687 #[test]
2688 fn test_json_each_path() {
2689 let rows = json_each(r#"{"a":{"b":1,"c":2}}"#, Some("$.a")).unwrap();
2690 assert_eq!(rows.len(), 2);
2691 assert_eq!(rows[0].path, "$.a");
2692 assert_eq!(rows[1].path, "$.a");
2693 }
2694
2695 #[test]
2696 fn test_json_tree_recursive() {
2697 let rows = json_tree(r#"{"a":{"b":1}}"#, None).unwrap();
2698 assert!(rows.iter().any(|row| row.fullkey == "$.a"));
2699 assert!(rows.iter().any(|row| row.fullkey == "$.a.b"));
2700 }
2701
2702 #[test]
2703 fn test_json_tree_columns() {
2704 let rows = json_tree(r#"{"a":{"b":1}}"#, None).unwrap();
2705 let row = rows
2706 .iter()
2707 .find(|candidate| candidate.fullkey == "$.a.b")
2708 .expect("nested row should exist");
2709 assert_eq!(row.key, SqliteValue::Text("b".to_owned()));
2710 assert_eq!(row.value, SqliteValue::Integer(1));
2711 assert_eq!(row.type_name, "integer");
2712 assert_eq!(row.atom, SqliteValue::Integer(1));
2713 assert_eq!(row.path, "$.a");
2714 }
2715
2716 #[test]
2717 fn test_json_each_columns() {
2718 let rows = json_each(r#"{"a":1}"#, None).unwrap();
2719 let row = rows.first().unwrap();
2720 assert_eq!(row.key, SqliteValue::Text("a".to_owned()));
2721 assert_eq!(row.value, SqliteValue::Integer(1));
2722 assert_eq!(row.type_name, "integer");
2723 assert_eq!(row.atom, SqliteValue::Integer(1));
2724 assert_eq!(row.parent, SqliteValue::Null);
2725 assert_eq!(row.fullkey, "$.a");
2726 assert_eq!(row.path, "$");
2727 }
2728
2729 #[test]
2730 fn test_json_each_vtab_cursor_scan() {
2731 let cx = Cx::new();
2732 let vtab = JsonEachVtab::connect(&cx, &[]).unwrap();
2733 let mut cursor = vtab.open().unwrap();
2734 cursor
2735 .filter(&cx, 0, None, &[SqliteValue::Text("[4,5]".to_owned())])
2736 .unwrap();
2737
2738 let mut values = Vec::new();
2739 while !cursor.eof() {
2740 let mut key_ctx = ColumnContext::new();
2741 let mut value_ctx = ColumnContext::new();
2742 cursor.column(&mut key_ctx, 0).unwrap();
2743 cursor.column(&mut value_ctx, 1).unwrap();
2744 values.push((
2745 key_ctx.take_value().unwrap(),
2746 value_ctx.take_value().unwrap(),
2747 ));
2748 cursor.next(&cx).unwrap();
2749 }
2750
2751 assert_eq!(
2752 values,
2753 vec![
2754 (SqliteValue::Integer(0), SqliteValue::Integer(4)),
2755 (SqliteValue::Integer(1), SqliteValue::Integer(5)),
2756 ]
2757 );
2758 }
2759
2760 #[test]
2761 fn test_json_tree_vtab_cursor_scan() {
2762 let cx = Cx::new();
2763 let vtab = JsonTreeVtab::connect(&cx, &[]).unwrap();
2764 let mut cursor = vtab.open().unwrap();
2765 cursor
2766 .filter(
2767 &cx,
2768 0,
2769 None,
2770 &[
2771 SqliteValue::Text(r#"{"a":{"b":1}}"#.to_owned()),
2772 SqliteValue::Text("$.a".to_owned()),
2773 ],
2774 )
2775 .unwrap();
2776
2777 let mut fullkeys = Vec::new();
2778 while !cursor.eof() {
2779 let mut ctx = ColumnContext::new();
2780 cursor.column(&mut ctx, 6).unwrap();
2781 let fullkey = ctx.take_value().unwrap();
2782 if let SqliteValue::Text(text) = fullkey {
2783 fullkeys.push(text);
2784 }
2785 cursor.next(&cx).unwrap();
2786 }
2787
2788 assert_eq!(fullkeys, vec!["$.a".to_owned(), "$.a.b".to_owned()]);
2789 }
2790
2791 #[test]
2792 fn test_jsonb_chain_validity() {
2793 let first = jsonb_set(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(9))]).unwrap();
2794 let first_text = json_from_jsonb(&first).unwrap();
2795 let second = jsonb_patch(&first_text, r#"{"b":2}"#).unwrap();
2796 assert_eq!(
2797 json_valid_blob(&second, Some(JSON_VALID_JSONB_STRICT_FLAG)),
2798 1
2799 );
2800 }
2801
2802 #[test]
2807 fn test_json_minify_whitespace() {
2808 assert_eq!(json(" { \"a\" : 1 } ").unwrap(), r#"{"a":1}"#);
2809 }
2810
2811 #[test]
2812 fn test_json_scalar_string() {
2813 assert_eq!(json(r#""hello""#).unwrap(), r#""hello""#);
2814 }
2815
2816 #[test]
2817 fn test_json_scalar_number() {
2818 assert_eq!(json("42").unwrap(), "42");
2819 }
2820
2821 #[test]
2822 fn test_json_scalar_null() {
2823 assert_eq!(json("null").unwrap(), "null");
2824 }
2825
2826 #[test]
2827 fn test_json_scalar_bool() {
2828 assert_eq!(json("true").unwrap(), "true");
2829 assert_eq!(json("false").unwrap(), "false");
2830 }
2831
2832 #[test]
2833 fn test_json_nested_structure() {
2834 let input = r#"{"a":{"b":[1,2,{"c":3}]}}"#;
2835 assert_eq!(json(input).unwrap(), input);
2836 }
2837
2838 #[test]
2839 fn test_json_unicode() {
2840 let input = r#"{"key":"\u00fc\u00e9"}"#;
2841 let result = json(input).unwrap();
2842 assert!(result.contains("key"));
2844 }
2845
2846 #[test]
2851 fn test_json_valid_zero_flags() {
2852 assert_eq!(json_valid(r#"{"a":1}"#, Some(0)), 0);
2853 }
2854
2855 #[test]
2856 fn test_json_valid_empty_string() {
2857 assert_eq!(json_valid("", None), 0);
2858 }
2859
2860 #[test]
2865 fn test_json_type_null() {
2866 assert_eq!(json_type("null", None).unwrap(), Some("null"));
2867 }
2868
2869 #[test]
2870 fn test_json_type_true() {
2871 assert_eq!(json_type("true", None).unwrap(), Some("true"));
2872 }
2873
2874 #[test]
2875 fn test_json_type_false() {
2876 assert_eq!(json_type("false", None).unwrap(), Some("false"));
2877 }
2878
2879 #[test]
2880 fn test_json_type_real() {
2881 assert_eq!(json_type("3.14", None).unwrap(), Some("real"));
2882 }
2883
2884 #[test]
2885 fn test_json_type_text() {
2886 assert_eq!(json_type(r#""hello""#, None).unwrap(), Some("text"));
2887 }
2888
2889 #[test]
2890 fn test_json_type_array() {
2891 assert_eq!(json_type("[1,2]", None).unwrap(), Some("array"));
2892 }
2893
2894 #[test]
2899 fn test_json_extract_missing_path_null() {
2900 let result = json_extract(r#"{"a":1}"#, &["$.b"]).unwrap();
2901 assert_eq!(result, SqliteValue::Null);
2902 }
2903
2904 #[test]
2905 fn test_json_extract_no_paths_error() {
2906 let empty: &[&str] = &[];
2907 assert!(json_extract(r#"{"a":1}"#, empty).is_err());
2908 }
2909
2910 #[test]
2911 fn test_json_extract_null_value() {
2912 let result = json_extract(r#"{"a":null}"#, &["$.a"]).unwrap();
2913 assert_eq!(result, SqliteValue::Null);
2914 }
2915
2916 #[test]
2917 fn test_json_extract_boolean() {
2918 let result = json_extract(r#"{"a":true}"#, &["$.a"]).unwrap();
2919 assert_eq!(result, SqliteValue::Integer(1));
2920 let result = json_extract(r#"{"a":false}"#, &["$.a"]).unwrap();
2921 assert_eq!(result, SqliteValue::Integer(0));
2922 }
2923
2924 #[test]
2925 fn test_json_extract_nested_array() {
2926 let result = json_extract(r#"{"a":[[1,2],[3,4]]}"#, &["$.a[1][0]"]).unwrap();
2927 assert_eq!(result, SqliteValue::Integer(3));
2928 }
2929
2930 #[test]
2931 fn test_json_extract_multiple_with_missing() {
2932 let result = json_extract(r#"{"a":1}"#, &["$.a", "$.b"]).unwrap();
2933 assert_eq!(result, SqliteValue::Text("[1,null]".to_owned()));
2934 }
2935
2936 #[test]
2941 fn test_json_arrow_missing_path_null() {
2942 let result = json_arrow(r#"{"a":1}"#, "$.b").unwrap();
2943 assert_eq!(result, SqliteValue::Null);
2944 }
2945
2946 #[test]
2947 fn test_json_arrow_number() {
2948 let result = json_arrow(r#"{"a":42}"#, "$.a").unwrap();
2949 assert_eq!(result, SqliteValue::Text("42".to_owned()));
2950 }
2951
2952 #[test]
2953 fn test_json_arrow_null() {
2954 let result = json_arrow(r#"{"a":null}"#, "$.a").unwrap();
2955 assert_eq!(result, SqliteValue::Text("null".to_owned()));
2956 }
2957
2958 #[test]
2963 fn test_json_array_length_nested_not_array() {
2964 assert_eq!(
2965 json_array_length(r#"{"a":"text"}"#, Some("$.a")).unwrap(),
2966 None
2967 );
2968 }
2969
2970 #[test]
2971 fn test_json_array_length_missing_path() {
2972 assert_eq!(json_array_length(r#"{"a":1}"#, Some("$.b")).unwrap(), None);
2973 }
2974
2975 #[test]
2980 fn test_json_error_position_empty() {
2981 assert!(json_error_position("") > 0);
2982 }
2983
2984 #[test]
2985 fn test_json_error_position_just_brace() {
2986 assert!(json_error_position("{") > 0);
2987 }
2988
2989 #[test]
2994 fn test_json_pretty_empty_array() {
2995 assert_eq!(json_pretty("[]", None).unwrap(), "[]");
2996 }
2997
2998 #[test]
2999 fn test_json_pretty_empty_object() {
3000 assert_eq!(json_pretty("{}", None).unwrap(), "{}");
3001 }
3002
3003 #[test]
3004 fn test_json_pretty_scalar() {
3005 assert_eq!(json_pretty("42", None).unwrap(), "42");
3006 }
3007
3008 #[test]
3009 fn test_json_pretty_nested() {
3010 let result = json_pretty(r#"{"a":[1,2]}"#, None).unwrap();
3011 assert!(result.contains('\n'));
3012 assert!(result.contains("\"a\""));
3013 }
3014
3015 #[test]
3020 fn test_json_pretty_object() {
3021 let output = json_pretty(r#"{"a":1,"b":[2,3]}"#, None).unwrap();
3022 assert!(output.contains('\n'));
3023 assert!(output.contains(" \"a\""));
3024 assert!(output.contains(" \"b\""));
3025 }
3026
3027 #[test]
3028 fn test_json_pretty_array() {
3029 let output = json_pretty("[1,2,3]", None).unwrap();
3030 assert!(output.contains('\n'));
3031 assert!(output.contains(" 1"));
3032 assert!(output.contains(" 2"));
3033 assert!(output.contains(" 3"));
3034 }
3035
3036 #[test]
3037 fn test_json_pretty_idempotent() {
3038 let input = r#"{"a":1,"b":[2,3]}"#;
3039 let first = json_pretty(input, None).unwrap();
3040 let second = json_pretty(&first, None).unwrap();
3041 assert_eq!(first, second, "json_pretty should be idempotent");
3042 }
3043
3044 #[test]
3045 fn test_jsonb_functions_available() {
3046 let blob = jsonb_array(&[SqliteValue::Integer(1), SqliteValue::Integer(2)]).unwrap();
3047 assert!(
3048 !blob.is_empty(),
3049 "jsonb_array should produce non-empty output"
3050 );
3051
3052 let blob2 = jsonb_set(r#"{"a":1}"#, &[("$.a", SqliteValue::Integer(9))]).unwrap();
3053 assert!(
3054 !blob2.is_empty(),
3055 "jsonb_set should produce non-empty output"
3056 );
3057
3058 let blob3 =
3059 jsonb_object(&[SqliteValue::Text("key".into()), SqliteValue::Integer(42)]).unwrap();
3060 assert!(
3061 !blob3.is_empty(),
3062 "jsonb_object should produce non-empty output"
3063 );
3064 }
3065
3066 #[test]
3071 fn test_json_quote_integer() {
3072 assert_eq!(json_quote(&SqliteValue::Integer(42)), "42");
3073 assert_eq!(json_quote(&SqliteValue::Integer(-1)), "-1");
3074 }
3075
3076 #[test]
3077 fn test_json_quote_float() {
3078 #[allow(clippy::approx_constant)]
3079 let result = json_quote(&SqliteValue::Float(3.14));
3080 assert!(result.starts_with("3.14"));
3081 }
3082
3083 #[test]
3084 fn test_json_quote_float_infinity() {
3085 assert_eq!(json_quote(&SqliteValue::Float(f64::INFINITY)), "null");
3086 assert_eq!(json_quote(&SqliteValue::Float(f64::NEG_INFINITY)), "null");
3087 assert_eq!(json_quote(&SqliteValue::Float(f64::NAN)), "null");
3088 }
3089
3090 #[test]
3091 fn test_json_quote_blob() {
3092 let result = json_quote(&SqliteValue::Blob(vec![0xDE, 0xAD]));
3093 assert_eq!(result, r#""dead""#);
3094 }
3095
3096 #[test]
3097 fn test_json_quote_text_special_chars() {
3098 let result = json_quote(&SqliteValue::Text("a\"b\\c".to_owned()));
3099 assert!(result.contains("\\\""));
3100 assert!(result.contains("\\\\"));
3101 }
3102
3103 #[test]
3108 fn test_json_object_odd_args_error() {
3109 let err = json_object(&[
3110 SqliteValue::Text("a".to_owned()),
3111 SqliteValue::Integer(1),
3112 SqliteValue::Text("b".to_owned()),
3113 ]);
3114 assert!(err.is_err());
3115 }
3116
3117 #[test]
3118 fn test_json_object_non_text_key_error() {
3119 let err = json_object(&[SqliteValue::Integer(1), SqliteValue::Integer(2)]);
3120 assert!(err.is_err());
3121 }
3122
3123 #[test]
3124 fn test_json_object_empty() {
3125 assert_eq!(json_object(&[]).unwrap(), "{}");
3126 }
3127
3128 #[test]
3129 fn test_json_object_duplicate_keys() {
3130 let out = json_object(&[
3131 SqliteValue::Text("k".to_owned()),
3132 SqliteValue::Integer(1),
3133 SqliteValue::Text("k".to_owned()),
3134 SqliteValue::Integer(2),
3135 ])
3136 .unwrap();
3137 assert_eq!(out, r#"{"k":2}"#);
3138 }
3139
3140 #[test]
3145 fn test_json_set_array_element() {
3146 let out = json_set("[1,2,3]", &[("$[1]", SqliteValue::Integer(99))]).unwrap();
3147 assert_eq!(out, "[1,99,3]");
3148 }
3149
3150 #[test]
3151 fn test_json_set_array_append_at_len() {
3152 let out = json_set("[1,2]", &[("$[2]", SqliteValue::Integer(3))]).unwrap();
3153 assert_eq!(out, "[1,2,3]");
3154 }
3155
3156 #[test]
3157 fn test_json_insert_array_append_at_len() {
3158 let out = json_insert("[1,2]", &[("$[2]", SqliteValue::Integer(3))]).unwrap();
3159 assert_eq!(out, "[1,2,3]");
3160 }
3161
3162 #[test]
3163 fn test_json_set_append_pseudo_index() {
3164 let out = json_set("[1,2]", &[("$[#]", SqliteValue::Integer(3))]).unwrap();
3165 assert_eq!(out, "[1,2,3]");
3166 }
3167
3168 #[test]
3169 fn test_json_replace_append_pseudo_index_noop() {
3170 let out = json_replace("[1,2]", &[("$[#]", SqliteValue::Integer(3))]).unwrap();
3171 assert_eq!(out, "[1,2]");
3172 }
3173
3174 #[test]
3175 fn test_json_replace_array_element() {
3176 let out = json_replace("[1,2,3]", &[("$[0]", SqliteValue::Integer(0))]).unwrap();
3177 assert_eq!(out, "[0,2,3]");
3178 }
3179
3180 #[test]
3181 fn test_json_set_multiple_paths() {
3182 let out = json_set(
3183 r#"{"a":1,"b":2}"#,
3184 &[
3185 ("$.a", SqliteValue::Integer(10)),
3186 ("$.c", SqliteValue::Integer(30)),
3187 ],
3188 )
3189 .unwrap();
3190 let parsed: serde_json::Value = serde_json::from_str(&out).unwrap();
3191 assert_eq!(parsed["a"], 10);
3192 assert_eq!(parsed["c"], 30);
3193 }
3194
3195 #[test]
3200 fn test_json_remove_missing_key_no_change() {
3201 let out = json_remove(r#"{"a":1}"#, &["$.b"]).unwrap();
3202 assert_eq!(out, r#"{"a":1}"#);
3203 }
3204
3205 #[test]
3206 fn test_json_remove_multiple_paths() {
3207 let out = json_remove(r#"{"a":1,"b":2,"c":3}"#, &["$.a", "$.c"]).unwrap();
3208 assert_eq!(out, r#"{"b":2}"#);
3209 }
3210
3211 #[test]
3212 fn test_json_remove_from_end_index() {
3213 let out = json_remove("[1,2,3]", &["$[#-1]"]).unwrap();
3214 assert_eq!(out, "[1,2]");
3215 }
3216
3217 #[test]
3222 fn test_json_patch_non_object_replaces() {
3223 let out = json_patch(r#"{"a":1}"#, "42").unwrap();
3224 assert_eq!(out, "42");
3225 }
3226
3227 #[test]
3228 fn test_json_patch_nested_merge() {
3229 let out = json_patch(r#"{"a":{"b":1,"c":2}}"#, r#"{"a":{"b":10,"d":4}}"#).unwrap();
3230 let parsed: serde_json::Value = serde_json::from_str(&out).unwrap();
3231 assert_eq!(parsed["a"]["b"], 10);
3232 assert_eq!(parsed["a"]["c"], 2);
3233 assert_eq!(parsed["a"]["d"], 4);
3234 }
3235
3236 #[test]
3241 fn test_json_each_scalar() {
3242 let rows = json_each("42", None).unwrap();
3243 assert_eq!(rows.len(), 1);
3244 assert_eq!(rows[0].key, SqliteValue::Null);
3245 assert_eq!(rows[0].value, SqliteValue::Integer(42));
3246 assert_eq!(rows[0].type_name, "integer");
3247 }
3248
3249 #[test]
3250 fn test_json_each_empty_array() {
3251 let rows = json_each("[]", None).unwrap();
3252 assert!(rows.is_empty());
3253 }
3254
3255 #[test]
3256 fn test_json_each_empty_object() {
3257 let rows = json_each("{}", None).unwrap();
3258 assert!(rows.is_empty());
3259 }
3260
3261 #[test]
3262 fn test_json_each_missing_path() {
3263 let rows = json_each(r#"{"a":1}"#, Some("$.b")).unwrap();
3264 assert!(rows.is_empty());
3265 }
3266
3267 #[test]
3268 fn test_json_each_nested_value_is_json_text() {
3269 let rows = json_each(r#"{"a":[1,2]}"#, None).unwrap();
3270 assert_eq!(rows[0].value, SqliteValue::Text("[1,2]".to_owned()));
3271 assert_eq!(rows[0].atom, SqliteValue::Null); }
3273
3274 #[test]
3279 fn test_json_tree_scalar() {
3280 let rows = json_tree("42", None).unwrap();
3281 assert_eq!(rows.len(), 1);
3282 assert_eq!(rows[0].type_name, "integer");
3283 }
3284
3285 #[test]
3286 fn test_json_tree_empty_array() {
3287 let rows = json_tree("[]", None).unwrap();
3288 assert_eq!(rows.len(), 1);
3289 assert_eq!(rows[0].type_name, "array");
3290 }
3291
3292 #[test]
3293 fn test_json_tree_parent_ids() {
3294 let rows = json_tree(r#"{"a":1}"#, None).unwrap();
3295 assert_eq!(rows.len(), 2);
3296 assert_eq!(rows[0].parent, SqliteValue::Null); assert_eq!(rows[1].parent, SqliteValue::Integer(rows[0].id)); }
3299
3300 #[test]
3301 fn test_json_tree_missing_path() {
3302 let rows = json_tree(r#"{"a":1}"#, Some("$.b")).unwrap();
3303 assert!(rows.is_empty());
3304 }
3305
3306 #[test]
3311 fn test_jsonb_null() {
3312 let blob = jsonb("null").unwrap();
3313 assert_eq!(json_from_jsonb(&blob).unwrap(), "null");
3314 }
3315
3316 #[test]
3317 fn test_jsonb_booleans() {
3318 assert_eq!(json_from_jsonb(&jsonb("true").unwrap()).unwrap(), "true");
3319 assert_eq!(json_from_jsonb(&jsonb("false").unwrap()).unwrap(), "false");
3320 }
3321
3322 #[test]
3323 fn test_jsonb_integer() {
3324 let blob = jsonb("42").unwrap();
3325 assert_eq!(json_from_jsonb(&blob).unwrap(), "42");
3326 }
3327
3328 #[test]
3329 fn test_jsonb_float() {
3330 let blob = jsonb("3.14").unwrap();
3331 let text = json_from_jsonb(&blob).unwrap();
3332 assert!(text.starts_with("3.14"));
3333 }
3334
3335 #[test]
3336 fn test_jsonb_nested_array() {
3337 let blob = jsonb("[[1],[2,3]]").unwrap();
3338 assert_eq!(json_from_jsonb(&blob).unwrap(), "[[1],[2,3]]");
3339 }
3340
3341 #[test]
3342 fn test_jsonb_empty_string() {
3343 let blob = jsonb(r#""""#).unwrap();
3344 assert_eq!(json_from_jsonb(&blob).unwrap(), r#""""#);
3345 }
3346
3347 #[test]
3348 fn test_jsonb_extract_multiple_paths() {
3349 let blob = jsonb_extract(r#"{"a":1,"b":2}"#, &["$.a", "$.b"]).unwrap();
3350 assert_eq!(json_from_jsonb(&blob).unwrap(), "[1,2]");
3351 }
3352
3353 #[test]
3354 fn test_jsonb_extract_no_paths_error() {
3355 let empty: &[&str] = &[];
3356 assert!(jsonb_extract(r#"{"a":1}"#, empty).is_err());
3357 }
3358
3359 #[test]
3360 fn test_jsonb_decode_trailing_bytes() {
3361 let mut blob = jsonb("42").unwrap();
3362 blob.push(0xFF); assert!(json_from_jsonb(&blob).is_err());
3364 }
3365
3366 #[test]
3367 fn test_jsonb_decode_empty() {
3368 assert!(json_from_jsonb(&[]).is_err());
3369 }
3370
3371 #[test]
3376 fn test_path_invalid_no_dollar() {
3377 assert!(json_extract(r#"{"a":1}"#, &["a"]).is_err());
3378 }
3379
3380 #[test]
3381 fn test_path_empty_key_error() {
3382 assert!(json_extract(r#"{"a":1}"#, &["$."]).is_err());
3383 }
3384
3385 #[test]
3386 fn test_path_unclosed_bracket() {
3387 assert!(json_extract(r"[1,2]", &["$[0"]).is_err());
3388 }
3389
3390 #[test]
3391 fn test_path_from_end_zero_error() {
3392 assert!(json_extract("[1,2,3]", &["$[#-0]"]).is_err());
3393 }
3394
3395 #[test]
3396 fn test_path_from_end_beyond_length() {
3397 let result = json_extract("[1,2,3]", &["$[#-10]"]).unwrap();
3398 assert_eq!(result, SqliteValue::Null);
3399 }
3400
3401 #[test]
3406 fn test_json_group_object_non_text_key_error() {
3407 let err = json_group_object(&[(SqliteValue::Integer(1), SqliteValue::Integer(2))]);
3408 assert!(err.is_err());
3409 }
3410
3411 #[test]
3412 fn test_json_group_object_empty() {
3413 assert_eq!(json_group_object(&[]).unwrap(), "{}");
3414 }
3415
3416 #[test]
3421 fn test_json_array_empty() {
3422 assert_eq!(json_array(&[]).unwrap(), "[]");
3423 }
3424
3425 #[test]
3426 fn test_json_array_with_blob() {
3427 let out = json_array(&[SqliteValue::Blob(vec![0xCA, 0xFE])]).unwrap();
3428 assert_eq!(out, r#"["cafe"]"#);
3429 }
3430}