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
15pub(super) fn parse_json(s: &str) -> Result<serde_json::Value> {
16 serde_json::from_str::<serde_json::Value>(s)
17 .map_err(|e| SQLError::TypeMismatch(format!("invalid JSON: {e}")))
18}
19
20pub(super) fn format_json(value: &serde_json::Value, jsonb: bool) -> String {
23 if !jsonb {
24 return serde_json::to_string(value).expect("serializing a JSON value cannot fail");
25 }
26 match value {
27 serde_json::Value::Null => "null".to_string(),
28 serde_json::Value::Bool(value) => value.to_string(),
29 serde_json::Value::Number(value) => {
30 let text = value.to_string();
31 DecimalValue::parse(&text).map_or(text, |value| value.to_sql_string())
32 }
33 serde_json::Value::String(value) => serde_json::Value::String(value.clone()).to_string(),
34 serde_json::Value::Array(values) => {
35 let values = values
36 .iter()
37 .map(|value| format_json(value, true))
38 .collect::<Vec<_>>();
39 format!("[{}]", values.join(", "))
40 }
41 serde_json::Value::Object(values) => {
42 let mut values = values.iter().collect::<Vec<_>>();
43 values.sort_by(|(left, _), (right, _)| {
44 left.len()
45 .cmp(&right.len())
46 .then_with(|| left.as_bytes().cmp(right.as_bytes()))
47 });
48 let values = values
49 .into_iter()
50 .map(|(key, value)| {
51 let key = serde_json::Value::String(key.clone()).to_string();
52 format!("{key}: {}", format_json(value, true))
53 })
54 .collect::<Vec<_>>();
55 format!("{{{}}}", values.join(", "))
56 }
57 }
58}
59
60pub(super) fn format_jsonb_pretty(value: &serde_json::Value) -> String {
61 format_jsonb_pretty_at_depth(value, 0)
62}
63
64fn format_jsonb_pretty_at_depth(value: &serde_json::Value, depth: usize) -> String {
65 let indent = " ".repeat(depth * 4);
66 let child_indent = " ".repeat((depth + 1) * 4);
67 match value {
68 serde_json::Value::Array(values) => {
69 if values.is_empty() {
70 return format!("[\n{indent}]");
71 }
72 let values = values
73 .iter()
74 .map(|value| {
75 format!(
76 "{child_indent}{}",
77 format_jsonb_pretty_at_depth(value, depth + 1)
78 )
79 })
80 .collect::<Vec<_>>();
81 format!("[\n{}\n{indent}]", values.join(",\n"))
82 }
83 serde_json::Value::Object(values) => {
84 if values.is_empty() {
85 return format!("{{\n{indent}}}");
86 }
87 let mut values = values.iter().collect::<Vec<_>>();
88 values.sort_by(|(left, _), (right, _)| {
89 left.len()
90 .cmp(&right.len())
91 .then_with(|| left.as_bytes().cmp(right.as_bytes()))
92 });
93 let values = values
94 .into_iter()
95 .map(|(key, value)| {
96 let key = serde_json::Value::String(key.clone()).to_string();
97 format!(
98 "{child_indent}{key}: {}",
99 format_jsonb_pretty_at_depth(value, depth + 1)
100 )
101 })
102 .collect::<Vec<_>>();
103 format!("{{\n{}\n{indent}}}", values.join(",\n"))
104 }
105 _ => format_json(value, true),
106 }
107}
108
109pub(super) fn typed_json_value(value: &serde_json::Value, jsonb: bool) -> Result<Value> {
110 if jsonb {
111 validate_jsonb_numbers(value)?;
112 }
113 let text = format_json(value, jsonb);
114 if jsonb {
115 Ok(Value::JsonB(text))
116 } else {
117 Ok(Value::Json(text))
118 }
119}
120
121fn validate_jsonb_numbers(value: &serde_json::Value) -> Result<()> {
122 match value {
123 serde_json::Value::Number(value) => DecimalValue::parse(&value.to_string())
124 .map(|_| ())
125 .ok_or_else(|| out_of_range("numeric")),
126 serde_json::Value::Array(values) => values.iter().try_for_each(validate_jsonb_numbers),
127 serde_json::Value::Object(values) => values.values().try_for_each(validate_jsonb_numbers),
128 _ => Ok(()),
129 }
130}
131
132pub fn value_to_json_text(value: &Value) -> String {
135 match value {
136 Value::Null => "null".to_string(),
137 Value::Bool(value) => value.to_string(),
138 Value::Int(value) => value.to_string(),
139 Value::Float(value) => match serde_json::Number::from_f64(*value) {
140 Some(number) => number.to_string(),
141 None if value.is_nan() => "\"NaN\"".to_string(),
142 None if value.is_sign_positive() => "\"Infinity\"".to_string(),
143 None => "\"-Infinity\"".to_string(),
144 },
145 Value::Decimal(value) => value.to_sql_string(),
146 Value::Str(value) => serde_json::Value::String(value.clone()).to_string(),
147 Value::FixedChar(value) => {
148 serde_json::Value::String(value.trim_end_matches(' ').to_string()).to_string()
149 }
150 Value::Bytes(value) => {
151 serde_json::Value::String(format!("0x{}", hex_encode(value))).to_string()
152 }
153 Value::Temporal(value) => serde_json::Value::String(value.to_sql_string()).to_string(),
154 Value::Json(text) | Value::JsonB(text) => text.clone(),
155 Value::Array(array) => {
156 let values = array
157 .elements()
158 .iter()
159 .map(value_to_json_text)
160 .collect::<Vec<_>>();
161 format!("[{}]", values.join(","))
162 }
163 Value::List(values) => {
164 let values = values.iter().map(value_to_json_text).collect::<Vec<_>>();
165 format!("[{}]", values.join(","))
166 }
167 Value::Row(values) => record_json_text(
168 values
169 .iter()
170 .enumerate()
171 .map(|(index, value)| (format!("f{}", index + 1), value)),
172 ),
173 Value::Record(fields) => {
174 record_json_text(fields.iter().map(|(name, value)| (name.clone(), value)))
175 }
176 Value::Map(values) => {
177 let values = values
178 .iter()
179 .map(|(key, value)| {
180 let key = serde_json::Value::String(key.clone()).to_string();
181 format!("{key}:{}", value_to_json_text(value))
182 })
183 .collect::<Vec<_>>();
184 format!("{{{}}}", values.join(","))
185 }
186 }
187}
188
189fn record_json_text<'a>(fields: impl IntoIterator<Item = (String, &'a Value)>) -> String {
190 let fields = fields
191 .into_iter()
192 .map(|(name, value)| {
193 let name = serde_json::Value::String(name).to_string();
194 format!("{name}:{}", value_to_json_text(value))
195 })
196 .collect::<Vec<_>>();
197 format!("{{{}}}", fields.join(","))
198}
199
200pub(super) fn json_build_array_value(args: &[Value], jsonb: bool) -> Result<Value> {
201 let text = format!(
202 "[{}]",
203 args.iter()
204 .map(value_to_json_text)
205 .collect::<Vec<_>>()
206 .join(", ")
207 );
208 if jsonb {
209 typed_json_value(&parse_json(&text)?, true)
210 } else {
211 Ok(Value::Json(text))
212 }
213}
214
215pub(super) fn json_build_object_value(args: &[Value], jsonb: bool) -> Result<Value> {
216 if !args.len().is_multiple_of(2) {
217 return Err(SQLError::TypeMismatch(
218 "json_build_object requires an even number of args".into(),
219 ));
220 }
221 let mut fields = Vec::with_capacity(args.len() / 2);
222 for pair in args.chunks_exact(2) {
223 if matches!(pair[0], Value::Null) {
224 return Err(SQLError::TypeMismatch(
225 "json_build_object key must not be NULL".into(),
226 ));
227 }
228 let key = serde_json::Value::String(value_to_string(&pair[0])).to_string();
229 fields.push(format!("{key} : {}", value_to_json_text(&pair[1])));
230 }
231 let text = format!("{{{}}}", fields.join(", "));
232 if jsonb {
233 typed_json_value(&parse_json(&text)?, true)
234 } else {
235 Ok(Value::Json(text))
236 }
237}
238
239pub(super) fn value_to_json(v: &Value) -> serde_json::Value {
240 match v {
241 Value::Null => serde_json::Value::Null,
242 Value::Bool(b) => serde_json::Value::Bool(*b),
243 Value::Int(i) => serde_json::Value::Number((*i).into()),
244 Value::Float(f) => serde_json::Number::from_f64(*f).map_or_else(
245 || {
246 let label = if f.is_nan() {
247 "NaN"
248 } else if f.is_sign_positive() {
249 "Infinity"
250 } else {
251 "-Infinity"
252 };
253 serde_json::Value::String(label.to_string())
254 },
255 serde_json::Value::Number,
256 ),
257 Value::Decimal(d) => {
258 if d.is_nan() || d.is_infinite() {
259 serde_json::Value::String(d.to_sql_string())
260 } else {
261 d.to_sql_string()
262 .parse::<serde_json::Number>()
263 .map(serde_json::Value::Number)
264 .unwrap_or_else(|_| serde_json::Value::String(d.to_sql_string()))
265 }
266 }
267 Value::Str(s) => serde_json::Value::String(s.clone()),
268 Value::FixedChar(s) => serde_json::Value::String(s.trim_end_matches(' ').to_string()),
269 Value::Bytes(b) => serde_json::Value::String(format!("0x{}", hex_encode(b))),
270 Value::Temporal(t) => serde_json::Value::String(t.to_sql_string()),
271 Value::Json(text) | Value::JsonB(text) => {
272 serde_json::from_str(text).unwrap_or_else(|_| serde_json::Value::String(text.clone()))
273 }
274 Value::Array(array) => {
275 serde_json::Value::Array(array.elements().iter().map(value_to_json).collect())
276 }
277 Value::List(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
278 Value::Row(values) => serde_json::Value::Object(
279 values
280 .iter()
281 .enumerate()
282 .map(|(index, value)| (format!("f{}", index + 1), value_to_json(value)))
283 .collect(),
284 ),
285 Value::Record(fields) => serde_json::Value::Object(
286 fields
287 .iter()
288 .map(|(name, value)| (name.clone(), value_to_json(value)))
289 .collect(),
290 ),
291 Value::Map(map) => {
292 let mut obj = serde_json::Map::new();
293 for (k, v) in map {
294 obj.insert(k.clone(), value_to_json(v));
295 }
296 serde_json::Value::Object(obj)
297 }
298 }
299}
300
301#[allow(dead_code)]
302pub(super) fn json_to_value(json: &serde_json::Value) -> Value {
303 match json {
304 serde_json::Value::Null => Value::Null,
305 serde_json::Value::Bool(b) => Value::Bool(*b),
306 serde_json::Value::Number(n) => {
307 if let Some(i) = n.as_i64() {
308 Value::Int(i)
309 } else if let Some(d) = DecimalValue::parse(&n.to_string()) {
310 Value::Decimal(d)
311 } else if let Some(f) = n.as_f64() {
312 Value::Float(f)
313 } else {
314 Value::Null
315 }
316 }
317 serde_json::Value::String(s) => Value::Str(s.clone()),
318 serde_json::Value::Array(arr) => Value::List(arr.iter().map(json_to_value).collect()),
319 serde_json::Value::Object(obj) => {
320 if let Ok(temporal) =
321 serde_json::from_value::<TemporalValue>(serde_json::Value::Object(obj.clone()))
322 {
323 return Value::Temporal(temporal);
324 }
325 let mut map = std::collections::BTreeMap::new();
326 for (k, v) in obj {
327 map.insert(k.clone(), json_to_value(v));
328 }
329 Value::Map(map)
330 }
331 }
332}
333
334pub(super) fn json_typeof(v: &serde_json::Value) -> &'static str {
335 match v {
336 serde_json::Value::Null => "null",
337 serde_json::Value::Bool(_) => "boolean",
338 serde_json::Value::Number(_) => "number",
339 serde_json::Value::String(_) => "string",
340 serde_json::Value::Array(_) => "array",
341 serde_json::Value::Object(_) => "object",
342 }
343}
344
345pub(super) fn json_extract_path(args: &[Value], as_text: bool, jsonb: bool) -> Result<Value> {
346 if args.len() < 2 {
347 return Err(SQLError::TypeMismatch(
348 "json_extract_path takes 2+ args".into(),
349 ));
350 }
351 let jsonb = jsonb || matches!(args[0], Value::JsonB(_));
352 let mut current = parse_json(&value_to_string(&args[0]))?;
353 for key in &args[1..] {
354 let key_str = value_to_string(key);
355 current = match current {
356 serde_json::Value::Object(mut obj) => {
357 obj.remove(&key_str).unwrap_or(serde_json::Value::Null)
358 }
359 serde_json::Value::Array(arr) => json_array_index(arr.len(), &key_str)
360 .and_then(|idx| arr.into_iter().nth(idx))
361 .unwrap_or(serde_json::Value::Null),
362 _ => serde_json::Value::Null,
363 };
364 }
365 if as_text {
366 Ok(Value::Str(match current {
367 serde_json::Value::String(s) => s,
368 serde_json::Value::Null => return Ok(Value::Null),
369 other => format_json(&other, jsonb),
370 }))
371 } else if matches!(current, serde_json::Value::Null) {
372 Ok(Value::Null)
373 } else {
374 typed_json_value(¤t, jsonb)
375 }
376}
377
378fn json_array_index(len: usize, key: &str) -> Option<usize> {
379 let index = key.parse::<i64>().ok()?;
380 let normalized = if index < 0 { len as i64 + index } else { index };
381 usize::try_from(normalized).ok().filter(|idx| *idx < len)
382}
383
384pub(super) fn json_contains(args: &[Value]) -> Result<Value> {
385 if args.len() != 2 {
386 return Err(SQLError::TypeMismatch("json_contains takes 2 args".into()));
387 }
388 let lhs = parse_json(&value_to_string(&args[0]))?;
389 let rhs = parse_json(&value_to_string(&args[1]))?;
390 Ok(Value::Bool(json_contains_value(&lhs, &rhs)))
391}
392
393pub(super) fn json_contained_by(args: &[Value]) -> Result<Value> {
394 if args.len() != 2 {
395 return Err(SQLError::TypeMismatch(
396 "json_contained_by takes 2 args".into(),
397 ));
398 }
399 let lhs = parse_json(&value_to_string(&args[0]))?;
400 let rhs = parse_json(&value_to_string(&args[1]))?;
401 Ok(Value::Bool(json_contains_value(&rhs, &lhs)))
402}
403
404fn json_contains_value(lhs: &serde_json::Value, rhs: &serde_json::Value) -> bool {
405 json_contains_value_at_depth(lhs, rhs, true)
406}
407
408fn json_contains_value_at_depth(
409 lhs: &serde_json::Value,
410 rhs: &serde_json::Value,
411 top_level: bool,
412) -> bool {
413 match (lhs, rhs) {
414 (serde_json::Value::Object(l), serde_json::Value::Object(r)) => r.iter().all(|(k, rv)| {
415 l.get(k)
416 .is_some_and(|lv| json_contains_value_at_depth(lv, rv, false))
417 }),
418 (serde_json::Value::Array(l), serde_json::Value::Array(r)) => r.iter().all(|rv| {
419 l.iter()
420 .any(|lv| json_contains_value_at_depth(lv, rv, false))
421 }),
422 (serde_json::Value::Array(l), r) if top_level && jsonb_is_primitive(r) => l
423 .iter()
424 .any(|lv| json_contains_value_at_depth(lv, r, false)),
425 _ => jsonb_values_equal(lhs, rhs),
426 }
427}
428
429fn jsonb_is_primitive(value: &serde_json::Value) -> bool {
430 !matches!(
431 value,
432 serde_json::Value::Array(_) | serde_json::Value::Object(_)
433 )
434}
435
436fn jsonb_values_equal(lhs: &serde_json::Value, rhs: &serde_json::Value) -> bool {
437 let lhs = serde_json::to_string(lhs).expect("serializing parsed JSON cannot fail");
438 let rhs = serde_json::to_string(rhs).expect("serializing parsed JSON cannot fail");
439 match (jsonb_equality_key(&lhs), jsonb_equality_key(&rhs)) {
440 (Some(lhs), Some(rhs)) => lhs == rhs,
441 _ => false,
442 }
443}
444
445pub(super) fn json_has_key(args: &[Value]) -> Result<Value> {
446 if args.len() != 2 {
447 return Err(SQLError::TypeMismatch("json_has_key takes 2 args".into()));
448 }
449 let obj = parse_json(&value_to_string(&args[0]))?;
450 let key = value_to_string(&args[1]);
451 Ok(Value::Bool(match obj {
452 serde_json::Value::Object(map) => map.contains_key(&key),
453 serde_json::Value::Array(items) => items
454 .iter()
455 .any(|item| matches!(item, serde_json::Value::String(value) if value == &key)),
456 _ => false,
457 }))
458}
459
460pub(super) fn json_has_keys(args: &[Value], require_all: bool) -> Result<Value> {
461 if args.len() != 2 {
462 return Err(SQLError::TypeMismatch("json_has_keys takes 2 args".into()));
463 }
464 let obj = parse_json(&value_to_string(&args[0]))?;
465 let keys = match &args[1] {
466 Value::Array(array) => array_strings(array.elements()),
467 Value::List(items) => array_strings(items),
468 other => {
469 return Err(SQLError::TypeMismatch(format!(
470 "json key list must be array, got {other:?}"
471 )));
472 }
473 };
474 let found = |key: &String| match &obj {
475 serde_json::Value::Object(map) => map.contains_key(key),
476 serde_json::Value::Array(items) => items
477 .iter()
478 .any(|item| matches!(item, serde_json::Value::String(value) if value == key)),
479 _ => false,
480 };
481 Ok(Value::Bool(if require_all {
482 keys.iter().all(found)
483 } else {
484 keys.iter().any(found)
485 }))
486}
487
488pub(super) fn jsonpath_exists(args: &[Value]) -> Result<Value> {
489 if args.len() < 2 {
490 return Err(SQLError::TypeMismatch(
491 "jsonpath_exists takes at least 2 args".into(),
492 ));
493 }
494 let root = parse_json(&value_to_string(&args[0]))?;
495 let path = value_to_string(&args[1]);
496 Ok(Value::Bool(jsonpath_exists_value(&root, &path)?))
497}
498
499pub(super) fn jsonpath_match(args: &[Value]) -> Result<Value> {
500 if args.len() < 2 {
501 return Err(SQLError::TypeMismatch(
502 "jsonpath_match takes at least 2 args".into(),
503 ));
504 }
505 let root = parse_json(&value_to_string(&args[0]))?;
506 let path = value_to_string(&args[1]);
507 Ok(Value::Bool(jsonpath_match_value(&root, &path)?))
508}
509
510pub(super) fn jsonpath_candidate(args: &[Value]) -> bool {
511 matches!(args.get(1), Some(Value::Str(path)) if path.trim_start().starts_with('$'))
512 && matches!(
513 args.first(),
514 Some(Value::Json(_) | Value::JsonB(_) | Value::Map(_) | Value::List(_))
515 )
516}
517
518fn jsonpath_exists_value(root: &serde_json::Value, path: &str) -> Result<bool> {
519 let path = normalize_jsonpath(path);
520 let (selector, filter) = split_jsonpath_filter(&path);
521 let values = jsonpath_select(root, selector)?;
522 let Some(filter) = filter else {
523 return Ok(!values.is_empty());
524 };
525 for value in values {
526 if eval_jsonpath_predicate(root, &value, filter)? {
527 return Ok(true);
528 }
529 }
530 Ok(false)
531}
532
533fn jsonpath_match_value(root: &serde_json::Value, path: &str) -> Result<bool> {
534 let path = normalize_jsonpath(path);
535 if let Some((left, op, right)) = split_jsonpath_comparison(&path) {
536 let values = if left == "@" {
537 vec![root.clone()]
538 } else {
539 jsonpath_select(root, left)?
540 };
541 let rhs = parse_jsonpath_literal(right)?;
542 return Ok(values
543 .iter()
544 .any(|value| compare_jsonpath_values(value, &rhs, op)));
545 }
546 let values = jsonpath_select(root, &path)?;
547 Ok(values
548 .first()
549 .is_some_and(|value| matches!(value, serde_json::Value::Bool(true))))
550}
551
552fn normalize_jsonpath(path: &str) -> String {
553 let path = path.trim();
554 path.strip_prefix("strict ")
555 .or_else(|| path.strip_prefix("lax "))
556 .unwrap_or(path)
557 .trim()
558 .to_string()
559}
560
561fn split_jsonpath_filter(path: &str) -> (&str, Option<&str>) {
562 let Some(pos) = path.find('?') else {
563 return (path.trim(), None);
564 };
565 let selector = path[..pos].trim();
566 let filter = path[pos + 1..].trim();
567 (selector, Some(strip_wrapping_parens(filter)))
568}
569
570fn strip_wrapping_parens(input: &str) -> &str {
571 let input = input.trim();
572 if input.starts_with('(') && input.ends_with(')') {
573 input[1..input.len() - 1].trim()
574 } else {
575 input
576 }
577}
578
579fn jsonpath_select(root: &serde_json::Value, selector: &str) -> Result<Vec<serde_json::Value>> {
580 let mut rest = selector.trim();
581 if rest == "$" {
582 return Ok(vec![root.clone()]);
583 }
584 let Some(after_root) = rest.strip_prefix('$') else {
585 return Err(SQLError::TypeMismatch(format!(
586 "jsonpath selector must start with $, got {selector:?}"
587 )));
588 };
589 rest = after_root;
590 let mut current = vec![root.clone()];
591 while !rest.is_empty() {
592 if let Some(next) = rest.strip_prefix('.') {
593 let (key, after_key) = take_jsonpath_key(next)?;
594 current = current
595 .into_iter()
596 .filter_map(|value| match value {
597 serde_json::Value::Object(map) => map.get(key).cloned(),
598 _ => None,
599 })
600 .collect();
601 rest = after_key;
602 } else if let Some(next) = rest.strip_prefix("[*]") {
603 current = current
604 .into_iter()
605 .flat_map(|value| match value {
606 serde_json::Value::Array(items) => items,
607 _ => Vec::new(),
608 })
609 .collect();
610 rest = next;
611 } else if let Some(next) = rest.strip_prefix('[') {
612 let Some(end) = next.find(']') else {
613 return Err(SQLError::TypeMismatch(format!(
614 "unterminated jsonpath array index in {selector:?}"
615 )));
616 };
617 let index = &next[..end];
618 current = current
619 .into_iter()
620 .filter_map(|value| match value {
621 serde_json::Value::Array(items) => {
622 json_array_index(items.len(), index).and_then(|idx| items.get(idx).cloned())
623 }
624 _ => None,
625 })
626 .collect();
627 rest = &next[end + 1..];
628 } else {
629 return Err(SQLError::TypeMismatch(format!(
630 "unsupported jsonpath selector tail {rest:?}"
631 )));
632 }
633 }
634 Ok(current)
635}
636
637fn take_jsonpath_key(input: &str) -> Result<(&str, &str)> {
638 if let Some(quoted) = input.strip_prefix('"') {
639 let Some(end) = quoted.find('"') else {
640 return Err(SQLError::TypeMismatch(
641 "unterminated quoted jsonpath key".into(),
642 ));
643 };
644 return Ok(("ed[..end], "ed[end + 1..]));
645 }
646 let end = input
647 .find(|ch: char| !(ch == '_' || ch.is_ascii_alphanumeric()))
648 .unwrap_or(input.len());
649 if end == 0 {
650 return Err(SQLError::TypeMismatch(format!(
651 "expected jsonpath key in {input:?}"
652 )));
653 }
654 Ok((&input[..end], &input[end..]))
655}
656
657fn eval_jsonpath_predicate(
658 root: &serde_json::Value,
659 current: &serde_json::Value,
660 predicate: &str,
661) -> Result<bool> {
662 if let Some((left, op, right)) = split_jsonpath_comparison(predicate) {
663 let values = if left == "@" {
664 vec![current.clone()]
665 } else if let Some(selector) = left.strip_prefix('@') {
666 jsonpath_select(current, &format!("${selector}"))?
667 } else {
668 jsonpath_select(root, left)?
669 };
670 let rhs = parse_jsonpath_literal(right)?;
671 return Ok(values
672 .iter()
673 .any(|value| compare_jsonpath_values(value, &rhs, op)));
674 }
675 let values = if predicate == "@" {
676 vec![current.clone()]
677 } else {
678 jsonpath_select(root, predicate)?
679 };
680 Ok(!values.is_empty())
681}
682
683fn split_jsonpath_comparison(input: &str) -> Option<(&str, &'static str, &str)> {
684 for op in ["==", "!=", ">=", "<=", ">", "<"] {
685 if let Some(pos) = input.find(op) {
686 return Some((input[..pos].trim(), op, input[pos + op.len()..].trim()));
687 }
688 }
689 None
690}
691
692fn parse_jsonpath_literal(input: &str) -> Result<serde_json::Value> {
693 let input = input.trim();
694 if let Ok(value) = serde_json::from_str::<serde_json::Value>(input) {
695 return Ok(value);
696 }
697 if input.starts_with('"') && input.ends_with('"') {
698 return Ok(serde_json::Value::String(
699 input[1..input.len() - 1].to_string(),
700 ));
701 }
702 Err(SQLError::TypeMismatch(format!(
703 "unsupported jsonpath literal {input:?}"
704 )))
705}
706
707fn compare_jsonpath_values(lhs: &serde_json::Value, rhs: &serde_json::Value, op: &str) -> bool {
708 match (lhs, rhs) {
709 (serde_json::Value::Number(left), serde_json::Value::Number(right)) => {
710 let Some(left) = left.as_f64() else {
711 return false;
712 };
713 let Some(right) = right.as_f64() else {
714 return false;
715 };
716 compare_f64(left, right, op)
717 }
718 (serde_json::Value::String(left), serde_json::Value::String(right)) => {
719 compare_ordering(left.cmp(right), op)
720 }
721 (serde_json::Value::Bool(left), serde_json::Value::Bool(right)) => {
722 compare_ordering(left.cmp(right), op)
723 }
724 (serde_json::Value::Null, serde_json::Value::Null) => matches!(op, "==" | ">=" | "<="),
725 _ => matches!(op, "!="),
726 }
727}
728
729fn compare_f64(left: f64, right: f64, op: &str) -> bool {
730 match op {
731 "==" => left == right,
732 "!=" => left != right,
733 ">" => left > right,
734 ">=" => left >= right,
735 "<" => left < right,
736 "<=" => left <= right,
737 _ => false,
738 }
739}
740
741fn compare_ordering(ordering: std::cmp::Ordering, op: &str) -> bool {
742 match op {
743 "==" => ordering.is_eq(),
744 "!=" => !ordering.is_eq(),
745 ">" => ordering.is_gt(),
746 ">=" => ordering.is_ge(),
747 "<" => ordering.is_lt(),
748 "<=" => ordering.is_le(),
749 _ => false,
750 }
751}
752
753pub(super) fn json_concat(args: &[Value]) -> Result<Option<Value>> {
754 if args.len() != 2 {
755 return Err(SQLError::TypeMismatch("json_concat takes 2 args".into()));
756 }
757 if !args.iter().any(|arg| matches!(arg, Value::JsonB(_))) {
758 return Ok(None);
759 }
760 let lhs = value_to_json(&args[0]);
761 let rhs = value_to_json(&args[1]);
762 let out = match (lhs, rhs) {
763 (serde_json::Value::Object(mut left), serde_json::Value::Object(right)) => {
764 for (key, value) in right {
765 left.insert(key, value);
766 }
767 serde_json::Value::Object(left)
768 }
769 (serde_json::Value::Array(mut left), serde_json::Value::Array(right)) => {
770 left.extend(right);
771 serde_json::Value::Array(left)
772 }
773 (serde_json::Value::Array(mut left), right) => {
774 left.push(right);
775 serde_json::Value::Array(left)
776 }
777 (left, serde_json::Value::Array(mut right)) => {
778 let mut out = vec![left];
779 out.append(&mut right);
780 serde_json::Value::Array(out)
781 }
782 (left, right) => serde_json::Value::Array(vec![left, right]),
783 };
784 typed_json_value(&out, true).map(Some)
785}
786
787pub(super) fn json_delete(args: &[Value]) -> Result<Option<Value>> {
788 if args.len() != 2 {
789 return Err(SQLError::TypeMismatch("json_delete takes 2 args".into()));
790 }
791 if !matches!(args[0], Value::JsonB(_) | Value::Map(_) | Value::List(_)) {
792 return Ok(None);
793 }
794 let mut target = value_to_json(&args[0]);
795 match &args[1] {
796 Value::Int(index) => delete_array_index(&mut target, *index),
797 Value::Array(array) => {
798 for key in array_strings(array.elements()) {
799 delete_key_or_string(&mut target, &key);
800 }
801 }
802 Value::List(keys) => {
803 for key in array_strings(keys) {
804 delete_key_or_string(&mut target, &key);
805 }
806 }
807 key => delete_key_or_string(&mut target, &value_to_string(key)),
808 }
809 typed_json_value(&target, true).map(Some)
810}
811
812pub(super) fn json_delete_path(args: &[Value]) -> Result<Value> {
813 if args.len() != 2 {
814 return Err(SQLError::TypeMismatch(
815 "json_delete_path takes 2 args".into(),
816 ));
817 }
818 let mut target = value_to_json(&args[0]);
819 let path = path_arg(&args[1])?;
820 delete_path(&mut target, &path);
821 typed_json_value(&target, true)
822}
823
824fn path_arg(value: &Value) -> Result<Vec<String>> {
825 match value {
826 Value::Array(array) => Ok(array_strings(array.elements())),
827 Value::List(items) => Ok(array_strings(items)),
828 Value::Str(s) => Ok(s
829 .trim_matches(|c| c == '{' || c == '}')
830 .split(',')
831 .filter(|part| !part.is_empty())
832 .map(|part| part.trim().to_string())
833 .collect()),
834 other => Err(SQLError::TypeMismatch(format!(
835 "JSON path must be an array, got {other:?}"
836 ))),
837 }
838}
839
840fn array_strings(values: &[Value]) -> Vec<String> {
841 fn append(values: &[Value], output: &mut Vec<String>) {
842 for value in values {
843 if let Value::List(nested) = value {
844 append(nested, output);
845 } else {
846 output.push(value_to_string(value));
847 }
848 }
849 }
850
851 let mut output = Vec::new();
852 append(values, &mut output);
853 output
854}
855
856fn delete_key_or_string(target: &mut serde_json::Value, key: &str) {
857 match target {
858 serde_json::Value::Object(map) => {
859 map.remove(key);
860 }
861 serde_json::Value::Array(items) => {
862 items.retain(|item| !matches!(item, serde_json::Value::String(value) if value == key));
863 }
864 _ => {}
865 }
866}
867
868fn delete_array_index(target: &mut serde_json::Value, index: i64) {
869 let serde_json::Value::Array(items) = target else {
870 return;
871 };
872 let normalized = if index < 0 {
873 items.len() as i64 + index
874 } else {
875 index
876 };
877 if let Ok(index) = usize::try_from(normalized) {
878 if index < items.len() {
879 items.remove(index);
880 }
881 }
882}
883
884fn delete_path(target: &mut serde_json::Value, path: &[String]) {
885 let Some((head, rest)) = path.split_first() else {
886 return;
887 };
888 if rest.is_empty() {
889 match target {
890 serde_json::Value::Object(map) => {
891 map.remove(head);
892 }
893 serde_json::Value::Array(items) => {
894 if let Some(index) = json_array_index(items.len(), head) {
895 items.remove(index);
896 }
897 }
898 _ => {}
899 }
900 return;
901 }
902 match target {
903 serde_json::Value::Object(map) => {
904 if let Some(next) = map.get_mut(head) {
905 delete_path(next, rest);
906 }
907 }
908 serde_json::Value::Array(items) => {
909 if let Some(index) = json_array_index(items.len(), head) {
910 delete_path(&mut items[index], rest);
911 }
912 }
913 _ => {}
914 }
915}
916
917pub(super) fn jsonb_set(args: &[Value]) -> Result<Value> {
918 if !(3..=4).contains(&args.len()) {
919 return Err(SQLError::TypeMismatch("jsonb_set takes 3-4 args".into()));
920 }
921 let mut current = parse_json(&value_to_string(&args[0]))?;
922 let path = path_arg(&args[1])?;
923 let new_val = parse_json(&value_to_string(&args[2]))
924 .unwrap_or_else(|_| serde_json::Value::String(value_to_string(&args[2])));
925 let create_missing = args.get(3).is_none_or(|value| match value {
926 Value::Bool(value) => *value,
927 Value::Null => false,
928 other => value_to_string(other).eq_ignore_ascii_case("true"),
929 });
930 json_set_path(&mut current, &path, new_val, create_missing);
931 typed_json_value(¤t, true)
932}
933
934pub(super) fn jsonb_insert(args: &[Value]) -> Result<Value> {
935 if !(3..=4).contains(&args.len()) {
936 return Err(SQLError::TypeMismatch("jsonb_insert takes 3-4 args".into()));
937 }
938 let mut current = parse_json(&value_to_string(&args[0]))?;
939 let path = path_arg(&args[1])?;
940 let new_val = parse_json(&value_to_string(&args[2]))
941 .unwrap_or_else(|_| serde_json::Value::String(value_to_string(&args[2])));
942 let insert_after = args.get(3).is_some_and(|value| match value {
943 Value::Bool(value) => *value,
944 other => value_to_string(other).eq_ignore_ascii_case("true"),
945 });
946 json_insert_path(&mut current, &path, new_val, insert_after);
947 typed_json_value(¤t, true)
948}
949
950fn json_insert_path(
951 current: &mut serde_json::Value,
952 path: &[String],
953 new_val: serde_json::Value,
954 insert_after: bool,
955) -> bool {
956 let Some((head, rest)) = path.split_first() else {
957 return false;
958 };
959 if rest.is_empty() {
960 return match current {
961 serde_json::Value::Object(map) => {
962 if map.contains_key(head) {
963 false
964 } else {
965 map.insert(head.clone(), new_val);
966 true
967 }
968 }
969 serde_json::Value::Array(items) => {
970 let Some(index) = json_insert_index(items.len(), head, insert_after) else {
971 return false;
972 };
973 items.insert(index, new_val);
974 true
975 }
976 _ => false,
977 };
978 }
979 match current {
980 serde_json::Value::Object(map) => map
981 .get_mut(head)
982 .is_some_and(|next| json_insert_path(next, rest, new_val, insert_after)),
983 serde_json::Value::Array(items) => json_array_index(items.len(), head)
984 .is_some_and(|index| json_insert_path(&mut items[index], rest, new_val, insert_after)),
985 _ => false,
986 }
987}
988
989fn json_insert_index(len: usize, key: &str, insert_after: bool) -> Option<usize> {
990 let raw = key.parse::<i64>().ok()?;
991 let len_i64 = len as i64;
992 let index = if raw >= 0 {
993 if raw >= len_i64 {
994 len_i64
995 } else if insert_after {
996 raw + 1
997 } else {
998 raw
999 }
1000 } else {
1001 let normalized = len_i64 + raw;
1002 if normalized < 0 {
1003 0
1004 } else if insert_after {
1005 normalized + 1
1006 } else {
1007 normalized
1008 }
1009 };
1010 usize::try_from(index.clamp(0, len_i64)).ok()
1011}
1012
1013fn json_set_path(
1014 current: &mut serde_json::Value,
1015 path: &[String],
1016 new_val: serde_json::Value,
1017 create_missing: bool,
1018) -> bool {
1019 if path.is_empty() {
1020 *current = new_val;
1021 return true;
1022 }
1023 let head = &path[0];
1024 let rest = &path[1..];
1025 match current {
1026 serde_json::Value::Object(obj) => {
1027 if !obj.contains_key(head) && !create_missing {
1028 return false;
1029 }
1030 let entry = obj.entry(head.clone()).or_insert(serde_json::Value::Null);
1031 json_set_path(entry, rest, new_val, create_missing)
1032 }
1033 serde_json::Value::Array(arr) => {
1034 if let Some(idx) = json_array_index(arr.len(), head) {
1035 json_set_path(&mut arr[idx], rest, new_val, create_missing)
1036 } else if create_missing && rest.is_empty() {
1037 if let Ok(idx) = head.parse::<usize>() {
1038 while arr.len() <= idx {
1039 arr.push(serde_json::Value::Null);
1040 }
1041 arr[idx] = new_val;
1042 true
1043 } else {
1044 false
1045 }
1046 } else {
1047 false
1048 }
1049 }
1050 _ if create_missing => {
1051 let mut new_obj = serde_json::Map::new();
1052 new_obj.insert(head.clone(), serde_json::Value::Null);
1053 let mut wrapper = serde_json::Value::Object(new_obj);
1054 let changed = json_set_path(&mut wrapper, path, new_val, create_missing);
1055 if changed {
1056 *current = wrapper;
1057 }
1058 changed
1059 }
1060 _ => false,
1061 }
1062}
1063pub(super) fn strip_nulls(value: &mut serde_json::Value, strip_in_arrays: bool) {
1064 match value {
1065 serde_json::Value::Object(obj) => {
1066 obj.retain(|_, v| !v.is_null());
1067 for v in obj.values_mut() {
1068 strip_nulls(v, strip_in_arrays);
1069 }
1070 }
1071 serde_json::Value::Array(arr) => {
1072 if strip_in_arrays {
1073 arr.retain(|value| !value.is_null());
1074 }
1075 for v in arr.iter_mut() {
1076 strip_nulls(v, strip_in_arrays);
1077 }
1078 }
1079 _ => {}
1080 }
1081}
1082
1083#[cfg(test)]
1084mod pretty_tests {
1085 use super::{format_jsonb_pretty, parse_json, typed_json_value, DecimalValue};
1086
1087 #[test]
1088 fn jsonb_pretty_uses_postgresql_layout_and_key_order() {
1089 let value = parse_json(r#"{"zz":1,"b":[],"aa":{"long":3,"x":2}}"#).unwrap();
1090 assert_eq!(
1091 format_jsonb_pretty(&value),
1092 "{\n \"b\": [\n ],\n \"aa\": {\n \"x\": 2,\n \"long\": 3\n },\n \"zz\": 1\n}"
1093 );
1094 assert_eq!(format_jsonb_pretty(&parse_json("[]").unwrap()), "[\n]");
1095 assert_eq!(format_jsonb_pretty(&parse_json("{}").unwrap()), "{\n}");
1096 assert_eq!(
1097 format_jsonb_pretty(&parse_json("1e-1000").unwrap()),
1098 DecimalValue::parse("1e-1000").unwrap().to_sql_string()
1099 );
1100 assert_eq!(format_jsonb_pretty(&parse_json("1.00").unwrap()), "1.00");
1101 assert_eq!(format_jsonb_pretty(&parse_json("-0").unwrap()), "0");
1102 }
1103
1104 #[test]
1105 fn jsonb_rejects_numbers_outside_postgresql_numeric_range() {
1106 let maximum = parse_json("1e131071").unwrap();
1107 assert!(typed_json_value(&maximum, true).is_ok());
1108
1109 for text in ["1e131072", "1e-16384", "[1e131072]", r#"{"n":1e131072}"#] {
1110 let error = typed_json_value(&parse_json(text).unwrap(), true).unwrap_err();
1111 assert_eq!(error.sqlstate(), Some("22003"));
1112 }
1113
1114 assert!(typed_json_value(&parse_json("1e200000").unwrap(), false).is_ok());
1115 assert!(typed_json_value(&parse_json("0e200000").unwrap(), true).is_ok());
1116 }
1117}