From 874d68696485d083ded4d8e03c5d9bd89ed87ad2 Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Wed, 21 May 2025 18:29:04 +0100 Subject: [PATCH 1/4] chore: test functions against a real PostgreSQL server --- .../ORM/Query/AST/Functions/JsonTestCase.php | 8 +- .../ORM/Query/AST/Functions/JsonbAggTest.php | 30 +------ .../AST/Functions/JsonbArrayElementsTest.php | 39 +++++++++ .../Functions/JsonbArrayElementsTextTest.php | 39 +++++++++ .../Query/AST/Functions/JsonbInsertTest.php | 70 ++++++++++++++++ .../AST/Functions/JsonbObjectAggTest.php | 29 +++++++ .../AST/Functions/JsonbObjectKeysTest.php | 26 ++++++ .../AST/Functions/JsonbPathQueryArrayTest.php | 79 +++++++++++++++++++ .../AST/Functions/JsonbPathQueryFirstTest.php | 78 ++++++++++++++++++ .../AST/Functions/JsonbPathQueryTest.php | 74 +++++++++++++++++ .../Query/AST/Functions/JsonbPrettyTest.php | 26 ++++++ .../Query/AST/Functions/JsonbSetLaxTest.php | 73 +++++++++++++++++ .../ORM/Query/AST/Functions/JsonbSetTest.php | 73 +++++++++++++++++ .../AST/Functions/JsonbStripNullsTest.php | 37 +++++++++ 14 files changed, 653 insertions(+), 28 deletions(-) create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php create mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php index f1965cd7..cad26d6d 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php @@ -39,12 +39,18 @@ protected function insertTestDataForJsonFixture(): void { $json1 = '{"name": "John", "age": 30, "tags": ["developer", "manager"], "address": {"city": "New York"}}'; $json2 = '{"name": "Jane", "age": 25, "tags": ["designer"], "address": {"city": "Boston"}}'; + $json3 = '{"name": "Micky", "age": 30, "tags": [], "address": {"city": "New York"}}'; + $json4 = '{}'; + $json5 = '{"name": "John", "age": null, "tags": ["developer"], "address": {"city": "New York", "zip": null}}'; $sql = \sprintf(' INSERT INTO %s.containsjsons (object1, object2) VALUES (\'%s\', \'%s\'), + (\'%s\', \'%s\'), + (\'%s\', \'%s\'), + (\'%s\', \'%s\'), (\'%s\', \'%s\') - ', self::DATABASE_SCHEMA, $json1, $json1, $json2, $json2); + ', self::DATABASE_SCHEMA, $json1, $json1, $json2, $json2, $json3, $json3, $json4, $json4, $json5, $json5); $this->connection->executeStatement($sql); } } diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php index b452e73d..8e51cbe9 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php @@ -31,35 +31,11 @@ public function test_jsonb_agg_with_single_row(): void $this->assertEqualsCanonicalizing($expected, $actual); } - public function test_jsonb_agg_with_all_rows(): void + public function test_jsonb_agg_with_multiple_rows(): void { $dql = 'SELECT JSONB_AGG(t.object1) as result - FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t'; - $result = $this->executeDqlQuery($dql); - $this->assertIsString($result[0]['result']); - $actual = \json_decode($result[0]['result'], true); - $this->assertIsArray($actual); - $expected = [ - [ - 'name' => 'John', - 'age' => 30, - 'tags' => ['developer', 'manager'], - 'address' => ['city' => 'New York'], - ], - [ - 'name' => 'Jane', - 'age' => 25, - 'tags' => ['designer'], - 'address' => ['city' => 'Boston'], - ], - ]; - $this->assertEqualsCanonicalizing($expected, $actual); - } - - public function test_jsonb_agg_with_object2_column(): void - { - $dql = 'SELECT JSONB_AGG(t.object2) as result - FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t'; + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id IN (1, 2)'; $result = $this->executeDqlQuery($dql); $this->assertIsString($result[0]['result']); $actual = \json_decode($result[0]['result'], true); diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php new file mode 100644 index 00000000..5a76f2a2 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php @@ -0,0 +1,39 @@ + JsonbArrayElements::class, + ]; + } + + public function test_jsonb_array_elements(): void + { + $dql = 'SELECT JSONB_ARRAY_ELEMENTS(t.object1) as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql); + $this->assertIsArray($result); + $this->assertCount(2, $result); + $this->assertSame('"developer"', $result[0]['result']); + $this->assertSame('"manager"', $result[1]['result']); + } + + public function test_jsonb_array_elements_with_empty_array(): void + { + $dql = 'SELECT JSONB_ARRAY_ELEMENTS(t.object1) as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 3'; + $result = $this->executeDqlQuery($dql); + $this->assertIsArray($result); + $this->assertCount(0, $result); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php new file mode 100644 index 00000000..f72008cf --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php @@ -0,0 +1,39 @@ + JsonbArrayElementsText::class, + ]; + } + + public function test_jsonb_array_elements_text(): void + { + $dql = 'SELECT JSONB_ARRAY_ELEMENTS_TEXT(t.object1) as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql); + $this->assertIsArray($result); + $this->assertCount(2, $result); + $this->assertSame('developer', $result[0]['result']); + $this->assertSame('manager', $result[1]['result']); + } + + public function test_jsonb_array_elements_text_with_empty_array(): void + { + $dql = 'SELECT JSONB_ARRAY_ELEMENTS_TEXT(t.object1) as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 3'; + $result = $this->executeDqlQuery($dql); + $this->assertIsArray($result); + $this->assertCount(0, $result); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php new file mode 100644 index 00000000..c47e88b3 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php @@ -0,0 +1,70 @@ + JsonbInsert::class, + ]; + } + + public function test_jsonb_insert_new_value(): void + { + $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{email}', + 'value' => '"john@example.com"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('john@example.com', $decoded['email']); + } + + public function test_jsonb_insert_nested_path(): void + { + $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{address,zip}', + 'value' => '"10001"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('10001', $decoded['address']['zip']); + } + + public function test_jsonb_insert_existing_path(): void + { + $this->expectException(Exception::class); + $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $this->executeDqlQuery($dql, [ + 'path' => '{name}', + 'value' => '"John Doe"', + ]); + } + + public function test_jsonb_insert_with_insert_if_missing_true(): void + { + $this->expectException(Exception::class); + $dql = "SELECT JSONB_INSERT(t.object1, :path, :value, 'true') as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 1"; + $this->executeDqlQuery($dql, [ + 'path' => '{name}', + 'value' => '"John Doe"', + ]); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php new file mode 100644 index 00000000..2c3bc35e --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php @@ -0,0 +1,29 @@ + JsonbObjectAgg::class, + ]; + } + + public function test_jsonb_object_agg(): void + { + $dql = "SELECT JSONB_OBJECT_AGG('key', 'value') as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 1"; + $result = $this->executeDqlQuery($dql); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertSame(['key' => 'value'], $decoded); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php new file mode 100644 index 00000000..b37f4b28 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php @@ -0,0 +1,26 @@ + JsonbObjectKeys::class, + ]; + } + + public function test_jsonb_object_keys(): void + { + $dql = 'SELECT JSONB_OBJECT_KEYS(t.object1) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql); + $this->assertIsString($result[0]['result']); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php new file mode 100644 index 00000000..311ecb34 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php @@ -0,0 +1,79 @@ + JsonbPathQueryArray::class, + ]; + } + + public function test_jsonb_path_query_array_simple(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"a": 1, "b": 2}', + 'path' => '$.b', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertCount(1, $decoded); + $this->assertSame(2, $decoded[0]); + } + + public function test_jsonb_path_query_array_multiple_values(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [1, 2, 3]}', + 'path' => '$.items[*]', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertCount(3, $decoded); + $this->assertSame([1, 2, 3], $decoded); + } + + public function test_jsonb_path_query_array_with_filter(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [{"id": 1}, {"id": 2}, {"id": 3}]}', + 'path' => '$.items[*] ? (@.id > 1)', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertCount(2, $decoded); + $this->assertSame(['id' => 2], $decoded[0]); + $this->assertSame(['id' => 3], $decoded[1]); + } + + public function test_jsonb_path_query_array_with_column_reference(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(t.object1, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, ['path' => '$.tags[*]']); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertCount(2, $decoded); + $this->assertSame(['developer', 'manager'], $decoded); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php new file mode 100644 index 00000000..fd69f09b --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php @@ -0,0 +1,78 @@ + JsonbPathQueryFirst::class, + ]; + } + + public function test_jsonb_path_query_first_simple(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_FIRST(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"a": 1, "b": 2}', + 'path' => '$.b', + ]); + $this->assertIsString($result[0]['result']); + $this->assertSame('2', $result[0]['result']); + } + + public function test_jsonb_path_query_first_array(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_FIRST(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [1, 2, 3]}', + 'path' => '$.items[*]', + ]); + $this->assertIsString($result[0]['result']); + $this->assertSame('1', $result[0]['result']); + } + + public function test_jsonb_path_query_first_with_filter(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_FIRST(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [{"id": 1}, {"id": 2}, {"id": 3}]}', + 'path' => '$.items[*] ? (@.id > 1)', + ]); + $this->assertIsString($result[0]['result']); + $this->assertSame('{"id": 2}', $result[0]['result']); + } + + public function test_jsonb_path_query_first_with_no_match(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_FIRST(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [{"id": 1}]}', + 'path' => '$.items[*] ? (@.id > 1)', + ]); + $this->assertNull($result[0]['result']); + } + + public function test_jsonb_path_query_first_with_column_reference(): void + { + $dql = 'SELECT JSONB_PATH_QUERY_FIRST(t.object1, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, ['path' => '$.tags[*]']); + $this->assertIsString($result[0]['result']); + $this->assertSame('"developer"', $result[0]['result']); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php new file mode 100644 index 00000000..1f02dd1d --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php @@ -0,0 +1,74 @@ + JsonbPathQuery::class, + ]; + } + + public function test_jsonb_path_query_simple(): void + { + $dql = 'SELECT JSONB_PATH_QUERY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"a": 1, "b": 2}', + 'path' => '$.b', + ]); + $this->assertIsArray($result); + $this->assertCount(1, $result); + $this->assertSame('2', $result[0]['result']); + } + + public function test_jsonb_path_query_array(): void + { + $dql = 'SELECT JSONB_PATH_QUERY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [1, 2, 3]}', + 'path' => '$.items[*]', + ]); + $this->assertIsArray($result); + $this->assertCount(3, $result); + $this->assertSame('1', $result[0]['result']); + $this->assertSame('2', $result[1]['result']); + $this->assertSame('3', $result[2]['result']); + } + + public function test_jsonb_path_query_with_filter(): void + { + $dql = 'SELECT JSONB_PATH_QUERY(:json, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'json' => '{"items": [{"id": 1}, {"id": 2}, {"id": 3}]}', + 'path' => '$.items[*] ? (@.id > 1)', + ]); + $this->assertIsArray($result); + $this->assertCount(2, $result); + $this->assertSame('{"id": 2}', $result[0]['result']); + $this->assertSame('{"id": 3}', $result[1]['result']); + } + + public function test_jsonb_path_query_with_column_reference(): void + { + $dql = 'SELECT JSONB_PATH_QUERY(t.object1, :path) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, ['path' => '$.tags[*]']); + $this->assertIsArray($result); + $this->assertCount(2, $result); + $this->assertSame('"developer"', $result[0]['result']); + $this->assertSame('"manager"', $result[1]['result']); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php new file mode 100644 index 00000000..d6c1e611 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php @@ -0,0 +1,26 @@ + JsonbPretty::class, + ]; + } + + public function test_jsonb_pretty(): void + { + $dql = 'SELECT JSONB_PRETTY(t.object1) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql); + $this->assertIsString($result[0]['result']); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php new file mode 100644 index 00000000..b38f2b6e --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php @@ -0,0 +1,73 @@ + JsonbSetLax::class, + ]; + } + + public function test_jsonb_set_lax_update_existing_value(): void + { + $dql = 'SELECT JSONB_SET_LAX(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{name}', + 'value' => '"John Doe"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('John Doe', $decoded['name']); + } + + public function test_jsonb_set_lax_add_new_value(): void + { + $dql = 'SELECT JSONB_SET_LAX(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{email}', + 'value' => '"john@example.com"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('john@example.com', $decoded['email']); + } + + public function test_jsonb_set_lax_nested_path(): void + { + $dql = 'SELECT JSONB_SET_LAX(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{address,zip}', + 'value' => '"10001"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('10001', $decoded['address']['zip']); + } + + public function test_jsonb_set_lax_with_invalid_path(): void + { + $dql = 'SELECT JSONB_SET_LAX(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{invalid,path}', + 'value' => '"value"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertArrayNotHasKey('invalid', $decoded); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php new file mode 100644 index 00000000..6e5c6993 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php @@ -0,0 +1,73 @@ + JsonbSet::class, + ]; + } + + public function test_jsonb_set_update_existing_value(): void + { + $dql = 'SELECT JSONB_SET(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{name}', + 'value' => '"John Doe"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('John Doe', $decoded['name']); + } + + public function test_jsonb_set_add_new_value(): void + { + $dql = 'SELECT JSONB_SET(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{email}', + 'value' => '"john@example.com"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('john@example.com', $decoded['email']); + } + + public function test_jsonb_set_nested_path(): void + { + $dql = 'SELECT JSONB_SET(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{address,zip}', + 'value' => '"10001"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertSame('10001', $decoded['address']['zip']); + } + + public function test_jsonb_set_with_create_missing_false(): void + { + $dql = "SELECT JSONB_SET(t.object1, :path, :value, 'false') as result + FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t + WHERE t.id = 1"; + $result = $this->executeDqlQuery($dql, [ + 'path' => '{nonexistent}', + 'value' => '"value"', + ]); + $this->assertIsString($result[0]['result']); + $decoded = \json_decode($result[0]['result'], true); + $this->assertArrayNotHasKey('nonexistent', $decoded); + } +} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php new file mode 100644 index 00000000..68be7955 --- /dev/null +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php @@ -0,0 +1,37 @@ + JsonbStripNulls::class, + ]; + } + + public function test_jsonb_strip_nulls(): void + { + $dql = 'SELECT JSONB_STRIP_NULLS(t.object1) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 1'; + $result = $this->executeDqlQuery($dql); + $this->assertIsString($result[0]['result']); + } + + public function test_jsonb_strip_nulls_with_null_values(): void + { + $dql = 'SELECT JSONB_STRIP_NULLS(t.object1) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 5'; + $result = $this->executeDqlQuery($dql); + $this->assertIsString($result[0]['result']); + $this->assertStringNotContainsString('"age": null', $result[0]['result']); + $this->assertStringNotContainsString('"zip": null', $result[0]['result']); + } +} From 0924b2627eeb6d351dd581aacf0c62c0a558059f Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Wed, 21 May 2025 18:34:04 +0100 Subject: [PATCH 2/4] no message --- .../AST/Functions/JsonbArrayElementsTest.php | 39 ------------------- .../Functions/JsonbArrayElementsTextTest.php | 39 ------------------- .../Query/AST/Functions/JsonbInsertTest.php | 6 +++ .../Query/AST/Functions/JsonbSetLaxTest.php | 11 +++++- .../ORM/Query/AST/Functions/JsonbSetTest.php | 11 +++++- 5 files changed, 26 insertions(+), 80 deletions(-) delete mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php delete mode 100644 tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php deleted file mode 100644 index 5a76f2a2..00000000 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTest.php +++ /dev/null @@ -1,39 +0,0 @@ - JsonbArrayElements::class, - ]; - } - - public function test_jsonb_array_elements(): void - { - $dql = 'SELECT JSONB_ARRAY_ELEMENTS(t.object1) as result - FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t - WHERE t.id = 1'; - $result = $this->executeDqlQuery($dql); - $this->assertIsArray($result); - $this->assertCount(2, $result); - $this->assertSame('"developer"', $result[0]['result']); - $this->assertSame('"manager"', $result[1]['result']); - } - - public function test_jsonb_array_elements_with_empty_array(): void - { - $dql = 'SELECT JSONB_ARRAY_ELEMENTS(t.object1) as result - FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t - WHERE t.id = 3'; - $result = $this->executeDqlQuery($dql); - $this->assertIsArray($result); - $this->assertCount(0, $result); - } -} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php deleted file mode 100644 index f72008cf..00000000 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php +++ /dev/null @@ -1,39 +0,0 @@ - JsonbArrayElementsText::class, - ]; - } - - public function test_jsonb_array_elements_text(): void - { - $dql = 'SELECT JSONB_ARRAY_ELEMENTS_TEXT(t.object1) as result - FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t - WHERE t.id = 1'; - $result = $this->executeDqlQuery($dql); - $this->assertIsArray($result); - $this->assertCount(2, $result); - $this->assertSame('developer', $result[0]['result']); - $this->assertSame('manager', $result[1]['result']); - } - - public function test_jsonb_array_elements_text_with_empty_array(): void - { - $dql = 'SELECT JSONB_ARRAY_ELEMENTS_TEXT(t.object1) as result - FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t - WHERE t.id = 3'; - $result = $this->executeDqlQuery($dql); - $this->assertIsArray($result); - $this->assertCount(0, $result); - } -} diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php index c47e88b3..773f989b 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php @@ -27,6 +27,8 @@ public function test_jsonb_insert_new_value(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('email', $decoded); $this->assertSame('john@example.com', $decoded['email']); } @@ -41,6 +43,10 @@ public function test_jsonb_insert_nested_path(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('address', $decoded); + $this->assertIsArray($decoded['address']); + $this->assertArrayHasKey('zip', $decoded['address']); $this->assertSame('10001', $decoded['address']['zip']); } diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php index b38f2b6e..59229340 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php @@ -26,6 +26,8 @@ public function test_jsonb_set_lax_update_existing_value(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('name', $decoded); $this->assertSame('John Doe', $decoded['name']); } @@ -40,6 +42,8 @@ public function test_jsonb_set_lax_add_new_value(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('email', $decoded); $this->assertSame('john@example.com', $decoded['email']); } @@ -54,6 +58,10 @@ public function test_jsonb_set_lax_nested_path(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('address', $decoded); + $this->assertIsArray($decoded['address']); + $this->assertArrayHasKey('zip', $decoded['address']); $this->assertSame('10001', $decoded['address']['zip']); } @@ -68,6 +76,7 @@ public function test_jsonb_set_lax_with_invalid_path(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); - $this->assertArrayNotHasKey('invalid', $decoded); + $this->assertIsArray($decoded); + self::assertArrayNotHasKey('invalid', $decoded); } } diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php index 6e5c6993..c1268666 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php @@ -26,6 +26,8 @@ public function test_jsonb_set_update_existing_value(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('name', $decoded); $this->assertSame('John Doe', $decoded['name']); } @@ -40,6 +42,8 @@ public function test_jsonb_set_add_new_value(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('email', $decoded); $this->assertSame('john@example.com', $decoded['email']); } @@ -54,6 +58,10 @@ public function test_jsonb_set_nested_path(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); + $this->assertIsArray($decoded); + $this->assertArrayHasKey('address', $decoded); + $this->assertIsArray($decoded['address']); + $this->assertArrayHasKey('zip', $decoded['address']); $this->assertSame('10001', $decoded['address']['zip']); } @@ -68,6 +76,7 @@ public function test_jsonb_set_with_create_missing_false(): void ]); $this->assertIsString($result[0]['result']); $decoded = \json_decode($result[0]['result'], true); - $this->assertArrayNotHasKey('nonexistent', $decoded); + $this->assertIsArray($decoded); + self::assertArrayNotHasKey('nonexistent', $decoded); } } From ec954a5af8ab5cf5152f79f3da2af4556ec5385e Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Wed, 21 May 2025 19:12:29 +0100 Subject: [PATCH 3/4] no message --- .../ORM/Query/AST/Functions/JsonbInsertTest.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php index 773f989b..2b99b909 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php @@ -50,7 +50,7 @@ public function test_jsonb_insert_nested_path(): void $this->assertSame('10001', $decoded['address']['zip']); } - public function test_jsonb_insert_existing_path(): void + public function test_throws_exception_when_inserting_at_existing_object_key(): void { $this->expectException(Exception::class); $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) as result @@ -62,15 +62,17 @@ public function test_jsonb_insert_existing_path(): void ]); } - public function test_jsonb_insert_with_insert_if_missing_true(): void + public function test_throws_exception_when_inserting_at_existing_nested_path(): void { $this->expectException(Exception::class); - $dql = "SELECT JSONB_INSERT(t.object1, :path, :value, 'true') as result - FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t - WHERE t.id = 1"; + + $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) as result + FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t + WHERE t.id = 5'; + $this->executeDqlQuery($dql, [ - 'path' => '{name}', - 'value' => '"John Doe"', + 'path' => '{address,zip}', + 'value' => '"10001"', ]); } } From 8b2bdee709fd9a5e5f50a508d24292c37384144b Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Wed, 21 May 2025 19:22:40 +0100 Subject: [PATCH 4/4] no message --- .../Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php index 2b99b909..537ff017 100644 --- a/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php +++ b/tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php @@ -71,7 +71,7 @@ public function test_throws_exception_when_inserting_at_existing_nested_path(): WHERE t.id = 5'; $this->executeDqlQuery($dql, [ - 'path' => '{address,zip}', + 'path' => '{address,zip}', 'value' => '"10001"', ]); }