1use uqa_core::{jsonb_equality_key, DecimalValue, TemporalValue, Value};
10
11use crate::error::{Result, SQLError};
12
13use super::{hex_encode, out_of_range, value_to_string};
14
15mod path;
16
17pub(super) use path::{jsonpath_candidate, jsonpath_exists, jsonpath_match};
18
19pub(super) fn parse_json(s: &str) -> Result<serde_json::Value> {
20 serde_json::from_str::<serde_json::Value>(s)
21 .map_err(|_| super::json_strip::invalid_json_input(s))
22}
23
24pub(super) fn format_json(value: &serde_json::Value, jsonb: bool) -> String {
27 if !jsonb {
28 return serde_json::to_string(value).expect("serializing a JSON value cannot fail");
29 }
30 match value {
31 serde_json::Value::Null => "null".to_string(),
32 serde_json::Value::Bool(value) => value.to_string(),
33 serde_json::Value::Number(value) => {
34 let text = value.to_string();
35 DecimalValue::parse(&text).map_or(text, |value| value.to_sql_string())
36 }
37 serde_json::Value::String(value) => serde_json::Value::String(value.clone()).to_string(),
38 serde_json::Value::Array(values) => {
39 let values = values
40 .iter()
41 .map(|value| format_json(value, true))
42 .collect::<Vec<_>>();
43 format!("[{}]", values.join(", "))
44 }
45 serde_json::Value::Object(values) => {
46 let mut values = values.iter().collect::<Vec<_>>();
47 values.sort_by(|(left, _), (right, _)| {
48 left.len()
49 .cmp(&right.len())
50 .then_with(|| left.as_bytes().cmp(right.as_bytes()))
51 });
52 let values = values
53 .into_iter()
54 .map(|(key, value)| {
55 let key = serde_json::Value::String(key.clone()).to_string();
56 format!("{key}: {}", format_json(value, true))
57 })
58 .collect::<Vec<_>>();
59 format!("{{{}}}", values.join(", "))
60 }
61 }
62}
63
64pub(super) fn format_jsonb_pretty(value: &serde_json::Value) -> String {
65 format_jsonb_pretty_at_depth(value, 0)
66}
67
68fn format_jsonb_pretty_at_depth(value: &serde_json::Value, depth: usize) -> String {
69 let indent = " ".repeat(depth * 4);
70 let child_indent = " ".repeat((depth + 1) * 4);
71 match value {
72 serde_json::Value::Array(values) => {
73 if values.is_empty() {
74 return format!("[\n{indent}]");
75 }
76 let values = values
77 .iter()
78 .map(|value| {
79 format!(
80 "{child_indent}{}",
81 format_jsonb_pretty_at_depth(value, depth + 1)
82 )
83 })
84 .collect::<Vec<_>>();
85 format!("[\n{}\n{indent}]", values.join(",\n"))
86 }
87 serde_json::Value::Object(values) => {
88 if values.is_empty() {
89 return format!("{{\n{indent}}}");
90 }
91 let mut values = values.iter().collect::<Vec<_>>();
92 values.sort_by(|(left, _), (right, _)| {
93 left.len()
94 .cmp(&right.len())
95 .then_with(|| left.as_bytes().cmp(right.as_bytes()))
96 });
97 let values = values
98 .into_iter()
99 .map(|(key, value)| {
100 let key = serde_json::Value::String(key.clone()).to_string();
101 format!(
102 "{child_indent}{key}: {}",
103 format_jsonb_pretty_at_depth(value, depth + 1)
104 )
105 })
106 .collect::<Vec<_>>();
107 format!("{{\n{}\n{indent}}}", values.join(",\n"))
108 }
109 _ => format_json(value, true),
110 }
111}
112
113pub(super) fn typed_json_value(value: &serde_json::Value, jsonb: bool) -> Result<Value> {
114 if jsonb {
115 validate_jsonb_numbers(value)?;
116 }
117 let text = format_json(value, jsonb);
118 if jsonb {
119 Ok(Value::JsonB(text))
120 } else {
121 Ok(Value::Json(text))
122 }
123}
124
125fn validate_jsonb_numbers(value: &serde_json::Value) -> Result<()> {
126 match value {
127 serde_json::Value::Number(value) => DecimalValue::parse(&value.to_string())
128 .map(|_| ())
129 .ok_or_else(|| out_of_range("numeric")),
130 serde_json::Value::Array(values) => values.iter().try_for_each(validate_jsonb_numbers),
131 serde_json::Value::Object(values) => values.values().try_for_each(validate_jsonb_numbers),
132 _ => Ok(()),
133 }
134}
135
136pub fn value_to_json_text(value: &Value) -> String {
139 match value {
140 Value::Null => "null".to_string(),
141 Value::Void => "\"\"".to_string(),
142 Value::Bool(value) => value.to_string(),
143 Value::Int(value) => value.to_string(),
144 Value::Float(value) => match serde_json::Number::from_f64(*value) {
145 Some(number) => number.to_string(),
146 None if value.is_nan() => "\"NaN\"".to_string(),
147 None if value.is_sign_positive() => "\"Infinity\"".to_string(),
148 None => "\"-Infinity\"".to_string(),
149 },
150 Value::Decimal(value) => value.to_sql_string(),
151 Value::Str(value) => serde_json::Value::String(value.clone()).to_string(),
152 Value::FixedChar(value) => {
153 serde_json::Value::String(value.trim_end_matches(' ').to_string()).to_string()
154 }
155 Value::Bytes(value) => {
156 serde_json::Value::String(format!("0x{}", hex_encode(value))).to_string()
157 }
158 Value::Temporal(value) => serde_json::Value::String(value.to_sql_string()).to_string(),
159 Value::Json(text) | Value::JsonB(text) => text.clone(),
160 Value::Array(array) => {
161 let values = array
162 .elements()
163 .iter()
164 .map(value_to_json_text)
165 .collect::<Vec<_>>();
166 format!("[{}]", values.join(","))
167 }
168 Value::List(values) => {
169 let values = values.iter().map(value_to_json_text).collect::<Vec<_>>();
170 format!("[{}]", values.join(","))
171 }
172 Value::Row(values) => record_json_text(
173 values
174 .iter()
175 .enumerate()
176 .map(|(index, value)| (format!("f{}", index + 1), value)),
177 ),
178 Value::Record(fields) => {
179 record_json_text(fields.iter().map(|(name, value)| (name.clone(), value)))
180 }
181 Value::Map(values) => {
182 let values = values
183 .iter()
184 .map(|(key, value)| {
185 let key = serde_json::Value::String(key.clone()).to_string();
186 format!("{key}:{}", value_to_json_text(value))
187 })
188 .collect::<Vec<_>>();
189 format!("{{{}}}", values.join(","))
190 }
191 }
192}
193
194fn record_json_text<'a>(fields: impl IntoIterator<Item = (String, &'a Value)>) -> String {
195 let fields = fields
196 .into_iter()
197 .map(|(name, value)| {
198 let name = serde_json::Value::String(name).to_string();
199 format!("{name}:{}", value_to_json_text(value))
200 })
201 .collect::<Vec<_>>();
202 format!("{{{}}}", fields.join(","))
203}
204
205pub(super) fn json_build_array_value(args: &[Value], jsonb: bool) -> Result<Value> {
206 let text = format!(
207 "[{}]",
208 args.iter()
209 .map(value_to_json_text)
210 .collect::<Vec<_>>()
211 .join(", ")
212 );
213 if jsonb {
214 typed_json_value(&parse_json(&text)?, true)
215 } else {
216 Ok(Value::Json(text))
217 }
218}
219
220pub(super) fn json_build_object_value(args: &[Value], jsonb: bool) -> Result<Value> {
221 if !args.len().is_multiple_of(2) {
222 return Err(SQLError::TypeMismatch(
223 "json_build_object requires an even number of args".into(),
224 ));
225 }
226 let mut fields = Vec::with_capacity(args.len() / 2);
227 for pair in args.chunks_exact(2) {
228 if matches!(pair[0], Value::Null) {
229 return Err(SQLError::TypeMismatch(
230 "json_build_object key must not be NULL".into(),
231 ));
232 }
233 let key = serde_json::Value::String(value_to_string(&pair[0])).to_string();
234 fields.push(format!("{key} : {}", value_to_json_text(&pair[1])));
235 }
236 let text = format!("{{{}}}", fields.join(", "));
237 if jsonb {
238 typed_json_value(&parse_json(&text)?, true)
239 } else {
240 Ok(Value::Json(text))
241 }
242}
243
244pub(super) fn value_to_json(v: &Value) -> serde_json::Value {
245 match v {
246 Value::Null => serde_json::Value::Null,
247 Value::Void => serde_json::Value::String(String::new()),
248 Value::Bool(b) => serde_json::Value::Bool(*b),
249 Value::Int(i) => serde_json::Value::Number((*i).into()),
250 Value::Float(f) => serde_json::Number::from_f64(*f).map_or_else(
251 || {
252 let label = if f.is_nan() {
253 "NaN"
254 } else if f.is_sign_positive() {
255 "Infinity"
256 } else {
257 "-Infinity"
258 };
259 serde_json::Value::String(label.to_string())
260 },
261 serde_json::Value::Number,
262 ),
263 Value::Decimal(d) => {
264 if d.is_nan() || d.is_infinite() {
265 serde_json::Value::String(d.to_sql_string())
266 } else {
267 d.to_sql_string()
268 .parse::<serde_json::Number>()
269 .map(serde_json::Value::Number)
270 .unwrap_or_else(|_| serde_json::Value::String(d.to_sql_string()))
271 }
272 }
273 Value::Str(s) => serde_json::Value::String(s.clone()),
274 Value::FixedChar(s) => serde_json::Value::String(s.trim_end_matches(' ').to_string()),
275 Value::Bytes(b) => serde_json::Value::String(format!("0x{}", hex_encode(b))),
276 Value::Temporal(t) => serde_json::Value::String(t.to_sql_string()),
277 Value::Json(text) | Value::JsonB(text) => {
278 serde_json::from_str(text).unwrap_or_else(|_| serde_json::Value::String(text.clone()))
279 }
280 Value::Array(array) => {
281 serde_json::Value::Array(array.elements().iter().map(value_to_json).collect())
282 }
283 Value::List(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
284 Value::Row(values) => serde_json::Value::Object(
285 values
286 .iter()
287 .enumerate()
288 .map(|(index, value)| (format!("f{}", index + 1), value_to_json(value)))
289 .collect(),
290 ),
291 Value::Record(fields) => serde_json::Value::Object(
292 fields
293 .iter()
294 .map(|(name, value)| (name.clone(), value_to_json(value)))
295 .collect(),
296 ),
297 Value::Map(map) => {
298 let mut obj = serde_json::Map::new();
299 for (k, v) in map {
300 obj.insert(k.clone(), value_to_json(v));
301 }
302 serde_json::Value::Object(obj)
303 }
304 }
305}
306
307#[allow(dead_code)]
308pub(super) fn json_to_value(json: &serde_json::Value) -> Value {
309 match json {
310 serde_json::Value::Null => Value::Null,
311 serde_json::Value::Bool(b) => Value::Bool(*b),
312 serde_json::Value::Number(n) => {
313 if let Some(i) = n.as_i64() {
314 Value::Int(i)
315 } else if let Some(d) = DecimalValue::parse(&n.to_string()) {
316 Value::Decimal(d)
317 } else if let Some(f) = n.as_f64() {
318 Value::Float(f)
319 } else {
320 Value::Null
321 }
322 }
323 serde_json::Value::String(s) => Value::Str(s.clone()),
324 serde_json::Value::Array(arr) => Value::List(arr.iter().map(json_to_value).collect()),
325 serde_json::Value::Object(obj) => {
326 if let Ok(temporal) =
327 serde_json::from_value::<TemporalValue>(serde_json::Value::Object(obj.clone()))
328 {
329 return Value::Temporal(temporal);
330 }
331 let mut map = std::collections::BTreeMap::new();
332 for (k, v) in obj {
333 map.insert(k.clone(), json_to_value(v));
334 }
335 Value::Map(map)
336 }
337 }
338}
339
340pub(super) fn json_typeof(v: &serde_json::Value) -> &'static str {
341 match v {
342 serde_json::Value::Null => "null",
343 serde_json::Value::Bool(_) => "boolean",
344 serde_json::Value::Number(_) => "number",
345 serde_json::Value::String(_) => "string",
346 serde_json::Value::Array(_) => "array",
347 serde_json::Value::Object(_) => "object",
348 }
349}
350
351pub(super) fn json_extract_path(args: &[Value], as_text: bool, jsonb: bool) -> Result<Value> {
352 if args.len() < 2 {
353 return Err(SQLError::TypeMismatch(
354 "json_extract_path takes 2+ args".into(),
355 ));
356 }
357 let jsonb = jsonb || matches!(args[0], Value::JsonB(_));
358 let mut current = parse_json(&value_to_string(&args[0]))?;
359 for key in &args[1..] {
360 let key_str = value_to_string(key);
361 current = match current {
362 serde_json::Value::Object(mut obj) => {
363 obj.remove(&key_str).unwrap_or(serde_json::Value::Null)
364 }
365 serde_json::Value::Array(arr) => json_array_index(arr.len(), &key_str)
366 .and_then(|idx| arr.into_iter().nth(idx))
367 .unwrap_or(serde_json::Value::Null),
368 _ => serde_json::Value::Null,
369 };
370 }
371 if as_text {
372 Ok(Value::Str(match current {
373 serde_json::Value::String(s) => s,
374 serde_json::Value::Null => return Ok(Value::Null),
375 other => format_json(&other, jsonb),
376 }))
377 } else if matches!(current, serde_json::Value::Null) {
378 Ok(Value::Null)
379 } else {
380 typed_json_value(¤t, jsonb)
381 }
382}
383
384fn json_array_index(len: usize, key: &str) -> Option<usize> {
385 let index = key.parse::<i64>().ok()?;
386 let normalized = if index < 0 { len as i64 + index } else { index };
387 usize::try_from(normalized).ok().filter(|idx| *idx < len)
388}
389
390pub(super) fn json_contains(args: &[Value]) -> Result<Value> {
391 if args.len() != 2 {
392 return Err(SQLError::TypeMismatch("json_contains takes 2 args".into()));
393 }
394 let lhs = parse_json(&value_to_string(&args[0]))?;
395 let rhs = parse_json(&value_to_string(&args[1]))?;
396 Ok(Value::Bool(json_contains_value(&lhs, &rhs)))
397}
398
399pub(super) fn json_contained_by(args: &[Value]) -> Result<Value> {
400 if args.len() != 2 {
401 return Err(SQLError::TypeMismatch(
402 "json_contained_by takes 2 args".into(),
403 ));
404 }
405 let lhs = parse_json(&value_to_string(&args[0]))?;
406 let rhs = parse_json(&value_to_string(&args[1]))?;
407 Ok(Value::Bool(json_contains_value(&rhs, &lhs)))
408}
409
410fn json_contains_value(lhs: &serde_json::Value, rhs: &serde_json::Value) -> bool {
411 json_contains_value_at_depth(lhs, rhs, true)
412}
413
414fn json_contains_value_at_depth(
415 lhs: &serde_json::Value,
416 rhs: &serde_json::Value,
417 top_level: bool,
418) -> bool {
419 match (lhs, rhs) {
420 (serde_json::Value::Object(l), serde_json::Value::Object(r)) => r.iter().all(|(k, rv)| {
421 l.get(k)
422 .is_some_and(|lv| json_contains_value_at_depth(lv, rv, false))
423 }),
424 (serde_json::Value::Array(l), serde_json::Value::Array(r)) => r.iter().all(|rv| {
425 l.iter()
426 .any(|lv| json_contains_value_at_depth(lv, rv, false))
427 }),
428 (serde_json::Value::Array(l), r) if top_level && jsonb_is_primitive(r) => l
429 .iter()
430 .any(|lv| json_contains_value_at_depth(lv, r, false)),
431 _ => jsonb_values_equal(lhs, rhs),
432 }
433}
434
435fn jsonb_is_primitive(value: &serde_json::Value) -> bool {
436 !matches!(
437 value,
438 serde_json::Value::Array(_) | serde_json::Value::Object(_)
439 )
440}
441
442fn jsonb_values_equal(lhs: &serde_json::Value, rhs: &serde_json::Value) -> bool {
443 let lhs = serde_json::to_string(lhs).expect("serializing parsed JSON cannot fail");
444 let rhs = serde_json::to_string(rhs).expect("serializing parsed JSON cannot fail");
445 match (jsonb_equality_key(&lhs), jsonb_equality_key(&rhs)) {
446 (Some(lhs), Some(rhs)) => lhs == rhs,
447 _ => false,
448 }
449}
450
451pub(super) fn json_has_key(args: &[Value]) -> Result<Value> {
452 if args.len() != 2 {
453 return Err(SQLError::TypeMismatch("json_has_key takes 2 args".into()));
454 }
455 let obj = parse_json(&value_to_string(&args[0]))?;
456 let key = value_to_string(&args[1]);
457 Ok(Value::Bool(match obj {
458 serde_json::Value::Object(map) => map.contains_key(&key),
459 serde_json::Value::Array(items) => items
460 .iter()
461 .any(|item| matches!(item, serde_json::Value::String(value) if value == &key)),
462 _ => false,
463 }))
464}
465
466pub(super) fn json_has_keys(args: &[Value], require_all: bool) -> Result<Value> {
467 if args.len() != 2 {
468 return Err(SQLError::TypeMismatch("json_has_keys takes 2 args".into()));
469 }
470 let obj = parse_json(&value_to_string(&args[0]))?;
471 let keys = match &args[1] {
472 Value::Array(array) => array_strings(array.elements()),
473 Value::List(items) => array_strings(items),
474 other => {
475 return Err(SQLError::TypeMismatch(format!(
476 "json key list must be array, got {other:?}"
477 )));
478 }
479 };
480 let found = |key: &String| match &obj {
481 serde_json::Value::Object(map) => map.contains_key(key),
482 serde_json::Value::Array(items) => items
483 .iter()
484 .any(|item| matches!(item, serde_json::Value::String(value) if value == key)),
485 _ => false,
486 };
487 Ok(Value::Bool(if require_all {
488 keys.iter().all(found)
489 } else {
490 keys.iter().any(found)
491 }))
492}
493
494pub(super) fn json_concat(args: &[Value]) -> Result<Option<Value>> {
495 if args.len() != 2 {
496 return Err(SQLError::TypeMismatch("json_concat takes 2 args".into()));
497 }
498 if !args.iter().any(|arg| matches!(arg, Value::JsonB(_))) {
499 return Ok(None);
500 }
501 let lhs = value_to_json(&args[0]);
502 let rhs = value_to_json(&args[1]);
503 let out = match (lhs, rhs) {
504 (serde_json::Value::Object(mut left), serde_json::Value::Object(right)) => {
505 for (key, value) in right {
506 left.insert(key, value);
507 }
508 serde_json::Value::Object(left)
509 }
510 (serde_json::Value::Array(mut left), serde_json::Value::Array(right)) => {
511 left.extend(right);
512 serde_json::Value::Array(left)
513 }
514 (serde_json::Value::Array(mut left), right) => {
515 left.push(right);
516 serde_json::Value::Array(left)
517 }
518 (left, serde_json::Value::Array(mut right)) => {
519 let mut out = vec![left];
520 out.append(&mut right);
521 serde_json::Value::Array(out)
522 }
523 (left, right) => serde_json::Value::Array(vec![left, right]),
524 };
525 typed_json_value(&out, true).map(Some)
526}
527
528pub(super) fn json_delete(args: &[Value]) -> Result<Option<Value>> {
529 if args.len() != 2 {
530 return Err(SQLError::TypeMismatch("json_delete takes 2 args".into()));
531 }
532 if !matches!(args[0], Value::JsonB(_) | Value::Map(_) | Value::List(_)) {
533 return Ok(None);
534 }
535 let mut target = value_to_json(&args[0]);
536 match &args[1] {
537 Value::Int(index) => delete_array_index(&mut target, *index),
538 Value::Array(array) => {
539 for key in array_strings(array.elements()) {
540 delete_key_or_string(&mut target, &key);
541 }
542 }
543 Value::List(keys) => {
544 for key in array_strings(keys) {
545 delete_key_or_string(&mut target, &key);
546 }
547 }
548 key => delete_key_or_string(&mut target, &value_to_string(key)),
549 }
550 typed_json_value(&target, true).map(Some)
551}
552
553pub(super) fn json_delete_path(args: &[Value]) -> Result<Value> {
554 if args.len() != 2 {
555 return Err(SQLError::TypeMismatch(
556 "json_delete_path takes 2 args".into(),
557 ));
558 }
559 let mut target = value_to_json(&args[0]);
560 let path = path_arg(&args[1])?;
561 delete_path(&mut target, &path);
562 typed_json_value(&target, true)
563}
564
565fn path_arg(value: &Value) -> Result<Vec<String>> {
566 match value {
567 Value::Array(array) => Ok(array_strings(array.elements())),
568 Value::List(items) => Ok(array_strings(items)),
569 Value::Str(s) => Ok(s
570 .trim_matches(|c| c == '{' || c == '}')
571 .split(',')
572 .filter(|part| !part.is_empty())
573 .map(|part| part.trim().to_string())
574 .collect()),
575 other => Err(SQLError::TypeMismatch(format!(
576 "JSON path must be an array, got {other:?}"
577 ))),
578 }
579}
580
581fn array_strings(values: &[Value]) -> Vec<String> {
582 fn append(values: &[Value], output: &mut Vec<String>) {
583 for value in values {
584 if let Value::List(nested) = value {
585 append(nested, output);
586 } else {
587 output.push(value_to_string(value));
588 }
589 }
590 }
591
592 let mut output = Vec::new();
593 append(values, &mut output);
594 output
595}
596
597fn delete_key_or_string(target: &mut serde_json::Value, key: &str) {
598 match target {
599 serde_json::Value::Object(map) => {
600 map.remove(key);
601 }
602 serde_json::Value::Array(items) => {
603 items.retain(|item| !matches!(item, serde_json::Value::String(value) if value == key));
604 }
605 _ => {}
606 }
607}
608
609fn delete_array_index(target: &mut serde_json::Value, index: i64) {
610 let serde_json::Value::Array(items) = target else {
611 return;
612 };
613 let normalized = if index < 0 {
614 items.len() as i64 + index
615 } else {
616 index
617 };
618 if let Ok(index) = usize::try_from(normalized) {
619 if index < items.len() {
620 items.remove(index);
621 }
622 }
623}
624
625fn delete_path(target: &mut serde_json::Value, path: &[String]) {
626 let Some((head, rest)) = path.split_first() else {
627 return;
628 };
629 if rest.is_empty() {
630 match target {
631 serde_json::Value::Object(map) => {
632 map.remove(head);
633 }
634 serde_json::Value::Array(items) => {
635 if let Some(index) = json_array_index(items.len(), head) {
636 items.remove(index);
637 }
638 }
639 _ => {}
640 }
641 return;
642 }
643 match target {
644 serde_json::Value::Object(map) => {
645 if let Some(next) = map.get_mut(head) {
646 delete_path(next, rest);
647 }
648 }
649 serde_json::Value::Array(items) => {
650 if let Some(index) = json_array_index(items.len(), head) {
651 delete_path(&mut items[index], rest);
652 }
653 }
654 _ => {}
655 }
656}
657
658pub(super) fn jsonb_set(args: &[Value]) -> Result<Value> {
659 if !(3..=4).contains(&args.len()) {
660 return Err(SQLError::TypeMismatch("jsonb_set takes 3-4 args".into()));
661 }
662 let mut current = parse_json(&value_to_string(&args[0]))?;
663 let path = path_arg(&args[1])?;
664 let new_val = parse_json(&value_to_string(&args[2]))
665 .unwrap_or_else(|_| serde_json::Value::String(value_to_string(&args[2])));
666 let create_missing = args.get(3).is_none_or(|value| match value {
667 Value::Bool(value) => *value,
668 Value::Null => false,
669 other => value_to_string(other).eq_ignore_ascii_case("true"),
670 });
671 json_set_path(&mut current, &path, new_val, create_missing);
672 typed_json_value(¤t, true)
673}
674
675pub(super) fn jsonb_insert(args: &[Value]) -> Result<Value> {
676 if !(3..=4).contains(&args.len()) {
677 return Err(SQLError::TypeMismatch("jsonb_insert takes 3-4 args".into()));
678 }
679 let mut current = parse_json(&value_to_string(&args[0]))?;
680 let path = path_arg(&args[1])?;
681 let new_val = parse_json(&value_to_string(&args[2]))
682 .unwrap_or_else(|_| serde_json::Value::String(value_to_string(&args[2])));
683 let insert_after = args.get(3).is_some_and(|value| match value {
684 Value::Bool(value) => *value,
685 other => value_to_string(other).eq_ignore_ascii_case("true"),
686 });
687 json_insert_path(&mut current, &path, new_val, insert_after);
688 typed_json_value(¤t, true)
689}
690
691fn json_insert_path(
692 current: &mut serde_json::Value,
693 path: &[String],
694 new_val: serde_json::Value,
695 insert_after: bool,
696) -> bool {
697 let Some((head, rest)) = path.split_first() else {
698 return false;
699 };
700 if rest.is_empty() {
701 return match current {
702 serde_json::Value::Object(map) => {
703 if map.contains_key(head) {
704 false
705 } else {
706 map.insert(head.clone(), new_val);
707 true
708 }
709 }
710 serde_json::Value::Array(items) => {
711 let Some(index) = json_insert_index(items.len(), head, insert_after) else {
712 return false;
713 };
714 items.insert(index, new_val);
715 true
716 }
717 _ => false,
718 };
719 }
720 match current {
721 serde_json::Value::Object(map) => map
722 .get_mut(head)
723 .is_some_and(|next| json_insert_path(next, rest, new_val, insert_after)),
724 serde_json::Value::Array(items) => json_array_index(items.len(), head)
725 .is_some_and(|index| json_insert_path(&mut items[index], rest, new_val, insert_after)),
726 _ => false,
727 }
728}
729
730fn json_insert_index(len: usize, key: &str, insert_after: bool) -> Option<usize> {
731 let raw = key.parse::<i64>().ok()?;
732 let len_i64 = len as i64;
733 let index = if raw >= 0 {
734 if raw >= len_i64 {
735 len_i64
736 } else if insert_after {
737 raw + 1
738 } else {
739 raw
740 }
741 } else {
742 let normalized = len_i64 + raw;
743 if normalized < 0 {
744 0
745 } else if insert_after {
746 normalized + 1
747 } else {
748 normalized
749 }
750 };
751 usize::try_from(index.clamp(0, len_i64)).ok()
752}
753
754fn json_set_path(
755 current: &mut serde_json::Value,
756 path: &[String],
757 new_val: serde_json::Value,
758 create_missing: bool,
759) -> bool {
760 if path.is_empty() {
761 *current = new_val;
762 return true;
763 }
764 let head = &path[0];
765 let rest = &path[1..];
766 match current {
767 serde_json::Value::Object(obj) => {
768 if !obj.contains_key(head) && !create_missing {
769 return false;
770 }
771 let entry = obj.entry(head.clone()).or_insert(serde_json::Value::Null);
772 json_set_path(entry, rest, new_val, create_missing)
773 }
774 serde_json::Value::Array(arr) => {
775 if let Some(idx) = json_array_index(arr.len(), head) {
776 json_set_path(&mut arr[idx], rest, new_val, create_missing)
777 } else if create_missing && rest.is_empty() {
778 if let Ok(idx) = head.parse::<usize>() {
779 while arr.len() <= idx {
780 arr.push(serde_json::Value::Null);
781 }
782 arr[idx] = new_val;
783 true
784 } else {
785 false
786 }
787 } else {
788 false
789 }
790 }
791 _ if create_missing => {
792 let mut new_obj = serde_json::Map::new();
793 new_obj.insert(head.clone(), serde_json::Value::Null);
794 let mut wrapper = serde_json::Value::Object(new_obj);
795 let changed = json_set_path(&mut wrapper, path, new_val, create_missing);
796 if changed {
797 *current = wrapper;
798 }
799 changed
800 }
801 _ => false,
802 }
803}
804pub(super) fn strip_nulls(value: &mut serde_json::Value, strip_in_arrays: bool) {
805 match value {
806 serde_json::Value::Object(obj) => {
807 obj.retain(|_, v| !v.is_null());
808 for v in obj.values_mut() {
809 strip_nulls(v, strip_in_arrays);
810 }
811 }
812 serde_json::Value::Array(arr) => {
813 if strip_in_arrays {
814 arr.retain(|value| !value.is_null());
815 }
816 for v in arr.iter_mut() {
817 strip_nulls(v, strip_in_arrays);
818 }
819 }
820 _ => {}
821 }
822}
823
824#[cfg(test)]
825mod pretty_tests {
826 use super::{format_jsonb_pretty, parse_json, typed_json_value, DecimalValue};
827
828 #[test]
829 fn jsonb_pretty_uses_postgresql_layout_and_key_order() {
830 let value = parse_json(r#"{"zz":1,"b":[],"aa":{"long":3,"x":2}}"#).unwrap();
831 assert_eq!(
832 format_jsonb_pretty(&value),
833 "{\n \"b\": [\n ],\n \"aa\": {\n \"x\": 2,\n \"long\": 3\n },\n \"zz\": 1\n}"
834 );
835 assert_eq!(format_jsonb_pretty(&parse_json("[]").unwrap()), "[\n]");
836 assert_eq!(format_jsonb_pretty(&parse_json("{}").unwrap()), "{\n}");
837 assert_eq!(
838 format_jsonb_pretty(&parse_json("1e-1000").unwrap()),
839 DecimalValue::parse("1e-1000").unwrap().to_sql_string()
840 );
841 assert_eq!(format_jsonb_pretty(&parse_json("1.00").unwrap()), "1.00");
842 assert_eq!(format_jsonb_pretty(&parse_json("-0").unwrap()), "0");
843 }
844
845 #[test]
846 fn jsonb_rejects_numbers_outside_postgresql_numeric_range() {
847 let maximum = parse_json("1e131071").unwrap();
848 assert!(typed_json_value(&maximum, true).is_ok());
849
850 for text in ["1e131072", "1e-16384", "[1e131072]", r#"{"n":1e131072}"#] {
851 let error = typed_json_value(&parse_json(text).unwrap(), true).unwrap_err();
852 assert_eq!(error.sqlstate(), Some("22003"));
853 }
854
855 assert!(typed_json_value(&parse_json("1e200000").unwrap(), false).is_ok());
856 assert!(typed_json_value(&parse_json("0e200000").unwrap(), true).is_ok());
857 }
858}