limbo/testing/json.test
2025-02-09 18:08:29 +02:00

915 lines
26 KiB
Tcl
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env tclsh
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test json5-ecma-script-1 {
select json('{a:5,b:6}') ;
} {{{"a":5,"b":6}}}
do_execsql_test json5-ecma-script-2 {
select json('{a:5,a:3}') ;
} {{{"a":5,"a":3}}}
do_execsql_test json5-ecma-script-3 {
SELECT json('{ MNO_123$xyz : 789 }');
} {{{"MNO_123$xyz":789}}}
do_execsql_test json5-with-single-trailing-comma-valid {
select json('{"a":5, "b":6, }');
} {{{"a":5,"b":6}}}
do_execsql_test json5-single-quoted {
SELECT json('{"a": ''abcd''}');
} {{{"a":"abcd"}}}
do_execsql_test json5-hexadecimal-1 {
SELECT json('{a: 0x0}')
} {{{"a":0}}}
do_execsql_test json5-hexadecimal-2 {
SELECT json('{a: 0xabcdef}')
} {{{"a":11259375}}}
do_execsql_test json5-hexadecimal-2 {
SELECT json('{a: -0xabcdef}')
} {{{"a":-11259375}}}
do_execsql_test json5-number-1 {
SELECT json('{x: 4.}')
} {{{"x":4.0}}}
do_execsql_test json5-number-2 {
SELECT json('{x: +4.}')
} {{{"x":4.0}}}
do_execsql_test json5-number-3 {
SELECT json('{x: -4.}')
} {{{"x":-4.0}}}
do_execsql_test json5-number-5 {
SELECT json('{x: Infinity}')
} {{{"x":9e999}}}
do_execsql_test json5-number-6 {
SELECT json('{x: -Infinity}')
} {{{"x":-9e999}}}
do_execsql_test json5-multi-comment {
SELECT json(' /* abc */ { /*def*/ aaa /* xyz */ : // to the end of line
123 /* xyz */ , /* 123 */ }')
} {{{"aaa":123}}}
do_execsql_test json5-ecma-script-1-pretty {
select json_pretty('{a:5,b:6}') ;
} {{{
"a": 5,
"b": 6
}}}
do_execsql_test json5-ecma-script-2-pretty {
select json_pretty('{a:5,a:3}') ;
} {{{
"a": 5,
"a": 3
}}}
do_execsql_test json5-ecma-script-3-pretty {
SELECT json_pretty('{ MNO_123$xyz : 789 }');
} {{{
"MNO_123$xyz": 789
}}}
do_execsql_test json5-with-single-trailing-comma-valid-pretty {
select json_pretty('{"a":5, "b":6, }');
} {{{
"a": 5,
"b": 6
}}}
do_execsql_test json5-single-quoted-pretty {
SELECT json_pretty('{"a": ''abcd''}');
} {{{
"a": "abcd"
}}}
do_execsql_test json5-hexadecimal-1-pretty {
SELECT json_pretty('{a: 0x0}');
} {{{
"a": 0
}}}
do_execsql_test json5-hexadecimal-2-pretty {
SELECT json_pretty('{a: 0xabcdef}');
} {{{
"a": 11259375
}}}
do_execsql_test json5-hexadecimal-2-pretty {
SELECT json_pretty('{a: -0xabcdef}');
} {{{
"a": -11259375
}}}
do_execsql_test json5-number-1-pretty {
SELECT json_pretty('{x: 4.}');
} {{{
"x": 4.0
}}}
do_execsql_test json5-number-2-pretty {
SELECT json_pretty('{x: +4.}');
} {{{
"x": 4.0
}}}
do_execsql_test json5-number-3-pretty {
SELECT json_pretty('{x: -4.}');
} {{{
"x": -4.0
}}}
do_execsql_test json5-number-5-pretty {
SELECT json_pretty('{x: Infinity}');
} {{{
"x": 9e999
}}}
do_execsql_test json5-number-6-pretty {
SELECT json_pretty('{x: -Infinity}');
} {{{
"x": -9e999
}}}
do_execsql_test json5-multi-comment-pretty {
SELECT json_pretty(' /* abc */ { /*def*/ aaa /* xyz */ : // to the end of line
123 /* xyz */ , /* 123 */ }');
} {{{
"aaa": 123
}}}
do_execsql_test json-pretty-ident-1 {
SELECT json_pretty('{x: 1}', '');
} {{{
"x": 1
}}}
do_execsql_test json-pretty-ident-2 {
SELECT json_pretty('{x: 1}', '11');
} {{{
11"x": 1
}}}
do_execsql_test json-pretty-ident-null {
SELECT json_pretty('{x: 1}', NULL);
} {{{
"x": 1
}}}
do_execsql_test json-pretty-ident-blob-1 {
SELECT json_pretty('{x: 1}', x'33');
} {{{
3"x": 1
}}}
# TODO
# Currently conversion from blob to string is not exactly the same as in sqlite.
# The blob below should evaluate to two whitespaces TEXT value
# do_execsql_test json-pretty-ident-blob-2 {
# SELECT json_pretty('{x: 1}', x'1111');
# } {{{
# "x": 1
# }}}
do_execsql_test json_array_str {
SELECT json_array('a')
} {{["a"]}}
do_execsql_test json_array_numbers {
SELECT json_array(1, 1.5)
} {{[1,1.5]}}
do_execsql_test json_array_numbers_2 {
SELECT json_array(1., +2., -2.)
} {{[1.0,2.0,-2.0]}}
do_execsql_test json_array_null {
SELECT json_array(null)
} {{[null]}}
do_execsql_test json_array_not_json {
SELECT json_array('{"a":1}')
} {{["{\"a\":1}"]}}
do_execsql_test json_array_json {
SELECT json_array(json('{"a":1}'))
} {{[{"a":1}]}}
do_execsql_test json_array_nested {
SELECT json_array(json_array(1,2,3), json('[1,2,3]'), '[1,2,3]')
} {{[[1,2,3],[1,2,3],"[1,2,3]"]}}
do_execsql_test json_extract_null {
SELECT json_extract(null, '$')
} {{}}
do_execsql_test json_extract_json_null_type {
SELECT typeof(json_extract('null', '$'))
} {{null}}
do_execsql_test json_arrow_json_null_type {
SELECT typeof('null' -> '$')
} {{text}}
do_execsql_test json_arrow_shift_json_null_type {
SELECT typeof('null' ->> '$')
} {{null}}
do_execsql_test json_extract_empty {
SELECT json_extract()
} {{}}
do_execsql_test json_extract_single_param {
SELECT json_extract(1)
} {{}}
do_execsql_test json_extract_null_invalid_path {
SELECT json_extract(null, 1)
} {{}}
do_execsql_test json_extract_null_invalid_path_2 {
SELECT json_extract(null, CAST(1 AS BLOB))
} {{}}
do_execsql_test json_extract_multiple_nulls {
SELECT json_extract(null, CAST(1 AS BLOB), null, 1, 2, 3)
} {{}}
do_execsql_test json_extract_number {
SELECT json_extract(1, '$')
} {{1}}
do_execsql_test json_extract_number_type {
SELECT typeof(json_extract(1, '$'))
} {{integer}}
do_execsql_test json_arrow_number {
SELECT 1 -> '$'
} {{1}}
do_execsql_test json_arrow_number_type {
SELECT typeof(1 -> '$')
} {{text}}
do_execsql_test json_arrow_shift_number {
SELECT 1 -> '$'
} {{1}}
do_execsql_test json_arrow_shift_number_type {
SELECT typeof(1 ->> '$')
} {{integer}}
do_execsql_test json_extract_object_1 {
SELECT json_extract('{"a": [1,2,3]}', '$.a')
} {{[1,2,3]}}
do_execsql_test json_arrow_object {
SELECT '{"a": [1,2,3]}' -> '$.a'
} {{[1,2,3]}}
do_execsql_test json_arrow_shift_object {
SELECT '{"a": [1,2,3]}' ->> '$.a'
} {{[1,2,3]}}
do_execsql_test json_extract_object_2 {
SELECT json_extract('{"a": [1,2,3]}', '$.a', '$.a[0]', '$.a[1]', '$.a[3]')
} {{[[1,2,3],1,2,null]}}
do_execsql_test json_extract_object_3 {
SELECT json_extract('{"a": [1,2,3]}', '$.a', '$.a[0]', '$.a[1]', null, '$.a[3]')
} {{}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
# \x61 is the ASCII code for 'a'
# do_execsql_test json_extract_with_escaping {
# SELECT json_extract('{"\x61": 1}', '$.a')
# } {{1}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
#do_execsql_test json_extract_with_escaping_2 {
# SELECT json_extract('{"\x61": 1}', '$.\x61')
#} {{1}}
do_execsql_test json_extract_null_path {
SELECT json_extract(1, null)
} {{}}
do_execsql_test json_arrow_null_path {
SELECT 1 -> null
} {{}}
do_execsql_test json_arrow_shift_null_path {
SELECT 1 ->> null
} {{}}
do_execsql_test json_extract_float {
SELECT typeof(json_extract(1.0, '$'))
} {{real}}
do_execsql_test json_arrow_float {
SELECT typeof(1.0 -> '$')
} {{text}}
do_execsql_test json_arrow_shift_float {
SELECT typeof(1.0 ->> '$')
} {{real}}
do_execsql_test json_extract_true {
SELECT json_extract('true', '$')
} {{1}}
do_execsql_test json_extract_true_type {
SELECT typeof(json_extract('true', '$'))
} {{integer}}
do_execsql_test json_arrow_true {
SELECT 'true' -> '$'
} {{true}}
do_execsql_test json_arrow_true_type {
SELECT typeof('true' -> '$')
} {{text}}
do_execsql_test json_arrow_shift_true {
SELECT 'true' ->> '$'
} {{1}}
do_execsql_test json_arrow_shift_true_type {
SELECT typeof('true' ->> '$')
} {{integer}}
do_execsql_test json_extract_false {
SELECT json_extract('false', '$')
} {{0}}
do_execsql_test json_extract_false_type {
SELECT typeof(json_extract('false', '$'))
} {{integer}}
do_execsql_test json_arrow_false {
SELECT 'false' -> '$'
} {{false}}
do_execsql_test json_arrow_false_type {
SELECT typeof('false' -> '$')
} {{text}}
do_execsql_test json_arrow_shift_false {
SELECT 'false' ->> '$'
} {{0}}
do_execsql_test json_arrow_shift_false_type {
SELECT typeof('false' ->> '$')
} {{integer}}
do_execsql_test json_extract_string {
SELECT json_extract('"string"', '$')
} {{string}}
do_execsql_test json_extract_string_type {
SELECT typeof(json_extract('"string"', '$'))
} {{text}}
do_execsql_test json_arrow_string {
SELECT '"string"' -> '$'
} {{"string"}}
do_execsql_test json_arrow_string_type {
SELECT typeof('"string"' -> '$')
} {{text}}
do_execsql_test json_arrow_shift_string {
SELECT '"string"' ->> '$'
} {{string}}
do_execsql_test json_arrow_shift_string_type {
SELECT typeof('"string"' ->> '$')
} {{text}}
do_execsql_test json_arrow_implicit_root_path {
SELECT '{"a":1}' -> 'a';
} {{1}}
do_execsql_test json_arrow_shift_implicit_root_path {
SELECT '{"a":1}' ->> 'a';
} {{1}}
# TODO: fix me after rebasing on top of https://github.com/tursodatabase/limbo/pull/631 - use the Option value in json_extract_single
#do_execsql_test json_arrow_implicit_root_path_undefined_key {
# SELECT '{"a":1}' -> 'x';
#} {{}}
do_execsql_test json_arrow_shift_implicit_root_path_undefined_key {
SELECT '{"a":1}' ->> 'x';
} {{}}
do_execsql_test json_arrow_implicit_root_path_array {
SELECT '[1,2,3]' -> 1;
} {{2}}
do_execsql_test json_arrow_shift_implicit_root_path_array {
SELECT '[1,2,3]' ->> 1;
} {{2}}
do_execsql_test json_arrow_implicit_root_path_array_negative_idx {
SELECT '[1,2,3]' -> -1;
} {{3}}
do_execsql_test json_arrow_shift_implicit_root_path_array_negative_idx {
SELECT '[1,2,3]' ->> -1;
} {{3}}
do_execsql_test json_arrow_implicit_real_cast {
SELECT '{"1.5":"abc"}' -> 1.5;
} {{"abc"}}
do_execsql_test json_arrow_shift_implicit_real_cast {
SELECT '{"1.5":"abc"}' -> 1.5;
} {{"abc"}}
do_execsql_test json_arrow_implicit_true_cast {
SELECT '[1,2,3]' -> true
} {{2}}
do_execsql_test json_arrow_shift_implicit_true_cast {
SELECT '[1,2,3]' ->> true
} {{2}}
do_execsql_test json_arrow_implicit_false_cast {
SELECT '[1,2,3]' -> false
} {{1}}
do_execsql_test json_arrow_shift_implicit_false_cast {
SELECT '[1,2,3]' ->> false
} {{1}}
do_execsql_test json_arrow_chained {
select '{"a":2,"c":[4,5,{"f":7}]}' -> 'c' -> 2 ->> 'f'
} {{7}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
do_execsql_test json_extract_multiple_null_paths {
SELECT json_extract(1, null, null, null)
} {{}}
do_execsql_test json_extract_array {
SELECT json_extract('[1,2,3]', '$')
} {{[1,2,3]}}
do_execsql_test json_arrow_array {
SELECT '[1,2,3]' -> '$'
} {{[1,2,3]}}
do_execsql_test json_arrow_shift_array {
SELECT '[1,2,3]' ->> '$'
} {{[1,2,3]}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
#do_execsql_test json_extract_quote {
# SELECT json_extract('{"\"":1 }', '$.\"')
#} {{1}}
# Overflows 2**32 is equivalent to 0
do_execsql_test json_extract_overflow_int32_1 {
SELECT json_extract('[1,2,3]', '$[4294967296]')
} {{1}}
# Overflows 2**32 + 1 is equivalent to 1
do_execsql_test json_extract_overflow_int32_2 {
SELECT json_extract('[1,2,3]', '$[4294967297]')
} {{2}}
# Overflows -2**32 - 1 is equivalent to -1
do_execsql_test json_extract_overflow_int32_3 {
SELECT json_extract('[1,2,3]', '$[#-4294967297]')
} {{3}}
# Overflows -2**32 - 2 is equivalent to -2
do_execsql_test json_extract_overflow_int32_3 {
SELECT json_extract('[1,2,3]', '$[#-4294967298]')
} {{2}}
# pow(2,63) + 1 == 9223372036854775808
do_execsql_test json_extract_overflow_int64 {
SELECT json_extract('[1,2,3]', '$[9223372036854775808]');
} {{1}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
# pow(2, 127) + 1 == 170141183460469231731687303715884105729
#do_execsql_test json_extract_overflow_int128 {
# SELECT json_extract('[1, 2, 3]', '$[170141183460469231731687303715884105729]');
#} {{2}}
# TODO: fix me - this passes on SQLite and needs to be fixed in Limbo.
#do_execsql_test json_extract_blob {
# select json_extract(CAST('[1,2,3]' as BLOB), '$[1]')
#} {{2}}
do_execsql_test json_array_length {
SELECT json_array_length('[1,2,3,4]');
} {{4}}
do_execsql_test json_array_length_empty {
SELECT json_array_length('[]');
} {{0}}
do_execsql_test json_array_length_root {
SELECT json_array_length('[1,2,3,4]', '$');
} {{4}}
do_execsql_test json_array_length_not_array {
SELECT json_array_length('{"one":[1,2,3]}');
} {{0}}
do_execsql_test json_array_length_via_prop {
SELECT json_array_length('{"one":[1,2,3]}', '$.one');
} {{3}}
do_execsql_test json_array_length_via_index {
SELECT json_array_length('[[1,2,3,4]]', '$[0]');
} {{4}}
do_execsql_test json_array_length_via_index_not_array {
SELECT json_array_length('[1,2,3,4]', '$[2]');
} {{0}}
do_execsql_test json_array_length_via_bad_prop {
SELECT json_array_length('{"one":[1,2,3]}', '$.two');
} {{}}
do_execsql_test json_array_length_nested {
SELECT json_array_length('{"one":[[1,2,3],2,3]}', '$.one[0]');
} {{3}}
do_execsql_test json_type_no_path {
select json_type('{"a":[2,3.5,true,false,null,"x"]}')
} {{object}}
do_execsql_test json_type_root_path {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$')
} {{object}}
do_execsql_test json_type_array {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a')
} {{array}}
do_execsql_test json_type_integer {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]')
} {{integer}}
do_execsql_test json_type_real {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]')
} {{real}}
do_execsql_test json_type_true {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]')
} {{true}}
do_execsql_test json_type_false {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]')
} {{false}}
do_execsql_test json_type_null {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]')
} {{null}}
do_execsql_test json_type_text {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]')
} {{text}}
do_execsql_test json_type_NULL {
select json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]')
} {{}}
do_execsql_test json_type_cast {
select json_type(1)
} {{integer}}
do_execsql_test json_type_null_arg {
select json_type(null)
} {{}}
do_execsql_test json_error_position_valid {
SELECT json_error_position('{"a":55,"b":72,}');
} {{0}}
do_execsql_test json_error_position_valid_ws {
SELECT json_error_position('{"a":55,"b":72 , }');
} {{0}}
do_execsql_test json_error_position_object {
SELECT json_error_position('{"a":55,"b":72,,}');
} {{16}}
do_execsql_test json_error_position_array_valid {
SELECT json_error_position('["a",55,"b",72,]');
} {{0}}
do_execsql_test json_error_position_array_valid_ws {
SELECT json_error_position('["a",55,"b",72 , ]');
} {{0}}
do_execsql_test json_error_position_array {
SELECT json_error_position('["a",55,"b",72,,]');
} {{16}}
do_execsql_test json_error_position_null {
SELECT json_error_position(NULL);
} {{}}
do_execsql_test json_error_position_complex {
SELECT json_error_position('{a:null,{"h":[1,[1,2,3]],"j":"abc"}:true}');
} {{9}}
do_execsql_test json_object_simple {
SELECT json_object('key', 'value');
} {{{"key":"value"}}}
do_execsql_test json_object_nested {
SELECT json_object('grandparent',json_object('parent', json_object('child', 'value')));
} {{{"grandparent":{"parent":{"child":"value"}}}}}
do_execsql_test json_object_quoted_json {
SELECT json_object('parent', '{"child":"value"}');
} {{{"parent":"{\"child\":\"value\"}"}}}
do_execsql_test json_object_unquoted_json {
SELECT json_object('parent', json('{"child":"value"}'));
} {{{"parent":{"child":"value"}}}}
do_execsql_test json_object_multiple_values {
SELECT json_object('text', 'value', 'json', json_object('key', 'value'), 'int', 1, 'float', 1.5, 'null', null);
} {{{"text":"value","json":{"key":"value"},"int":1,"float":1.5,"null":null}}}
do_execsql_test json_object_empty {
SELECT json_object();
} {{{}}}
do_execsql_test json_object_json_array {
SELECT json_object('ex',json('[52,3]'));
} {{{"ex":[52,3]}}}
do_execsql_test json_from_json_object {
SELECT json(json_object('key','value'));
} {{{"key":"value"}}}
# FIXME: this behaviour differs from sqlite. Although, sqlite docs states
# that this could change in a "future enhancement" (https://www.sqlite.org/json1.html#jobj)
#do_execsql_test json_object_duplicated_keys {
# SELECT json_object('key', 'value', 'key', 'value2');
#} {{{"key":"value2"}}}
#
do_execsql_test json_valid_1 {
SELECT json_valid('{"a":55,"b":72}');
} {1}
do_execsql_test json_valid_2 {
SELECT json_valid('["a",55,"b",72]');
} {1}
do_execsql_test json_valid_3 {
SELECT json_valid( CAST('{"a":1}' AS BLOB) );
} {1}
do_execsql_test json_valid_4 {
SELECT json_valid(123);
} {1}
do_execsql_test json_valid_5 {
SELECT json_valid(12.3);
} {1}
do_execsql_test json_valid_6 {
SELECT json_valid('not a valid json');
} {0}
do_execsql_test json_valid_7 {
SELECT json_valid('{"a":"55,"b":72}');
} {0}
do_execsql_test json_valid_8 {
SELECT json_valid('{"a":55 "b":72}');
} {0}
do_execsql_test json_valid_3 {
SELECT json_valid( CAST('{"a":"1}' AS BLOB) );
} {0}
do_execsql_test json_valid_9 {
SELECT json_valid(NULL);
} {}
do_execsql_test json-patch-basic-1 {
select json_patch('{"a":1}', '{"b":2}');
} {{{"a":1,"b":2}}}
do_execsql_test json-patch-basic-2 {
select json_patch('{"x":100,"y":200}', '{"z":300}');
} {{{"x":100,"y":200,"z":300}}}
do_execsql_test json-patch-preserve-duplicates-1 {
select json_patch('{"x":100,"x":200}', '{"z":300}');
} {{{"x":100,"x":200,"z":300}}}
do_execsql_test json-patch-preserve-duplicates-2 {
select json_patch('{"x":100,"x":200}', '{"x":900}');
} {{{"x":900,"x":200}}}
do_execsql_test json-patch-last-update-wins {
select json_patch('{"x":100,"c":200}', '{"x":900, "x":null}');
} {{{"c":200}}}
do_execsql_test json-patch-override-1 {
select json_patch('{"a":1,"b":2}', '{"b":3}');
} {{{"a":1,"b":3}}}
do_execsql_test json-patch-override-2 {
select json_patch('{"name":"john","age":25}', '{"age":26,"city":"NYC"}');
} {{{"name":"john","age":26,"city":"NYC"}}}
do_execsql_test json-patch-nested-1 {
select json_patch('{"user":{"name":"john"}}', '{"user":{"age":30}}');
} {{{"user":{"name":"john","age":30}}}}
do_execsql_test json-patch-nested-2 {
select json_patch('{"settings":{"theme":"dark"}}', '{"settings":{"theme":"light","font":"arial"}}');
} {{{"settings":{"theme":"light","font":"arial"}}}}
do_execsql_test json-patch-array-1 {
select json_patch('{"arr":[1,2,3]}', '{"arr":[4,5,6]}');
} {{{"arr":[4,5,6]}}}
do_execsql_test json-patch-array-2 {
select json_patch('{"list":["a","b"]}', '{"list":["c"]}');
} {{{"list":["c"]}}}
do_execsql_test json-patch-empty-1 {
select json_patch('{}', '{"a":1}');
} {{{"a":1}}}
do_execsql_test json-patch-empty-2 {
select json_patch('{"a":1}', '{}');
} {{{"a":1}}}
do_execsql_test json-patch-deep-nested-1 {
select json_patch(
'{"level1":{"level2":{"value":100}}}',
'{"level1":{"level2":{"newValue":200}}}'
);
} {{{"level1":{"level2":{"value":100,"newValue":200}}}}}
do_execsql_test json-patch-mixed-types-1 {
select json_patch(
'{"str":"hello","num":42,"bool":true}',
'{"arr":[1,2,3],"obj":{"x":1}}'
);
} {{{"str":"hello","num":42,"bool":true,"arr":[1,2,3],"obj":{"x":1}}}}
do_execsql_test json-patch-add-all-dup-keys-from-patch {
select json_patch(
'{"x":100,"x":200}',
'{"z":{}, "z":5, "z":100}'
);
} {{{"x":100,"x":200,"z":100}}}
do_execsql_test json-patch-first-occurrence-patch {
select json_patch('{"x":100,"x":200}','{"x":{}, "x":5, "x":100}');
} {{{"x":100,"x":200}}}
do_execsql_test json-patch-complex-nested-dup-keys {
select json_patch(
'{"a":{"x":1,"x":2},"a":{"y":3},"b":[{"z":4,"z":5}]}',
'{"a":{"w":6},"b":[{"z":7,"z":8}],"b":{"z":9}}'
);
} {{{"a":{"x":1,"x":2,"w":6},"a":{"y":3},"b":{"z":9}}}}
do_execsql_test json-patch-unicode-dup-keys {
select json_patch(
'{"🔑":1,"🔑":2}',
'{"🗝":3,"🗝":4}'
);
} {{{"🔑":1,"🔑":2,"🗝":4}}}
do_execsql_test json-patch-empty-string-dup-keys {
select json_patch(
'{"":1,"":2}',
'{"":3,"":4}'
);
} {{{"":4,"":2}}}
do_execsql_test json-patch-multiple-types-dup-keys {
select json_patch(
'{"x":100,"x":"str","x":true,"x":null}',
'{"y":1,"y":{},"y":[],"y":false}'
);
} {{{"x":100,"x":"str","x":true,"x":null,"y":false}}}
do_execsql_test json-patch-deep-nested-dup-keys {
select json_patch(
'{"a":{"b":{"c":1}},"a":{"b":{"c":2}},"a":{"b":{"d":3}}}',
'{"x":{"y":{"z":4}},"x":{"y":{"z":5}}}'
);
} {{{"a":{"b":{"c":1}},"a":{"b":{"c":2}},"a":{"b":{"d":3}},"x":{"y":{"z":5}}}}}
do_execsql_test json-patch-abomination {
select json_patch(
'{"a":{"b":{"x":1,"x":2,"y":{"z":3,"z":{"w":4}}},"b":[{"c":5,"c":6},{"d":{"e":7,"e":null}}],"f":{"g":[1,2,3],"g":{"h":8,"h":[4,5,6]}},"i":{"j":true,"j":{"k":false,"k":{"l":null,"l":"string"}}},"m":{"n":{"o":{"p":9,"p":{"q":10}},"o":{"r":11}}},"m":[{"s":{"t":12}},{"s":{"t":13,"t":{"u":14}}}]},"a":{"v":{"w":{"x":{"y":{"z":15}}}},"v":{"w":{"x":16,"x":{"y":17}}},"aa":[{"bb":{"cc":18,"cc":{"dd":19}}},{"bb":{"cc":{"dd":20},"cc":21}}]}}',
'{"a":{"b":{"x":{"new":"value"},"y":null},"b":{"c":{"updated":true},"d":{"e":{"replaced":100}}},"f":{"g":{"h":{"nested":"deep"}}},"i":{"j":{"k":{"l":{"modified":false}}}},"m":{"n":{"o":{"p":{"q":{"extra":"level"}}}},"s":null},"aa":[{"bb":{"cc":{"dd":{"ee":"new"}}}},{"bb":{"cc":{"dd":{"ff":"value"}}}}],"v":{"w":{"x":{"y":{"z":{"final":"update"}}}}}},"newTop":{"level":{"key":{"with":{"deep":{"nesting":true}}},"key":[{"array":{"in":{"deep":{"structure":null}}}}]}}}'
);
} {{{"a":{"b":{"x":{"new":"value"},"x":2,"c":{"updated":true},"d":{"e":{"replaced":100}}},"b":[{"c":5,"c":6},{"d":{"e":7,"e":null}}],"f":{"g":{"h":{"nested":"deep"}},"g":{"h":8,"h":[4,5,6]}},"i":{"j":{"k":{"l":{"modified":false}}},"j":{"k":false,"k":{"l":null,"l":"string"}}},"m":{"n":{"o":{"p":{"q":{"extra":"level"}},"p":{"q":10}},"o":{"r":11}}},"m":[{"s":{"t":12}},{"s":{"t":13,"t":{"u":14}}}],"aa":[{"bb":{"cc":{"dd":{"ee":"new"}}}},{"bb":{"cc":{"dd":{"ff":"value"}}}}],"v":{"w":{"x":{"y":{"z":{"final":"update"}}}}}},"a":{"v":{"w":{"x":{"y":{"z":15}}}},"v":{"w":{"x":16,"x":{"y":17}}},"aa":[{"bb":{"cc":18,"cc":{"dd":19}}},{"bb":{"cc":{"dd":20},"cc":21}}]},"newTop":{"level":{"key":[{"array":{"in":{"deep":{"structure":null}}}}]}}}}}
do_execsql_test json-remove-1 {
select json_remove('{"a": 5, "a": [5,4,3,2,1]}','$.a', '$.a[4]', '$.a[5]', '$.a');
} {{{}}}
do_execsql_test json-remove-2 {
SELECT json_remove('{"a": {"b": {"c": 1, "c": 2}, "b": [1,2,3]}}', '$.a.b.c', '$.a.b[1]');
} {{{"a":{"b":{"c":2},"b":[1,2,3]}}}}
do_execsql_test json-remove-3 {
SELECT json_remove('[1,2,3,4,5]', '$[0]', '$[4]', '$[5]');
} {{[2,3,4,5]}}
do_execsql_test json-remove-4 {
SELECT json_remove('{"arr": [1,2,3,4,5]}', '$.arr[#-1]', '$.arr[#-3]', '$.arr[#-1]');
} {{{"arr":[1,3]}}}
do_execsql_test json-remove-5 {
SELECT json_remove('{}', '$.a');
} {{{}}}
do_execsql_test json-remove-6 {
SELECT json_remove('{"a": [[1,2], [3,4]]}', '$.a[0][1]', '$.a[1]');
} {{{"a":[[1]]}}}
do_execsql_test json-remove-7 {
SELECT json_remove('{"a": 1, "b": [1,2], "c": {"d": 3}}', '$.a', '$.b[0]', '$.c.d');
} {{{"b":[2],"c":{}}}}
do_execsql_test json_set_field_empty_object {
SELECT json_set('{}', '$.field', 'value');
} {{{"field":"value"}}}
do_execsql_test json_set_replace_field {
SELECT json_set('{"field":"old_value"}', '$.field', 'new_value');
} {{{"field":"new_value"}}}
do_execsql_test json_set_set_deeply_nested_key {
SELECT json_set('{}', '$.object.doesnt.exist', 'value');
} {{{"object":{"doesnt":{"exist":"value"}}}}}
do_execsql_test json_set_add_value_to_empty_array {
SELECT json_set('[]', '$[0]', 'value');
} {{["value"]}}
do_execsql_test json_set_add_value_to_nonexistent_array {
SELECT json_set('{}', '$.some_array[0]', 123);
} {{{"some_array":[123]}}}
do_execsql_test json_set_add_value_to_array {
SELECT json_set('[123]', '$[1]', 456);
} {{[123,456]}}
do_execsql_test json_set_add_value_to_array_out_of_bounds {
SELECT json_set('[123]', '$[200]', 456);
} {{[123]}}
do_execsql_test json_set_replace_value_in_array {
SELECT json_set('[123]', '$[0]', 456);
} {{[456]}}
do_execsql_test json_set_null_path {
SELECT json_set('{}', NULL, 456);
} {{{}}}
do_execsql_test json_set_multiple_keys {
SELECT json_set('[123]', '$[0]', 456, '$[1]', 789);
} {{[456,789]}}
do_execsql_test json_set_add_array_in_nested_object {
SELECT json_set('{}', '$.object[0].field', 123);
} {{{"object":[{"field":123}]}}}
do_execsql_test json_set_add_array_in_array_in_nested_object {
SELECT json_set('{}', '$.object[0][0]', 123);
} {{{"object":[[123]]}}}
do_execsql_test json_set_add_array_in_array_in_nested_object_out_of_bounds {
SELECT json_set('{}', '$.object[123].another', 'value', '$.field', 'value');
} {{{"field":"value"}}}
# The json_quote() function transforms an SQL value into a JSON value.
# String values are quoted and interior quotes are escaped. NULL values
# are rendered as the unquoted string "null".
#
do_execsql_test json_quote_string_literal {
SELECT json_quote('abc"xyz');
} {{"abc\"xyz"}}
do_execsql_test json_quote_float {
SELECT json_quote(3.14159);
} {3.14159}
do_execsql_test json_quote_integer {
SELECT json_quote(12345);
} {12345}
do_execsql_test json_quote_null {
SELECT json_quote(null);
} {"null"}
do_execsql_test json_quote_null_caps {
SELECT json_quote(NULL);
} null
do_execsql_test json_quote_json_value {
SELECT json_quote(json('{a:1, b: "test"}'));
} {{{"a":1,"b":"test"}}}
# Escape character tests in sqlite source depend on json_valid and in some syntax that is not implemented
# yet in limbo.
# See https://github.com/sqlite/sqlite/blob/255548562b125e6c148bb27d49aaa01b2fe61dba/test/json102.test#L690
# So for now not all control characters escaped are tested
# do_execsql_test json102-1501 {
# WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x1f)
# SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x;
# } {31}