Skip to content

Commit 5c32f66

Browse files
no message
1 parent 3b30f5c commit 5c32f66

File tree

17 files changed

+364
-74
lines changed

17 files changed

+364
-74
lines changed

fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@
1010
#[ORM\Entity()]
1111
class ContainsJsons extends Entity
1212
{
13+
#[ORM\Column(type: 'jsonb')]
14+
public array $jsonbObject1;
15+
16+
#[ORM\Column(type: 'jsonb')]
17+
public array $jsonbObject2;
18+
1319
#[ORM\Column(type: Types::JSON)]
14-
public array $object1;
20+
public array $jsonObject1;
1521

1622
#[ORM\Column(type: Types::JSON)]
17-
public array $object2;
23+
public array $jsonObject2;
1824
}

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\IRegexp;
88
use PHPUnit\Framework\Attributes\Test;
99

10-
class IRegexpTest extends JsonTestCase
10+
class IRegexpTest extends TextTestCase
1111
{
1212
protected function getStringFunctions(): array
1313
{
@@ -17,21 +17,47 @@ protected function getStringFunctions(): array
1717
}
1818

1919
#[Test]
20-
public function iregexp(): void
20+
public function returns_true_when_pattern_matches_text_field(): void
2121
{
22-
// NOTE: Using string literals for arguments due to DQL limitations with field extraction.
23-
$dql = "SELECT IREGEXP('John', 'j.*n') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
22+
$dql = "SELECT IREGEXP(t.text1, 'test.*string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
2423
$result = $this->executeDqlQuery($dql);
2524
$this->assertIsBool($result[0]['result']);
2625
$this->assertTrue($result[0]['result']);
2726
}
2827

2928
#[Test]
30-
public function iregexp_negative(): void
29+
public function returns_true_when_pattern_matches_with_case_insensitive(): void
3130
{
32-
$dql = "SELECT IREGEXP('John', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
31+
$dql = "SELECT IREGEXP(t.text1, 'TEST.*STRING') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
32+
$result = $this->executeDqlQuery($dql);
33+
$this->assertIsBool($result[0]['result']);
34+
$this->assertTrue($result[0]['result']);
35+
}
36+
37+
#[Test]
38+
public function returns_false_when_pattern_does_not_match(): void
39+
{
40+
$dql = "SELECT IREGEXP(t.text1, 'nonexistent.*pattern') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
3341
$result = $this->executeDqlQuery($dql);
3442
$this->assertIsBool($result[0]['result']);
3543
$this->assertFalse($result[0]['result']);
3644
}
45+
46+
#[Test]
47+
public function returns_true_when_matching_second_text_field(): void
48+
{
49+
$dql = "SELECT IREGEXP(t.text2, 'another.*string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
50+
$result = $this->executeDqlQuery($dql);
51+
$this->assertIsBool($result[0]['result']);
52+
$this->assertTrue($result[0]['result']);
53+
}
54+
55+
#[Test]
56+
public function returns_true_when_matching_word_boundaries(): void
57+
{
58+
$dql = "SELECT IREGEXP(t.text1, '\\bis\\b') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
59+
$result = $this->executeDqlQuery($dql);
60+
$this->assertIsBool($result[0]['result']);
61+
$this->assertTrue($result[0]['result']);
62+
}
3763
}

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Ilike;
88
use PHPUnit\Framework\Attributes\Test;
99

10-
class IlikeTest extends JsonTestCase
10+
class IlikeTest extends TextTestCase
1111
{
1212
protected function getStringFunctions(): array
1313
{
@@ -17,19 +17,42 @@ protected function getStringFunctions(): array
1717
}
1818

1919
#[Test]
20-
public function ilike(): void
20+
public function returns_true_for_case_insensitive_matching_string(): void
2121
{
22-
// NOTE: Using string literals for arguments due to DQL limitations with field extraction.
23-
$dql = "SELECT ILIKE('John', 'john') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
22+
$dql = "SELECT ILIKE(t.text1, 'test') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
2423
$result = $this->executeDqlQuery($dql);
2524
$this->assertTrue($result[0]['result']);
2625
}
2726

2827
#[Test]
29-
public function ilike_negative(): void
28+
public function returns_true_for_case_insensitive_matching_with_different_case(): void
3029
{
31-
$dql = "SELECT ILIKE('John', 'jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
30+
$dql = "SELECT ILIKE(t.text1, 'TEST') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
31+
$result = $this->executeDqlQuery($dql);
32+
$this->assertTrue($result[0]['result']);
33+
}
34+
35+
#[Test]
36+
public function returns_false_for_non_matching_string(): void
37+
{
38+
$dql = "SELECT ILIKE(t.text1, 'nonexistent') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
3239
$result = $this->executeDqlQuery($dql);
3340
$this->assertFalse($result[0]['result']);
3441
}
42+
43+
#[Test]
44+
public function returns_true_when_matching_second_text_field(): void
45+
{
46+
$dql = "SELECT ILIKE(t.text2, 'another') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
47+
$result = $this->executeDqlQuery($dql);
48+
$this->assertTrue($result[0]['result']);
49+
}
50+
51+
#[Test]
52+
public function returns_true_when_matching_partial_string(): void
53+
{
54+
$dql = "SELECT ILIKE(t.text1, '%test%') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
55+
$result = $this->executeDqlQuery($dql);
56+
$this->assertTrue($result[0]['result']);
57+
}
3558
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;
6+
7+
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonEach;
8+
use PHPUnit\Framework\Attributes\Test;
9+
10+
class JsonEachTest extends JsonTestCase
11+
{
12+
protected function getStringFunctions(): array
13+
{
14+
return [
15+
'JSON_EACH' => JsonEach::class,
16+
];
17+
}
18+
19+
#[Test]
20+
public function extracts_key_value_pairs_from_standard_json_object(): void
21+
{
22+
$dql = 'SELECT JSON_EACH(t.jsonObject1) as result
23+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
24+
WHERE t.id = 1';
25+
$result = $this->executeDqlQuery($dql);
26+
$this->assertCount(4, $result);
27+
28+
$extractedKeys = [];
29+
foreach ($result as $row) {
30+
$this->assertIsArray($row);
31+
$this->assertArrayHasKey('result', $row);
32+
$this->assertIsString($row['result']);
33+
34+
$decoded = \json_decode($row['result'], true);
35+
if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
36+
$key = $decoded['key'];
37+
} else {
38+
$parts = \explode(':', \trim($row['result'], '{}"'));
39+
$key = $parts[0] ?? null;
40+
}
41+
42+
$this->assertNotNull($key);
43+
$extractedKeys[] = $key;
44+
}
45+
46+
$expectedKeys = ['name', 'age', 'address', 'tags'];
47+
foreach ($expectedKeys as $expectedKey) {
48+
$this->assertContains($expectedKey, $extractedKeys, \sprintf("Expected key '%s' should be extracted", $expectedKey));
49+
}
50+
}
51+
52+
#[Test]
53+
public function returns_empty_result_for_empty_object(): void
54+
{
55+
$dql = 'SELECT JSON_EACH(t.jsonObject1) as result
56+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
57+
WHERE t.id = 4';
58+
$result = $this->executeDqlQuery($dql);
59+
$this->assertCount(0, $result);
60+
}
61+
62+
#[Test]
63+
public function extracts_key_value_pairs_from_alternative_json_object(): void
64+
{
65+
$dql = 'SELECT JSON_EACH(t.jsonObject1) as result
66+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
67+
WHERE t.id = 2';
68+
$result = $this->executeDqlQuery($dql);
69+
$this->assertCount(4, $result);
70+
71+
foreach ($result as $row) {
72+
$this->assertIsArray($row);
73+
$this->assertArrayHasKey('result', $row);
74+
$this->assertIsString($row['result']);
75+
76+
$decoded = \json_decode($row['result'], true);
77+
$this->assertNotNull($decoded, 'Result should be valid JSON');
78+
}
79+
}
80+
81+
#[Test]
82+
public function extracts_key_value_pairs_when_json_contains_null_values(): void
83+
{
84+
$dql = 'SELECT JSON_EACH(t.jsonObject1) as result
85+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
86+
WHERE t.id = 5';
87+
$result = $this->executeDqlQuery($dql);
88+
$this->assertCount(4, $result);
89+
90+
foreach ($result as $row) {
91+
$this->assertIsArray($row);
92+
$this->assertArrayHasKey('result', $row);
93+
$this->assertIsString($row['result']);
94+
95+
$decoded = \json_decode($row['result'], true);
96+
$this->assertNotNull($decoded, 'Result should be valid JSON even with null values');
97+
}
98+
}
99+
100+
#[Test]
101+
public function extracts_key_value_pairs_when_json_contains_empty_array(): void
102+
{
103+
$dql = 'SELECT JSON_EACH(t.jsonObject1) as result
104+
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
105+
WHERE t.id = 3';
106+
$result = $this->executeDqlQuery($dql);
107+
$this->assertCount(4, $result);
108+
109+
foreach ($result as $row) {
110+
$this->assertIsArray($row);
111+
$this->assertArrayHasKey('result', $row);
112+
$this->assertIsString($row['result']);
113+
114+
$decoded = \json_decode($row['result'], true);
115+
$this->assertNotNull($decoded, 'Result should be valid JSON even with empty arrays');
116+
}
117+
}
118+
}

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectAggTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ protected function getStringFunctions(): array
1919
#[Test]
2020
public function can_aggregate_key_value_pairs_to_json_object(): void
2121
{
22-
$dql = "SELECT JSON_OBJECT_AGG('key', t.object1) as result
23-
FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t
22+
$dql = "SELECT JSON_OBJECT_AGG('key', t.jsonObject1) as result
23+
FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t
2424
WHERE t.id = 3";
2525
$result = $this->executeDqlQuery($dql);
2626
$this->assertIsString($result[0]['result']);

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ protected function createTestTableForJsonFixture(): void
2727
$sql = \sprintf('
2828
CREATE TABLE %s (
2929
id SERIAL PRIMARY KEY,
30-
object1 JSONB,
31-
object2 JSONB
30+
jsonbObject1 JSONB,
31+
jsonbObject2 JSONB,
32+
jsonObject1 JSON,
33+
jsonObject2 JSON
3234
)
3335
', $fullTableName);
3436

@@ -43,14 +45,37 @@ protected function insertTestDataForJsonFixture(): void
4345
$json4 = '{}';
4446
$json5 = '{"name": "John", "age": null, "tags": ["developer"], "address": {"city": "New York", "zip": null}}';
4547

46-
$sql = \sprintf('
47-
INSERT INTO %s.containsjsons (object1, object2) VALUES
48-
(\'%s\', \'%s\'),
49-
(\'%s\', \'%s\'),
50-
(\'%s\', \'%s\'),
51-
(\'%s\', \'%s\'),
52-
(\'%s\', \'%s\')
53-
', self::DATABASE_SCHEMA, $json1, $json1, $json2, $json2, $json3, $json3, $json4, $json4, $json5, $json5);
48+
$sql = \sprintf(
49+
'
50+
INSERT INTO %s.containsjsons (jsonbObject1, jsonbObject2, jsonObject1, jsonObject2) VALUES
51+
(\'%s\', \'%s\', \'%s\', \'%s\'),
52+
(\'%s\', \'%s\', \'%s\', \'%s\'),
53+
(\'%s\', \'%s\', \'%s\', \'%s\'),
54+
(\'%s\', \'%s\', \'%s\', \'%s\'),
55+
(\'%s\', \'%s\', \'%s\', \'%s\')
56+
',
57+
self::DATABASE_SCHEMA,
58+
$json1,
59+
$json1,
60+
$json1,
61+
$json1,
62+
$json2,
63+
$json2,
64+
$json2,
65+
$json2,
66+
$json3,
67+
$json3,
68+
$json3,
69+
$json3,
70+
$json4,
71+
$json4,
72+
$json4,
73+
$json4,
74+
$json5,
75+
$json5,
76+
$json5,
77+
$json5
78+
);
5479
$this->connection->executeStatement($sql);
5580
}
5681
}

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ protected function getStringFunctions(): array
1919
#[Test]
2020
public function extracts_key_value_pairs_from_standard_json_object(): void
2121
{
22-
$dql = 'SELECT JSONB_EACH(t.object1) as result
22+
$dql = 'SELECT JSONB_EACH(t.jsonbObject1) as result
2323
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
2424
WHERE t.id = 1';
2525
$result = $this->executeDqlQuery($dql);
@@ -52,7 +52,7 @@ public function extracts_key_value_pairs_from_standard_json_object(): void
5252
#[Test]
5353
public function returns_empty_result_for_empty_object(): void
5454
{
55-
$dql = 'SELECT JSONB_EACH(t.object1) as result
55+
$dql = 'SELECT JSONB_EACH(t.jsonbObject1) as result
5656
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
5757
WHERE t.id = 4';
5858
$result = $this->executeDqlQuery($dql);
@@ -62,7 +62,7 @@ public function returns_empty_result_for_empty_object(): void
6262
#[Test]
6363
public function extracts_key_value_pairs_from_alternative_json_object(): void
6464
{
65-
$dql = 'SELECT JSONB_EACH(t.object1) as result
65+
$dql = 'SELECT JSONB_EACH(t.jsonbObject1) as result
6666
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
6767
WHERE t.id = 2';
6868
$result = $this->executeDqlQuery($dql);
@@ -81,7 +81,7 @@ public function extracts_key_value_pairs_from_alternative_json_object(): void
8181
#[Test]
8282
public function extracts_key_value_pairs_when_json_contains_null_values(): void
8383
{
84-
$dql = 'SELECT JSONB_EACH(t.object1) as result
84+
$dql = 'SELECT JSONB_EACH(t.jsonbObject1) as result
8585
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
8686
WHERE t.id = 5';
8787
$result = $this->executeDqlQuery($dql);
@@ -100,7 +100,7 @@ public function extracts_key_value_pairs_when_json_contains_null_values(): void
100100
#[Test]
101101
public function extracts_key_value_pairs_when_json_contains_empty_array(): void
102102
{
103-
$dql = 'SELECT JSONB_EACH(t.object1) as result
103+
$dql = 'SELECT JSONB_EACH(t.jsonbObject1) as result
104104
FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
105105
WHERE t.id = 3';
106106
$result = $this->executeDqlQuery($dql);

0 commit comments

Comments
 (0)