edgedb/tests/test_edgeql_json.py
Michael J. Sullivan d8d1fab02c
Fix object->json casts inside functions (#6016)
Functions are compiled with object shapes suppressed, so the generated
code was invalid.

Whenever we are switching the output_format for shape serialization
purposes, we should unsuppress object shapes. This also fixes an issue
with materialization.

Fixes #5938.
2023-09-01 16:18:53 -07:00

2105 lines
63 KiB
Python

#
# This source file is part of the EdgeDB open source project.
#
# Copyright 2018-present MagicStack Inc. and the EdgeDB authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import json
import os.path
import edgedb
from edb.schema import defines as s_defs
from edb.testbase import server as tb
from edb.tools import test
class TestEdgeQLJSON(tb.QueryTestCase):
SCHEMA = os.path.join(os.path.dirname(__file__), 'schemas',
'json.esdl')
SETUP = os.path.join(os.path.dirname(__file__), 'schemas',
'json_setup.edgeql')
async def test_edgeql_json_cast_01(self):
await self.assert_query_result(
r'''SELECT to_json('"qwerty"');''',
# JSON:
['qwerty'],
# Binary:
['"qwerty"'],
)
await self.assert_query_result(
r'''SELECT to_json('1');''',
# JSON:
[1],
# Binary:
['1'],
)
await self.assert_query_result(
r'''SELECT to_json('2.3e-2');''',
# JSON:
[0.023],
# Binary:
['0.023'],
)
await self.assert_query_result(
r'''SELECT to_json('true');''',
# JSON:
[True],
# Binary:
['true'],
)
await self.assert_query_result(
r'''SELECT to_json('false');''',
# JSON:
[False],
# Binary:
['false'],
)
await self.assert_query_result(
r'''SELECT to_json('null');''',
# JSON:
[None],
# Binary:
['null'],
)
await self.assert_query_result(
r'''SELECT to_json('[2, "a", 3.456]');''',
# JSON:
[[2, 'a', 3.456]],
# Binary:
['[2, "a", 3.456]'],
)
await self.assert_query_result(
r'''SELECT to_json('[2, "a", 3.456, [["b", 1]]]');''',
# JSON:
[[2, 'a', 3.456, [['b', 1]]]],
# Binary:
['[2, "a", 3.456, [["b", 1]]]']
)
async def test_edgeql_json_cast_02(self):
await self.assert_query_result(
r'''SELECT <str>to_json('"qwerty"');''',
['qwerty'],
)
await self.assert_query_result(
r'''SELECT <int64>to_json('1');''',
[1],
)
await self.assert_query_result(
r'''SELECT <float64>to_json('2.3e-2');''',
[0.023],
)
await self.assert_query_result(
r'''SELECT <bool>to_json('true');''',
[True],
)
await self.assert_query_result(
r'''SELECT <bool>to_json('false');''',
[False],
)
async def test_edgeql_json_cast_03(self):
await self.assert_query_result(
r'''SELECT <str>to_json('null');''',
[],
)
await self.assert_query_result(
r'''SELECT <int64>to_json('null');''',
[],
)
await self.assert_query_result(
r'''SELECT <float64>to_json('null');''',
[],
)
await self.assert_query_result(
r'''SELECT <bool>to_json('null');''',
[],
)
async def test_edgeql_json_cast_04(self):
await self.assert_query_result(
r'''SELECT <str>to_json('null') ?= <str>{};''',
[True],
)
await self.assert_query_result(
r'''SELECT <int64>to_json('null') ?= <int64>{};''',
[True],
)
await self.assert_query_result(
r'''SELECT <float64>to_json('null') ?= <float64>{};''',
[True],
)
await self.assert_query_result(
r'''SELECT <bool>to_json('null') ?= <bool>{};''',
[True],
)
async def test_edgeql_json_cast_05(self):
await self.assert_query_result(
"""
SELECT <json>{} ?= (
SELECT x := to_json('1') FILTER x = to_json('2')
);
""",
[True],
)
await self.assert_query_result(
"""SELECT <json>{} ?= to_json('null');""",
[False],
)
@test.not_implemented('''
# casting into tuples or other deeply nested structures
# is not currently implemented
''')
async def test_edgeql_json_cast_06(self):
await self.assert_query_result(
r'''SELECT <tuple<int64, str>><json>[1, 2];''',
[[1, '2']],
)
await self.assert_query_result(
r'''SELECT <array<int64>>to_json('[2, 3, 5]');''',
[[2, 3, 5]],
)
async def test_edgeql_json_cast_07(self):
"""Check that JSON of array preserves order."""
await self.assert_query_result(
r'''
SELECT <json>array_agg(
(SELECT JSONTest{number}
FILTER .number IN {0, 1}
ORDER BY .j_string)
) = to_json(
'[{"number": 1}, {"number": 0}]'
)
''',
[True]
)
async def test_edgeql_json_accessor_01(self):
await self.assert_query_result(
r'''SELECT (to_json('[1, "a", 3]'))[0] = to_json('1');''',
[True],
)
await self.assert_query_result(
r'''SELECT (to_json('[1, "a", 3]'))[1] = to_json('"a"');''',
[True],
)
await self.assert_query_result(
r'''SELECT (to_json('[1, "a", 3]'))[2] = to_json('3');''',
[True],
)
await self.assert_query_result(
r'''SELECT (to_json('[1, "a", 3]'))[<int16>0] = to_json('1');''',
[True],
)
await self.assert_query_result(
r'''SELECT (to_json('[1, "a", 3]'))[<int32>0] = to_json('1');''',
[True],
)
async def test_edgeql_json_accessor_02(self):
await self.assert_query_result(
r'''
SELECT (to_json('{"a": 1, "b": null}'))["a"] =
to_json('1');
''',
[True],
)
await self.assert_query_result(
r'''
SELECT (to_json('{"a": 1, "b": null}'))["b"] =
to_json('null');
''',
[True],
)
async def test_edgeql_json_accessor_03(self):
await self.assert_query_result(
"""
SELECT (<str>(to_json('["qwerty"]'))[0])[1];
""",
['w'],
)
async def test_edgeql_json_accessor_04(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index 10 is out of bounds'):
await self.con.query(r"""
SELECT (to_json('[1, "a", 3]'))[10];
""")
async def test_edgeql_json_accessor_05(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index -10 is out of bounds'):
await self.con.query(r"""
SELECT (to_json('[1, "a", 3]'))[-10];
""")
async def test_edgeql_json_accessor_06(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON array by text'):
await self.con.query(r"""
SELECT (to_json('[1, "a", 3]'))['1'];
""")
async def test_edgeql_json_accessor_07(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"JSON index 'c' is out of bounds"):
await self.con.query(r"""
SELECT (to_json('{"a": 1, "b": null}'))["c"];
""")
async def test_edgeql_json_accessor_08(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON object by bigint'):
await self.con.execute(r"""
SELECT (to_json('{"a": 1, "b": null}'))[0];
""")
async def test_edgeql_json_accessor_09(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON null'):
await self.con.query(r"""
SELECT (to_json('null'))[0];
""")
async def test_edgeql_json_accessor_10(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON boolean'):
await self.con.execute(r"""
SELECT (to_json('true'))[0];
""")
async def test_edgeql_json_accessor_11(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON number'):
await self.con.execute(r"""
SELECT (to_json('123'))[0];
""")
async def test_edgeql_json_accessor_13(self):
await self.assert_query_result(
r"""
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['b']['bar'][2]['bingo'];
""",
['42!'],
['"42!"'],
)
await self.assert_query_result(
r"""
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['b']['bar'][-1]['bingo'];
""",
['42!'],
['"42!"'],
)
async def test_edgeql_json_accessor_14(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index 10 is out of bounds'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['b']['bar'][10]['bingo'];
""")
async def test_edgeql_json_accessor_15(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index -10 is out of bounds'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[-10]['b']['bar'][2]['bingo'];
""")
async def test_edgeql_json_accessor_16(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON array by text'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data['4']['b']['bar'][10]['bingo'];
""")
async def test_edgeql_json_accessor_17(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"JSON index 'c' is out of bounds"):
await self.con.execute(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['b']['c'][2]['bingo'];
""")
async def test_edgeql_json_accessor_18(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON object by bigint'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4][1]['bar'][2]['bingo'];
""")
async def test_edgeql_json_accessor_19(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON null'):
await self.con.execute(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['b']['bar'][0]['bingo'];
""")
async def test_edgeql_json_accessor_20(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON boolean'):
await self.con.execute(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[-1]['b']['bar'][2]['bingo'];
""")
async def test_edgeql_json_accessor_21(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON number'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[0]['b']['bar'][2]['bingo'];
""")
async def test_edgeql_json_accessor_22(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'cannot index JSON string'):
await self.con.execute(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[2]['b']['bar'][2]['bingo'];
""")
async def test_edgeql_json_accessor_23(self):
await self.assert_query_result(
r'''select to_json('"hello"')[0] = <json>'h';''',
[True],
)
await self.assert_query_result(
r'''select to_json('"hello"')[-2] = <json>'l';''',
[True],
)
async def test_edgeql_json_accessor_24(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index 10 is out of bounds'):
await self.con.query(r"""
select to_json('"hello"')[10];
""")
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index -10 is out of bounds'):
await self.con.query(r"""
select to_json('"hello"')[-10];
""")
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index 10 is out of bounds'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['c'][10];
""")
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'JSON index -10 is out of bounds'):
await self.con.query(r"""
WITH
JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT JT3.data[4]['c'][-10];
""")
async def test_edgeql_json_null_01(self):
await self.assert_query_result(
r'''
SELECT (
SELECT JSONTest FILTER .number = 0
).data ?= <json>{};
''',
{False},
)
await self.assert_query_result(
r'''
SELECT (
SELECT JSONTest FILTER .number = 0
).data ?= to_json('null');
''',
{True},
)
await self.assert_query_result(
r'''
SELECT (
SELECT JSONTest FILTER .number = 2
).data ?= <json>{};
''',
{True},
)
await self.assert_query_result(
r'''
SELECT (
SELECT JSONTest FILTER .number = 2
).data ?= to_json('null');
''',
{False},
)
async def test_edgeql_json_typeof_01(self):
await self.assert_query_result(
r'''SELECT json_typeof(to_json('2'));''',
['number'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('"foo"'));''',
['string'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('true'));''',
['boolean'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('false'));''',
['boolean'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('null'));''',
['null'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('[]'));''',
['array'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('[2]'));''',
['array'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('{}'));''',
['object'],
)
await self.assert_query_result(
r'''SELECT json_typeof(to_json('{"a": 2}'));''',
['object'],
)
await self.assert_query_result(
r'''SELECT json_typeof(<json>{});''',
[],
)
async def test_edgeql_json_typeof_02(self):
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.j_string);''',
['string', 'string', 'string'],
sort=True,
)
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.j_number);''',
['number', 'number', 'number'],
sort=True,
)
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.j_boolean);''',
['boolean', 'boolean', 'boolean'],
sort=True,
)
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.j_array);''',
['array', 'array', 'array'],
sort=True,
)
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.j_object);''',
['object', 'object'],
sort=True,
)
await self.assert_query_result(
r'''SELECT json_typeof(JSONTest.data);''',
['array', 'null', 'object'],
sort=True,
)
async def test_edgeql_json_array_unpack_01(self):
await self.assert_query_result(
"""
SELECT json_array_unpack(to_json('[1, "a", null]'));
""",
# JSON:
[1, 'a', None],
# Binary:
['1', '"a"', 'null'],
)
async def test_edgeql_json_array_unpack_02(self):
async with self.assertRaisesRegexTx(
edgedb.QueryError,
r"operator 'IN' cannot.*'std::json' and 'std::int64'"):
await self.con.query(r'''
SELECT json_array_unpack(to_json('[2,3,4]')) IN
{2, 3, 4};
''')
async def test_edgeql_json_array_unpack_03(self):
async with self.assertRaisesRegexTx(
edgedb.QueryError,
r"operator 'IN' cannot.*'std::json' and 'std::str'"):
await self.con.query_json(r'''
SELECT json_array_unpack(to_json('[2,3,4]')) IN
{'2', '3', '4'};
''')
async def test_edgeql_json_array_unpack_04(self):
await self.assert_query_result(
r'''
SELECT json_array_unpack(to_json('[2,3,4]')) IN
<json>{2, 3, 4};
''',
[True, True, True],
)
await self.assert_query_result(
r'''
SELECT json_array_unpack(to_json('[2,3,4]')) NOT IN
<json>{2, 3, 4};
''',
[False, False, False],
)
async def test_edgeql_json_array_unpack_05(self):
async with self.assertRaisesRegexTx(
edgedb.QueryError,
r"operator '=' cannot.*'std::json' and 'std::int64'"):
await self.con.query_json(r'''
WITH
JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_array_unpack(JT0.j_array) = 1;
''')
async def test_edgeql_json_array_unpack_06(self):
await self.assert_query_result(
r'''
WITH
JT0 := (SELECT JSONTest FILTER .number = 0)
# unpacking [1, 1, 1]
SELECT json_array_unpack(JT0.j_array) = to_json('1');
''',
[True, True, True],
)
async def test_edgeql_json_array_unpack_07(self):
await self.assert_query_result(
r'''
WITH
JT0 := (SELECT JSONTest FILTER .number = 2)
# unpacking [2, "q", [3], {}, null], should preserve the
# order
SELECT array_agg(json_array_unpack(JT0.j_array)) =
<array<json>>JT0.j_array;
''',
[True],
)
async def test_edgeql_json_array_unpack_08(self):
await self.assert_query_result(
r'''
WITH
JT0 := (SELECT JSONTest FILTER .number = 2)
# unpacking [2, "q", [3], {}, null], should preserve the
# order
SELECT json_typeof(json_array_unpack(JT0.j_array));
''',
['number', 'string', 'array', 'object', 'null'],
)
async def test_edgeql_json_object_01(self):
await self.assert_query_result(
r'''
SELECT to_json('{"a":1,"b":2}') =
to_json('{"b":2,"a":1}');
''',
[True],
)
await self.assert_query_result(
r'''
SELECT to_json('{"a":1,"b":2}') =
to_json('{"b":3,"a":1,"b":2}');
''',
[True],
)
async def test_edgeql_json_object_unpack_01(self):
await self.assert_query_result(
r'''
SELECT json_object_unpack(to_json('{
"q": 1,
"w": [2, null, 3],
"e": null
}'));
''',
# JSON:
[
# Nones in the output are legitimate JSON nulls
['e', None],
['q', 1],
['w', [2, None, 3]],
],
# Binary:
[
['e', 'null'],
['q', '1'],
['w', '[2, null, 3]'],
],
sort=lambda x: x[0],
)
async def test_edgeql_json_object_unpack_02(self):
await self.assert_query_result(
r'''
SELECT
_ := json_object_unpack(JSONTest.j_object)
ORDER BY _.0 THEN _.1;
''',
# JSON:
[['a', 1], ['b', 1], ['b', 2], ['c', 2]],
# Binary:
[['a', '1'], ['b', '1'], ['b', '2'], ['c', '2']],
)
await self.assert_query_result(
r'''
SELECT json_object_unpack(JSONTest.j_object) =
('c', to_json('1'));
''',
[False, False, False, False],
)
await self.assert_query_result(
r'''
SELECT json_object_unpack(JSONTest.j_object).0 IN
{'a', 'b', 'c'};
''',
[True, True, True, True],
)
await self.assert_query_result(
r'''
SELECT json_object_unpack(JSONTest.j_object).1 IN
<json>{1, 2};
''',
[True, True, True, True],
)
await self.assert_query_result(
r'''
SELECT json_object_unpack(JSONTest.j_object).1 IN
<json>{'1', '2'};
''',
[False, False, False, False],
)
async def test_edgeql_json_object_unpack_03(self):
async with self.assertRaisesRegexTx(
# FIXME: a different error should be used here, this
# one leaks postgres types
edgedb.InvalidValueError,
r'cannot call jsonb_each on a non-object'):
await self.con.query_json(r'''
WITH
JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT
count(json_object_unpack(JT0.data));
''')
async def test_edgeql_json_object_unpack_04(self):
await self.assert_query_result(
r'''
WITH
JT1 := (SELECT JSONTest FILTER .number = 1),
JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT (
count(json_object_unpack(JT1.data)),
count(json_object_unpack(JT2.data)),
);
''',
[[0, 0]],
)
async def test_edgeql_json_object_unpack_05(self):
await self.assert_query_result(
r'''
WITH
q := enumerate(
json_object_unpack(to_json('{
"q": 1,
"w": 2
}'))
)
SELECT
<int64>q.1.1
ORDER BY
q.1.0;
''',
[1, 2]
)
async def test_edgeql_json_object_pack(self):
await self.assert_query_result(
r'''
select std::json_object_pack({
("foo", to_json("1")),
("bar", to_json("null")),
("baz", to_json("[]"))
})
''',
[{'bar': None, 'baz': [], 'foo': 1}],
['{"bar": null, "baz": [], "foo": 1}'],
)
await self.assert_query_result(
r"""
select std::json_object_pack(
<tuple<str, json>>{}
)
""",
[{}],
["{}"],
)
await self.assert_query_result(
r"""
select std::json_object_pack(
array_unpack([
('foo', <json>1),
('bar', <json>2),
('baz', <json>3)
])
)
""",
[{"bar": 2, "baz": 3, "foo": 1}],
['{"bar": 2, "baz": 3, "foo": 1}'],
)
async def test_edgeql_json_get_01(self):
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '2');
''',
# JSON
{'Fraka'},
# Binary
{'"Fraka"'}
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '-1');
''',
# JSON
{True},
# Binary
{"true"}
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '100');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, 'foo');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '0', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '1', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '2', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '3', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '4', 'b', 'bar', '2', 'bingo');
''',
# JSON
{'42!'},
# Binary
{'"42!"'}
)
await self.assert_query_result(
r'''
WITH JT3 := (SELECT JSONTest FILTER .number = 3)
SELECT json_get(JT3.data, '4', 'b', 'foo', '2', 'bingo');
''',
[]
)
async def test_edgeql_json_get_02(self):
# since only one JSONTest has a non-trivial `data`, we
# don't need to filter to get the same results as above
await self.assert_query_result(
r'''SELECT json_get(JSONTest.data, '2');''',
{'Fraka'},
{'"Fraka"'},
)
await self.assert_query_result(
r'''SELECT json_get(JSONTest.data, '-1');''',
{True},
{'true'},
)
await self.assert_query_result(
r'''SELECT json_get(JSONTest.data, '100');''',
[],
)
await self.assert_query_result(
r'''SELECT json_get(JSONTest.data, 'foo');''',
[],
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '0', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '1', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '2', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '3', 'b', 'bar', '2', 'bingo');
''',
[],
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '4', 'b', 'bar', '2', 'bingo');
''',
{'42!'},
{'"42!"'},
)
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '4', 'b', 'foo', '2', 'bingo');
''',
[]
)
async def test_edgeql_json_get_03(self):
# chaining json_get should get the same effect as a single call
await self.assert_query_result(
r'''
SELECT json_get(JSONTest.data, '4', 'b', 'bar', '2', 'bingo');
''',
{'42!'},
{'"42!"'},
)
await self.assert_query_result(
r'''
SELECT json_get(json_get(json_get(json_get(json_get(
JSONTest.data, '4'), 'b'), 'bar'), '2'), 'bingo');
''',
{'42!'},
{'"42!"'},
)
await self.assert_query_result(
r'''
SELECT json_get(json_get(
JSONTest.data, '4', 'b'), 'bar', '2', 'bingo');
''',
{'42!'},
{'"42!"'},
)
async def test_edgeql_json_get_04(self):
await self.assert_query_result(
r'''SELECT json_get(JSONTest.data, 'bogus') ?? <json>'oups';''',
# JSON
['oups'],
# Binary
['"oups"'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bogus',
default := <json>'hello'
) ?? <json>'oups';
''',
['hello', 'hello', 'hello'],
['"hello"', '"hello"', '"hello"'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bogus',
default := <json>''
) ?? <json>'oups';
''',
['', '', ''],
['""', '""', '""'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bogus',
default := to_json('null')
) ?? <json>'oups';
''',
[None, None, None],
['null', 'null', 'null'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bogus',
default := <json>{}
) ?? <json>'oups';
''',
['oups'],
['"oups"'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bingo',
default := <json>''
) ?? <json>'oups';
''',
['', '', '42!'],
['""', '""', '"42!"'],
)
await self.assert_query_result(
r'''
SELECT json_get(
JSONTest.data, '4', 'b', 'bar', '2', 'bingo'
) ?? <json>'oups';
''',
['42!'],
['"42!"']
)
async def test_edgeql_json_set_01(self):
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(JT0.j_object, 'a', value := <json>42);
''',
[{"a": 42, "b": 2}],
['{"a": 42, "b": 2}'],
)
# by default create_if_missing should create new value
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(JT0.j_object, 'c', value := <json>42);
''',
[{"a": 1, "b": 2, "c": 42}],
['{"a": 1, "b": 2, "c": 42}'],
)
# create_if_missing should also work inside of nested objects
# by variadic path
await self.assert_query_result(
r'''
WITH j_object := to_json('{"a": {"b": {}}}')
SELECT json_set(j_object, 'a', 'b', 'c', value := <json>42);
''',
[{"a": {"b": {"c": 42}}}],
['{"a": {"b": {"c": 42}}}'],
)
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'c',
value := <json>42,
create_if_missing := false,
);
''',
[{"a": 1, "b": 2}],
['{"a": 1, "b": 2}'],
)
# by default empty_treatment should return empty set
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(JT0.j_object, 'a', value := <json>{});
''',
[],
[],
)
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'a',
value := <json>{},
empty_treatment := JsonEmpty.ReturnEmpty,
);
''',
[],
[],
)
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'a',
value := <json>{},
empty_treatment := JsonEmpty.ReturnTarget,
);
''',
[{"a": 1, "b": 2}],
['{"a": 1, "b": 2}'],
)
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'a',
value := <json>{},
empty_treatment := JsonEmpty.UseNull,
);
''',
[{"a": None, "b": 2}],
['{"a": null, "b": 2}'],
)
await self.assert_query_result(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'a',
value := <json>{},
empty_treatment := JsonEmpty.DeleteKey,
);
''',
[{"b": 2}],
['{"b": 2}'],
)
with self.assertRaisesRegex(
edgedb.InvalidValueError,
r"invalid empty JSON value"):
await self.con.execute(
r'''
WITH JT0 := (SELECT JSONTest FILTER .number = 0)
SELECT json_set(
JT0.j_object,
'a',
value := <json>{},
empty_treatment := JsonEmpty.Error,
);
''',
)
async def test_edgeql_json_cast_object_to_json_01(self):
res = await self.con.query("""
WITH MODULE schema
SELECT
to_str(<json>(
SELECT Object {
name,
foo := 'bar',
}
FILTER Object.name = 'std::json'
));
""")
val = res[0]
self.assertIsInstance(val, str)
self.assertEqual(
json.loads(val),
{"foo": "bar", "name": "std::json"}
)
async def test_edgeql_json_cast_object_to_json_02(self):
# Test that object-to-json cast works in non-SELECT clause.
await self.assert_query_result(
"""
WITH MODULE schema
SELECT
ScalarType {
name
}
FILTER
to_str(<json>(ScalarType {name})) LIKE '%std::json%';
""",
[{
'name': 'std::json',
}]
)
async def test_edgeql_json_cast_object_to_json_03(self):
# Test that object-to-json cast works in tuples as well.
await self.assert_query_result(
"""
WITH MODULE schema
SELECT
True
FILTER
to_str(
(
<tuple<json>>(
(
SELECT Object {
name,
foo := 'bar',
}
FILTER Object.name = 'std::json'
),
)
).0
)
LIKE '%std%';
""",
[True],
)
async def test_edgeql_json_cast_object_to_json_04(self):
# Test that object-to-json cast works in arrays as well.
await self.assert_query_result(
"""
WITH MODULE schema
SELECT
True
FILTER
to_str(<json>[(
SELECT Object {
name,
foo := 'bar',
}
FILTER Object.name = 'std::json'
)])
LIKE '%std%';
""",
[True],
)
async def test_edgeql_json_cast_object_to_json_05(self):
await self.assert_query_result(
r"""
# base case
SELECT
JSONTest {number, edb_string};
""",
[
{'number': 0, 'edb_string': 'jumps'},
{'number': 1, 'edb_string': 'over'},
{'number': 2, 'edb_string': None},
{'number': 3, 'edb_string': None},
],
sort=lambda x: x['number'],
)
await self.assert_query_result(
r"""
SELECT
JSONTest {number, edb_string}
FILTER
# casting all the way to the original type with a
# strict `=` will discard objects with empty `edb_string`
.edb_string =
<str>(<json>(JSONTest{edb_string}))['edb_string'];
""",
[
{'number': 0, 'edb_string': 'jumps'},
{'number': 1, 'edb_string': 'over'},
],
sort=lambda x: x['number'],
)
await self.assert_query_result(
r"""
SELECT
JSONTest {number, edb_string}
FILTER
# strict `=` will discard objects with empty `edb_string`
<json>.edb_string =
(<json>(JSONTest{edb_string}))['edb_string'];
""",
[
{'number': 0, 'edb_string': 'jumps'},
{'number': 1, 'edb_string': 'over'},
],
sort=lambda x: x['number'],
)
await self.assert_query_result(
r"""
SELECT
JSONTest {number, edb_string}
FILTER
# casting all the way to the original type with a
# weak `?=` will not discard anything
.edb_string ?=
<str>(<json>(JSONTest{edb_string}))['edb_string'];
""",
[
{'number': 0, 'edb_string': 'jumps'},
{'number': 1, 'edb_string': 'over'},
{'number': 2, 'edb_string': None},
{'number': 3, 'edb_string': None},
],
sort=lambda x: x['number'],
)
await self.assert_query_result(
r"""
SELECT
JSONTest {number, edb_string}
FILTER
# casting both sides into json combined with a
# weak `?=` will discard objects with empty `edb_string`
<json>.edb_string ?=
(<json>(JSONTest{edb_string}))['edb_string'];
""",
[
{'number': 0, 'edb_string': 'jumps'},
{'number': 1, 'edb_string': 'over'},
],
sort=lambda x: x['number'],
)
async def test_edgeql_json_cast_object_to_json_06(self):
res = await self.con.query("""
SELECT to_str(<json>{x := random()});
""")
val = res[0]
self.assertIsInstance(val, str)
data = json.loads(val)
self.assertTrue('id' not in data)
async def test_edgeql_json_cast_object_to_json_07(self):
await self.con.execute('''
create function _get(idx: int64) -> set of json {
using (
select <json> (
select JSONTest {
number, edb_string
} filter .number = idx
)
)
};
''')
await self.assert_query_result(
r"""
SELECT _get(0)
""",
[
{'number': 0, 'edb_string': 'jumps'},
],
json_only=True,
)
async def test_edgeql_json_cast_tuple_to_json_01(self):
res = await self.con.query("""
WITH MODULE schema
SELECT
to_str(<json>(
1,
(SELECT Object {
name,
foo := 'bar',
}
FILTER Object.name = 'std::json'),
));
""")
val = res[0]
self.assertIsInstance(val, str)
self.assertEqual(
json.loads(val),
[1, {"foo": "bar", "name": "std::json"}]
)
async def test_edgeql_json_cast_tuple_to_json_02(self):
res = await self.con.query("""
SELECT
to_str(<json>(
foo := 1,
bar := [1, 2, 3]
));
""")
val = res[0]
self.assertIsInstance(val, str)
self.assertEqual(
json.loads(val),
{"foo": 1, "bar": [1, 2, 3]}
)
async def test_edgeql_json_slice_01(self):
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[:1];''',
[[1]],
['[1]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[:-1];''',
[[1, 'a', 3]],
['[1, "a", 3]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[1:-1];''',
[['a', 3]],
['["a", 3]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[-1:1];''',
[[]],
['[]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[-100:100];''',
[[1, 'a', 3, None]],
['[1, "a", 3, null]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[100:-100];''',
[[]],
['[]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[100:];''',
[[]],
['[]'],
)
await self.assert_query_result(
r'''SELECT to_json('[1, "a", 3, null]')[:-100];''',
[[]],
['[]'],
)
async def test_edgeql_json_slice_02(self):
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[:1];
''',
[[2]],
['[2]'],
)
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[:-1];
''',
[[2, "q", [3], {}]],
['[2, "q", [3], {}]'],
)
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[1:-1];
''',
[["q", [3], {}]],
['["q", [3], {}]'],
)
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[-1:1];
''',
[[]],
['[]'],
)
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[-100:100];
''',
[[2, "q", [3], {}, None]],
['[2, "q", [3], {}, null]'],
)
await self.assert_query_result(
r'''
WITH JT2 := (SELECT JSONTest FILTER .number = 2)
SELECT JT2.j_array[100:-100];
''',
[[]],
['[]'],
)
async def test_edgeql_json_slice_03(self):
async with self.assertRaisesRegexTx(
edgedb.QueryError, r'cannot slice JSON array by.*str'):
await self.con.execute(r"""
SELECT to_json('[1, "a", 3, null]')[:'1'];
""")
async def test_edgeql_json_slice_04(self):
await self.assert_query_result(
r'''SELECT to_json('"hello"')[:1];''',
['h'],
['"h"'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[:-1];''',
['hell'],
['"hell"'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[1:-1];''',
['ell'],
['"ell"'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[-1:1];''',
[''],
['""'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[-100:100];''',
['hello'],
['"hello"'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[100:-100];''',
[''],
['""'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[:-100];''',
[''],
['""'],
)
await self.assert_query_result(
r'''SELECT to_json('"hello"')[100:];''',
[''],
['""'],
)
async def test_edgeql_json_slice_05(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError, r'cannot slice JSON number'):
await self.con.execute(r"""
select to_json('123')[0:1];
""")
async def test_edgeql_json_slice_06(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError, r'cannot slice JSON object'):
await self.con.execute(r"""
select to_json('{"a":123}')[0:1];
""")
async def test_edgeql_json_slice_07(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError, r'cannot slice JSON boolean'):
await self.con.execute(r"""
select to_json('true')[0:1];
""")
async def test_edgeql_json_slice_08(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError, r'cannot slice JSON null'):
await self.con.execute(r"""
select to_json('null')[0:1];
""")
async def test_edgeql_json_bytes_cast_01(self):
await self.assert_query_result(
r"""SELECT <json>b'foo';""",
['Zm9v'],
['"Zm9v"'],
)
await self.assert_query_result(
r"""SELECT <json>(foo := b'hello', bar := [b'world']);""",
[{'bar': ['d29ybGQ='], 'foo': 'aGVsbG8='}],
['{"bar": ["d29ybGQ="], "foo": "aGVsbG8="}'],
)
await self.assert_query_result(
r"""SELECT <json>{ x := b'hello' };""",
[{'x': 'aGVsbG8='}],
['{"x": "aGVsbG8="}'],
)
await self.assert_query_result(
r"""SELECT <json>[b'foo'];""",
[['Zm9v']],
['["Zm9v"]'],
)
await self.assert_query_result(
r"""SELECT <json>(b'foo',)""",
[['Zm9v']],
['["Zm9v"]'],
)
await self.assert_query_result(
r"""SELECT <json>[(b'foo',)][0]""",
[['Zm9v']],
['["Zm9v"]'],
)
await self.assert_query_result(
r"""SELECT <json>(a := b'foo')""",
[{"a": "Zm9v"}],
['{"a": "Zm9v"}'],
)
await self.assert_query_result(
r"""SELECT <json>[(a := b'foo')][0]""",
[{"a": "Zm9v"}],
['{"a": "Zm9v"}'],
)
async def test_edgeql_json_bytes_output_01(self):
await self.assert_query_result(
r"""SELECT b'foo';""",
['Zm9v'],
[b'foo'],
)
await self.assert_query_result(
r"""SELECT { x := b'hello' };""",
[{'x': 'aGVsbG8='}],
[{'x': b'hello'}],
)
await self.assert_query_result(
r"""SELECT (b'foo',)""",
[['Zm9v']],
[[b'foo']],
)
await self.assert_query_result(
r"""SELECT [(b'foo',)][0]""",
[['Zm9v']],
[[b'foo']],
)
await self.assert_query_result(
r"""SELECT (a := b'foo')""",
[{"a": "Zm9v"}],
[{"a": b'foo'}],
)
await self.assert_query_result(
r"""SELECT [(a := b'foo')][0]""",
[{"a": "Zm9v"}],
[{"a": b'foo'}],
)
await self.assert_query_result(
r"""SELECT [b'foo'];""",
[['Zm9v']],
[[b'foo']],
)
await self.assert_query_result(
r"""SELECT (foo := b'hello', bar := [b'world']);""",
[{'bar': ['d29ybGQ='], 'foo': 'aGVsbG8='}],
[{'bar': [b'world'], 'foo': b'hello'}],
)
async def test_edgeql_json_bytes_output_02(self):
await self.con.execute(r'''
CREATE SCALAR TYPE bytes2 EXTENDING bytes;
''')
await self.assert_query_result(
r"""SELECT [<bytes2>b'foo'];""",
[['Zm9v']],
[[b'foo']],
)
async def test_edgeql_json_alias_01(self):
await self.assert_query_result(
r'''
SELECT _ := json_get(JSONTest.j_array, '0')
ORDER BY _;
''',
# JSON
[1, 2],
# Binary
['1', '2'],
)
await self.assert_query_result(
r'''
SELECT _ := json_get(JSONTest.j_array, '10')
ORDER BY _;
''',
[],
)
await self.assert_query_result(
r'''
SELECT _ := json_get(JSONTest.j_array, {'-1', '4'})
ORDER BY _;
''',
# JSON
[None, None, 1],
# Binary
['null', 'null', '1'],
)
await self.assert_query_result(
r'''
SELECT _ := json_get(
JSONTest.data,
# Each of the variadic "steps" is a set, so we should
# get a cross-product of all the possibilities. It so
# happens that the only 2 valid paths are:
# - '4', 'b', 'bar', '1' -> null
# - '4', 'b', 'bar', '2' -> {"bingo": "42!"}
{'2', '4', '4'}, {'0', 'b'}, {'bar', 'foo'}, {'1', '2'}
)
ORDER BY _;
''',
# JSON
[None, None, {'bingo': '42!'}, {'bingo': '42!'}],
# Binary
['null', 'null', '{"bingo": "42!"}', '{"bingo": "42!"}']
)
async def test_edgeql_json_alias_02(self):
await self.assert_query_result(
r'''
SELECT _ := json_get(
JSONTest.data,
# Each of the variadic "steps" is a set, so we should
# get a cross-product of all the possibilities. It so
# happens that the only 2 valid paths are:
# - '4', 'b', 'bar', '1' -> null
# - '4', 'b', 'bar', '2' -> {"bingo": "42!"}
{'2', '4', '4'}, {'0', 'b'}, {'bar', 'foo'}, {'1', '2'},
default := <json>'N/A'
)
ORDER BY _;
''',
# JSON:
# We expect 3 * 2 * 2 * 2 = 24 results per JSONTest.data.
# There are 3 non-empty data properties. Out of them all
# only 4 will have a valid path. So we expect 24 * 3 - 4 =
# 68 default 'N/A' results, 2 JSON `nulls` represented as
# `None` and 2 JSON objects.
[None, None] + ['N/A'] * 68 + [{'bingo': '42!'}, {'bingo': '42!'}],
# Binary:
['null'] * 2 + ['"N/A"'] * 68 + ['{"bingo": "42!"}'] * 2,
)
async def test_edgeql_json_alias_03(self):
await self.assert_query_result(
r'''
WITH
JT := JSONTest
SELECT JSONTest {
a0 := (
SELECT _ := json_get(JT.j_array, '0')
ORDER BY _
),
a1 := (
SELECT _ := json_get(JT.j_array, '10')
ORDER BY _
),
a2 := (
SELECT _ := json_get(JT.j_array, {'-1', '4'})
ORDER BY _
),
a3 := (
SELECT _ := json_get(
JT.data,
# Each of the variadic "steps" is a set, so we should
# get a cross-product of all the possibilities. It so
# happens that the only 2 valid paths are:
# - '4', 'b', 'bar', '1' -> null
# - '4', 'b', 'bar', '2' -> {"bingo": "42!"}
{'2', '4', '4'}, {'0', 'b'}, {'bar', 'foo'}, {'1', '2'}
)
ORDER BY _
)
}
FILTER .number = 0;
''',
# JSON
[{
'a0': [1, 2],
'a1': [],
# Nones in the output are legitimate JSON nulls
'a2': [None, None, 1],
'a3': [None, None, {'bingo': '42!'}, {'bingo': '42!'}],
}],
# Binary
[{
'a0': ['1', '2'],
'a1': [],
# Nones in the output are legitimate JSON nulls
'a2': ['null', 'null', '1'],
'a3': ['null', 'null', '{"bingo": "42!"}', '{"bingo": "42!"}'],
}],
)
async def test_edgeql_json_alias_04(self):
await self.assert_query_result(
r'''
SELECT _ := json_get(
JSONTest.data,
'0', '1', '2',
default := <json>{'N/A', 'nope', '-'}
)
ORDER BY _;
''',
# JSON:
# None of the 3 data objects have the path 0, 1, 2, so we
# expect default values in the result in triplicate.
['-', '-', '-', 'N/A', 'N/A', 'N/A', 'nope', 'nope', 'nope'],
# Binary:
['"-"', '"-"', '"-"', '"N/A"', '"N/A"', '"N/A"',
'"nope"', '"nope"', '"nope"'],
)
async def test_edgeql_json_alias_05(self):
await self.assert_query_result(
r'''
WITH
JT := JSONTest
SELECT JSONTest {
a4 := (
SELECT _ := json_get(
JT.data,
'0', '1', '2',
default := <json>{'N/A', 'nope', '-'}
)
ORDER BY _
),
}
FILTER .number = 0;
''',
# JSON
[{
'a4': [
'-', '-', '-',
'N/A', 'N/A', 'N/A',
'nope', 'nope', 'nope'
],
}],
# Binary
[{
'a4': [
'"-"', '"-"', '"-"',
'"N/A"', '"N/A"', '"N/A"',
'"nope"', '"nope"', '"nope"'
],
}],
)
async def test_edgeql_json_str_function_01(self):
await self.assert_query_result(
r'''SELECT to_str(<json>[1, 2, 3, 4]);''',
{'[1, 2, 3, 4]'},
)
await self.assert_query_result(
r'''SELECT to_str(<json>[1, 2, 3, 4], 'pretty');''',
{'[\n 1,\n 2,\n 3,\n 4\n]'},
)
async def test_edgeql_json_str_function_02(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"format 'foo' is invalid"):
async with self.con.transaction():
await self.con.query(r'''
SELECT to_str(<json>[1, 2, 3, 4], 'foo');
''')
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r'"fmt" argument must be a non-empty string'):
async with self.con.transaction():
await self.con.query_json(r'''
SELECT to_str(<json>[1, 2, 3, 4], '');
''')
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"format 'PRETTY' is invalid"):
async with self.con.transaction():
await self.con.query(r'''
SELECT to_str(<json>[1, 2, 3, 4], 'PRETTY');
''')
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"format 'Pretty' is invalid"):
async with self.con.transaction():
await self.con.query_json(r'''
SELECT to_str(<json>[1, 2, 3, 4], 'Pretty');
''')
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"format 'p' is invalid"):
async with self.con.transaction():
await self.con.query(r'''
SELECT to_str(<json>[1, 2, 3, 4], 'p');
''')
async def test_edgeql_json_long_array(self):
count = s_defs.MAX_FUNC_ARG_COUNT + 11
await self.assert_query_result(
f'''SELECT to_str(<json>[
{", ".join(str(v) for v in range(count))}
]);''',
{f'[{", ".join(str(v) for v in range(count))}]'},
)
async def test_edgeql_json_long_tuple(self):
count = s_defs.MAX_FUNC_ARG_COUNT + 11
await self.assert_query_result(
f'''SELECT to_str(<json>(
{", ".join(str(v) for v in range(count))}
));''',
{f'[{", ".join(str(v) for v in range(count))}]'},
)
async def test_edgeql_json_long_named_tuple(self):
count = s_defs.MAX_FUNC_ARG_COUNT + 11
args = (f'_{i} := {v}' for i, v in enumerate(range(count)))
result = (f'"_{i}": {v}' for i, v in enumerate(range(count)))
await self.assert_query_result(
f'SELECT to_str(<json>({", ".join(args)}));',
{f'{{{", ".join(result)}}}'},
)
async def test_edgeql_json_long_shape(self):
count = s_defs.MAX_FUNC_ARG_COUNT + 11
args = (f'_{i} := {v}' for i, v in enumerate(range(count)))
result = (f'"_{i}": {v}' for i, v in enumerate(range(count)))
await self.assert_query_result(
f'''
SELECT to_str(<json>JSONTest{{ {", ".join(args)} }})
LIMIT 1
''',
{f'{{{", ".join(result)}}}'},
)
async def test_edgeql_json_concatenate_01(self):
await self.assert_query_result(
r'''SELECT to_str(to_json('[1, 2]') ++ to_json('[3]'));''',
{'[1, 2, 3]'}
)
await self.assert_query_result(
r'''SELECT to_str(to_json('{"a": 1}') ++ to_json('{"b": 2}'));''',
{'{"a": 1, "b": 2}'}
)
await self.assert_query_result(
r'''SELECT to_str(to_json('{"a": 1}') ++ to_json('{"a": 2}'));''',
{'{"a": 2}'}
)
await self.assert_query_result(
r'''SELECT to_str(to_json('"123"') ++ to_json('"456"'));''',
{'"123456"'}
)
async def test_edgeql_json_concatenate_02(self):
async with self.assertRaisesRegexTx(
edgedb.InvalidValueError,
r"invalid JSON values for \+\+ operator"):
await self.con.query_json(
r'''SELECT to_str(to_json('"123"') ++ to_json('42'));'''
)