Skip to content

Conversation

@martin-georgiev
Copy link
Owner

@martin-georgiev martin-georgiev commented Aug 26, 2025

Summary by CodeRabbit

  • Tests
    • Migrated many tests to attribute-based discovery (#[Test]) and renamed them for clarity.
    • Replaced static PHPUnit assertions with instance-style ($this->assert*).
    • Added new integration/unit tests and expanded coverage for text/JSON/regex scenarios.
    • Updated test fixtures and JSON/JSONB field names; adjusted some expected results (range bounds, array positions) — test logic mostly unchanged.

@coveralls
Copy link

coveralls commented Aug 26, 2025

Coverage Status

coverage: 94.381%. remained the same
when pulling dcfa5cc on tests-attribute
into d4f6794 on main.

@coderabbitai
Copy link

coderabbitai bot commented Aug 26, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Walkthrough

Converted a large set of tests to PHPUnit PHP‑8 attribute discovery (use PHPUnit\Framework\Attributes\Test; + #[Test]), renamed many test methods to descriptive names, reformatted some function-mapping arrays, replaced many static self::assert* calls with instance $this->assert*, and updated JSON/JSONB fixture fields and related test data.

Changes

Cohort / File(s) Change Summary
Array functions tests
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/*Array*.php, tests/Integration/.../ArrayPositionTest.php, .../ArrayPositionsTest.php
Added use PHPUnit\Framework\Attributes\Test; and #[Test], renamed many test methods to descriptive names, reformatted getStringFunctions() arrays; minor DQL/expected-value tweaks in ArrayPosition/ArrayPositions.
JSON / JSONB fixtures & tests
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php, tests/Integration/.../Json*, tests/Unit/.../Json*/Jsonb*, tests/Integration/.../JsonTestCase.php
Added JSONB/JSON fields (jsonbObject1/2, renamed object1/2jsonObject1/2), updated schema/insert data, added JsonEachTest, switched many tests to #[Test], and updated DQL/SQL expectations to use new field names.
Regexp / ILike / text tests
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/{IRegexp,NotIRegexp,RegexpLike,RegexpReplace,Regexp,RegexpInstr,Ilike}.php
Switched to attribute discovery, sometimes changed base test case to TextTestCase, renamed tests, added new cases (word boundaries, second-field matches, case sensitivity), and updated fixtures/DQL to use text fields.
Math / numeric / trig / rounding tests
tests/Integration/.../{Ceil,Floor,Degrees,Exp,Ln,Log,Pi,Random,Power,Sign,WidthBucket,Cbrt,Round,Radians}Test.php
Applied #[Test] + renamed methods (removed test_), preserved test logic and assertions.
Date/time & formatting/parsing
tests/Integration/.../{DateExtract,ToChar,ToNumber,ToTimestamp,ToDate}Test.php
Migrated to #[Test], renamed methods, standardized TO_DATE mapping in ToDateTest, and updated some assertions from static to instance style.
Range functions
tests/Integration/.../{Daterange,Int4range,Int8range,Numrange,Tsrange,Tstzrange}Test.php
Migrated to #[Test], renamed methods, and updated expected range bound representations for several custom-bound tests.
Cast/contains/in-array/delete-at-path & misc integration
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/*
Large-scale attribute migration and method renames across many integration tests; preserved logic, small assertion/formatting tweaks in spots.
Unit tests: DBAL types, value objects, utils
tests/Unit/MartinGeorgiev/** (many files)
Replaced static self::assert* with instance $this->assert* across many unit tests and helper methods; no behavioral changes.
Test helpers / TestCase
tests/Unit/.../Query/AST/Functions/TestCase.php, tests/Integration/.../JsonTestCase.php
Converted static assertions to instance assertions in helpers; updated JsonTestCase schema/data to match renamed JSON/JSONB fields.

Sequence Diagram(s)

(Skipped) — changes are test refactors and fixture renames; no new runtime control flow to illustrate.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

dx

Poem

🐇 I hopped through tests with nimble paws,
swapped prefixes for attributes because.
Assertions softened, fixtures renamed,
tidy tests sprouted — none were blamed.
🥕 Small refactors, a rabbit's applause.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tests-attribute

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (46)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LnTest.php (2)

19-21: Consider renaming the method for consistency with existing naming in Integration tests.

Other numeric function tests (e.g., CeilTest) use the pattern with. Suggest aligning this one to improve scan-ability in IDEs and CI outputs.

Apply this minimal rename:

-    #[Test]
-    public function ln(): void
+    #[Test]
+    public function ln_with_decimal_literal(): void

27-33: Minor naming tweak for consistency.

To mirror CeilTest’s “..._with_column_value” style, consider renaming for uniformity across the suite.

-    #[Test]
-    public function ln_with_entity_property(): void
+    #[Test]
+    public function ln_with_column_value(): void
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (2)

17-51: Optional: DRY the three identical test shapes via a DataProvider

All three tests differ only by field/array type. Consider consolidating into a single parameterized test to reduce duplication and speed up future additions (e.g., jsonb arrays).

Apply this diff to collapse the three methods into one (PHPUnit 10+):

@@
-    #[Test]
-    public function array_number_of_dimensions_with_text_array(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.textArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
-
-    #[Test]
-    public function array_number_of_dimensions_with_integer_array(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.integerArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
-
-    #[Test]
-    public function array_number_of_dimensions_with_boolean_array(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.boolArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
+    #[Test]
+    #[DataProvider('arrayFields')]
+    public function array_number_of_dimensions_with_various_arrays(string $field): void
+    {
+        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(' . $field . ') as result 
+                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
+                WHERE t.id = 1';
+
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
+        $this->assertSame(1, $result[0]['result']);
+    }
+
+    public static function arrayFields(): array
+    {
+        return [
+            ['t.textArray'],
+            ['t.integerArray'],
+            ['t.boolArray'],
+        ];
+    }

Additional import required at the top of the file:

use PHPUnit\Framework\Attributes\DataProvider;

If you prefer to keep this PR focused strictly on migrating discovery, feel free to defer this refactor.


24-26: Nit: consider dropping redundant assertIsInt

assertSame(1, $result[0]['result']) already guarantees integer type and value; the preceding assertIsInt is therefore redundant. Keeping both is harmless but slightly noisy.

Also applies to: 36-38, 48-50

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsrangeTest.php (2)

27-33: Minor: simplify DQL string escaping and/or prefer ::class for the entity FQCN.

Current double-escaping of backslashes in the double-quoted PHP string is unnecessary and slightly noisy. Two optional tweaks:

  • Minimal change (keep current style, reduce escaping):
-        $dql = "SELECT TSRANGE(t.datetime1, t.datetime2, '(]') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsDates t WHERE t.id = 1";
+        $dql = "SELECT TSRANGE(t.datetime1, t.datetime2, '(]') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsDates t WHERE t.id = 1";
  • Preferable for maintainability: use the entity ::class so refactors are safer (apply similarly to the first test method):
use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsDates;

// ...
$dql = "SELECT TSRANGE(t.datetime1, t.datetime2, '(]') as result FROM " . ContainsDates::class . " t WHERE t.id = 1";

8-8: PHPUnit attributes support confirmed

  • composer.json specifies phpunit/phpunit ^10.5.53, which includes support for attribute-based tests in PHPUnit 10+.
  • The use PHPUnit\Framework\Attributes\Test; import is correct and will enable #[Test] discovery.
  • We counted 124 tests using #[Test] in this directory, showing attribute-based tests are in use.
  • There are still numerous legacy function test_* methods in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions; PHPUnit will continue to discover these alongside attributes.

For consistency, you may optionally migrate those legacy test_ methods to #[Test], but no changes are strictly required here.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/WidthBucketTest.php (1)

19-25: Optional: collapse the two nearly identical tests into a single parameterized one

Both tests differ only by DQL and share identical flow/expectation. You can reduce duplication with a DataProvider attribute.

Apply within this file:

@@
-    #[Test]
-    public function width_bucket(): void
-    {
-        $dql = 'SELECT WIDTH_BUCKET(5.35, 0.024, 10.06, 5) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertSame(3, $result[0]['result']);
-    }
-
-    #[Test]
-    public function width_bucket_with_entity_property(): void
-    {
-        $dql = 'SELECT WIDTH_BUCKET(n.decimal1, 0.0, 20.0, 4) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n WHERE n.id = 1';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertSame(3, $result[0]['result']);
-    }
+    #[Test]
+    #[DataProvider('widthBucketCases')]
+    public function width_bucket_cases(string $dql, int $expected): void
+    {
+        $result = $this->executeDqlQuery($dql);
+        $this->assertSame($expected, $result[0]['result']);
+    }
+
+    public static function widthBucketCases(): iterable
+    {
+        yield 'with constants' => [
+            'SELECT WIDTH_BUCKET(5.35, 0.024, 10.06, 5) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
+            3,
+        ];
+        yield 'with entity property' => [
+            'SELECT WIDTH_BUCKET(n.decimal1, 0.0, 20.0, 4) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n WHERE n.id = 1',
+            3,
+        ];
+    }

And add this import (outside the selected lines):

use PHPUnit\Framework\Attributes\DataProvider;

Also applies to: 27-33

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

19-21: Name the test more descriptively (optional) and consider TestDox for nicer output

Method name iregexp() is succinct but not very descriptive. Consider a clearer name and optional TestDox for readable test reports.

Apply within the selected range:

-    #[Test]
-    public function iregexp(): void
+    #[Test]
+    public function iregexp_matches_pattern(): void

Additionally add this import near the other use statements (outside the selected range):

use PHPUnit\Framework\Attributes\TestDox;

And, if you want nicer output:

-    #[Test]
+    #[Test, TestDox('IREGEXP matches /j.*n/ for "John"')]

29-31: Mirror the positive case naming and optional TestDox for the negative scenario

Keep naming symmetrical and human-readable in reports.

Apply within the selected range:

-    #[Test]
-    public function iregexp_negative(): void
+    #[Test]
+    public function iregexp_does_not_match_pattern(): void

Optionally, with TestDox:

-    #[Test]
+    #[Test, TestDox('IREGEXP does not match "Jane" against "John"')]

19-21: Optional: collapse both cases via a DataProvider for less duplication

Not required, but this reduces duplication and makes it easy to add more cases.

Example (requires adding the DataProvider attribute import and provider method outside these ranges):

use PHPUnit\Framework\Attributes\DataProvider;

Within the selected ranges, replace both methods with a single parametrized one:

-    #[Test]
-    public function iregexp(): void
-    {
-        $dql = "SELECT IREGEXP('John', 'j.*n') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsBool($result[0]['result']);
-        $this->assertTrue($result[0]['result']);
-    }
-
-    #[Test]
-    public function iregexp_negative(): void
-    {
-        $dql = "SELECT IREGEXP('John', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsBool($result[0]['result']);
-        $this->assertFalse($result[0]['result']);
-    }
+    #[Test, DataProvider('iregexpCases')]
+    public function iregexp_behaves_as_expected(string $input, string $pattern, bool $expected): void
+    {
+        $dql = "SELECT IREGEXP('$input', '$pattern') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertSame($expected, $result[0]['result']);
+    }

Add this provider outside the selected ranges:

public static function iregexpCases(): array
{
    return [
        'matches case-insensitively' => ['John', 'j.*n', true],
        'does not match'             => ['John', 'Jane', false],
    ];
}

Also applies to: 29-31

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

19-21: Method migrated to #[Test] and de-prefixed — LGTM

Discovery will rely on the attribute now; naming is consistent with the rest of the suite.

If you want sharper failure messages on JSON decode, consider enabling exceptions:

$decoded = \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);

This will fail the test with the decoding error context instead of a generic assertion later.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RandomTest.php (2)

19-21: Tighten upper bound to the mathematical spec (optional)

PostgreSQL RANDOM() returns values in [0, 1). Using < 1.0 instead of <= 1.0 more precisely reflects this and avoids masking unexpected behavior.

Consider:

-        $this->assertLessThanOrEqual(1.0, $result[0]['result']);
+        $this->assertLessThan(1.0, $result[0]['result']);

28-30: Same optional bound tweak for the offset test

For consistency with the previous test, prefer < 11.5 rather than <= 11.5. Functionally fine either way.

Suggested change:

-        $this->assertLessThanOrEqual(11.5, $result[0]['result']);
+        $this->assertLessThan(11.5, $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/LogTest.php (1)

19-21: Two-argument LOG test migration — LGTM

Covers the base-10 form as intended.

Optionally add a single-argument LOG(x) test to assert the alias behavior (PostgreSQL treats it as natural log), unless LnTest already provides sufficient coverage for the single-argument path.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php (2)

17-19: Single-row JSONB_AGG test migrated correctly

Decode-and-assert pattern remains intact; this is fine.

If you prefer clearer failures on invalid JSON, you can decode with JSON_THROW_ON_ERROR:

$actual = \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);

36-38: Multi-row JSONB_AGG test — ordering considerations

Using assertEqualsCanonicalizing is pragmatic because aggregate ordering without ORDER BY is not guaranteed. Note this also disregards ordering within nested arrays (e.g., tags), which may or may not be desirable.

If you need to keep inner-array order strict while being agnostic to row order, consider asserting per-row by key:

$rowsByName = [];
foreach ($actual as $row) {
    $rowsByName[$row['name']] = $row;
}

$this->assertSame(['developer', 'manager'], $rowsByName['John']['tags']);
$this->assertSame(['designer'], $rowsByName['Jane']['tags']);

This keeps top-level order flexible but enforces deterministic expectations within each object.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php (3)

19-26: Optional: assert boolean type explicitly before truthiness

To make the intent crystal clear, you can assert the DB boolean mapping first.

         $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue($result[0]['result']);

28-34: Mirror boolean type check in the negative case

Same idea as above; assert it’s a bool first for symmetry.

         $result = $this->executeDqlQuery($dql);
-        $this->assertFalse($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse($result[0]['result']);

23-23: Minor consistency nit: unify DQL string quoting

You mix single- and double-quoted PHP strings for DQL in this file. Consider using one style consistently (single quotes are prevalent in the suite, resorting to double only when interpolation/escaping demands it).

Also applies to: 31-31

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DaterangeTest.php (1)

22-22: Nit: consistent quoting for DQL

Single vs double quotes are mixed between the two tests; consider standardizing for readability.

Also applies to: 30-30

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php (1)

29-39: Prefer structural checks over substring matching for null stripping

String containment can be brittle with formatting changes. Optionally decode and assert no null values remain in objects.

Example inline enhancement (keeps your current assertions, adds structural check):

         $result = $this->executeDqlQuery($dql);
         $this->assertIsString($result[0]['result']);
-        $this->assertStringNotContainsString('"age": null', $result[0]['result']);
-        $this->assertStringNotContainsString('"zip": null', $result[0]['result']);
+        $this->assertStringNotContainsString('"age": null', $result[0]['result']);
+        $this->assertStringNotContainsString('"zip": null', $result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsArray($decoded);
+        $hasNull = static function ($value) use (&$hasNull): bool {
+            if ($value === null) {
+                return true;
+            }
+            if (\is_array($value)) {
+                foreach ($value as $v) {
+                    if ($hasNull($v)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        };
+        $this->assertFalse($hasNull($decoded), 'JSON contains null values after JSONB_STRIP_NULLS');
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int8rangeTest.php (1)

22-22: Nit: align DQL string quoting style

Single vs double quoting differs between the two tests; consider standardizing.

Also applies to: 30-30

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonAggTest.php (1)

45-57: Optional: use JSON_THROW_ON_ERROR for stricter decoding

This fails fast on malformed JSON and simplifies debugging if something regresses.

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, JSON_THROW_ON_ERROR);

Apply the same change to the other two tests in this class.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CeilTest.php (3)

19-25: Good migration; consider strict assertion if type is guaranteed

If Doctrine returns an int here, prefer assertSame for stricter checks; otherwise current assertEquals avoids type flakiness from drivers returning strings.

Apply if types are stable:

-        $this->assertEquals(11, $result[0]['result']);
+        $this->assertSame(11, $result[0]['result']);

27-33: Negative input case migrated correctly

Expectation of -10 for CEIL(-10.5) is correct. Same optional note about strictness applies.

Suggested change (only if result type is guaranteed to be int):

-        $this->assertEquals(-10, $result[0]['result']);
+        $this->assertSame(-10, $result[0]['result']);

35-41: Column value case aligns with fixtures; optional strictness

Behaviour matches Floor/Floor/Ceil test family. Consider assertSame if the DBAL mapping returns ints for CEIL.

-        $this->assertEquals(11, $result[0]['result']);
+        $this->assertSame(11, $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/SignTest.php (2)

19-27: Use a single-line DQL string for consistency with other tests

Most tests in this suite keep DQL on one line; consolidating improves consistency and removes indentation whitespace.

Apply:

-        $dql = 'SELECT SIGN(0) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n 
-                WHERE n.id = 1';
+        $dql = 'SELECT SIGN(0) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n WHERE n.id = 1';

Also, if the driver returns integers, you may tighten the assertion:

-        $this->assertEquals(0, $result[0]['result']);
+        $this->assertSame(0, $result[0]['result']);

29-37: Same style nitpick and optional strict assertion

Mirror the style from the previous test for readability and consistency.

Apply:

-        $dql = 'SELECT SIGN(n.decimal1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n 
-                WHERE n.id = 1';
+        $dql = 'SELECT SIGN(n.decimal1) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n WHERE n.id = 1';

Optional strictness:

-        $this->assertEquals(1, $result[0]['result']);
+        $this->assertSame(1, $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/FloorTest.php (3)

19-25: Prefer strict assertions for integers: use assertSame.

Be consistent with many other integration tests that use strict comparisons.

-        $this->assertEquals(10, $result[0]['result']);
+        $this->assertSame(10, $result[0]['result']);

27-33: Prefer strict assertions for integers: use assertSame.

-        $this->assertEquals(-11, $result[0]['result']);
+        $this->assertSame(-11, $result[0]['result']);

35-41: Prefer strict assertions for integers: use assertSame.

-        $this->assertEquals(10, $result[0]['result']);
+        $this->assertSame(10, $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3)

17-26: Optionally assert type as well for parity with other array tests.

Several array tests assert type before value. You could add assertIsInt for clarity.

         $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
         $this->assertSame(3, $result[0]['result']);

28-37: Repeat optional type assertion here.

         $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
         $this->assertSame(3, $result[0]['result']);

39-48: Repeat optional type assertion here.

         $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
         $this->assertSame(3, $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToNumberTest.php (1)

21-27: Nit: prefer consistent SQL keyword casing and NULL literal

Purely cosmetic, but most files use uppercase SQL keywords. Suggest capitalizing AS and NULL for consistency.

Apply this minimal diff:

-        $dql = "SELECT to_number('12,454.8-', '99G999D9S') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = "SELECT to_number('12,454.8-', '99G999D9S') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";

-        $dql = "SELECT to_number('12,454.8-', null) FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = "SELECT to_number('12,454.8-', NULL) FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";

-        $dql = "SELECT to_number(123456, '999D99S') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = "SELECT to_number(123456, '999D99S') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";

Also applies to: 29-35, 37-43, 45-51

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

22-25: Nit: standardize SQL keyword casing for readability

Optional but improves consistency across the suite.

-        $dql = 'SELECT JSONB_EACH(t.object1) as result 
+        $dql = 'SELECT JSONB_EACH(t.object1) AS result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
                 WHERE t.id = 1';

(Apply the same AS capitalization in the other methods in this class.)

Also applies to: 48-53, 58-63, 68-73, 78-83


27-43: Tighten assertions to verify both key and value presence when JSON-decoding succeeds

Currently the loop only asserts that $key is not null. When the database returns a JSON blob with {"key": ..., "value": ...}, we can cheaply assert both keys are present without changing semantics for rows where a fallback parse is needed.

-            $decoded = \json_decode($row['result'], true);
-            if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
-                $key = $decoded['key'];
-                $value = $decoded['value'];
+            $decoded = \json_decode($row['result'], true);
+            if (\is_array($decoded) && \array_key_exists('key', $decoded)) {
+                // Presence assertions still allow null values (covered by jsonb_each_with_nulls)
+                $this->assertArrayHasKey('value', $decoded);
+                $key = $decoded['key'];
+                $value = $decoded['value'] ?? null;
             } else {
                 $parts = \explode(':', \trim($row['result'], '{}"'));
                 $key = $parts[0] ?? null;
                 $value = $parts[1] ?? null;
             }
 
             $this->assertNotNull($key);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php (2)

17-25: Potential duplication between year extraction tests

Both date_extract_with_year() and date_extract_with_column_reference() execute identical DQL and assertions. If there isn’t an intended distinction (e.g., different argument forms), consider consolidating to one test to reduce duplication.

Also applies to: 47-55


20-25: Nit: uppercase SQL keywords to match suite style

Optional stylistic pass for consistency.

-        $dql = "SELECT DATE_EXTRACT('year', t.date1) as result 
+        $dql = "SELECT DATE_EXTRACT('year', t.date1) AS result 
                 FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsDates t 
                 WHERE t.id = 1";
-        $dql = "SELECT DATE_EXTRACT('month', t.date1) as result 
+        $dql = "SELECT DATE_EXTRACT('month', t.date1) AS result 
-        $dql = "SELECT DATE_EXTRACT('day', t.date1) as result 
+        $dql = "SELECT DATE_EXTRACT('day', t.date1) AS result 
-        $dql = "SELECT DATE_EXTRACT('year', t.date1) as result 
+        $dql = "SELECT DATE_EXTRACT('year', t.date1) AS result 

Also applies to: 30-35, 40-45, 50-55

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldAsTextTest.php (1)

24-27: Nit: prefer uppercase SQL keyword AS for consistency

Cosmetic but aligns with the rest of the suite.

-        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(t.object1, 'name') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(t.object1, 'name') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'tags'), 0) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'tags'), 0) AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'address'), 'city') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'address'), 'city') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(t.object1, 'age') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 5";
+        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(t.object1, 'age') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 5";
-        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'tags'), 10) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = "SELECT JSON_GET_FIELD_AS_TEXT(JSON_GET_FIELD(t.object1, 'tags'), 10) AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";

Also applies to: 32-35, 40-43, 48-51, 56-59

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php (2)

22-29: Nit: uppercase AS in DQL for consistency with the suite

Optional style tweak.

-        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) AS result 
-        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) AS result 
-        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(:json, :path) AS result 
-        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(t.object1, :path) as result 
+        $dql = 'SELECT JSONB_PATH_QUERY_ARRAY(t.object1, :path) AS result 

Also applies to: 39-46, 56-63, 74-78


53-69: Optional: add one negative-path case for invalid JSONPath

To harden coverage for error handling, consider a test asserting the expected exception (or empty array) for an invalid path expression, e.g., '$..[?(@ >' (malformed). If this is out-of-scope for the migration PR, feel free to ignore.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php (4)

19-30: Prefer JSON-aware assertions over string equality for stability.
PostgreSQL may vary output formatting across versions; decoding asserts intent, not representation.

Apply this diff:

-        $this->assertSame('2', $result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsInt($decoded);
+        $this->assertSame(2, $decoded);

32-43: Same here: decode and assert the actual JSON value.

-        $this->assertSame('1', $result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsInt($decoded);
+        $this->assertSame(1, $decoded);

45-56: Decode object result to avoid brittle string comparisons.

-        $this->assertSame('{"id": 2}', $result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsArray($decoded);
+        $this->assertSame(['id' => 2], $decoded);

71-79: Decode JSON string elements to assert semantic equality.
Quoting of JSON strings can differ; asserting decoded value is more robust.

-        $this->assertSame('"developer"', $result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsString($decoded);
+        $this->assertSame('developer', $decoded);

namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exp;
use PHPUnit\Framework\Attributes\Test;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Quick sanity checks to ensure the migration is safe across the repo

Run these to verify PHPUnit version compatibility and find any leftover test_ methods or @test annotations.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== phpunit version constraint in composer.json =="
if [ -f composer.json ]; then
  jq -r '.["require-dev"]["phpunit/phpunit"] // .require["phpunit/phpunit"] // "(not specified)"' composer.json
else
  echo "composer.json not found"
fi

echo
echo "== any methods still using test_ prefix? =="
rg -nP --glob '!vendor/**' '\bfunction\s+test_[A-Za-z0-9_]+\s*\(' tests || true

echo
echo "== any legacy @test annotations lingering? =="
rg -nP --glob '!vendor/**' '@test\b' tests || true

echo
echo "== attribute usage tally =="
rg -n '\#\[\s*Test\s*\]' tests | wc -l | awk '{print "Found #[Test] attributes: "$1}'

Length of output: 18906


Sanity Check Results for PHPUnit Attribute Migration

  • PHPUnit version: ^10.5.53 (attributes are fully supported)
  • Legacy @test annotations: none found
  • #[Test] attribute count: 479
  • Methods still using test_ prefix: numerous tests under tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/*.php (for example, ArrayDimensionsTest.php, InArrayTest.php, JsonbPathMatchTest.php, etc.) continue to use the old test_* naming convention without the new #[Test] attribute.

Next steps:

  • Rename all remaining public function test_*(): void methods to a descriptive name (e.g. public function arrayDimensionsWithTextArray(): void).
  • Annotate each renamed method with #[Test] to ensure PHPUnit discovers it.
  • Remove the test_ prefix once the attribute is in place.
  • Rerun the above sanity-check script to confirm zero test_ prefixes remain.
🤖 Prompt for AI Agents
In tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ExpTest.php
around line 8, the test methods still use the legacy test_ prefix without the
PHPUnit #[Test] attribute; rename any public function test_*(): void methods to
descriptive names and add the #[Test] attribute above each renamed method (e.g.,
change public function test_something(): void to #[Test] public function
somethingDescriptive(): void), remove the test_ prefix, and repeat across the
other files in
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ so the
PHPUnit attribute migration leaves no remaining test_ prefixed methods and the
sanity-check passes.

namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Regexp;
use PHPUnit\Framework\Attributes\Test;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Attribute migration looks good; verify PHPUnit version support and missing imports across the suite

Nice switch to #[Test]. Please confirm the repo requires a PHPUnit version that supports attributes and that no files using #[Test] forgot the import.

Run the following to catch leftovers:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find any remaining test_*-named methods (should be 0):"
rg -nP --type=php '\bfunction\s+test_[a-zA-Z0-9_]+\s*\(' tests || true

echo
echo "2) Files using #[Test] but missing the attribute import:"
for f in $(rg -l -nP --type=php '#\[\s*Test\s*\]' tests); do
  if ! rg -q -nP 'use\s+PHPUnit\\Framework\\Attributes\\Test\s*;' "$f"; then
    echo "Missing import in: $f"
  fi
done

echo
echo "3) PHPUnit version declared in composer files (must support attributes):"
rg -n '"phpunit/phpunit"\s*:\s*".*"' composer.json composer.lock || true

Length of output: 47628


Ensure complete PHPUnit attribute migration

We’ve confirmed that composer.json requires PHPUnit ^10.5.53, which supports PHP 8 attributes—no changes needed there. However, running the provided script revealed two critical issues:

  • Numerous methods across the suite are still using the old test_ prefix (should be 0 when fully migrated).
  • Several test files use #[Test] but lack the corresponding import:
    use PHPUnit\Framework\Attributes\Test;

Action items:

  • In every test class annotated with #[Test], add:
    use PHPUnit\Framework\Attributes\Test;
  • Remove the test_ prefix from methods that are now annotated with #[Test] (rename to descriptive names).
  • Rerun the verification script to ensure zero leftover test_ methods and no missing imports before merging.
🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpTest.php
around line 8, add the missing PHPUnit attribute import and remove legacy test_
method prefixes: add the statement importing PHPUnit\Framework\Attributes\Test
at the top of the file, then for any methods annotated with #[Test] rename them
to descriptive names without the test_ prefix (update any references/usages
accordingly), and run the verification script to ensure no remaining test_
methods or missing imports across the suite.

Comment on lines 33 to 39
#[Test]
public function tochar_for_timestamp(): void
{
$dql = "SELECT to_char(t.datetimetz1, 'HH12:MI:SS') AS result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsDates t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
static::assertSame('10:30:00', $result[0]['result']);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Migration to #[Test] with non-prefixed method names looks good across all tests.
Test logic remains untouched and expectations align with the local fixtures built in this class.

To ensure the suite is fully migrated, run this quick check for any remaining test_ methods:

Also applies to: 41-47, 49-55, 57-63, 65-71, 73-79, 81-87, 89-95, 97-103


🏁 Script executed:

#!/bin/bash
# List any remaining test_-prefixed methods across the test suite
rg -nP --type=php '\bfunction\s+test_[A-Za-z0-9_]*\s*\(' tests || true

Length of output: 18163


Convert all remaining PHPUnit test methods from test_* prefixes to #[Test] attributes
Your migration to attribute-based tests is not yet complete—our regex scan still found numerous public function test_*() declarations under the AST functions integration tests. All of these must be updated to drop the test_ prefix and use #[Test] instead.

Key locations requiring fixes:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
  • …and every other *Test.php file in
    tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/
    that still contains public function test_*(): void

Example transformation:

-    public function test_power_with_integer_exponent(): void
+    #[Test]
+    public function power_with_integer_exponent(): void

Please update each of the remaining prefixed methods accordingly to ensure full PHPUnit 10 compatibility.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php
around lines 33 to 39, the method still uses the old test_* prefix instead of
the PHPUnit 10 attribute style; rename the method to remove the test_ prefix
(e.g., tochar_for_timestamp already used here — keep that name) and add the
#[Test] attribute above it (ensure the PHPUnit Test attribute is imported or
fully-qualified), then repeat this change across all files under
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ that contain
public function test_*(): void by removing the test_ prefix, adding #[Test]
before the method, and updating any references if needed so all tests use
attribute-based declarations.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (1)

1-36: Action Required: Convert Legacy test_* Methods to #[Test] Attributes and Import the PHPUnit Test Attribute

The repository still contains numerous legacy test methods named with a test_ prefix that lack the new #[Test] attribute. These methods will be skipped by PHPUnit 10+ and must be updated. Additionally, none of the test files import the PHPUnit\Framework\Attributes\Test attribute, so existing #[Test] annotations are unresolved.

• Files under tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions with legacy methods (examples):
Int4rangeTest.php:
• public function test_int4range(): void
• public function test_int4range_with_bounds(): void
RegexpInstrTest.php:
• public function test_regexp_instr(): void
• public function test_regexp_instr_negative(): void
ToDateTest.php, NotIRegexpTest.php, DeleteAtPathTest.php, InArrayTest.php, ArrayShuffleTest.php, ArrayPrependTest.php, CastTest.php, IlikeTest.php, NumrangeTest.php, ArrayPositionsTest.php, … and many more across the Integration suite.

• No test files import the Test attribute: none contain use PHPUnit\Framework\Attributes\Test;, so all #[Test] annotations currently in use will not be recognized.

Please update each test class as follows:

  1. Add an import at the top of the file:
    use PHPUnit\Framework\Attributes\Test;
  2. Replace legacy test_-prefixed methods by:
    • Removing the test_ prefix from the method name.
    • Preceding the method with #[Test].

Example diff:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpReplace;
+use PHPUnit\Framework\Attributes\Test;

 class RegexpReplaceTest extends JsonTestCase
 {
-    public function test_regexp_replace(): void
+    #[Test]
+    public function regexp_replace(): void
     {
         // ...
     }
 }

Repeat across all affected files to ensure the full test suite runs under PHPUnit 10+ and that annotations resolve correctly.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (1)

17-59: Migrate all legacy test_* methods to attribute-based tests

Our scan uncovered numerous leftover methods using the old test_ prefix (which will no longer be executed once prefix-based discovery is disabled). These live in your integration test suite under tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/. For example:

  • DeleteAtPathTest.php:
    • test_delete_at_path_simple() (line 16)
    • test_delete_at_path_multiple_elements() (line 28)
    • test_delete_at_path_with_array() (line 40)
    • test_delete_at_path_with_column_reference() (line 52)
  • RegexpInstrTest.php:
    • test_regexp_instr() (line 18)
    • test_regexp_instr_negative() (line 26)
  • ToDateTest.php:
    • test_todate() (line 20)
    • test_todate_throws_with_invalid_input() (line 27)
    • test_todate_with_invalid_format() (line 34)
    • test_todate_throws_with_unsupported_format_type() (line 41)
    • test_todate_throws_with_unsupported_null_input() (line 48)
      …plus many more across the same directory.

To restore test discovery:

  • Rename each public function test_<something>() to drop the test_ prefix and use a descriptive method name (e.g. public function deleteAtPathSimple(): void).
  • Annotate each with #[Test] immediately above the method declaration.
  • Ensure the file imports the attribute with use PHPUnit\Framework\Attributes\Test; at the top.

No existing attribute-based tests were missing the import (your #[Test] scans returned zero files without it), so you only need to refactor the legacy-prefixed methods.

🧹 Nitpick comments (34)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)

19-21: Optional: strengthen assertions to cover multiple returned rows

JSONB_OBJECT_KEYS() is set-returning; asserting only the first row’s type is a bit weak. Without depending on specific fixture content, we can assert non-empty results and that each row is a string.

Apply this refinement:

-        $this->assertIsString($result[0]['result']);
+        self::assertNotEmpty($result);
+        foreach ($result as $row) {
+            $this->assertIsString($row['result']);
+        }
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)

19-27: Method migrated to #[Test] correctly; consider strengthening the assertion

Migration matches the pattern used across the suite. As an optional improvement, assert the string is valid JSON and that it’s pretty-printed (contains newlines), not just that it’s a string.

Apply this focused diff:

@@
-        $this->assertIsString($result[0]['result']);
+        $this->assertIsString($result[0]['result']);
+        // Ensure the output is valid JSON and pretty-printed
+        $this->assertJson($result[0]['result']);
+        $this->assertStringContainsString("\n", $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (4)

17-19: Good migration; consider a DataProvider to deduplicate positive cases

Both “text array” and “integer array” success paths share structure. A single test with a DataProvider would reduce duplication and speed up future additions.

Example (outside the selected range):

use PHPUnit\Framework\Attributes\DataProvider;

#[Test]
#[DataProvider('containsPositiveCases')]
public function contains_returns_true_for_present_values(string $field, array $needle): void
{
    $dql = sprintf("SELECT CONTAINS(t.%s, :value) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsArrays t WHERE t.id = 1", $field);
    $result = $this->executeDqlQuery($dql, ['value' => $needle]);
    $this->assertTrue($result[0]['result']);
}

public static function containsPositiveCases(): array
{
    return [
        'text array'    => ['textArray', ['banana']],
        'integer array' => ['integerArray', [2]],
    ];
}

28-30: Same suggestion as above: fold into a DataProvider

This method can be covered by the parameterized test suggested earlier. If you prefer to keep separate tests, it’s still fine as-is.


39-41: Minor: add a type assertion for clarity

Add an explicit type check before asserting false to make failures more informative and keep style consistent with other tests that assert types (e.g., ArrayPositionTest).

Proposed snippet (outside the selected range):

$result = $this->executeDqlQuery($dql, ['value' => ['mango']]);
$this->assertIsBool($result[0]['result']);
$this->assertFalse($result[0]['result']);

8-8: Attribute-based tests supported; optional coverage metadata

Verified that the project’s composer.json requires PHP ^8.1 and PHPUnit ^10.5.53, both of which support PHP 8 attributes (including #[Test] and #[CoversClass]). No further runtime compatibility checks are needed.

Optional refactor: Import and apply the coverage attribute to improve code-coverage reports.
• Add to your imports in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
diff use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Contains; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\CoversClass;
• Annotate the test class itself:
php #[CoversClass(Contains::class)] class ContainsTest extends ArrayTestCase { // ... }

LGTM once you’re ready to merge.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (2)

30-31: Optional: decode JSON with JSON_THROW_ON_ERROR to hard-fail on malformed payloads

This makes failures more actionable if the DB returns invalid JSON (rare, but clearer when it happens). Apply similarly across the four tests.

Example change within one test:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, JSON_THROW_ON_ERROR);

Also applies to: 47-47, 64-64, 83-83


85-85: Optional: standardize PHPUnit assertion call style

The file mixes $this->assert* and self::assert*. Consider sticking to one (the file mostly uses $this->...), for consistency.

-        self::assertArrayNotHasKey('nonexistent', $decoded);
+        $this->assertArrayNotHasKey('nonexistent', $decoded);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (1)

8-8: Migration Incomplete: Legacy test_* Methods Detected

– No remaining @test annotations found across tests/ (✔)
– Total of 554 methods already annotated with #[Test] (sanity-check)
– PHPUnit constraint is "phpunit/phpunit": "^10.5.53", which fully supports attributes (✔)

However, the scan uncovered numerous methods still named with the legacy test_ prefix (e.g. in
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php,
ToDateTest.php, etc.), indicating the migration to attribute-only tests isn’t yet complete.

• Please rename these methods to drop the test_ prefix (e.g. castTextToInteger)
and annotate them with #[Test] instead of relying on the legacy naming convention.
• You can re-run the provided script to identify all straggler methods and update them in bulk.

This will ensure full consistency in using PHPUnit’s attributes and remove any remaining legacy tests.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (3)

20-35: Migration to #[Test] and descriptive method name is consistent and clear

Good conversion from name-based discovery to attribute-based. Body reads well.

Consider failing fast on invalid JSON to avoid silent nulls by enabling JSON exceptions:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, JSON_THROW_ON_ERROR);

If you prefer to DRY this across JSON-related tests, a small helper in JsonTestCase like assertJsonDecodesToArray(string $json): array that wraps json_decode(..., JSON_THROW_ON_ERROR) and asserts the result is an array would reduce repetition.


37-54: Nested-path test conversion LGTM; optional stricter JSON decode

The attribute and rename are correct; assertions cover shape well.

Apply the same JSON exception pattern here:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, JSON_THROW_ON_ERROR);

56-67: Exception test migrated correctly

The use of expectException(Exception::class) is appropriate for integration behavior; keeping the assertion broad avoids coupling to driver-specific exception classes.

If you want a tad more specificity without over-coupling, you could assert on the SQLSTATE class or a stable fragment of the server error with expectExceptionMessageMatches()—only if the message is stable across supported PG/DBAL versions.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2)

19-25: Migration to #[Test] looks good; consider multiline DQL for consistency.

Style-only nit: elsewhere in Integration tests DQL strings are split over multiple lines for readability. Consider matching that convention.

-        $dql = 'SELECT RADIANS(180) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1';
+        $dql = 'SELECT RADIANS(180) as result
+                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t
+                WHERE t.id = 1';

27-33: Second test migrated correctly; apply the same DQL formatting nit.

Same readability consideration as above; optional but keeps this file consistent with peers like ArrayAppendTest and PowerTest.

-        $dql = 'SELECT RADIANS(n.decimal1) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n WHERE n.id = 1';
+        $dql = 'SELECT RADIANS(n.decimal1) as result
+                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics n
+                WHERE n.id = 1';
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (3)

19-21: Method migration to attributes is correct; consider a slightly more expressive name

The conversion (rename + #[Test]) is sound. If you want parity with other tests that describe behavior in the method name, consider renaming to make the intent explicit.

Apply if you prefer more descriptive method names:

-    public function regexp_replace(): void
+    public function regexp_replace_replaces_match(): void

28-30: Second test migration is solid; optional wording tweak

The attribute-based migration looks good. Optionally, a more descriptive name can make failure output clearer.

-    public function regexp_replace_no_match(): void
+    public function regexp_replace_no_match_returns_original(): void

19-30: Optional: Collapse the two cases via a DataProvider for less duplication

Both tests follow the same arrange/act/assert pattern with only inputs/expectations differing. You could reduce duplication with a data provider while keeping readability.

Example refactor:

 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\DataProvider;

@@
-    #[Test]
-    public function regexp_replace(): void
-    {
-        // NOTE: Using string literals for arguments due to DQL limitations with field extraction.
-        $dql = "SELECT REGEXP_REPLACE('John', 'J.*n', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertSame('Jane', $result[0]['result']);
-    }
-
-    #[Test]
-    public function regexp_replace_no_match(): void
-    {
-        $dql = "SELECT REGEXP_REPLACE('John', 'Jane', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertSame('John', $result[0]['result']);
-    }
+    public static function cases(): array
+    {
+        return [
+            'match replaced' => ["SELECT REGEXP_REPLACE('John', 'J.*n', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1", 'Jane'],
+            'no match'       => ["SELECT REGEXP_REPLACE('John', 'Jane', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1", 'John'],
+        ];
+    }
+
+    #[Test]
+    #[DataProvider('cases')]
+    public function regexp_replace_behaviour(string $dql, string $expected): void
+    {
+        // NOTE: Using string literals for arguments due to DQL limitations with field extraction.
+        $result = $this->executeDqlQuery($dql);
+        $this->assertSame($expected, $result[0]['result']);
+    }
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php (4)

19-21: Method rename + #[Test] attribute keep discovery intact.

Renaming test_tsmatch() to tsmatch() with #[Test] is correct and preserves intent.

Optional: consider a more descriptive name to aid TestDox and readability, e.g. tsmatch_returns_true_when_term_is_present().


27-29: Negative case migration is correct.

The #[Test] attribute and method rename look good; behavior unchanged.

Similarly, a clearer name like tsmatch_returns_false_when_term_is_absent() improves diagnostics.


8-10: Optionally declare coverage target to tighten code-coverage mapping.

Adding #[CoversClass] helps coverage tooling tie these tests explicitly to Tsmatch.

Apply this diff:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Tsmatch;
+use PHPUnit\Framework\Attributes\CoversClass;
 use PHPUnit\Framework\Attributes\Test;

+#[CoversClass(Tsmatch::class)]
 class TsmatchTest extends JsonTestCase

19-33: Consider consolidating the two assertions via a Data Provider to reduce duplication.

Not required for this PR’s objective, but using a provider makes the pattern easier to scale when adding more cases.

Example:

use PHPUnit\Framework\Attributes\DataProvider;

#[DataProvider('cases')]
#[Test]
public function tsmatch_behaviour(string $document, string $query, bool $expected): void
{
    $dql = sprintf(
        "SELECT TSMATCH('%s', '%s') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1",
        $document,
        $query
    );

    $result = $this->executeDqlQuery($dql);
    $this->assertSame($expected, $result[0]['result']);
}

public static function cases(): array
{
    return [
        ['developer manager', 'developer', true],
        ['developer manager', 'doctor', false],
    ];
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (1)

17-54: Optional: collapse the three near-identical tests with a DataProvider to reduce duplication.

If you prefer fewer, parameterized tests, PHPUnit’s DataProvider attribute can consolidate these while keeping readability. This is optional; keeping separate tests is also fine for failure pinpointing.

Example (sketch):

use PHPUnit\Framework\Attributes\DataProvider;

#[Test]
#[DataProvider('appendCases')]
public function array_append_is_applied(string $dql, array $expected): void
{
    $result = $this->executeDqlQuery($dql);
    $actual = $this->transformPostgresArray($result[0]['result']);
    $this->assertIsArray($actual);
    $this->assertSame($expected, $actual);
}

public static function appendCases(): array
{
    return [
        'text' => [
            'SELECT ARRAY_APPEND(t.textArray, \'orange\') as result 
             FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
             WHERE t.id = 1',
            ['apple', 'banana', 'orange', 'orange'],
        ],
        'int' => [
            'SELECT ARRAY_APPEND(t.integerArray, 3) as result 
             FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
             WHERE t.id = 1',
            [1, 2, 3, 3],
        ],
        'bool' => [
            'SELECT ARRAY_APPEND(t.boolArray, true) as result 
             FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
             WHERE t.id = 1',
            [true, false, true, true],
        ],
    ];
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)

7-10: Optional: Add #[CoversClass] for precise coverage mapping

To keep coverage attribution tight as you migrate tests, consider explicitly declaring the covered class. This helps static analysis and coverage tools.

Apply this diff to add the attribute import:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbObjectAgg;
+use PHPUnit\Framework\Attributes\CoversClass;
 use PHPUnit\Framework\Attributes\Test;

Then annotate the class (outside the changed lines; shown here for clarity):

#[CoversClass(JsonbObjectAgg::class)]
class JsonbObjectAggTest extends JsonTestCase
{
    // ...
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (1)

39-41: Method name vs. assertion intent mismatch (array element vs. key).

jsonb_exists_with_array_element() passes 'tags' as the key, which checks a top-level key, not an array element. If the intention is to check for an element within the tags array, consider one of:

  • Rename the method to reflect current semantics (key existence), or
  • Adjust the query to target the array and check the element, for example:
SELECT JSONB_EXISTS(JSON_GET_FIELD(t.object1, 'tags'), :element) as result ...
-- or the dedicated array-membership operator wrapper in this project (RIGHT_EXISTS_ON_LEFT) if available:
-- SELECT RIGHT_EXISTS_ON_LEFT(JSON_GET_FIELD(t.object1, 'tags'), :element) as result ...
-    public function jsonb_exists_with_array_element(): void
+    public function jsonb_exists_with_array_key(): void
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (1)

24-25: Prefer strict assertions for integer results.

For integer-returning cases, assertSame avoids type-coercion surprises between DBAL drivers; keep assertEquals for float precision cases.

-        $this->assertEquals(3, $result[0]['result']);
+        $this->assertSame(3, $result[0]['result']);
@@
-        $this->assertEquals(-3, $result[0]['result']);
+        $this->assertSame(-3, $result[0]['result']);
@@
-        $this->assertEquals(300, $result[0]['result']);
+        $this->assertSame(300, $result[0]['result']);
@@
-        $this->assertEquals(11, $result[0]['result']);
+        $this->assertSame(11, $result[0]['result']);

Also applies to: 34-35, 60-61, 70-71

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (1)

33-47: Optional: reduce assertion boilerplate and improve robustness.

  • Consider decoding JSON once and asserting on typed values, or
  • Compare the entire projection in one assertion to reduce noise.

For example:

$actual = array_column($result, 'result');
$this->assertSame(['1', '2', '3'], $actual); // or decode and assert on [1,2,3]
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php (1)

19-25: Intentional JSON value assertions—good distinction from “as text” variants.

Asserting "John" (including quotes) verifies JSON-typed behavior vs. the ...AS_TEXT counterparts that assert unquoted scalars. Consider adding a brief comment to highlight that intentional distinction for future readers.

-        $this->assertSame('"John"', $result[0]['result']);
+        // Intentionally asserting JSON string (quotes included); see JsonGetFieldAsTextTest for unquoted variant
+        $this->assertSame('"John"', $result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (1)

17-28: Optional: collapse repeated assertion boilerplate into a helper

Each test repeats the same “execute/transform/assert” sequence. A tiny helper would reduce duplication and make intent pop. Safe, local refactor.

Apply diffs within each method body:

@@ public function array_remove_with_text_array(): void
-        $result = $this->executeDqlQuery($dql);
-        $actual = $this->transformPostgresArray($result[0]['result']);
-        $this->assertIsArray($actual);
-        $this->assertSame(['apple', 'orange'], $actual);
+        $this->assertArrayResult($dql, ['apple', 'orange']);
@@ public function array_remove_with_integer_array(): void
-        $result = $this->executeDqlQuery($dql);
-        $actual = $this->transformPostgresArray($result[0]['result']);
-        $this->assertIsArray($actual);
-        $this->assertSame([1, 3], $actual);
+        $this->assertArrayResult($dql, [1, 3]);
@@ public function array_remove_with_boolean_array(): void
-        $result = $this->executeDqlQuery($dql);
-        $actual = $this->transformPostgresArray($result[0]['result']);
-        $this->assertIsArray($actual);
-        $this->assertSame([true, true], $actual);
+        $this->assertArrayResult($dql, [true, true]);
@@ public function array_remove_with_not_found_element(): void
-        $result = $this->executeDqlQuery($dql);
-        $actual = $this->transformPostgresArray($result[0]['result']);
-        $this->assertIsArray($actual);
-        $this->assertSame(['apple', 'banana', 'orange'], $actual);
+        $this->assertArrayResult($dql, ['apple', 'banana', 'orange']);

Add this helper inside the class (outside the changed ranges):

private function assertArrayResult(string $dql, array $expected): void
{
    $result = $this->executeDqlQuery($dql);
    $actual = $this->transformPostgresArray($result[0]['result']);
    $this->assertIsArray($actual);
    $this->assertSame($expected, $actual);
}

Also applies to: 30-41, 43-54, 56-67

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (1)

39-47: Optional: add edge-case for non-integer fractional exponent on negative base.

Consider a test documenting behavior for something like POWER(-2.0, 0.5) (NaN/exception, depending on platform/driver). This locks in semantics across environments and upgrades. I can draft it if useful.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (3)

30-30: Harden JSON parsing by throwing on decode errors.

Optional safety: make failures more explicit if the SQL function returns malformed JSON. This keeps failures crisp and avoids silent nulls.

Apply across the four decode calls:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);

Also applies to: 47-47, 64-64, 83-83


85-85: Unify assertion call style (avoid static invocation).

The rest of the file uses $this->* assertions; this line uses a static call. Prefer one style to avoid static analysis warnings with newer PHPUnit.

-        self::assertArrayNotHasKey('invalid', $decoded);
+        $this->assertArrayNotHasKey('invalid', $decoded);

8-8: Verify PHPUnit Attribute Support and Test Discovery

  • composer.json requires PHP ^8.1 and PHPUnit ^10.5.53, which fully support PHP 8 attributes and PHPUnit’s attribute-based test discovery.
  • No @test annotations were found in the entire tests/ directory.
  • Legacy test_-prefixed methods are still present throughout the integration tests (e.g. in tests/Integration/.../RegexpInstrTest.php and others). PHPUnit 10 continues to recognize both attribute-marked methods and those whose names begin with test, so mixed discovery is safe.

✅ LGTM. If you’d like to standardize on attributes exclusively, you can optionally migrate those remaining prefix-based methods; otherwise, you may proceed with the current mixed approach.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (2)

39-40: Extract a reusable tolerance to reduce duplication and ease future tweaks.

All four tests use the same 0.0001 delta. A class constant improves readability and consistency.

Example:

private const DELTA = 1e-4;

// ...
$this->assertEqualsWithDelta(3.0, $result[0]['result'], self::DELTA);

8-8: Attribute import verified; optional coverage attribute suggested

  • Composer constraints confirm PHP ^8.1 and PHPUnit ^10.5.53 are in use, satisfying the requirement for PHPUnit 10+ and PHP 8.1+ environments.
  • In the codebase there are 554 #[Test] methods versus 47 legacy test_* methods, confirming the shift to attribute-based tests.
  • CI workflows reference PHP 8.x (matrix.php in unit‐ and integration‐test jobs, plus a fixed PHP 8.4 in ci.yml), aligning with the composer requirement.

No regressions detected—your import

use PHPUnit\Framework\Attributes\Test;

is correct. As noted, you may optionally add class‐level coverage metadata to the test:

 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;

- class CbrtTest extends NumericTestCase
+ #[CoversClass(Cbrt::class)]
+class CbrtTest extends NumericTestCase

This is purely for enhanced coverage mapping and not required for functionality.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0799468 and 69c5e33.

📒 Files selected for processing (22)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php (2 hunks)
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php
📚 Learning: 2025-04-22T00:03:37.733Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#357
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php:28-62
Timestamp: 2025-04-22T00:03:37.733Z
Learning: This project focuses on providing Doctrine ORM interfaces to PostgreSQL functions. Tests should validate correct DQL-to-SQL translation rather than PostgreSQL functionality itself. Test cases should focus on parameter passing and SQL generation, not on testing specific PostgreSQL regex pattern behaviors.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
📚 Learning: 2025-03-13T15:04:55.052Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#277
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonExistsTest.php:10-0
Timestamp: 2025-03-13T15:04:55.052Z
Learning: The implementation of JSON_EXISTS in this library supports only the basic form with two parameters (target_json, path_text) and doesn't support additional features like strict mode (third boolean parameter), ON ERROR clause, or other advanced PostgreSQL JSON_EXISTS capabilities due to DQL limitations.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
📚 Learning: 2025-03-11T17:02:51.971Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#0
File: :0-0
Timestamp: 2025-03-11T17:02:51.971Z
Learning: The PostgreSQL-for-doctrine library implements the JSON array element existence check using the `RIGHT_EXISTS_ON_LEFT` DQL function, which maps to PostgreSQL's `?` operator. This is used for checking if a specific value exists in a JSONB array column.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
🧬 Code graph analysis (22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (2)
  • Test (17-26)
  • Test (28-37)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (2)
  • Test (17-27)
  • Test (29-39)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (1)
  • Test (17-26)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldAsIntegerTest.php (5)
  • Test (21-27)
  • Test (29-40)
  • Test (42-48)
  • Test (50-56)
  • Test (58-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldAsTextTest.php (5)
  • Test (21-27)
  • Test (29-35)
  • Test (37-43)
  • Test (45-51)
  • Test (53-59)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (6)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (4)
  • Test (19-31)
  • Test (33-47)
  • Test (49-62)
  • Test (64-74)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)
  • Test (19-27)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (2)
  • Test (19-34)
  • Test (36-51)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsmatchTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (4)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
  • Test (49-57)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-27)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (2)
  • Test (17-26)
  • Test (28-37)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-27)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (4)
  • Test (19-31)
  • Test (33-47)
  • Test (49-62)
  • Test (64-74)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php (1)
  • Test (17-26)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (2)
  • Test (17-28)
  • Test (30-41)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (4)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
  • Test (49-57)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (5)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
  • Test (49-57)
  • Test (59-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (5)
  • Test (17-25)
  • Test (27-35)
  • Test (37-48)
  • Test (50-61)
  • Test (63-71)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (2)
  • Test (19-31)
  • Test (33-47)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (17-26)
  • Test (28-37)
  • Test (39-48)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (17-27)
  • Test (29-39)
  • Test (41-51)
  • Test (53-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
  • Test (56-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (2)
  • Test (17-26)
  • Test (28-37)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-27)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (4)
  • Test (19-31)
  • Test (33-47)
  • Test (49-62)
  • Test (64-74)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (17-28)
  • Test (30-41)
  • Test (43-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (5)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
  • Test (49-57)
  • Test (59-67)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (5)
  • Test (17-25)
  • Test (27-35)
  • Test (37-48)
  • Test (50-61)
  • Test (63-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 1.2
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (21)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (2)

19-21: LGTM on migrating to #[Test].

Method rename + attribute usage align with the PR objective; no functional changes introduced.

Optionally, you could collapse positive/negative cases and add wildcard coverage via a data provider to exercise true ILIKE semantics:

use PHPUnit\Framework\Attributes\DataProvider;

public static function ilikeCases(): iterable
{
    yield 'case-insensitive equality' => ['John', 'john', true];
    yield 'wildcard suffix'          => ['John', 'Jo%',  true];
    yield 'wildcard prefix'          => ['John', '%hn',  true];
    yield 'negative'                 => ['John', 'jane', false];
}

#[Test]
#[DataProvider('ilikeCases')]
public function ilike_cases(string $left, string $pattern, bool $expected): void
{
    $dql = sprintf(
        "SELECT ILIKE('%s','%s') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1",
        addslashes($left),
        addslashes($pattern),
    );
    $result = $this->executeDqlQuery($dql);
    $this->assertSame($expected, $result[0]['result']);
}

If you prefer parameter binding, switch to placeholders (:left, :pattern) and pass them through executeDqlQuery($dql, ['left' => $left, 'pattern' => $pattern]).


8-8: PHPUnit 10+ Confirmed; optional: add CoversClass attribute

  • Composer constraints show PHP ^8.1 and phpunit/phpunit ^10.5.53 in require-dev, so #[Test] attributes will be discovered by PHPUnit 10.5+ without issue.
  • A ripgrep scan found no legacy test_* methods or @test annotations in the tests/ directory.
  • (Optional) To improve coverage attribution, you can import and apply #[CoversClass] at the class level:
 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Ilike;
 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;
#[CoversClass(Ilike::class)]
class IlikeTest extends JsonTestCase
{
    // ...
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (2)

19-21: Method rename + attribute-based discovery is consistent with the PR scope.

Looks good and matches the suite’s newer style.

  • Consider parameterizing the literals for readability and to mirror other tests using executeDqlQuery with parameters:
$dql = 'SELECT NOT_IREGEXP(:subject, :pattern) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1';
$result = $this->executeDqlQuery($dql, ['subject' => 'John', 'pattern' => 'jane']);
  • Align with the suite’s prevailing string style (single-quoted PHP strings) to avoid double backslashes:
$dql = 'SELECT NOT_IREGEXP(\'John\', \'jane\') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1';

28-30: Add a case-insensitivity check to assert the translation uses the case-insensitive operator (~*).

Given the library’s goal (correct DQL-to-SQL translation), a minimal extra assertion would demonstrate that NOT_IREGEXP compiles to the case-insensitive variant without delving into regex semantics.

You could add:

#[Test]
public function not_iregexp_is_case_insensitive_negative(): void
{
    $dql = 'SELECT NOT_IREGEXP(\'John\', \'john\') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1';
    $result = $this->executeDqlQuery($dql);
    $this->assertFalse($result[0]['result']);
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (2)

19-26: Rename + #[Test] are consistent; assertions remain strict

The migration from test_regexp_instr() to regexp_instr() with #[Test] is correct, keeps type-strict assertions, and preserves behavior.

For consistency with nearby integration tests (which mostly use single-quoted PHP strings for DQL), consider switching to single quotes:

-        $dql = "SELECT REGEXP_INSTR('John', 'J.*n') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = 'SELECT REGEXP_INSTR(\'John\', \'J.*n\') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1';

28-34: Negative case migration is correct; semantics match expected PG behavior

Using #[Test] with the renamed regexp_instr_negative() is fine, and asserting 0 for “no match” aligns with REGEXP_INSTR semantics.

Apply the same quoting style tweak for consistency:

-        $dql = "SELECT REGEXP_INSTR('John', 'Jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
+        $dql = 'SELECT REGEXP_INSTR(\'John\', \'Jane\') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1';
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php (2)

8-8: Switch to attributes looks good; consider adding class coverage attribute.

To improve coverage mapping and reports in PHPUnit 10/11, annotate the test class with CoversClass and import the attribute.

Apply:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayShuffle;
-use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;
 
-class ArrayShuffleTest extends ArrayTestCase
+#[CoversClass(ArrayShuffle::class)]
+class ArrayShuffleTest extends ArrayTestCase

28-28: Prefer PHPUnit assertions over PHP’s assert() to avoid INI-dependent behavior.

Using PHP’s assert() depends on zend.assertions and can be compiled out; in tests, prefer PHPUnit’s assertions for deterministic failures and clearer messages. Aligns with ArrayAppendTest which uses assertIsArray().

Apply:

-        \assert(\is_countable($actual));
+        $this->assertIsArray($actual);

Repeat the same replacement at Line 42 and Line 56.

Also applies to: 42-42, 56-56

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (1)

32-34: No stale references found; test rename is safe
Verified that the array_prepend_with_integer_array method is defined only in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php and isn’t referenced or depended on elsewhere—so the rename and attribute migration are correct, and the existing assertions against the seeded data remain valid.

Optional nitpick:

  • Consider using a heredoc/nowdoc for the multi-line DQL to reduce escaping and indentation noise.
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (3)

58-60: Optional: make the column-reference test assert the semantic effect

Right now we only assert “string” and “valid JSON”. Consider asserting the actual transformation semantics (e.g., unchanged JSON when the path doesn’t exist), which guards against silent operator or casting regressions.

Example tweak (outside the changed lines): first fetch t.object1 as-is for id=1, then compare:

// arrange
$original = $this->executeDqlQuery(
    'SELECT t.object1 AS result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1'
)[0]['result'];

// act
$result = $this->executeDqlQuery(
    'SELECT DELETE_AT_PATH(t.object1, :path) AS result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1',
    ['path' => '{nested,value}']
)[0]['result'];

// assert
$this->assertJsonStringEqualsJsonString($original, $result);

10-10: Optional: add coverage metadata via #[CoversClass]

Adding #[CoversClass(DeleteAtPath::class)] helps coverage tools map these tests precisely to the production unit and enables strict coverage settings.

Apply this diff:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\DeleteAtPath;
+use PHPUnit\Framework\Attributes\CoversClass;
 use PHPUnit\Framework\Attributes\Test;

-class DeleteAtPathTest extends JsonTestCase
+#[CoversClass(DeleteAtPath::class)]
+class DeleteAtPathTest extends JsonTestCase

29-29: Optional: prefer JSON-aware assertions for stability

Using assertJsonStringEqualsJsonString avoids brittleness from potential key order differences in JSONB serialization.

Suggested replacements (outside the changed lines):

-        $this->assertSame('{"a": {}}', $result[0]['result']);
+        $this->assertJsonStringEqualsJsonString('{"a": {}}', $result[0]['result']);

-        $this->assertSame('{"a": {"c": 2}}', $result[0]['result']);
+        $this->assertJsonStringEqualsJsonString('{"a": {"c": 2}}', $result[0]['result']);

-        $this->assertSame('{"a": [1, 3]}', $result[0]['result']);
+        $this->assertJsonStringEqualsJsonString('{"a": [1, 3]}', $result[0]['result']);

Also applies to: 42-42, 55-55

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (1)

30-31: Unify string quoting for consistency (nitpick)

We mix single-quoted SQL in Line 22 with a double-quoted string here. Prefer single quotes when no interpolation is needed. Suggested change:

-        $dql = "SELECT NUMRANGE(t.decimal1, t.decimal2, '(]') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsNumerics t WHERE t.id = 1";
+        $dql = 'SELECT NUMRANGE(t.decimal1, t.decimal2, \'(]\') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1';
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (2)

45-47: Add a multi-hit scenario to exercise duplicates.

Current cases validate single-position results. Add a test where the searched value occurs multiple times to better exercise ARRAY_POSITIONS ordering and completeness (e.g., row 3’s bool array).

Example addition:

#[Test]
public function array_positions_with_boolean_array_multiple_matches(): void
{
    $dql = 'SELECT ARRAY_POSITIONS(t.boolArray, :value) as result 
            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
            WHERE t.id = 3';

    $result = $this->executeDqlQuery($dql, ['value' => true]);
    $actual = $this->transformPostgresArray($result[0]['result']);

    $this->assertIsArray($actual);
    // Row 3 boolArray is [true, true, false, true] => positions 1,2,4
    $this->assertSame([1, 2, 4], $actual);
}

8-8: Verified PHPUnit Attribute Support; Optional Class-Level Coverage

I’ve confirmed that your repository is fully migrated to PHPUnit’s attribute-based discovery:

  • composer.json specifies PHPUnit ^10.5.53, which supports attributes.
  • No legacy test_* methods remain under tests/.
  • Numerous #[Test] attributes are already in use across the suite.

As an optional enhancement to tighten your coverage reports, you can add a #[CoversClass] attribute to the ArrayPositionsTest class:

• File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayPositions;
+use PHPUnit\Framework\Attributes\CoversClass;
 use PHPUnit\Framework\Attributes\Test;
 
-class ArrayPositionsTest extends ArrayTestCase
+#[CoversClass(ArrayPositions::class)]
+class ArrayPositionsTest extends ArrayTestCase

This change is purely optional and aimed at improving your code-coverage mapping.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (1)

19-21: Reduce duplication across the three IN_ARRAY tests (optional).

All three tests differ only by field/value/expectation. Consider a single parameterized test to cut duplication and ease future maintenance.

Example using a DataProvider:

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;

#[Test]
#[DataProvider('inArrayProvider')]
public function in_array(string $field, mixed $value, bool $expected): void
{
    $dql = \sprintf(
        'SELECT IN_ARRAY(:value, t.%s) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t WHERE t.id = 1',
        $field
    );

    $result = $this->executeDqlQuery($dql, ['value' => $value]);
    self::assertSame($expected, (bool) $result[0]['result']);
}

public static function inArrayProvider(): array
{
    return [
        'text element present'      => ['textArray', 'banana', true],
        'integer element present'   => ['integerArray', 2, true],
        'text element not present'  => ['textArray', 'mango', false],
    ];
}

Minor nit: In this file you use instance assertions ($this->assertTrue/False), whereas other tests (e.g., ToDateTest) use static assertions. If you have a preferred style, you might unify for consistency.

Also applies to: 30-32, 41-43

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (1)

24-24: Optional: simplify DQL string quoting to avoid backslash escaping.

The double-quoted strings require escaping backslashes in the FQCN. You can improve readability by using sprintf with single-quoted literals or a nowdoc.

Example:

$dql = \sprintf(
    "SELECT TO_DATE('05 Dec 2000', 'DD Mon YYYY') as result FROM %s t WHERE t.id = 1",
    'Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsTexts'
);

or:

$dql = <<<'DQL'
SELECT TO_DATE('05 Dec 2000', 'DD Mon YYYY') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsTexts t WHERE t.id = 1
DQL;

Also applies to: 33-33, 40-40, 49-49, 57-57

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (3)

59-59: Prefer strict comparison for decimal-string assertions.

Doctrine DBAL typically returns DECIMAL/NUMERIC as strings; use assertSame to avoid type juggling.

Apply:

-        static::assertEquals('123.00', $result[0]['result']);
+        static::assertSame('123.00', $result[0]['result']);
-        static::assertEquals('10.00', $result[0]['result']);
+        static::assertSame('10.00', $result[0]['result']);

Also applies to: 109-109


66-69: Strengthen array CAST assertions by parsing the Postgres array.

Right now we only check that the result “looks like” a Postgres array string. Parse it (as done in other integration tests) and assert structure/content for higher signal.

Example for two methods:

         $result = $this->executeDqlQuery($dql);
-        static::assertIsString($result[0]['result']);
-        static::assertStringContainsString('{', $result[0]['result']);
+        $actual = $this->transformPostgresArray($result[0]['result']);
+        static::assertIsArray($actual);
+        static::assertCount(3, $actual);
+        foreach ($actual as $v) {
+            static::assertIsString($v);
+        }
+        static::assertSame(['10', '20', '30'], array_values($actual)); // integerArray -> TEXT[]
         $result = $this->executeDqlQuery($dql);
-        static::assertIsString($result[0]['result']);
-        static::assertStringContainsString('{', $result[0]['result']);
+        $actual = $this->transformPostgresArray($result[0]['result']);
+        static::assertSame([1, 0, 1], $actual); // boolArray -> INTEGER[]

For DECIMAL(10, 2)[], consider asserting count and that each element matches /^\d+\.?\d{2}$/. If you prefer, I can send a follow-up patch covering all array-cast tests similarly.

Also applies to: 75-78, 149-153


101-101: Clarify the rounding comment to be precise about Postgres behavior.

Minor wording tweak to reflect behavior more exactly: casting NUMERIC to an integral type rounds to the nearest integer; ties for NUMERIC round away from zero (vs. TRUNC which truncates toward zero).

-        static::assertSame(11, $result[0]['result']); // PostgreSQL rounds 10.5 to 11
+        static::assertSame(11, $result[0]['result']); // Casting NUMERIC to INTEGER rounds to nearest; 10.5 → 11 (ties for NUMERIC round away from zero)

Notes: NUMERIC rounding tie behavior is documented; community guidance confirms casts to integral types round rather than truncate (contrast with trunc()). (postgresql.org, stackoverflow.com)

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (1)

27-33: Nit: unify PHP string quoting for DQL literals.

Both queries can use single-quoted PHP strings; in the bounds case escape the inner SQL quotes. This keeps style consistent across the two tests.

Apply:

-        $dql = "SELECT INT4RANGE(t.integer1, t.integer2, '(]') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsNumerics t WHERE t.id = 1";
+        $dql = 'SELECT INT4RANGE(t.integer1, t.integer2, \'(]\') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1';
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 69c5e33 and 02ceeb0.

📒 Files selected for processing (22)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToStringTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonAggTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php (1 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToStringTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
📚 Learning: 2025-04-22T00:03:37.733Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#357
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php:28-62
Timestamp: 2025-04-22T00:03:37.733Z
Learning: This project focuses on providing Doctrine ORM interfaces to PostgreSQL functions. Tests should validate correct DQL-to-SQL translation rather than PostgreSQL functionality itself. Test cases should focus on parameter passing and SQL generation, not on testing specific PostgreSQL regex pattern behaviors.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
📚 Learning: 2025-03-11T12:32:10.726Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#263
File: src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Numrange.php:19-21
Timestamp: 2025-03-11T12:32:10.726Z
Learning: In the postgresql-for-doctrine repository, PostgreSQL range functions have distinct implementations for different data types. The `Numrange` function works with numeric/decimal values and is tested using the `ContainsDecimals` fixture with properties typed as `float`. In contrast, the `Int4range` function works with 32-bit integers and is tested using the `ContainsIntegers` fixture with properties typed as `int`. While the PHP implementations share a similar structure (extending `BaseFunction`), they are semantically different as they handle different PostgreSQL data types.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php
📚 Learning: 2025-04-11T11:23:44.192Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#340
File: tests/MartinGeorgiev/Doctrine/DBAL/Types/InetArrayTest.php:145-145
Timestamp: 2025-04-11T11:23:44.192Z
Learning: In the PostgreSQL for Doctrine test cases, methods that test database-to-PHP conversions should use `mixed` type for parameter and include non-string test cases in their data providers, following the pattern in classes like InetTest, CidrTest, and MacaddrTest.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
📚 Learning: 2025-08-24T16:52:32.488Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#0
File: :0-0
Timestamp: 2025-08-24T16:52:32.488Z
Learning: This repository uses BaseType extension pattern for custom Doctrine DBAL types with PostgreSQL platform assertions, comprehensive unit and integration testing with data providers, and dedicated exception classes for type conversion errors.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
📚 Learning: 2025-05-03T00:18:09.078Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#366
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php:1-36
Timestamp: 2025-05-03T00:18:09.078Z
Learning: Always check the current official PostgreSQL documentation at https://www.postgresql.org/docs/ to verify function signatures and behaviors before suggesting improvements or additional tests. The `array_positions` function specifically has a fixed signature with exactly two parameters (array and search value), while `array_position` is variadic with 2-3 parameters.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
🧬 Code graph analysis (12)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (1)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php (1)
  • JsonTestCase (9-56)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPath.php (1)
  • DeleteAtPath (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (4)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArray.php (1)
  • InArray (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffle.php (1)
  • ArrayShuffle (15-22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (7)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (2)
  • Test (19-30)
  • Test (32-43)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php (3)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (7)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (2)
  • Test (19-30)
  • Test (32-43)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (4)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • getStringFunctions (12-17)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (1)
  • ArrayPrependTest (10-38)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrepend.php (1)
  • ArrayPrepend (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (4)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (2)
  • ToDateTest (12-43)
  • getStringFunctions (14-19)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDate.php (1)
  • ToDate (13-21)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositions.php (1)
  • ArrayPositions (15-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PHP 8.4 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 1.2
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (37)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (1)

28-30: LGTM on the negative case.

The attribute migration is correct and keeps intent clear.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (1)

8-8: Confirmed attribute-based tests are fully supported

  • composer.json requires "phpunit/phpunit": "^10.5.53" on PHP ^8.1, both of which natively support the #[Test] attribute.
  • No remaining test_* methods or @test annotations were found in tests/**, so all tests will be discovered by the attribute-based runner.

With these constraints in place, the migration to #[Test] is safe and complete—approving the changes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (1)

8-8: CI PHPUnit Version Valid
Confirmed that composer.json specifies phpunit/phpunit at ^10.5.53, which fully supports attribute-based discovery (attributes were introduced in PHPUnit 9.5.10 and are first‐class in PHPUnit 10). No changes are needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php (2)

14-16: LGTM: String function registration remains correct and explicit.

The mapping of 'ARRAY_SHUFFLE' to ArrayShuffle::class is clear and matches the project’s convention. No behavioral change introduced.


19-21: LGTM: Migration from test_ prefix to #[Test] is consistent.

  • Method names no longer need the test_ prefix.
  • #[Test] is correctly applied to each public test method.
  • Consistent with neighboring tests (e.g., ArrayAppendTest).

Also applies to: 33-35, 47-49

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (4)

14-16: String function mapping retained; readability improved.

No functional change; mapping to ArrayPrepend::class remains correct.


19-21: No lingering references found for the renamed test method
All occurrences of test_array_prepend_with_text_array (including any @depends) have been removed—no matches surfaced in the tests/ directory.

Optional refactor (unchanged suggestion):

  • To DRY up your array‐function tests, consider adding this helper in ArrayTestCase and replacing individual assertions with a one-liner:
    protected function assertArrayFunctionResult(string $dql, array $expected): void
    {
        $result = $this->executeDqlQuery($dql);
        $actual = $this->transformPostgresArray($result[0]['result']);
        $this->assertIsArray($actual);
        $this->assertSame($expected, $actual);
    }

45-47: All good – test present and correctly migrated

The array_prepend_with_boolean_array method appears exactly once in the test suite (no unexpected duplicates or leftover references) and the test’s annotation, rename, and assertions correctly reflect the intended prepend semantics. Approving these changes.

∙ tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (lines 45–47)


8-8: Attribute-based test discovery compatibility confirmed

Verified that the project’s composer.json declares:

  • PHP >= 8.1 (via "php": "^8.1")
  • PHPUnit >= 10.5.53 (via "phpunit/phpunit": "^10.5.53" in require-dev)

These versions fully support PHPUnit attributes (#[Test]) without issue. No platform override is set (config.platform.php empty), and omitting a composer.lock in a library is expected. No further changes needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (5)

14-16: LGTM: array mapping formatting

Reformatting getStringFunctions() to a multi-line array with a trailing comma improves diffs and matches common style in this test suite.


19-21: LGTM: migrated to #[Test] and descriptive method name

Attribute-based test declaration is correct; the method name remains descriptive and consistent with neighboring tests.


32-34: LGTM: attribute migration for second case

Clean conversion; no functional changes to the test body.


45-47: LGTM: attribute migration for array index deletion case

Good coverage of array element removal via #- path with numeric component.


8-8: PHPUnit attribute import is supported by current constraints

The project’s composer.json specifies PHP ^8.1 and PHPUnit ^10.5.53, so attribute-based test discovery via
use PHPUnit\Framework\Attributes\Test;
is fully supported at runtime—no further changes needed.

• composer.json → require php: ^8.1 (ensures PHP ≥ 8.1)
• composer.json → require-dev phpunit/phpunit: ^10.5.53 (ensures PHPUnit ≥ 9.5, here ≥ 10.5)

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (4)

8-8: Adopting #[Test] attribute import is correct

Importing PHPUnit\Framework\Attributes\Test aligns this class with attribute-based discovery. No issues spotted.


19-21: Method rename + #[Test]: discovery migration looks good

Renaming from test_numrange() to numrange() with #[Test] keeps behavior while modernizing discovery. Assertions and DQL stay the same.


27-29: Second test migrated correctly as well

The numrange_with_bounds() conversion mirrors the first change; expectations for numeric ranges remain appropriate.


8-8: Composer constraints verified for attribute-based tests

Composer.json specifies PHPUnit ^10.5.53 and PHP ^8.1, which satisfies the requirement for PHPUnit ≥ 9.6 (and PHP ≥ 8.0). Attribute-based tests are fully supported in CI—no further changes needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (4)

14-16: Minor formatting of function registration looks good.

Expanded array literal improves readability without changing behavior.


19-21: Text-array case migrated and still valid.

Assertion matches row 2 seed data; discovery via #[Test] will pick this up.


32-34: Integer-array case migrated and correct.

Using assertSame enforces int typing of positions, which is ideal here.


58-60: Not-found case remains clear and correct.

Confirms PostgreSQL returns an empty array for missing values; good use of assertSame([],...).

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (2)

14-16: Alias mapping preserved and consistent.

Mapping 'IN_ARRAY' => InArray::class matches the project’s uppercase convention for DQL function aliases in integration tests. Looks good.


8-8: PHPUnit version constraint validated, attribute import is correct.

The project’s composer.json specifies a requirement on phpunit/phpunit at “^10.5.53”, which falls within PHPUnit 10.x (fully supporting attribute-based tests) . Therefore, the use PHPUnit\Framework\Attributes\Test; import is appropriate and no changes are needed. Approving these code changes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (7)

10-10: Attribute import is correct.

Correct import for PHPUnit attributes. No issues.


21-23: Migration to #[Test] with clearer method names looks good.

The rename-and-annotate pattern is clean and focused on discovery only. No behavioral changes introduced.

Also applies to: 29-31, 37-39, 45-47, 53-55


29-31: Exception expectation relies on driver behavior—please confirm stability across PG versions.

Expecting Doctrine\DBAL\Exception\DriverException for TO_DATE('invalid_date', ...) might vary by PostgreSQL version/locale. If your CI spans multiple PG versions, verify determinism or constrain the matrix accordingly.


37-39: Sanity-check the 'invalid_format' behavior across PostgreSQL versions.

The expected '2005-01-01' result for an invalid format is very specific and may be version-dependent. Please confirm against the PG version(s) you support in CI to avoid brittle tests.


45-47: Good negative test coverage for unsupported format type.

Passing a non-string second argument should fail during DQL parsing; asserting QueryException here is appropriate.


53-55: Good guard for null input.

Asserting QueryException for null input in the first argument is appropriate at the DQL level. LGTM.


17-17: ✅ Integration tests fully updated to use the uppercase ‘TO_DATE’ alias

Confirmed there are no remaining mappings or calls to the old lowercase to_date in tests/Integration/. The integration suite now aligns with the unit-test mapping and DQL usage.
Approving these changes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (2)

30-36: Migration to #[Test] and descriptive method names looks consistent and clean.

All test methods are properly annotated with #[Test] and the legacy test_ prefix is removed. This aligns with the pattern used elsewhere in the suite and keeps naming descriptive (e.g., cast_text_to_integer). No functional changes in the DQL/assertions are introduced, which is appropriate for this PR’s scope.

Also applies to: 38-44, 46-52, 54-60, 62-69, 71-78, 80-86, 88-94, 96-102, 104-110, 112-118, 120-126, 128-135, 137-144, 146-153


10-10: Confirmed PHPUnit 10+ and PHP ≥ 8.1 Compatibility

– composer.json declares “php”: “^8.1”
– require-dev includes “phpunit/phpunit”: “^10.5.53”
– attribute-based tests (#[Test]) are already present throughout the suite

No further action needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (4)

8-8: Adopting #[Test] attribute import looks correct.

Consistent with the PR’s migration approach and other integration tests.


19-25: Method migrated to attribute-based discovery — OK.

Rename from a test_*-prefixed method to an attribute-based one is clean and consistent.


27-33: Bounds expectation [11,21) is correct for int4range due to discrete-range canonicalization.

PostgreSQL canonicalizes discrete ranges (int4range/int8range/daterange) to [lower, upper) form; (10,20] becomes [11,21), matching the asserted value.


19-25: ContainsNumerics fixture correctly defines integer1 and integer2
Verified that fixtures/MartinGeorgiev/Doctrine/Entity/ContainsNumerics.php declares both
public int $integer1; and public int $integer2;, so the integration test’s use of this fixture is valid.

namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayShuffle;
use PHPUnit\Framework\Attributes\Test;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify PHPUnit version supports attributes.

Attributes require PHPUnit ≥ 9.5.10 (PHP 8) and are first-class in PHPUnit 10+. Please confirm the repo’s composer constraints and lockfile align.

Run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate composer files
fd -a 'composer.*' | sort

# Show PHP and PHPUnit constraints from composer.json (if present)
if fd -q composer.json; then
  echo '--- composer.json constraints ---'
  cat composer.json | jq -r '
    {
      php: .require.php // "not set",
      phpunit_dev: .require_dev["phpunit/phpunit"] // "not set",
      phpunit: .require["phpunit/phpunit"] // "not set"
    }'
fi

# Quick scan: count attribute-based tests present
echo '--- #[Test] attribute usage count in tests/ ---'
rg -nP --type=php '#\[\s*Test\s*\]' tests | wc -l

Length of output: 1000


I’ll re-run a more focused check on your composer constraints and lockfile, plus verify attribute usage:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1. Show PHP requirement from composer.json
echo '--- composer.json PHP requirement ---'
jq -r '.require.php? // "not set"' composer.json

# 2. Show PHPUnit constraints from composer.json
echo '--- composer.json require_dev phpunit/phpunit ---'
jq -r '.require_dev["phpunit/phpunit"]? // "not set"' composer.json
echo '--- composer.json require phpunit/phpunit ---'
jq -r '.require["phpunit/phpunit"]? // "not set"' composer.json

# 3. Check locked PHPUnit version in composer.lock (both packages and packages-dev)
if [ -f composer.lock ]; then
  echo '--- composer.lock locked phpunit/phpunit versions ---'
  jq -r '.packages[]?, .["packages-dev"][]? 
         | select(.name == "phpunit/phpunit") 
         | .version' composer.lock || echo "none found"
else
  echo 'composer.lock not present'
fi

# 4. Count usage of #[Test] in tests directory
echo '--- Count of attribute-based tests (#\[Test]) ---'
rg -nP --type=php '#\[\s*Test\s*\]' tests | wc -l

Length of output: 775


Ensure PHPUnit ≥ 9.5.10 (PHP 8.1+) is declared and locked
Your composer.json requires PHP ^8.1, which is sufficient for attributes, but there’s no phpunit/phpunit entry and no composer.lock present. Without explicitly declaring and locking PHPUnit ≥ 9.5.10 (or ideally PHPUnit 10+), all 601 of your attribute-based tests (#[Test]) may fail in CI or on other environments.

• composer.json

  • require.php: ^8.1 ✔️
  • require_dev phpunit/phpunit: not set → add "phpunit/phpunit": "^10.0 || ^9.5.10"
    • composer.lock: missing → commit lockfile to pin PHPUnit version
    • Attribute usage count: 601 instances of #[Test] in tests/

Please update composer.json and include composer.lock to guarantee your test suite runs correctly with attribute support.

🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php
around line 8, the project uses PHPUnit attribute tests but composer.json lacks
a phpunit/phpunit dev requirement and composer.lock is missing; add a
require-dev entry `"phpunit/phpunit": "^10.0 || ^9.5.10"` (or pin to a specific
supported version), run composer update/require to generate and commit
composer.lock, and ensure CI uses the lockfile so attribute-based tests
(#[Test]) run on PHP 8.1+ environments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (2)

31-33: LGTM; see consolidation suggestion above.

The method is correct as-is; can be covered by the proposed parameterized test.


43-45: LGTM; see consolidation suggestion above.

The method is correct as-is; can be covered by the proposed parameterized test.

🧹 Nitpick comments (9)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (6)

19-27: Migration to #[Test] and descriptive name—LGTM; optional stricter assertion.

Functionality unchanged. If you want stricter type checks for integer results, you can assert on an explicit int.

Apply within the selected lines:

-        $this->assertEquals(3, $result[0]['result']);
+        $this->assertSame(3, (int) $result[0]['result'])

29-37: Negative value case—LGTM; optionally assert strict int.

Apply within the selected lines:

-        $this->assertEquals(-3, $result[0]['result']);
+        $this->assertSame(-3, (int) $result[0]['result']);

39-50: Precision case—consider tolerance-based assertion for floats.

Depending on driver/platform, the result may be string or float. Using a delta avoids fragile float comparisons.

Apply within the selected lines:

-        $this->assertEquals(3.14, $result[0]['result']);
+        $this->assertEqualsWithDelta(3.14, (float) $result[0]['result'], 1e-9);

52-63: Negative precision case—LGTM; optionally assert strict int.

Apply within the selected lines:

-        $this->assertEquals(300, $result[0]['result']);
+        $this->assertSame(300, (int) $result[0]['result']);

65-73: Column case—LGTM; optionally assert strict int.

Apply within the selected lines:

-        $this->assertEquals(11, $result[0]['result']);
+        $this->assertSame(11, (int) $result[0]['result']);

19-73: Reduce duplication with a DataProvider (optional).

Five tests repeat the same DQL/execution pattern. Consider a single parameterized test with a #[DataProvider] to shrink boilerplate and make it easier to add more cases.

Example:

use PHPUnit\Framework\Attributes\DataProvider;

#[Test]
#[DataProvider('roundCases')]
public function round_behaviour(string $dql, array $params, float|int $expected, ?float $delta = null): void
{
    $result = $this->executeDqlQuery($dql, $params);
    $actual = $result[0]['result'];

    if ($delta !== null) {
        $this->assertEqualsWithDelta($expected, (float)$actual, $delta);
    } else {
        $this->assertSame($expected, (int)$actual);
    }
}

public static function roundCases(): array
{
    return [
        'positive number' => [
            'SELECT ROUND(:number) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
            ['number' => 3.14159],
            3,
            null,
        ],
        'negative number' => [
            'SELECT ROUND(:number) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
            ['number' => -3.14159],
            -3,
            null,
        ],
        'precision 2' => [
            'SELECT ROUND(:number, :precision) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
            ['number' => 3.14159, 'precision' => 2],
            3.14,
            1e-9,
        ],
        'negative precision -2' => [
            'SELECT ROUND(:number, :precision) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
            ['number' => 314.159, 'precision' => -2],
            300,
            null,
        ],
        'column value' => [
            'SELECT ROUND(t.decimal1) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1',
            [],
            11,
            null,
        ],
    ];
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (3)

19-53: Optional: consolidate the three identical “dimension = 1” cases into one parameterized test.

Reduces duplication and speeds execution without changing behavior.

Apply this diff within this hunk to replace the three tests with one parameterized test:

-    #[Test]
-    public function array_length_with_text_array(): void
-    {
-        $dql = 'SELECT ARRAY_LENGTH(t.textArray, 1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(3, $result[0]['result']);
-    }
-
-    #[Test]
-    public function array_length_with_integer_array(): void
-    {
-        $dql = 'SELECT ARRAY_LENGTH(t.integerArray, 1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(3, $result[0]['result']);
-    }
-
-    #[Test]
-    public function array_length_with_boolean_array(): void
-    {
-        $dql = 'SELECT ARRAY_LENGTH(t.boolArray, 1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(3, $result[0]['result']);
-    }
+    #[Test]
+    #[TestWith(['textArray', 3])]
+    #[TestWith(['integerArray', 3])]
+    #[TestWith(['boolArray', 3])]
+    public function array_length_with_various_arrays(string $field, int $expected): void
+    {
+        $dql = \sprintf(
+            'SELECT ARRAY_LENGTH(t.%s, 1) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t WHERE t.id = 1',
+            $field
+        );
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
+        $this->assertSame($expected, $result[0]['result']);
+    }

Additionally, add this import (outside the selected lines):

use PHPUnit\Framework\Attributes\TestWith;

55-57: Good negative (invalid dimension) case; consider adding edge dims 0 and -1.

PostgreSQL returns NULL for out-of-range dimensions; explicitly asserting dims 0 and -1 improves robustness.

Example:

#[Test]
#[TestWith([0])]
#[TestWith([-1])]
public function array_length_with_non_positive_dimension_returns_null(int $dim): void
{
    $dql = \sprintf(
        'SELECT ARRAY_LENGTH(t.textArray, %d) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t WHERE t.id = 1',
        $dim
    );
    $result = $this->executeDqlQuery($dql);
    $this->assertNull($result[0]['result']);
}

10-11: Optional: add coverage mapping with #[CoversClass].

Helps coverage tools and IDEs associate this test with ArrayLength.

Apply:

@@
-use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;
@@
-class ArrayLengthTest extends ArrayTestCase
+#[CoversClass(ArrayLength::class)]
+class ArrayLengthTest extends ArrayTestCase
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 02ceeb0 and a762c30.

📒 Files selected for processing (11)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php
🧬 Code graph analysis (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (5)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
  • getStringFunctions (12-17)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (1)
  • ArrayRemoveTest (10-38)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemove.php (1)
  • ArrayRemove (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (2)
  • Test (19-32)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumericTestCase.php (1)
  • NumericTestCase (9-49)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Round.php (1)
  • Round (15-31)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (5)
  • Test (19-32)
  • Test (34-47)
  • Test (49-62)
  • Test (64-74)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLength.php (1)
  • ArrayLength (15-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.3
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.3
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PHP 8.4 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (10)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (6)

8-8: LGTM: Modern PHP attribute import added correctly.

The import for PHP 8+ attribute-based test discovery is properly added and aligns with the PR objective to migrate away from test_ prefixed method names.


14-16: LGTM: Code formatting improvement.

The multi-line array formatting improves readability while maintaining the same functionality.


19-20: LGTM: Proper migration to attribute-based test discovery.

The #[Test] attribute is correctly applied and the method name has been appropriately updated from test_array_remove_with_text_array to array_remove_with_text_array, following modern PHPUnit conventions.


32-33: LGTM: Consistent attribute usage and method naming.

The test method correctly uses the #[Test] attribute and follows the established naming pattern by removing the test_ prefix.


45-46: LGTM: Proper attribute application and method renaming.

The #[Test] attribute is correctly applied and the method name follows the consistent pattern established in this migration.


58-59: LGTM: Final test method correctly migrated.

The last test method properly implements the attribute-based approach with correct naming convention.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (2)

14-16: Formatting-only change—LGTM and consistent with other tests.

Switching to a multi-line array improves diffs and matches the suite’s style.


8-8: Verified PHP/PHPUnit support for #[Test] attribute

  • composer.json requires PHP ^8.1 and phpunit/phpunit ^10.5.53, both of which support PHPUnit\Framework\Attributes\Test (PHP ≥ 8.0; PHPUnit ≥ 9.5) – attributes are fully available.
  • No public function test_… methods remain in tests/ (all tests now use #[Test]).
  • A number of existing integration tests under tests/Integration/.../Functions already use #[Test], confirming consistency with the new RoundTest changes.

No further adjustments are needed; the CI matrix and composer constraints already guarantee attribute support.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (2)

14-16: String function mapping looks correct.

Key remains 'ARRAY_LENGTH' mapped to ArrayLength::class; only formatting changed. No functional impact.


8-8: Attribute-based test discovery requirements satisfied

  • composer.json specifies PHP “^8.1” and phpunit/phpunit “^10.5.53”
  • No legacy function test_* methods remain in the tests/ directory

All checks pass—ready to merge.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (9)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php (4)

19-26: Make aggregation order deterministic with ORDER BY

PostgreSQL’s string_agg without ORDER BY can yield non-deterministic ordering. Since the expected string relies on insertion order, make the result stable by ordering by t.id.

Apply:

-        $dql = "SELECT STRING_AGG(t.text1, ',') as result 
+        $dql = "SELECT STRING_AGG(t.text1, ',' ORDER BY t.id) as result 
                 FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t";

28-35: Stabilize delimiter test with explicit ordering

Same rationale as above; add ORDER BY t.id inside STRING_AGG(...).

-        $dql = "SELECT STRING_AGG(t.text2, ';') as result 
+        $dql = "SELECT STRING_AGG(t.text2, ';' ORDER BY t.id) as result 
                 FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t";

37-43: Stabilize the space-delimited aggregation

Add an order clause to avoid flakiness across PG versions/plans.

-        $dql = "SELECT STRING_AGG(t.text1, ' ') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t";
+        $dql = "SELECT STRING_AGG(t.text1, ' ' ORDER BY t.id) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t";

45-51: Prefer deterministic aggregation even when filtering

For the filtered case, ordering by t.id ensures the expected '1,4' order consistently.

-        $dql = "SELECT STRING_AGG(t.text1, ',') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id in (1, 4)";
+        $dql = "SELECT STRING_AGG(t.text1, ',' ORDER BY t.id) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id in (1, 4)";
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (3)

19-21: Nit: consider #[TestDox] for clearer test output

Names are already descriptive. If you want even nicer PHPUnit output, annotate with TestDox.

Example:

-use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\TestDox;

-#[Test]
+#[Test, TestDox('matches a simple JSONPath predicate')]
 public function can_match_simple_path(): void

32-34: Optional: consolidate similar cases via a DataProvider

The first three tests follow the same arrange/act/assert pattern with different inputs. A parameterized test reduces duplication and speeds future additions.

Example (additions shown; adjust names to your style):

+use PHPUnit\Framework\Attributes\DataProvider;

-#[Test]
-public function can_match_comparison_expression(): void { /* ... */ }
-
-#[Test]
-public function returns_false_for_non_matching_path(): void { /* ... */ }
+public static function jsonbPathMatchCases(): array
+{
+    return [
+        'simple exists'     => ['{"a":1}',   'exists($.a)',    true],
+        'comparison passes' => ['{"a":5}',   '$.a > 3',        true],
+        'missing key'       => ['{"a":1}',   'exists($.b)',    false],
+    ];
+}
+
+#[Test]
+#[DataProvider('jsonbPathMatchCases')]
+public function matches_paths_as_expected(string $json, string $path, bool $expected): void
+{
+    $dql = 'SELECT JSONB_PATH_MATCH(:json, :path) as result 
+            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
+            WHERE t.id = 1';
+    $result = $this->executeDqlQuery($dql, ['json' => $json, 'path' => $path]);
+    $expected ? $this->assertTrue($result[0]['result']) : $this->assertFalse($result[0]['result']);
+}

58-60: Optional: add coverage for the 3rd and 4th args (vars, silent) supported by JsonbPathMatch

The implementation allows up to 4 args and validates the 4th as boolean. Adding one test that uses vars and one that toggles silent would harden integration coverage.

Illustrative additions:

#[Test]
public function can_match_with_vars_and_silent(): void
{
    $dql = 'SELECT JSONB_PATH_MATCH(:json, :path, :vars, :silent) as result 
            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
            WHERE t.id = 1';

    $params = [
        'json'   => '{"a": 5}',
        'path'   => '$.a > $min',
        'vars'   => '{"min": 3}',
        'silent' => true,
    ];

    $result = $this->executeDqlQuery($dql, $params);
    $this->assertTrue($result[0]['result']);
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (2)

45-55: Array index deletion looks right; consider adding a zero-index and out-of-range case.

Postgres uses zero-based indexes for json arrays. Adding one more example (index 0) and one out-of-range index would guard against off-by-one and noop behavior.

Example additional tests (outside this hunk):

#[Test]
public function deletes_first_array_element_with_zero_index(): void
{
    $dql = 'SELECT DELETE_AT_PATH(:json, :path) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1';
    $result = $this->executeDqlQuery($dql, ['json' => '{"a": [1, 2, 3]}', 'path' => '{a,0}']);
    $this->assertSame('{"a": [2, 3]}', $result[0]['result']);
}

#[Test]
public function out_of_range_array_index_is_noop(): void
{
    $dql = 'SELECT DELETE_AT_PATH(:json, :path) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1';
    $result = $this->executeDqlQuery($dql, ['json' => '{"a": [1, 2, 3]}', 'path' => '{a,10}']);
    $this->assertSame('{"a": [1, 2, 3]}', $result[0]['result']);
}

58-67: Strengthen assertion by comparing semantic JSON equality.

Path '{nested,value}' does not exist in row 1; the operator should return the original json unchanged. Instead of only type/validity checks, assert semantic equality (order-insensitive).

Apply this diff:

-        $this->assertIsString($result[0]['result']);
-        $this->assertJson($result[0]['result']);
+        // Row 1 object1 comes from JsonTestCase::insertTestDataForJsonFixture()
+        $expected = '{"name": "John", "age": 30, "tags": ["developer", "manager"], "address": {"city": "New York"}}';
+        $this->assertJsonStringEqualsJsonString($expected, $result[0]['result']);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a762c30 and eb0bd59.

📒 Files selected for processing (8)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToStringTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayShuffleTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToStringTest.php
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php
🧬 Code graph analysis (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php (1)
  • JsonTestCase (9-56)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatch.php (1)
  • JsonbPathMatch (24-57)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (4)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (5)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • Test (58-66)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php (1)
  • JsonTestCase (9-56)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPath.php (1)
  • DeleteAtPath (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php (6)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAggTest.php (4)
  • Test (19-27)
  • Test (29-37)
  • Test (39-47)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPrependTest.php (4)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayReplaceTest.php (5)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
  • Test (58-69)
  • getStringFunctions (12-17)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAgg.php (1)
  • StringAgg (24-69)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PHP 8.4 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 1.2
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (11)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/StringAggTest.php (2)

14-16: LGTM: function registration is correct

STRING_AGG is mapped to the expected implementation and the array style/trailing comma match the suite’s conventions.


8-8: PHPUnit Attribute Support Verified

Composer and the codebase already meet the requirements for attribute-based tests:

  • composer.json requires PHP ^8.1 (line 40) and phpunit/phpunit ^10.5.53 (line 55), which supports PHPUnit\Framework\Attributes\Test.
  • No phpunit.xml or phpunit.xml.dist files were found imposing legacy “test*” naming conventions.

All good to proceed with attribute-based tests.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (5)

1-68: Overall: migration to #[Test] looks good and focused

Method names are now descriptive, attribute-based discovery is in place, and the string function mapping remains intact. No functional changes detected in the test logic.


14-16: String function registration unchanged — LGTM

Mapping to 'JSONB_PATH_MATCH' => JsonbPathMatch::class is preserved; formatting change only.


45-47: Negative path case reads clearly — LGTM

Good coverage for the non-matching scenario using assertFalse.


1-68: All tests use attributes; no residual test_ prefixes or @test docblocks found

The repository-wide scan confirms that there are no leftover PHPUnit-style test method names or docblock annotations:

  • No functions with a test_ prefix detected under tests/
  • No @test annotations present in docblocks under tests/

All test cases have been successfully migrated to use the #[Test] attribute.


8-8: No changes needed: PHPUnit Attributes are supported
Confirmed that the project’s composer.json declares PHPUnit ^10.5.53 (≥10.x), which includes the Attributes API used by use PHPUnit\Framework\Attributes\Test;. There is no composer.lock, but the version constraint guarantees compatibility.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (4)

14-16: String function registration reformat only.

Multiline array read is clearer; mapping to DeleteAtPath::class remains unchanged.


19-30: Simple path deletion test reads well and matches Postgres #- semantics.

Input, path, and expected output align with jsonb path removal.


32-43: Multiple element deletion scenario is correct.

Good coverage of sibling key removal under the same parent.


8-8: Approved: PHPUnit Attribute Support Confirmed

The import of #[Test] is valid and fully supported by our current dependencies. Composer requires PHP ^8.1 and PHPUnit ^10.5.53, which includes attribute-based test declarations.

• composer.json → "php": "^8.1"
• composer.json → "phpunit/phpunit": "^10.5.53"

Code changes can be merged.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (1)

8-8: Attributes import OK — ensure PHPUnit version supports it

Same note as in ArrayPositionTest: ensure composer requires a PHPUnit version that discovers #[Test] methods.

Use the composer/phpunit check script shared above.

🧹 Nitpick comments (10)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)

19-29: Text-array case updated correctly; consider parameterizing for consistency

Querying 'orange' at id=1 should yield 3 — assertion is right. For consistency with other tests that use parameters, pass the searched value via a bound parameter.

Apply:

-        $dql = 'SELECT ARRAY_POSITION(t.textArray, \'orange\') as result 
+        $dql = 'SELECT ARRAY_POSITION(t.textArray, :value) as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
                 WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
+        $result = $this->executeDqlQuery($dql, ['value' => 'orange']);

31-41: Integer-array case looks good; align with parameter style

Result 2 is correct. Aligning to parameter usage reduces quoting differences and keeps tests uniform.

-        $dql = 'SELECT ARRAY_POSITION(t.integerArray, 2) as result 
+        $dql = 'SELECT ARRAY_POSITION(t.integerArray, :value) as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
                 WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
+        $result = $this->executeDqlQuery($dql, ['value' => 2]);

43-53: Boolean-array case correct; add offset test to cover 3rd arg of array_position

Value false at id=1 -> 2 is correct. Since array_position accepts 2–3 args (per earlier learnings), add a test for the optional start-position argument to prevent regressions in the variadic path.

Add (new method):

#[Test]
public function can_find_position_with_offset_argument(): void
{
    // boolArray at id=1: [true, false, true] -> searching true starting from position 2 should return 3
    $dql = 'SELECT ARRAY_POSITION(t.boolArray, :value, :start) as result 
            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
            WHERE t.id = 1';

    $result = $this->executeDqlQuery($dql, ['value' => true, 'start' => 2]);
    $this->assertIsInt($result[0]['result']);
    $this->assertSame(3, $result[0]['result']);
}

55-64: Null-on-miss case is correct; minor consistency nit

Behavior and assertion are spot on. Optionally switch to a bound parameter for symmetry with the other tests.

-        $dql = 'SELECT ARRAY_POSITION(t.textArray, \'mango\') as result 
+        $dql = 'SELECT ARRAY_POSITION(t.textArray, :value) as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
                 WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
+        $result = $this->executeDqlQuery($dql, ['value' => 'mango']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (1)

45-56: Boolean-array case is fine; add coverage for multiple matches

For id=1 the bool array contains true twice ([1,3]). Adding a test for multiple positions would better exercise array_positions’ core behavior.

Add (new method):

#[Test]
public function can_find_multiple_positions_in_boolean_array(): void
{
    $dql = 'SELECT ARRAY_POSITIONS(t.boolArray, :value) as result 
            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
            WHERE t.id = 1';

    $result = $this->executeDqlQuery($dql, ['value' => true]);
    $actual = $this->transformPostgresArray($result[0]['result']);
    $this->assertIsArray($actual);
    $this->assertSame([1, 3], $actual);
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (3)

54-60: Prefer assertSame for stricter type safety on DECIMAL results

DBAL typically returns decimals as strings; asserting strict equality avoids accidental numeric coercion.

Apply:

-        $this->assertEquals('123.00', $result[0]['result']);
+        $this->assertSame('123.00', $result[0]['result']);

62-69: Minor: also assert closing brace in array string output

You already assert the opening {. Adding a check for } makes the shape validation a tad stronger with negligible cost.

         $this->assertIsString($result[0]['result']);
         $this->assertStringContainsString('{', $result[0]['result']);
+        $this->assertStringContainsString('}', $result[0]['result']);

Also applies to: 71-78


88-94: Unify assertion style: prefer $this->assert in this file*

Elsewhere in the suite (e.g., ArrayAppendTest) assertions use $this->…. This file mixes $this-> and static::. For consistency and readability, consider switching the static calls here to $this->…. While at it, make the decimal assertion strict.

-        static::assertNotEmpty($result);
+        $this->assertNotEmpty($result);
-        static::assertSame(11, $result[0]['result']); // PostgreSQL rounds 10.5 to 11
+        $this->assertSame(11, $result[0]['result']); // PostgreSQL rounds 10.5 to 11
-        static::assertEquals('10.00', $result[0]['result']);
+        $this->assertSame('10.00', $result[0]['result']);
-        static::assertIsString($result[0]['result']);
-        static::assertStringContainsString('{', $result[0]['result']);
+        $this->assertIsString($result[0]['result']);
+        $this->assertStringContainsString('{', $result[0]['result']);
-        static::assertIsString($result[0]['result']);
-        static::assertStringContainsString('{', $result[0]['result']);
+        $this->assertIsString($result[0]['result']);
+        $this->assertStringContainsString('{', $result[0]['result']);
-        static::assertIsString($result[0]['result']);
-        static::assertStringContainsString('{', $result[0]['result']);
+        $this->assertIsString($result[0]['result']);
+        $this->assertStringContainsString('{', $result[0]['result']);

Also applies to: 96-102, 104-110, 128-135, 137-144, 146-153

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (1)

27-29: Bounds canonicalization is correct; consider simplifying the DQL string quoting

Using '(]' for bounds on a discrete range canonicalizes to [11,21), so the expectation below is correct. Minor nit: prefer a single-quoted PHP string to avoid double-escaping namespace backslashes.

Replace the DQL assignment with a single-quoted PHP string to improve readability:

$dql = 'SELECT INT4RANGE(t.integer1, t.integer2, \'(]\') as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsNumerics t WHERE t.id = 1';

Optional: If you want to reduce duplication between the two tests, you could introduce a data provider with cases for default and custom bounds using #[DataProvider].

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (1)

19-53: Optional: consolidate the three tests via a DataProvider to remove duplication.

You can parameterize by field name; reduces repetition without changing coverage.

Apply this diff:

@@
-use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\DataProvider;
@@
-    #[Test]
-    public function can_get_text_array_number_of_dimensions(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.textArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
-
-    #[Test]
-    public function can_get_integer_array_number_of_dimensions(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.integerArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
-
-    #[Test]
-    public function can_get_boolean_array_number_of_dimensions(): void
-    {
-        $dql = 'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.boolArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsInt($result[0]['result']);
-        $this->assertSame(1, $result[0]['result']);
-    }
+    #[Test]
+    #[DataProvider('arrayFieldsProvider')]
+    public function can_get_array_number_of_dimensions(string $field): void
+    {
+        $dql = \sprintf(
+            'SELECT ARRAY_NUMBER_OF_DIMENSIONS(t.%s) as result 
+             FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
+             WHERE t.id = 1',
+            $field
+        );
+
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsInt($result[0]['result']);
+        $this->assertSame(1, $result[0]['result']);
+    }
+
+    public static function arrayFieldsProvider(): array
+    {
+        return [
+            ['textArray'],
+            ['integerArray'],
+            ['boolArray'],
+        ];
+    }

Optionally, add explicit coverage to assist tooling:

use PHPUnit\Framework\Attributes\CoversClass;

#[CoversClass(ArrayNumberOfDimensions::class)]
class ArrayNumberOfDimensionsTest extends ArrayTestCase
{
    // ...
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between eb0bd59 and b1a47dc.

📒 Files selected for processing (14)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonAggTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayToJsonTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CbrtTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DateExtractTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCardinalityTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
📚 Learning: 2025-04-11T11:23:44.192Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#340
File: tests/MartinGeorgiev/Doctrine/DBAL/Types/InetArrayTest.php:145-145
Timestamp: 2025-04-11T11:23:44.192Z
Learning: In the PostgreSQL for Doctrine test cases, methods that test database-to-PHP conversions should use `mixed` type for parameter and include non-string test cases in their data providers, following the pattern in classes like InetTest, CidrTest, and MacaddrTest.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
📚 Learning: 2025-08-24T16:52:32.488Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#0
File: :0-0
Timestamp: 2025-08-24T16:52:32.488Z
Learning: This repository uses BaseType extension pattern for custom Doctrine DBAL types with PostgreSQL platform assertions, comprehensive unit and integration testing with data providers, and dedicated exception classes for type conversion errors.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php
📚 Learning: 2025-05-03T00:18:09.078Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#366
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php:1-36
Timestamp: 2025-05-03T00:18:09.078Z
Learning: Always check the current official PostgreSQL documentation at https://www.postgresql.org/docs/ to verify function signatures and behaviors before suggesting improvements or additional tests. The `array_positions` function specifically has a fixed signature with exactly two parameters (array and search value), while `array_position` is variadic with 2-3 parameters.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
📚 Learning: 2025-03-11T12:32:10.726Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#263
File: src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Numrange.php:19-21
Timestamp: 2025-03-11T12:32:10.726Z
Learning: In the postgresql-for-doctrine repository, PostgreSQL range functions have distinct implementations for different data types. The `Numrange` function works with numeric/decimal values and is tested using the `ContainsDecimals` fixture with properties typed as `float`. In contrast, the `Int4range` function works with 32-bit integers and is tested using the `ContainsIntegers` fixture with properties typed as `int`. While the PHP implementations share a similar structure (extending `BaseFunction`), they are semantically different as they handle different PostgreSQL data types.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php
🧬 Code graph analysis (6)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayRemoveTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCat.php (1)
  • ArrayCat (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
tests/Integration/MartinGeorgiev/TestCase.php (3)
  • getStringFunctions (234-237)
  • executeDqlQuery (271-285)
  • transformPostgresArray (255-264)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositions.php (1)
  • ArrayPositions (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensions.php (1)
  • ArrayNumberOfDimensions (15-22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayAppendTest.php (3)
  • Test (19-30)
  • Test (32-43)
  • Test (45-56)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPosition.php (1)
  • ArrayPosition (15-39)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.3
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.3
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.3
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.3
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayCatTest.php (6)

14-16: LGTM: mapping reformat is functionally identical

Trailing comma and multi-line array improve diffs/readability. No functional change.


19-21: Renamed to descriptive method + #[Test] is correct

Matches the PR goal and the naming style used elsewhere in the suite (e.g., can_find_position_in_text_array).


34-36: Consistent migration to attribute-based test

Good rename and attribute usage; assertions remain unchanged and strict.


49-51: Boolean arrays case migrated cleanly

Attribute-based discovery and strict assertions look good.


64-66: Column-to-column concat test migrated correctly

Attribute is in place; test intent unchanged.


8-8: Environment supports #[Test] attributes––no action needed

  • composer.json requires PHP ^8.1 and PHPUnit ^10.5.53, satisfying PHP ≥8.0 and PHPUnit ≥9.5 requirements
  • Ripgrep found zero legacy function test_* methods under tests/
  • 601 occurrences of #[Test] across the test suite confirm attribute use is already widespread

All checks pass; the attribute import is recognized and CI discovery won’t break.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (2)

14-16: Mapping reformat only — OK

Switch to multi-line array with trailing comma is fine and consistent with the broader migration.


8-8: Attribute-based tests compatibility confirmed

Composer’s require-dev specifies PHPUnit ^10.5.53, so the #[Test] attribute is fully supported. A quick scan shows 601 attribute-marked tests and zero legacy test* methods, so the test runner will discover all cases correctly. No further changes needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (4)

14-16: Function mapping reformat — OK

Pure formatting; semantics unchanged.


19-30: Text-array case updated to id=3/‘kiwi’ — assertions match fixture

array_positions should return [3] for 'kiwi' in ['banana','orange','kiwi','mango'] — correct. Using a bound parameter is also a nice consistency touch here.


32-43: Integer-array case remains correct and idiomatic

Value 1 at id=2 -> [2] is correct given [4,1]. No issues.


58-69: Not-found case correct

Correctly asserts empty array when value is absent.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/CastTest.php (3)

30-36: LGTM: clean migration to #[Test] with descriptive method names

The attribute-based discovery and renamed methods read well and keep assertions focused. No functional concerns.

Also applies to: 38-44, 46-52, 71-78, 80-86, 96-102, 112-118, 128-135, 137-144, 146-153


120-126: Double-check expected exception type for CAST(NULL AS INTEGER)

Depending on Doctrine/DBAL and platform behavior, CAST(NULL AS INTEGER) can yield NULL rather than a parser error. If this test ever flakes across platform versions, consider asserting on the exception message/pattern or replacing with a case that is guaranteed to error at parse-time (like an obviously invalid type name).

Would you like me to scan the repo for similar tests and align the expectation accordingly?


10-10: PHPUnit #[Test] attribute support confirmed

The project’s composer.json specifies:

  • PHP: ^8.1
  • phpunit/phpunit (require-dev): ^10.5.53

These constraints satisfy the minimum requirements for PHPUnit\Framework\Attributes\Test (PHPUnit ≥ 10) on PHP ≥ 8.1. No further changes are needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int4rangeTest.php (2)

8-8: Attribute-based tests fully supported; no legacy test_ methods detected

  • composer.json requires phpunit/phpunit ^10.5.53, which includes the PHPUnit\Framework\Attributes\Test attribute.
  • Ripgrep found 601 tests using #[Test].
  • No function test_* methods remain in the tests/** directory.

All criteria for migrating to attribute-based tests are satisfied—no further changes needed.


19-21: Ignore fixture‐type concern for unit test

This unit test solely verifies DQL→SQL translation and does not load or execute against any entity fixtures. The ContainsIntegers reference in the SQL string is purely symbolic; there is no runtime inspection of integer1 or integer2 types. You can safely disregard the fixture‐backing check in this context.

Likely an incorrect or invalid review comment.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayNumberOfDimensionsTest.php (5)

14-16: String function registration is tidy and consistent.

The multiline array with trailing comma improves diffability; the key matches the DQL used below. No issues.


19-29: Renamed test + #[Test] attribute look good.

Clearer method name, same assertions. All good.


31-41: LGTM on integer array case.

Consistent pattern and assertions.


43-53: LGTM on boolean array case.

Consistent with the other two tests; assertions are precise.


8-8: Composer constraints confirmed for attribute support

  • PHP requirement is ^8.1 (≥ 8.1), so PHP attributes are available.
  • require-dev includes "phpunit/phpunit": "^10.5.53", and PHPUnit 10 fully supports the #[Test] attribute.
  • No remaining legacy test_* methods found across the test suite.

All checks pass—attributes are safe to use here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php (1)

152-166: Remove Remaining Static Assertion Calls

Composer.json already specifies PHPUnit ^10.5.53, so attribute support is confirmed. There are no legacy test_* methods or @test annotations remaining. However, the following integration tests still use self::assert* or static::assert* and should be refactored to instance assertions (e.g. $this->assert*):

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php:85
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php:26, 42
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php:85

Please update these to use $this->assert* methods for consistency with attribute-based tests.

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php (1)

1-325: Convert remaining static assertions to instance assertions

The migration to use PHPUnit attributes requires replacing all self::/static:: assertions with $this->-based calls to ensure consistency across tests. While unit tests are clean, several integration tests still use the old static style and must be updated.

• tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php:85
└─ self::assertArrayNotHasKey('invalid', $decoded);
• tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php:26,42
└─ static::assertSame('2000-12-05', $result[0]['result']);
└─ static::assertSame('2005-01-01', $result[0]['result']);
• tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php:85
└─ self::assertArrayNotHasKey('nonexistent', $decoded);

Additionally, PHPUnit is pinned at "phpunit/phpunit": "^10.5.53" in composer.json, which fully supports attribute-based tests, and all subclasses of BaseRangeTestCase have been detected, so the attribute-driven tests will execute as expected.

Please update the static assertions above to use $this->assert*() calls to complete the migration.

♻️ Duplicate comments (1)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToCharTest.php (1)

33-39: Quick sweep: ensure no lingering test_-prefixed methods remain in this directory

This file is fully migrated. To finish the directory-wide migration, run the check below and update any leftovers to #[Test] + non-prefixed names.

#!/bin/bash
# List any remaining test_-prefixed methods under the AST/Functions integration tests
rg -nP --type=php '\bfunction\s+test_[A-Za-z0-9_]*\s*\(' tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions || true

Expected: no output.

Also applies to: 41-47, 49-55, 57-63, 65-71, 73-79, 81-88, 89-96, 97-103

🧹 Nitpick comments (65)
tests/Integration/MartinGeorgiev/Utils/PostgresArrayToPHPArrayTransformerTest.php (2)

173-177: Prefer assertSame for stricter type-safe comparison

Good switch to instance assertions. Given both sides are arrays of strings, assertSame will enforce type and value equality recursively and tighten the test.

-        $this->assertEquals(
+        $this->assertSame(
             $expected,
             $retrieved,
             \sprintf('Direct retrieval failed for %s', $description)
         );

182-186: Use assertSame for the parsed text round-trip as well

Same rationale: stricter equality helps catch subtle coercions (e.g., numeric-string vs int) during parsing.

-        $this->assertEquals(
+        $this->assertSame(
             $expected,
             $parsed,
             \sprintf('Text representation parsing failed for %s', $description)
         );
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/DoublePrecisionArrayTest.php (1)

23-23: Prefer assertSame for strict comparison

Use assertSame for stricter type-safe equality on strings.

-        $this->assertEquals('double precision[]', $this->fixture->getName());
+        $this->assertSame('double precision[]', $this->fixture->getName());
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseFloatArrayTestCase.php (2)

42-47: Method name suggests a conversion but only validates — consider renaming for clarity

The test named “can_transform_from_php_value” only asserts validity via isValidArrayItemForDatabase(). Consider a clearer name to reflect behavior.

-    public function can_transform_from_php_value(float $phpValue, string $postgresValue): void
+    public function validates_array_item_for_database(float $phpValue, string $postgresValue): void

53-53: Float comparison: prefer delta to avoid precision pitfalls

Direct float equality can be brittle. Using assertEqualsWithDelta makes the test more robust without changing semantics.

-        $this->assertEquals($phpValue, $this->fixture->transformArrayItemForPHP($postgresValue));
+        $this->assertEqualsWithDelta($phpValue, $this->fixture->transformArrayItemForPHP($postgresValue), 1.0E-12);
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/TsRangeTest.php (1)

292-292: Optional: assert the absence of timezone artifacts

Since the contract says formatting omits timezone info, add a negative assertion to lock this in.

-        $this->assertStringContainsString('2023-01-01 10:00:00.000000', $formatted);
+        $this->assertStringContainsString('2023-01-01 10:00:00.000000', $formatted);
+        // Ensure no timezone indicators leaked into formatting
+        $this->assertStringNotContainsString('+', $formatted);
+        $this->assertStringNotContainsString('Z', $formatted);
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/GeometryTypeTest.php (1)

65-70: Optional: parameterize invalid cases via a DataProvider to scale negative coverage.

Current null assertions are fine. If you want to expand invalid inputs (whitespace, case differences, unknown tokens) without duplicating asserts, consider a small refactor:

Apply within this block:

-    #[Test]
-    public function returns_null_for_invalid_types(): void
-    {
-        $this->assertNull(GeometryType::tryFrom('INVALID_TYPE'));
-        $this->assertNull(GeometryType::tryFrom(''));
-    }
+    #[DataProvider('provideInvalidGeometryTypes')]
+    #[Test]
+    public function returns_null_for_invalid_types(string $invalid): void
+    {
+        $this->assertNull(GeometryType::tryFrom($invalid));
+    }

Add this helper (outside the selected lines, e.g., below the valid provider):

/**
 * @return array<string, array{string}>
 */
public static function provideInvalidGeometryTypes(): array
{
    return [
        'unknown token' => ['INVALID_TYPE'],
        'empty' => [''],
        'lowercased valid token' => ['point'],
        'whitespace padded' => [' POLYGON '],
    ];
}
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/SmallIntArrayTest.php (2)

17-21: Use assertSame and the type’s constant for stricter and future-proof assertion.

Assert strictly and avoid duplicating the literal type name.

Apply this diff:

-        $this->assertEquals('smallint[]', $this->fixture->getName());
+        $this->assertSame(SmallIntArray::TYPE_NAME, $this->fixture->getName());

1-80: Leftover static assertions in integration tests—please refactor

We discovered two occurrences of legacy static assertions that should be converted to instance-based assertions for consistency with the attribute-driven tests:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (line 85)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (line 85)

No methods still use the old test* prefix, and every PHP test file includes at least one #[Test] attribute.

• Replace

self::assertArrayNotHasKey('nonexistent', $decoded);

with

$this->assertArrayNotHasKey('nonexistent', $decoded);

(and likewise in the Lax test) to fully migrate off static assertions.

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Int4RangeTest.php (1)

135-135: Use assertSame for stricter comparison (nice move to instance assertions).

Switching from static to instance assertion aligns with PHPUnit 10+ best practices. While here both sides are strings, prefer assertSame to enforce type-strict equality consistently across the suite.

-        $this->assertEquals('[-2147483648,2147483647)', (string) $int4Range);
+        $this->assertSame('[-2147483648,2147483647)', (string) $int4Range);
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TestCase.php (4)

112-112: Prefer strict comparison for SQL strings

Switching to instance assertions is fine. For strings, assertSame provides stricter, intention-revealing checks without type juggling.

-        $this->assertEquals($expectedSql, $query->getSQL(), $message);
+        $this->assertSame($expectedSql, $query->getSQL(), $message);

95-107: Prevent key-mismatch bugs and improve failure diagnostics

Counting equality doesn’t guarantee aligned keys; $dqls[$key] can be undefined if arrays use different keys. Also, prefer assertions over throwing to keep PHPUnit-friendly output, and include the DQL in the failure message for context.

     #[Test]
     public function dql_is_transformed_to_valid_sql(): void
     {
-        $expectedSqls = $this->getExpectedSqlStatements();
-        $dqls = $this->getDqlStatements();
-        if (\count($expectedSqls) !== \count($dqls)) {
-            throw new \LogicException(\sprintf('You need ot provide matching expected SQL for every DQL, currently there are %d SQL statements for %d DQL statements', \count($expectedSqls), \count($dqls)));
-        }
-
-        foreach ($expectedSqls as $key => $expectedSql) {
-            $this->assertSqlFromDql($expectedSql, $dqls[$key], \sprintf('Assertion failed for expected SQL statement "%s"', $expectedSql));
-        }
+        $expectedSqls = \array_values($this->getExpectedSqlStatements());
+        $dqls        = \array_values($this->getDqlStatements());
+
+        $this->assertSame(
+            \count($expectedSqls),
+            \count($dqls),
+            \sprintf(
+                'You need to provide matching expected SQL for every DQL; currently there are %d SQL statements for %d DQL statements',
+                \count($expectedSqls),
+                \count($dqls)
+            )
+        );
+
+        foreach ($expectedSqls as $i => $expectedSql) {
+            $this->assertSqlFromDql(
+                $expectedSql,
+                $dqls[$i],
+                \sprintf('Assertion failed for DQL "%s": expected SQL "%s"', $dqls[$i], $expectedSql)
+            );
+        }
     }

78-83: Tighten the return type for static analysis

These are DQL function registrations; advertise class-string in the phpdoc.

     /**
-     * @return array<string, string>
+     * @return array<string, class-string<FunctionNode>>
      */
     protected function getStringFunctions(): array

115-118: Consider using EntityManager::create(...) for broader ORM compatibility

The factory method tends to be more stable across ORM versions than calling the constructor directly.

Please verify against your supported Doctrine ORM versions in CI before changing this.

-        return new EntityManager(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'memory' => true], $this->configuration), $this->configuration);
+        return EntityManager::create(['driver' => 'pdo_sqlite', 'memory' => true], $this->configuration);
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php (3)

145-146: Tighten equality check: consider assertSame for strings

Switching to instance assertions is fine. For string equality, assertSame provides stricter comparison and catches subtle mismatches.

-        $this->assertEquals('[2023-06-15,2023-06-16)', (string) $dateRange);
+        $this->assertSame('[2023-06-15,2023-06-16)', (string) $dateRange);

327-327: Optional: prefer assertSame for exact string match

Minor hardening: use assertSame for strict string comparison in expectation messages-driven tests.

-        $this->assertEquals($expectedString, (string) $dateRange, $description);
+        $this->assertSame($expectedString, (string) $dateRange, $description);

353-353: Optional: use assertSame for strictness

Same suggestion here for strict string equality.

-        $this->assertEquals($expectedString, (string) $dateRange, $description);
+        $this->assertSame($expectedString, (string) $dateRange, $description);
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseNetworkTypeArrayTest.php (3)

62-62: Use assertSame for array equality.

For array comparisons, assertSame prevents loose equality surprises and enforces exact structure and types.

Apply this diff:

-        $this->assertEquals($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
+        $this->assertSame($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));

58-60: Minor consistency: put DataProvider above Test attribute (matches nearby tests).

Other unit tests in this package often list #[DataProvider] before #[Test]. Order doesn’t affect execution but keeping it consistent aids readability.

Apply this diff:

-    #[Test]
-    #[DataProvider('provideValidTransformations')]
+    #[DataProvider('provideValidTransformations')]
+    #[Test]

65-81: Avoid associative keys in data providers to prevent parameter order surprises.

PHPUnit passes parameters by value order, not by associative keys. While PHP preserves insertion order, using indexed arrays is simpler and avoids ambiguity.

Apply this diff:

         return [
-            'null' => [
-                'phpValue' => null,
-                'postgresValue' => null,
-            ],
-            'empty array' => [
-                'phpValue' => [],
-                'postgresValue' => '{}',
-            ],
-            'valid array' => [
-                'phpValue' => ['valid_address', 'valid_address'],
-                'postgresValue' => '{"valid_address","valid_address"}',
-            ],
+            'null' => [null, null],
+            'empty array' => [[], '{}'],
+            'valid array' => [['valid_address', 'valid_address'], '{"valid_address","valid_address"}'],
         ];
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php (3)

168-176: Use assertSame() for string equality to tighten type checks

Since you’re comparing strings, assertSame() is a slightly stricter and clearer choice than assertEquals().

-        $this->assertEquals('[1,10.5)', (string) $range);
+        $this->assertSame('[1,10.5)', (string) $range);

-        $this->assertEquals('[1.5,10)', (string) $range2);
+        $this->assertSame('[1.5,10)', (string) $range2);

178-192: Mixed numeric comparisons: coverage is solid; optionally add exclusive int-vs-float equality case

You already cover inclusive equality across int/float and exclusive equality for float/float. For completeness, you could also assert exclusive equality across int vs float.

         $equalExclusive = new NumericRange(5.0, 5.0, false, false);
         $this->assertTrue($equalExclusive->isEmpty());
+        
+        // Optional: exclusive equality across int vs float should also be empty
+        $equalExclusiveMixed = new NumericRange(5, 5.0, false, false);
+        $this->assertTrue($equalExclusiveMixed->isEmpty());

194-205: Reduce repetition with a compact loop (readability-only)

Same assertion repeated three times; a small loop keeps intent while reducing duplication.

-        $range1 = new NumericRange(42, 100);
-        $this->assertStringContainsString('42', (string) $range1);
-
-        $range2 = new NumericRange(3.14, 10);
-        $this->assertStringContainsString('3.14', (string) $range2);
-
-        $range3 = new NumericRange(-2.5, 0);
-        $this->assertStringContainsString('-2.5', (string) $range3);
+        foreach ([[42, 100, '42'], [3.14, 10, '3.14'], [-2.5, 0, '-2.5']] as [$l, $u, $needle]) {
+            $this->assertStringContainsString($needle, (string) new NumericRange($l, $u));
+        }
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/IntegerArrayTest.php (2)

20-20: Prefer assertSame for strict type check on strings

Use assertSame to avoid implicit type juggling.

-        $this->assertEquals('integer[]', $this->fixture->getName());
+        $this->assertSame('integer[]', $this->fixture->getName());

8-10: Optional: add #[CoversClass(IntegerArray::class)] to improve coverage mapping

Annotating the test class clarifies intended coverage for reports and tooling.

 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;

-class IntegerArrayTest extends BaseIntegerArrayTestCase
+#[CoversClass(IntegerArray::class)]
+class IntegerArrayTest extends BaseIntegerArrayTestCase
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/PointTest.php (2)

35-35: Prefer assertSame for strict scalar comparison; instance assertions are a good move

String-to-string comparison benefits from assertSame to avoid type juggling. Forward-compat change to instance assertions looks good.

Apply this diff:

-        $this->assertEquals('point', $this->fixture->getName());
+        $this->assertSame('point', $this->fixture->getName());

42-42: Tighten equality: assertSame for string comparison

This compares strings; assertSame is slightly stricter and consistent with nearby tests.

Apply this diff:

-        $this->assertEquals($postgresValue, $this->fixture->convertToDatabaseValue($pointValueObject, $this->platform));
+        $this->assertSame($postgresValue, $this->fixture->convertToDatabaseValue($pointValueObject, $this->platform));
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/InetTest.php (1)

34-34: Consistently use assertSame for strings; good shift to instance assertions

These three are string comparisons; assertSame avoids implicit type coercion and aligns with PHPUnit best practices. The move away from static calls is 👍 for PHPUnit 10/11 forward-compat.

Apply this diff:

-        $this->assertEquals('inet', $this->fixture->getName());
+        $this->assertSame('inet', $this->fixture->getName());
-        $this->assertEquals($postgresValue, $this->fixture->convertToDatabaseValue($phpValue, $this->platform));
+        $this->assertSame($postgresValue, $this->fixture->convertToDatabaseValue($phpValue, $this->platform));
-        $this->assertEquals($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
+        $this->assertSame($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));

Also applies to: 41-41, 48-48

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Int8RangeTest.php (1)

95-96: Use assertSame for the string cast; keep assertFalse as-is

Minor tightening: prefer assertSame when comparing the string representation. The emptiness assertion is fine.

Apply this diff:

-        $this->assertEquals('['.PHP_INT_MIN.','.PHP_INT_MAX.')', (string) $int8Range);
+        $this->assertSame('['.PHP_INT_MIN.','.PHP_INT_MAX.')', (string) $int8Range);
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BigIntArrayTest.php (1)

22-22: Tighten equality to assertSame for string expectation

Since getName() returns a string, assertSame is slightly safer and matches usage elsewhere in the suite.

Apply this diff:

-        $this->assertEquals('bigint[]', $this->fixture->getName());
+        $this->assertSame('bigint[]', $this->fixture->getName());
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/GeographyArrayTest.php (2)

33-33: Prefer assertSame for string-to-string comparisons

Use assertSame for strict (type+value) comparisons of strings to avoid accidental type juggling in future changes.

Apply this diff:

-        $this->assertEquals('geography[]', $this->type->getName());
+        $this->assertSame('geography[]', $this->type->getName());
-        $this->assertInstanceOf(WktSpatialData::class, $result);
-        $this->assertEquals($expected, (string) $result);
+        $this->assertInstanceOf(WktSpatialData::class, $result);
+        $this->assertSame($expected, (string) $result);

Also applies to: 302-303


156-162: Optional: simplify per-item assertions with collection-level checks

You can avoid the foreach when validating the whole collection by asserting types and comparing normalized string representations in one go.

Apply this diff:

-        foreach ($result as $index => $item) {
-            $this->assertInstanceOf(WktSpatialData::class, $item);
-            $this->assertSame($expectedPhpArray[$index], (string) $item);
-        }
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $result);
+        $this->assertSame(
+            $expectedPhpArray,
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $result)
+        );

And similarly in the bidirectional test:

-        foreach ($convertedBack as $index => $item) {
-            $this->assertInstanceOf(WktSpatialData::class, $item);
-            $originalItem = $phpArray[$index];
-            $this->assertInstanceOf(WktSpatialData::class, $originalItem);
-            $this->assertSame((string) $originalItem, (string) $item);
-        }
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $convertedBack);
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $phpArray);
+        $this->assertSame(
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $phpArray),
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $convertedBack)
+        );

Also applies to: 228-236

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/GeometryArrayTest.php (2)

33-33: Use assertSame for strict string equality

For string WKT comparisons and the type name, assertSame avoids implicit coercion and slightly tightens the contract.

Apply this diff:

-        $this->assertEquals('geometry[]', $this->type->getName());
+        $this->assertSame('geometry[]', $this->type->getName());
-        $this->assertInstanceOf(WktSpatialData::class, $result);
-        $this->assertEquals($wktString, (string) $result);
+        $this->assertInstanceOf(WktSpatialData::class, $result);
+        $this->assertSame($wktString, (string) $result);
-        $this->assertInstanceOf(WktSpatialData::class, $result);
-        $this->assertEquals($expected, (string) $result);
+        $this->assertInstanceOf(WktSpatialData::class, $result);
+        $this->assertSame($expected, (string) $result);

Also applies to: 354-355, 372-373


150-153: Optional: collapse per-item checks using contains-only and map normalization

Minor readability gain by asserting the whole collection at once, mirroring the GeographyArrayTest suggestion.

Apply this diff:

-        foreach ($result as $index => $item) {
-            $this->assertInstanceOf(WktSpatialData::class, $item);
-            $this->assertSame($expectedPhpArray[$index], (string) $item);
-        }
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $result);
+        $this->assertSame(
+            $expectedPhpArray,
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $result)
+        );
-        foreach ($convertedBack as $index => $item) {
-            $this->assertInstanceOf(WktSpatialData::class, $item);
-            $originalItem = $phpArray[$index];
-            $this->assertInstanceOf(WktSpatialData::class, $originalItem);
-            $this->assertSame((string) $originalItem, (string) $item);
-        }
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $convertedBack);
+        $this->assertContainsOnlyInstancesOf(WktSpatialData::class, $phpArray);
+        $this->assertSame(
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $phpArray),
+            \array_map(static fn (WktSpatialData $i) => (string) $i, $convertedBack)
+        );

Also applies to: 276-281

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseArrayTest.php (1)

52-52: Prefer assertSame for array equality

Since convertToPHPValue returns ?array, assertSame ensures strict comparison (including types) and guards against subtle coercions.

Apply this diff:

-        $this->assertEquals($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
+        $this->assertSame($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
tests/Unit/MartinGeorgiev/Utils/PostgresJsonToPHPArrayTransformerTest.php (1)

20-20: Use assertSame to avoid JSON-related type coercion

JSON decoding yields specific PHP types (int, bool, null, array, string). assertEquals can pass for e.g. 123 vs '123'. assertSame prevents that and tightens expectations.

Apply this diff:

-        $this->assertEquals($phpValue, PostgresJsonToPHPArrayTransformer::transformPostgresJsonEncodedValueToPHPValue($postgresValue));
+        $this->assertSame($phpValue, PostgresJsonToPHPArrayTransformer::transformPostgresJsonEncodedValueToPHPValue($postgresValue));
-        $this->assertEquals($phpArray, PostgresJsonToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresArray));
+        $this->assertSame($phpArray, PostgresJsonToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresArray));
-        $this->assertEquals($phpArray, PostgresJsonToPHPArrayTransformer::transformPostgresJsonEncodedValueToPHPArray($item));
+        $this->assertSame($phpArray, PostgresJsonToPHPArrayTransformer::transformPostgresJsonEncodedValueToPHPArray($item));

Also applies to: 64-64, 92-92

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/MacaddrTest.php (2)

39-42: Silence PHPMD UnusedFormalParameter by asserting round-trip or suppressing the warning

PHPMD flags the unused parameters in these two tests: Line 39’s $phpValueAfterRetrievalFromDatabase and Line 46’s $phpInput. You can either use them to strengthen the assertions (preferred) or explicitly suppress for clarity.

  • Option A (preferred): Assert round-trips and use all parameters.
 public function can_transform_from_php_value(?string $phpInput, ?string $postgresValueAfterNormalization, ?string $phpValueAfterRetrievalFromDatabase): void
 {
-        $this->assertEquals($postgresValueAfterNormalization, $this->fixture->convertToDatabaseValue($phpInput, $this->platform));
+        $dbValue = $this->fixture->convertToDatabaseValue($phpInput, $this->platform);
+        $this->assertEquals($postgresValueAfterNormalization, $dbValue);
+        // Round-trip DB->PHP should match expected normalized PHP value
+        $this->assertEquals($phpValueAfterRetrievalFromDatabase, $this->fixture->convertToPHPValue($dbValue, $this->platform));
 }
 public function can_transform_to_php_value(?string $phpInput, ?string $postgresValueAfterNormalization, ?string $phpValueAfterRetrievalFromDatabase): void
 {
-        $this->assertEquals($phpValueAfterRetrievalFromDatabase, $this->fixture->convertToPHPValue($postgresValueAfterNormalization, $this->platform));
+        $phpValue = $this->fixture->convertToPHPValue($postgresValueAfterNormalization, $this->platform);
+        $this->assertEquals($phpValueAfterRetrievalFromDatabase, $phpValue);
+        // Also assert the PHP->DB path against normalization using the original input
+        $this->assertEquals($postgresValueAfterNormalization, $this->fixture->convertToDatabaseValue($phpInput, $this->platform));
 }
  • Option B: Suppress PHPMD for these methods.
+    /** @SuppressWarnings(PHPMD.UnusedFormalParameter) */
     #[DataProvider('provideValidTransformations')]
     #[Test]
     public function can_transform_from_php_value(?string $phpInput, ?string $postgresValueAfterNormalization, ?string $phpValueAfterRetrievalFromDatabase): void
+    /** @SuppressWarnings(PHPMD.UnusedFormalParameter) */
     #[DataProvider('provideValidTransformations')]
     #[Test]
     public function can_transform_to_php_value(?string $phpInput, ?string $postgresValueAfterNormalization, ?string $phpValueAfterRetrievalFromDatabase): void

Also applies to: 46-49


34-35: Prefer assertSame for string equality

Using assertSame ensures type-strict comparison for the type name.

-        $this->assertEquals('macaddr', $this->fixture->getName());
+        $this->assertSame('macaddr', $this->fixture->getName());
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/InetArrayTest.php (2)

136-141: Align DB→PHP invalid-value test with project pattern (use mixed and include non-strings)

Per earlier learnings in this repo, DB→PHP conversion tests should accept mixed and include non-string inputs. Consider broadening the test signature and provider.

-    public function throws_exception_for_invalid_php_value_inputs(string $postgresValue): void
+    public function throws_exception_for_invalid_php_value_inputs(mixed $postgresValue): void
     {
         $this->expectException(InvalidInetArrayItemForPHPException::class);

         $this->fixture->convertToPHPValue($postgresValue, $this->platform);
     }
     public static function provideInvalidPHPValueInputs(): array
     {
         return [
             'invalid format' => ['{"invalid-ip"}'],
             'invalid IPv4 in array' => ['{"256.256.256.256"}'],
             'invalid IPv6 in array' => ['{"2001:xyz::1"}'],
             'malformed array' => ['not-an-array'],
             'empty item in array' => ['{"192.168.1.1",""}'],
             'invalid item in array' => ['{"192.168.1.1","invalid-ip"}'],
             'invalid CIDR in array' => ['{"192.168.1.0/33"}'],
             'incomplete IPv4 in array' => ['{"192.168.1"}'],
             'incomplete IPv6 in array' => ['{"2001:db8"}'],
+            // non-string inputs to DB→PHP are invalid as well
+            'integer input' => [123],
+            'boolean input' => [true],
+            'array input' => [[1, 2, 3]],
+            'object input' => [new \stdClass()],
+            'null input' => [null],
         ];
     }

Also applies to: 146-158


33-34: Nit: assertSame for name check

Type-strict comparison is preferable for exact string names.

-        $this->assertEquals('inet[]', $this->fixture->getName());
+        $this->assertSame('inet[]', $this->fixture->getName());
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseTypeTest.php (1)

58-59: Nit: prefer assertSame for strings

The compared values are strings; assertSame enforces type-strict equality.

-        $this->assertEquals('custom_type', $type->getName());
+        $this->assertSame('custom_type', $type->getName());
-        $this->assertEquals('CUSTOM_SQL_TYPE', $result);
+        $this->assertSame('CUSTOM_SQL_TYPE', $result);

Also applies to: 75-76

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseTimestampRangeTestCase.php (1)

121-125: Fix “different DateTime implementations” to actually mix implementations

The current code instantiates DateTimeImmutable twice. Use DateTime for the first to exercise mixed implementations as per the test’s intent.

-        $dateTime = new \DateTimeImmutable($this->getTestStartTimeString());
+        $dateTime = new \DateTime($this->getTestStartTimeString());
         $dateTimeImmutable = new \DateTimeImmutable($this->getTestEndTimeString());
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/PointArrayTest.php (2)

34-35: Nit: assertSame for string and array comparisons

When possible, prefer assertSame for exact string and array equality in unit tests.

-        $this->assertEquals('point[]', $this->fixture->getName());
+        $this->assertSame('point[]', $this->fixture->getName());
-        $this->assertEquals([], $result1);
-        $this->assertEquals([], $result2);
-        $this->assertEquals([], $result3);
+        $this->assertSame([], $result1);
+        $this->assertSame([], $result2);
+        $this->assertSame([], $result3);
-        $this->assertEquals([], $result1);
-        $this->assertEquals([], $result2);
+        $this->assertSame([], $result1);
+        $this->assertSame([], $result2);

Also applies to: 183-186, 194-196


117-121: Broaden DB→PHP invalid test to accept mixed inputs (not only strings)

Following the pattern used in other type tests (e.g., Macaddr), consider accepting mixed for the DB→PHP invalid test and including non-string values in the provider.

-    public function throws_exception_for_invalid_php_value_inputs(string $postgresValue): void
+    public function throws_exception_for_invalid_php_value_inputs(mixed $postgresValue): void
     {
         $this->expectException(InvalidPointArrayItemForPHPException::class);
         $this->fixture->convertToPHPValue($postgresValue, $this->platform);
     }
     public static function provideInvalidPHPValueInputs(): array
     {
         return [
             'missing parentheses' => ['{"(1.23, 4.56)","(-7.89, 0.12"}'],
             'non-numeric values' => ['{"(abc, 4.56)","(-7.89, 0.12"}'],
             'too many coordinates' => ['{"(1.23, 4.56, 7,89)","(-7.89, 0.12"}'],
             'invalid array format' => ['{"(1.23,4.56)","(a,b)"}'],
             'invalid characters' => ['{"(1.23, 4.56)","(-7.89, @,?)"}'],
+            // Non-string inputs to DB→PHP
+            'integer input' => [123],
+            'boolean input' => [true],
+            'array input' => [[new Point(1, 2)]],
+            'object input' => [new \stdClass()],
+            'null input' => [null],
         ];
     }

Also applies to: 126-134

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/GeographyTest.php (1)

35-35: Prefer assertSame for string equality

Since these are strict string comparisons, assertSame provides type-safety and slightly clearer intent.

-        $this->assertEquals('geography', $this->fixture->getName());
+        $this->assertSame('geography', $this->fixture->getName());
-        $this->assertEquals($postgresValue, $this->fixture->convertToDatabaseValue($wktSpatialData, $this->platform));
+        $this->assertSame($postgresValue, $this->fixture->convertToDatabaseValue($wktSpatialData, $this->platform));
-        $this->assertEquals((string) $wktSpatialData, (string) $result);
+        $this->assertSame((string) $wktSpatialData, (string) $result);

Also applies to: 42-42, 57-57

tests/Unit/MartinGeorgiev/Utils/PostgresArrayToPHPArrayTransformerTest.php (2)

22-22: Use assertSame for exact string match

The transformer returns strings; assertSame avoids implicit type juggling.

-        $this->assertEquals($phpValue, PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue));
+        $this->assertSame($phpValue, PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue));

197-198: Likewise here: assertSame is safer for arrays of scalars

Strict comparison ensures both values and types (e.g., null/booleans) match exactly.

-        $this->assertEquals($phpValue, PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue));
+        $this->assertSame($phpValue, PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresValue));
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BooleanArrayTest.php (1)

33-33: Consider assertSame for stricter comparisons

  • has_name is a pure string check.
  • Transform round-trips should preserve boolean element types; assertSame will enforce that.
-        $this->assertEquals('bool[]', $this->fixture->getName());
+        $this->assertSame('bool[]', $this->fixture->getName());
-        $this->assertEquals($postgresValue, $this->fixture->convertToDatabaseValue($phpValue, $this->platform));
+        $this->assertSame($postgresValue, $this->fixture->convertToDatabaseValue($phpValue, $this->platform));
-        $this->assertEquals($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));
+        $this->assertSame($phpValue, $this->fixture->convertToPHPValue($postgresValue, $this->platform));

Also applies to: 44-45, 55-56

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseRangeTestCase.php (4)

41-41: Tighten to assertSame for type-safe name check

getName() returns string; assertSame avoids accidental truthiness matches.

-        $this->assertEquals($this->getExpectedTypeName(), $this->fixture->getName());
+        $this->assertSame($this->getExpectedTypeName(), $this->fixture->getName());

51-51: Exact string comparison recommended

For convertToDatabaseValue output, assertSame communicates strictness.

-        $this->assertEquals($postgresValue, $this->fixture->convertToDatabaseValue($range, $this->platform));
+        $this->assertSame($postgresValue, $this->fixture->convertToDatabaseValue($range, $this->platform));

66-69: Use strict assertions for string/boolean checks

These are deterministic and benefit from assertSame.

-            $this->assertEquals($range->__toString(), $result->__toString());
-            $this->assertEquals($range->isEmpty(), $result->isEmpty());
+            $this->assertSame($range->__toString(), $result->__toString());
+            $this->assertSame($range->isEmpty(), $result->isEmpty());

98-101: Optional: assertSame for the 'empty' sentinel

Small clarity gain; behavior remains the same.

-        $this->assertEquals('empty', (string) $result);
+        $this->assertSame('empty', (string) $result);
tests/Unit/MartinGeorgiev/Utils/PHPArrayToPostgresValueTransformerTest.php (2)

22-22: assertSame for strings

Transformer output is always a string; assertSame avoids loose comparisons.

-        $this->assertEquals($postgresValue, PHPArrayToPostgresValueTransformer::transformToPostgresTextArray($phpValue));
+        $this->assertSame($postgresValue, PHPArrayToPostgresValueTransformer::transformToPostgresTextArray($phpValue));

162-162: Nice variety of edge cases; minor tightening possible

Great coverage for objects (with/without __toString), open/closed resources, and mixed types. Where the expectation is a precise string, assertSame communicates that strictness (already used in several places; consider it for line 211 as well).

-        $this->assertEquals('{"string",123,1.5,true,NULL,"object",""}', PHPArrayToPostgresValueTransformer::transformToPostgresTextArray($input));
+        $this->assertSame('{"string",123,1.5,true,NULL,"object",""}', PHPArrayToPostgresValueTransformer::transformToPostgresTextArray($input));

Also applies to: 181-181, 190-190, 211-211

tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php (11)

27-28: Prefer strict string comparison for representation checks

Use assertSame for exact string match; type-juggling is unnecessary here.

-        $this->assertEquals($expectedString, (string) $range);
+        $this->assertSame($expectedString, (string) $range);

36-37: Use the dedicated helper for empty-range assertions

You already have assertRangeIsEmpty(); using it keeps tests consistent and DRY.

-        $this->assertEquals('empty', (string) $range);
-        $this->assertTrue($range->isEmpty());
+        $this->assertRangeIsEmpty($range);

45-46: Tighten equality: assertSame for string representation

-        $this->assertEquals('(,)', (string) $range);
+        $this->assertSame('(,)', (string) $range);

55-56: Use assertSame for exact string match

-        $this->assertEquals($expectedString, (string) $range);
+        $this->assertSame($expectedString, (string) $range);

66-66: Boolean expectation: use assertSame to avoid truthiness

-        $this->assertEquals($expected, $range->contains($value));
+        $this->assertSame($expected, $range->contains($value));

104-110: Comparison loop: prefer assertSame for boolean equality

-            $this->assertEquals(
+            $this->assertSame(
                 $testCase['expectedEmpty'],
                 $testCase['range']->isEmpty(),
                 'Comparison test failed: '.$description
             );

187-189: Avoid calling __toString() directly and prefer strict comparisons

Casting is clearer than calling magic methods; also use assertSame for both string and boolean comparisons.

-        $this->assertEquals($expected->__toString(), $actual->__toString(), $message.' (string representation)');
-        $this->assertEquals($expected->isEmpty(), $actual->isEmpty(), $message.' (isEmpty state)');
+        $this->assertSame((string) $expected, (string) $actual, $message.' (string representation)');
+        $this->assertSame($expected->isEmpty(), $actual->isEmpty(), $message.' (isEmpty state)');

230-231: Use assertSame for string equality in helper

-        $this->assertEquals($expected, (string) $range, $message);
+        $this->assertSame($expected, (string) $range, $message);

240-242: Tighten the empty-string assertion

-        $this->assertEquals('empty', (string) $range, $message.' - Empty range should have "empty" string representation');
+        $this->assertSame('empty', (string) $range, $message.' - Empty range should have "empty" string representation');

251-253: Prefer assertNotSame for string inequality

-        $this->assertNotEquals('empty', (string) $range, $message.' - Non-empty range should not have "empty" string representation');
+        $this->assertNotSame('empty', (string) $range, $message.' - Non-empty range should not have "empty" string representation');

264-268: Boundary tests: use assertSame for boolean equality

-            $this->assertEquals(
+            $this->assertSame(
                 $testCase['expected'],
                 $range->contains($testCase['value']),
                 $message.' - Boundary test failed: '.$description
             );

public function has_name(): void
{
self::assertEquals('test_network_array', $this->fixture->getName());
$this->assertEquals('test_network_array', $this->fixture->getName());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Switch to instance assertions is good; prefer strict comparison here.

The move from static to instance assertions aligns with modern PHPUnit usage. Since you're comparing strings, assertSame is a better fit to avoid any implicit type juggling.

Apply this diff:

-        $this->assertEquals('test_network_array', $this->fixture->getName());
+        $this->assertSame('test_network_array', $this->fixture->getName());

Run a quick repo-wide check to ensure remaining legacy styles are gone:


🏁 Script executed:

#!/bin/bash
# 1) Find legacy test_* methods that should be attribute-annotated instead
rg -nP --type=php -g 'tests/**' $'public\\s+function\\s+test\\w*\\s*\\('

# 2) Find static assertion calls (prefer $this->assert*)
rg -nP --type=php -g 'tests/**' $'\\b(self|static)::assert[A-Z]\\w*\\s*\\('

Length of output: 730


Prefer strict comparison and update remaining static assertions

Switching from assertEquals to assertSame here is spot on to enforce strict type- and value-comparison:

-        $this->assertEquals('test_network_array', $this->fixture->getName());
+        $this->assertSame('test_network_array', $this->fixture->getName());

In addition, the repo-wide check revealed legacy static assertion calls in integration tests. For consistency and to align with modern PHPUnit practices, please replace these with instance assertions ($this->assert…) as well:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php:

    • static::assertSame('2000-12-05', $result[0]['result']);
    • static::assertSame('2005-01-01', $result[0]['result']);
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php:

    • self::assertArrayNotHasKey('nonexistent', $decoded);
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php:

    • self::assertArrayNotHasKey('invalid', $decoded);

Updating these to $this->assertSame(…) and $this->assertArrayNotHasKey(…) will ensure all tests consistently use instance-based assertions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$this->assertEquals('test_network_array', $this->fixture->getName());
$this->assertSame('test_network_array', $this->fixture->getName());
🤖 Prompt for AI Agents
In tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/BaseNetworkTypeArrayTest.php
around line 55, replace assertEquals with a strict assertion by changing
$this->assertEquals('test_network_array', $this->fixture->getName()); to use
$this->assertSame(...) so both value and type are enforced; additionally update
the listed integration tests to use instance assertions instead of static calls:
change static::assertSame(...) and self::assertSame(...) to
$this->assertSame(...), and change self::assertArrayNotHasKey(...) to
$this->assertArrayNotHasKey(...) in the three specified files/lines so all
assertions use instance-based PHPUnit methods consistently.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (12)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)

19-30: Harden JSON decoding to fail fast on invalid JSON

Using JSON_THROW_ON_ERROR makes failures deterministic and easier to diagnose if the DB ever returns malformed JSON.

Apply this minimal change:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, JSON_THROW_ON_ERROR);

No try/catch is needed in a test—an exception will correctly fail the test.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (2)

19-21: Reduce duplication by consolidating the three nearly-identical tests via a DataProvider

All three tests differ only by the field name. A single parameterized test improves maintainability and keeps intent clear.

Example (keeps assertions identical):

use PHPUnit\Framework\Attributes\DataProvider;

#[Test]
#[DataProvider('arrayFieldProvider')]
public function can_get_array_dimensions(string $field, string $expected): void
{
    $dql = \sprintf(
        "SELECT ARRAY_DIMENSIONS(t.%s) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsArrays t WHERE t.id = 1",
        $field
    );

    $result = $this->executeDqlQuery($dql);
    $this->assertSame($expected, $result[0]['result']);
}

public static function arrayFieldProvider(): array
{
    return [
        'text'    => ['textArray',    '[1:3]'],
        'integer' => ['integerArray', '[1:3]'],
        'boolean' => ['boolArray',    '[1:3]'],
    ];
}

8-8: PHPUnit 10+ Verified & No Legacy test_… Methods Detected

Composer’s dev constraint pins phpunit/phpunit to ^10.5.53, so the #[Test] attribute is fully supported. A repository-wide ripgrep scan found no remaining function test_* methods under tests/, confirming test discovery will continue to work as expected.

All set to merge—attribute-based tests are correctly adopted.

Optional enhancement for clearer coverage mapping:

  • File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • Add a #[CoversClass(ArrayDimensions::class)] attribute at the class level
 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayDimensions;
 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;

- class ArrayDimensionsTest extends ArrayTestCase
+ #[CoversClass(ArrayDimensions::class)]
+ class ArrayDimensionsTest extends ArrayTestCase
 {
     // …
 }
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (1)

19-50: Optional: collapse the three cases via a DataProvider to reduce duplication

This would keep intent while de-duplicating DQL construction and assertions.

Example refactor:

@@
-use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\DataProvider;
@@
-    #[Test]
-    public function returns_true_when_text_element_exists_in_array(): void
-    {
-        $dql = 'SELECT IN_ARRAY(:value, t.textArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql, ['value' => 'banana']);
-        $this->assertTrue($result[0]['result']);
-    }
-
-    #[Test]
-    public function returns_true_when_integer_element_exists_in_array(): void
-    {
-        $dql = 'SELECT IN_ARRAY(:value, t.integerArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql, ['value' => 2]);
-        $this->assertTrue($result[0]['result']);
-    }
-
-    #[Test]
-    public function returns_false_for_non_existing_element(): void
-    {
-        $dql = 'SELECT IN_ARRAY(:value, t.textArray) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
-                WHERE t.id = 1';
-
-        $result = $this->executeDqlQuery($dql, ['value' => 'mango']);
-        $this->assertFalse($result[0]['result']);
-    }
+    public static function provideInArrayCases(): array
+    {
+        return [
+            'text hit'     => ['textArray',    1, 'banana', true],
+            'integer hit'  => ['integerArray', 1, 2,        true],
+            'text miss'    => ['textArray',    1, 'mango',  false],
+        ];
+    }
+
+    #[Test]
+    #[DataProvider('provideInArrayCases')]
+    public function in_array_behaves_as_expected(string $field, int $id, mixed $value, bool $expected): void
+    {
+        $dql = \sprintf(
+            'SELECT IN_ARRAY(:value, t.%s) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t WHERE t.id = %d',
+            $field,
+            $id
+        );
+        $result = $this->executeDqlQuery($dql, ['value' => $value]);
+        $this->assertSame($expected, $result[0]['result']);
+    }
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3)

19-30: Type-safety nit: assert the array contains only ints

To guard against driver/transformer differences that might coerce positions to strings, assert the element types as well.

-        $this->assertIsArray($actual);
+        $this->assertIsArray($actual);
+        $this->assertContainsOnly('int', $actual);
         $this->assertSame([3], $actual);

32-43: Same type-safety nit for integer positions

Mirror the element-type assertion here for consistency.

-        $this->assertIsArray($actual);
+        $this->assertIsArray($actual);
+        $this->assertContainsOnly('int', $actual);
         $this->assertSame([2], $actual);

45-56: Add coverage for multiple matches (array_positions returns all indices)

Current test validates a single match. Given row 3 has boolArray = [true, true, false, true], adding a test for multiple matches will harden against regressions and better exercise ARRAY_POSITIONS.

Inline nit for this test:

-        $this->assertIsArray($actual);
+        $this->assertIsArray($actual);
+        $this->assertContainsOnly('int', $actual);
         $this->assertSame([2], $actual);

Additional test to cover multiple matches (can be placed after this method):

#[Test]
public function returns_positions_when_multiple_boolean_elements_are_found(): void
{
    $dql = 'SELECT ARRAY_POSITIONS(t.boolArray, :value) as result 
            FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsArrays t 
            WHERE t.id = 3';

    $result = $this->executeDqlQuery($dql, ['value' => true]);
    $actual = $this->transformPostgresArray($result[0]['result']);
    $this->assertIsArray($actual);
    $this->assertContainsOnly('int', $actual);
    $this->assertSame([1, 2, 4], $actual);
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (2)

19-43: Optional: reduce repetition via DataProvider

All five tests repeat the same DQL and only vary the fixture id and expected row count. Consider a parameterized test to DRY things up. This is optional and can be a follow-up to keep this PR tightly scoped.

Here’s a minimal refactor sketch:

 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\DataProvider;

@@
-    #[Test]
-    public function extracts_key_value_pairs_from_standard_json_object(): void
-    {
-        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
-                WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertCount(4, $result);
-        foreach ($result as $row) {
-            $this->assertIsArray($row);
-            $this->assertArrayHasKey('result', $row);
-            $this->assertIsString($row['result']);
-            $decoded = \json_decode($row['result'], true);
-            if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
-                $key = $decoded['key'];
-                $value = $decoded['value'];
-            } else {
-                $parts = \explode(':', \trim($row['result'], '{}"'));
-                $key = $parts[0] ?? null;
-                $value = $parts[1] ?? null;
-            }
-            $this->assertNotNull($key);
-        }
-    }
-
-    #[Test]
-    public function returns_empty_result_for_empty_object(): void
-    {
-        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
-                WHERE t.id = 4';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertCount(0, $result);
-    }
-
-    #[Test]
-    public function extracts_key_value_pairs_from_alternative_json_object(): void
-    {
-        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
-                WHERE t.id = 2';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertCount(4, $result);
-    }
-
-    #[Test]
-    public function extracts_key_value_pairs_when_json_contains_null_values(): void
-    {
-        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
-                WHERE t.id = 5';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertCount(4, $result);
-    }
-
-    #[Test]
-    public function extracts_key_value_pairs_when_json_contains_empty_array(): void
-    {
-        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
-                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
-                WHERE t.id = 3';
-        $result = $this->executeDqlQuery($dql);
-        $this->assertCount(4, $result);
-    }
+    public static function jsonbEachTextCases(): iterable
+    {
+        yield 'standard object (id=1)' => [1, 4, true];
+        yield 'empty object (id=4)' => [4, 0, false];
+        yield 'alternative object (id=2)' => [2, 4, false];
+        yield 'contains nulls (id=5)' => [5, 4, false];
+        yield 'contains empty array (id=3)' => [3, 4, false];
+    }
+
+    #[Test]
+    #[DataProvider('jsonbEachTextCases')]
+    public function extracts_key_value_pairs_parameterized(int $id, int $expectedCount, bool $validateKeys): void
+    {
+        $dql = 'SELECT JSONB_EACH_TEXT(t.object1) as result 
+                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
+                WHERE t.id = :id';
+        $result = $this->executeDqlQuery($dql, ['id' => $id]);
+        $this->assertCount($expectedCount, $result);
+
+        if ($validateKeys) {
+            foreach ($result as $row) {
+                $this->assertIsArray($row);
+                $this->assertArrayHasKey('result', $row);
+                $this->assertIsString($row['result']);
+                $decoded = \json_decode($row['result'], true);
+                if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
+                    $key = $decoded['key'];
+                } else {
+                    $parts = \explode(':', \trim($row['result'], '{}"'));
+                    $key = $parts[0] ?? null;
+                }
+                $this->assertNotNull($key);
+            }
+        }
+    }

Also applies to: 45-53, 55-63, 65-73, 75-83


8-8: Add explicit CoversClass attribute and mark test class final

  • Confirmed the PHPUnit version constraint is ^10.5.53 in composer.json, ensuring support for attribute-based annotations.
  • Verified there are no legacy test*-prefixed methods or @test annotations across the tests/ directory, so attribute usage is consistent.

Apply this enhancement in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbEachText;
 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;

- class JsonbEachTextTest extends JsonTestCase
+#[CoversClass(JsonbEachText::class)]
+final class JsonbEachTextTest extends JsonTestCase
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (3)

69-71: LGTM: mirrored negative-path test moved to attributes

Pattern matches the previous case; fine as-is. Optional: both negative cases could be consolidated via a DataProvider to reduce duplication, but that’s outside the migration scope.


9-11: Add a class-level #[CoversClass] attribute to JsonbInsertTest for clearer coverage mapping

Verified that the project is on PHP 8.1 and PHPUnit ^10.5.53 (which fully supports PHPUnit attributes), with no remaining legacy test_… methods detected. Adding the #[CoversClass] attribute is purely optional but will help coverage tools associate this test class directly with the JsonbInsert function.

• File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
• Lines: immediately before the class JsonbInsertTest declaration

Suggested diff:

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbInsert;
 use PHPUnit\Framework\Attributes\Test;
+use PHPUnit\Framework\Attributes\CoversClass;

+#[CoversClass(JsonbInsert::class)]
 class JsonbInsertTest extends JsonTestCase

56-58: Align JSONB_INSERT error tests with DriverException
The JSONB_INSERT integration tests currently use a generic Exception::class expectation for runtime PostgreSQL errors. However, in the same suite, other tests that trigger database‐reported errors (e.g. invalid date in ToDateTest, invalid cast in CastTest) consistently narrow their expectations to Doctrine\DBAL\Exception\DriverException::class. To maintain consistency and ensure you’re catching the specific DBAL driver wrapper (rather than any PHP exception), update the JSONB_INSERT tests accordingly.

• tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
– Line 59: change
diff - $this->expectException(Exception::class); + $this->expectException(DriverException::class);
– Line 72: change
diff - $this->expectException(Exception::class); + $this->expectException(DriverException::class);

Optionally, to guard against future DBAL wrapping changes, you can also assert the SQLSTATE code via:

$this->expectExceptionMessageMatches('/SQLSTATE\[\d{5}\]/');
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4b92c63 and 3dd6f98.

📒 Files selected for processing (11)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayLengthTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php
📚 Learning: 2025-05-03T00:18:09.078Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#366
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php:1-36
Timestamp: 2025-05-03T00:18:09.078Z
Learning: Always check the current official PostgreSQL documentation at https://www.postgresql.org/docs/ to verify function signatures and behaviors before suggesting improvements or additional tests. The `array_positions` function specifically has a fixed signature with exactly two parameters (array and search value), while `array_position` is variadic with 2-3 parameters.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php
🧬 Code graph analysis (7)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (4)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
  • Test (52-61)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (2)
  • Test (20-35)
  • Test (37-54)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensions.php (1)
  • ArrayDimensions (15-22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (1)
  • Test (19-43)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (6)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ContainsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (4)
  • Test (19-43)
  • Test (45-53)
  • Test (55-63)
  • Test (65-73)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (1)
  • Test (19-30)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-27)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArray.php (1)
  • InArray (15-23)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayTestCase.php (1)
  • ArrayTestCase (9-51)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositions.php (1)
  • ArrayPositions (15-23)
tests/Integration/MartinGeorgiev/TestCase.php (2)
  • executeDqlQuery (271-285)
  • transformPostgresArray (255-264)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)
  • Test (19-28)
  • Test (30-39)
  • Test (41-50)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionTest.php (4)
  • Test (19-29)
  • Test (31-41)
  • Test (43-53)
  • Test (55-64)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (1)
  • Test (19-43)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (4)
  • Test (20-35)
  • Test (37-54)
  • Test (56-67)
  • Test (69-82)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.3
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.3
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.2
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: sloth
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2)

21-27: LGTM: Test logic preserved correctly

The test implementation remains functionally unchanged, maintaining the same DQL query and assertion logic. This ensures that the migration to attributes doesn't affect the actual test behavior.


1-28: All legacy test_* methods have been migrated
A search for remaining public function test_* methods in tests/Integration returned zero matches, and 105 out of 114 PHP files already use the #[Test] attribute. It appears there are no legacy test methods left to convert.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectAggTest.php (2)

19-20: Renamed method with #[Test] — aligned with the suite’s new style

Descriptive name + attribute-based discovery reads well and matches neighboring tests.


8-8: Attribute-based tests fully supported

Composer requires PHPUnit ^10.5.53, which natively supports the #[Test] attribute (see composer.json line 55). No phpunit.xml/phpunit.xml.dist files were found to override method-name discovery, so PHPUnit’s default behavior applies. All test classes—including JsonbObjectAggTest.php—import PHPUnit\Framework\Attributes\Test, and our grep shows zero legacy test_-prefixed methods anywhere under tests/. These findings confirm attribute-based tests will run correctly. Changes approved.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayDimensionsTest.php (3)

14-16: LGTM on function registration array

Pure formatting improvement; mapping remains correct and matches the DQL function identifier used in the tests.


30-32: LGTM: migration to #[Test] and descriptive name

Method name is descriptive, retains return type, and the attribute enables discovery without the legacy prefix.


41-43: LGTM: migration to #[Test] and descriptive name

Consistent with the other methods; no logic change introduced.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/InArrayTest.php (5)

14-16: LGTM: function map formatting

Multi-line array with trailing comma is consistent and the key matches the DQL call IN_ARRAY(...).


19-20: LGTM: migrated to attribute-based test with descriptive name

Clear intent; no behavior change.


30-31: LGTM: integer-path test migrated to #[Test]

Naming and assertion remain correct; reads well.


41-42: LGTM: negative case migrated to #[Test]

Covers the non-existing element path; solid.


8-8: ✅ PHPUnit 10+ Attribute Discovery Confirmed

All checks passed — no further action required.

  • composer.json require-dev constraint is phpunit/phpunit ^10.5.53, which supports attribute-based test discovery.
  • No legacy function test…() methods remain in the tests/ directory.
  • The import use PHPUnit\Framework\Attributes\Test; is correct and #[Test] attributes are applied throughout.
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ArrayPositionsTest.php (3)

14-16: DQL function mapping for ARRAY_POSITIONS is correct

Registration matches the DQL usage below and the production function name. The multiline style is consistent and readable.


58-69: Correct empty-array expectation for “not found”

Validates the documented behavior of array_positions returning an empty array (not NULL) when no occurrences are found. Looks good.


8-8: ✅ No legacy test_ methods found; attribute-based migration complete

  • A sweep of the tests directory shows zero occurrences of legacy function test_… methods.
  • Attribute usage (#[Test]) is confirmed across all test files, including the targeted ArrayPositionsTest.php.

All tests have been successfully migrated to attribute-based discovery. Approving these code changes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (5)

19-43: LGTM: migrated to attribute and descriptive name

Method is now discoverable via #[Test]; semantics unchanged. Name clearly describes behavior.


45-53: LGTM: attribute-based discovery + clearer intent

Reads cleanly; no logic changes beyond the rename and attribute addition.


55-63: LGTM: consistent with suite-wide migration

Naming and attribute usage match the surrounding tests and other files in the suite.


65-73: LGTM: migration-only change

No functional changes; attribute adoption is correct.


75-83: LGTM: attribute applied; name conveys scenario well

Consistent with the rest of the PR’s modernization work.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (2)

20-22: LGTM: migrated test uses #[Test] and descriptive name

Clear scenario name and unchanged assertions; this aligns with the attribute-based discovery used elsewhere in the suite.


37-39: LGTM: second positive path migrated cleanly

The attribute and method rename are consistent with other integration tests; assertions remain precise.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (8)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php (1)

19-25: Unify DQL string quoting/backslashes for consistency.

Minor nit: the first DQL uses single quotes with single backslashes (line 22), while the second uses double quotes with escaped backslashes (line 30). Consider aligning both. Example aligning line 22 with the style used on line 30:

-        $dql = 'SELECT TSTZRANGE(t.datetimetz1, t.datetimetz2) as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsDates t WHERE t.id = 1';
+        $dql = "SELECT TSTZRANGE(t.datetimetz1, t.datetimetz2) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsDates t WHERE t.id = 1";
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (2)

59-67: Stabilize the very large numeric assertion to avoid float precision brittleness

At ~8.6e20 magnitude, double precision ULP is on the order of 1e5. If DBAL returns a float, comparing with a fixed absolute delta of 0.0001 is brittle: either the values are bitwise-equal (delta 0) or the first differing value will exceed the delta by orders of magnitude. If DBAL returns a string for NUMERIC, coercion to float during the assertion reintroduces this risk.

Suggestion: assert string equality when the driver returns strings; otherwise, scale the delta relative to magnitude.

Apply this diff to make the assertion robust:

-        $this->assertEqualsWithDelta(859766721136081107225.6, $result[0]['result'], 0.0001);
+        $expected = 859766721136081107225.6;
+        $actual = $result[0]['result'];
+        if (\is_float($actual)) {
+            // At ~8.6e20, double precision ULP is ~1.9e5; allow a scaled delta to avoid false negatives.
+            $this->assertEqualsWithDelta($expected, $actual, \max(0.0001, \abs($expected) * 1e-15));
+        } else {
+            // If DBAL returns NUMERIC as string for high-precision values, assert exact match.
+            $this->assertSame((string) $expected, (string) $actual);
+        }

Please confirm which type Doctrine DBAL returns for this expression in your CI matrix (float vs string). If it varies by PHP/driver versions, the above change will keep the test stable across environments.


8-8: Verification complete: PHPUnit attribute import is correct; optional CoversClass attribute can be added

  • composer.json requires PHP ^8.1 and dev-dependency phpunit/phpunit ^10.5.53, so attribute-based tests are fully supported.
  • No legacy test_* methods found; suite uses attribute tests exclusively (601 vs 0), confirming consistent adoption.
  • No configuration in phpunit.xml is needed to enable attributes.

You may optionally add #[CoversClass] to improve coverage attribution:

File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
Around the class declaration (after existing imports):

 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Power;
+use PHPUnit\Framework\Attributes\CoversClass;
 use PHPUnit\Framework\Attributes\Test;

- class PowerTest extends NumericTestCase
+ #[CoversClass(Power::class)]
+ class PowerTest extends NumericTestCase
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (2)

19-34: Migration to #[Test] with descriptive name looks correct. Optional: make JSON decoding fail-fast.

The test reads clean and mirrors the existing JsonbSetTest style. Consider decoding with JSON_THROW_ON_ERROR to surface invalid JSON immediately and reduce follow-up noise in assertions.

Example change within this method body:

-        $decoded = \json_decode($result[0]['result'], true);
+        $decoded = \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);

Optionally, you could add a tiny helper in this class to DRY the decode step for all methods:

private function decodeResultArray(array $result): array
{
    $this->assertIsString($result[0]['result']);
    return \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);
}

72-86: Strengthen the “invalid path” case by asserting no-op behavior end-to-end.

Right now we assert that top-level key 'invalid' isn’t created. To fully capture LAX “no change” semantics, consider comparing the whole JSON with a baseline select of t.object1 for the same row.

Minimal augmentation inside this method:

         $result = $this->executeDqlQuery($dql, [
             'path' => '{invalid,path}',
             'value' => '"value"',
         ]);
-        $this->assertIsString($result[0]['result']);
-        $decoded = \json_decode($result[0]['result'], true);
+        $this->assertIsString($result[0]['result']);
+        $decoded = \json_decode($result[0]['result'], true, 512, \JSON_THROW_ON_ERROR);
         $this->assertIsArray($decoded);
         $this->assertArrayNotHasKey('invalid', $decoded);
+
+        // Optional stronger assertion: result equals original when path is invalid
+        $baseline = $this->executeDqlQuery(
+            'SELECT t.object1 as result FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t WHERE t.id = 1'
+        );
+        $this->assertIsString($baseline[0]['result']);
+        $this->assertSame(
+            $baseline[0]['result'],
+            $result[0]['result'],
+            'JSONB_SET_LAX should be a no-op for invalid path'
+        );
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (2)

19-34: Optional: DRY up JSON decode + shape assertions

The pattern “assertIsString → json_decode → assertIsArray → key/value assertions” repeats across tests. Consider extracting a small helper in JsonTestCase (e.g., decodeJsonResult(array $row): array and assertJsonHasKeys(array $decoded, array $keys): void) to reduce duplication and tighten failure messages.

// Example helper sketch in JsonTestCase
protected function decodeJsonResult(array $row): array
{
    $this->assertIsString($row['result']);
    $decoded = \json_decode($row['result'], true);
    $this->assertIsArray($decoded);
    return $decoded;
}

72-86: Nit: consider unquoted boolean for create_missing

Minor: In the DQL, create_missing is currently passed as the string literal 'false'. Postgres booleans are typically unquoted (false). Not blocking, but consider using an unquoted boolean or a bound parameter to avoid implicit casts.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (1)

21-27: Prefer ::class over hard-coded FQCN in DQL strings

Using the class constant for the fixture entity improves refactor-safety and static analysis, and keeps the file consistent with the Unit test variant that already uses ContainsTexts::class. Below patch imports the entity and updates all DQL strings in this method (and the rest of the file for consistency).

@@
 use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToDate;
+use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsTexts;
 use PHPUnit\Framework\Attributes\Test;
@@
-        $dql = "SELECT TO_DATE('05 Dec 2000', 'DD Mon YYYY') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = \sprintf("SELECT TO_DATE('05 Dec 2000', 'DD Mon YYYY') as result FROM %s t WHERE t.id = 1", ContainsTexts::class);

If you agree, apply similar edits to Lines 33, 40, 49, and 57:

-        $dql = "SELECT TO_DATE('invalid_date', 'DD Mon YYYY') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = \sprintf("SELECT TO_DATE('invalid_date', 'DD Mon YYYY') as result FROM %s t WHERE t.id = 1", ContainsTexts::class);

-        $dql = "SELECT TO_DATE('05 Dec 2000', 'invalid_format') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = \sprintf("SELECT TO_DATE('05 Dec 2000', 'invalid_format') as result FROM %s t WHERE t.id = 1", ContainsTexts::class);

-        $dql = "SELECT TO_DATE('05 Dec 2000', 1) as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = \sprintf("SELECT TO_DATE('05 Dec 2000', 1) as result FROM %s t WHERE t.id = 1", ContainsTexts::class);

-        $dql = "SELECT TO_DATE(null, 'DD Mon YYYY') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $dql = \sprintf("SELECT TO_DATE(null, 'DD Mon YYYY') as result FROM %s t WHERE t.id = 1", ContainsTexts::class);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3dd6f98 and 7ba442d.

📒 Files selected for processing (12)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectAggTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (4 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (6 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (5 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (1 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsrangeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectAggTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php
📚 Learning: 2025-03-11T12:32:10.726Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#263
File: src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Numrange.php:19-21
Timestamp: 2025-03-11T12:32:10.726Z
Learning: In the postgresql-for-doctrine repository, PostgreSQL range functions have distinct implementations for different data types. The `Numrange` function works with numeric/decimal values and is tested using the `ContainsDecimals` fixture with properties typed as `float`. In contrast, the `Int4range` function works with 32-bit integers and is tested using the `ContainsIntegers` fixture with properties typed as `int`. While the PHP implementations share a similar structure (extending `BaseFunction`), they are semantically different as they handle different PostgreSQL data types.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php
📚 Learning: 2025-04-11T11:23:44.192Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#340
File: tests/MartinGeorgiev/Doctrine/DBAL/Types/InetArrayTest.php:145-145
Timestamp: 2025-04-11T11:23:44.192Z
Learning: In the PostgreSQL for Doctrine test cases, methods that test database-to-PHP conversions should use `mixed` type for parameter and include non-string test cases in their data providers, following the pattern in classes like InetTest, CidrTest, and MacaddrTest.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
🧬 Code graph analysis (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NumrangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TsrangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DaterangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/Int8rangeTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-36)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-36)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (4)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (2)
  • ToDateTest (12-43)
  • getStringFunctions (14-19)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDate.php (1)
  • ToDate (13-21)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (5)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-36)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (4)
  • Test (19-34)
  • Test (36-51)
  • Test (53-70)
  • Test (72-86)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php (2)
  • Test (19-25)
  • Test (27-33)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RoundTest.php (5)
  • Test (19-27)
  • Test (29-37)
  • Test (39-50)
  • Test (52-63)
  • Test (65-73)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM 2.18 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.18 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM latest + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM latest + Doctrine Lexer 2.1
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (24)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TstzrangeTest.php (4)

8-8: Good move: import PHPUnit attribute class.

The use PHPUnit\Framework\Attributes\Test; import is correct and aligns with the migration to attribute-based tests.


19-21: Attribute-based test + descriptive name: looks good.

Clear, behavior-focused name and proper #[Test] usage. Matches naming in sibling tests (e.g., Tsrange/Numrange).


27-29: Second test migration also looks correct.

Consistent naming and attribute usage; assertions reflect custom bounds.


19-34: ✅ PHPUnit 10+ requirement met and no legacy test methods found

  • composer.json specifies phpunit/phpunit at ^10.5.53, which includes the #[Test] attribute support.
  • Ripgrep scan of tests/ returned no function test*() methods relying on name-based discovery.

No further changes needed here.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/PowerTest.php (4)

19-27: LGTM: integer exponent scenario ported cleanly to #[Test]

Naming is clearer and the assertion is unchanged. No issues.


29-37: LGTM: fractional exponent with delta remains precise and readable

Appropriate use of assertEqualsWithDelta for a non-integer result.


39-47: LGTM: negative base handled with explicit parentheses

Good call on parentheses around the negative base to avoid parsing pitfalls.


49-57: LGTM: negative exponent case is correct and stable

Clear expectation and a sensible delta.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (4)

36-51: Attribute + rename reads well and mirrors the non-LAX variant.

Consistent with JsonbSetTest::can_add_new_value() and the project-wide pattern. No functional concerns.


53-70: LGTM: nested path scenario is clearly asserted.

Good coverage of nested key presence and value equality. Matches the existing tests for the non-LAX function.


85-85: Assertion style switch to instance method is fine.

Using $this->assertArrayNotHasKey (vs static) keeps assertion style consistent with the rest of the file and modern PHPUnit guidance.


8-8: Attribute-based test migration verified

All necessary runtime support is in place and no legacy PHPUnit discovery patterns remain:

  • composer.json requires phpunit/phpunit ^10.5.53 (attribute support) and php ^8.1, satisfying PHPUnit 10’s attribute-based testing requirements.
  • 601 occurrences of the #[Test] attribute across the tests directory, confirming widespread adoption of attribute-based discovery.
  • No remaining legacy function test_* methods found.
  • No @test docblock annotations detected.

The codebase is now fully aligned with attribute-based test discovery—approving these changes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (6)

8-8: Adopts #[Test] attribute import correctly

Importing PHPUnit\Framework\Attributes\Test is correct for attribute-based discovery. No extra imports required.


19-21: Clear, behavior-focused test name with #[Test] — good migration

Switch from test_ prefix to a descriptive name plus attribute is aligned with modern PHPUnit practices.


36-38: Consistent naming and attribute usage

The updated name reads well and mirrors the JsonbSetLaxTest counterpart.


53-55: Good coverage for nested path scenario

Attribute-based test with explicit nested path casing looks good.


72-74: Accurate intent expressed in name; attribute added

Test name precisely describes the create_missing=false behavior.


85-85: Instance assertion aligns with project-wide style

Switching to $this->assertArrayNotHasKey improves consistency with other updated tests in this PR.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php (6)

10-10: Adopting PHPUnit #[Test] attribute — LGTM

Importing PHPUnit\Framework\Attributes\Test aligns with the PR objective and the rest of the suite’s migration.


16-18: Use of uppercase DQL function key 'TO_DATE' is correct

Matches the convention used elsewhere (Unit tests) and still compiles to lower-case SQL via the function prototype in ToDate. No issues spotted.


29-35: Invalid input should bubble up as DriverException — LGTM

Expecting Doctrine DBAL’s DriverException for server-side parsing failure is appropriate here for an Integration test.


45-51: Type safety for format argument — LGTM

Expecting QueryException when a non-string (int) is provided for the format aligns with the AST node mappings (StringPrimary).


53-59: Null input parsing — LGTM

Expecting QueryException for a null first argument is consistent with the function’s declared node mappings. Using 'null' in DQL is fine (case-insensitive).


37-43: Verify TO_DATE fallback for invalid format across PostgreSQL versions

Please confirm that SELECT TO_DATE('05 Dec 2000', 'invalid_format') indeed returns '2005-01-01' on each of our supported PostgreSQL versions (9.6, 10, 11, 12, 13, 14, 15, 16, 17). If any version differs, update the test or add a brief comment explaining the discrepancy and linking to the relevant PostgreSQL behavior.

You can reproduce the behavior with psql (or any SQL client):

SELECT TO_DATE('05 Dec 2000', 'invalid_format');

Locations to adjust or document:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ToDateTest.php
    • returns_default_date_for_invalid_format (around lines 38–42)

If all versions return '2005-01-01' consistently, consider adding above the test:

// PostgreSQL defaults missing fields to MM=01, DD=01 and, for an entirely non-matching mask,
// uses a fixed fallback of '2005-01-01' (confirmed on PG 9.6–17).

namespace Tests\Integration\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbSet;
use PHPUnit\Framework\Attributes\Test;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify PHPUnit version supports attributes

Ensure composer requires a PHPUnit version that supports #[Test] (PHPUnit 10+). Run this to confirm:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
if command -v jq >/dev/null 2>&1; then
  echo "composer.json → phpunit/phpunit constraints (require / require-dev):"
  jq -r '.require["phpunit/phpunit"], .require-dev["phpunit/phpunit"]' composer.json 2>/dev/null | sed '/null/d' || true
else
  echo "composer.json → phpunit/phpunit constraints (grep):"
  rg -nP '"phpunit/phpunit"\s*:\s*"[^\"]+"' composer.json -n -C0 || true
fi

Length of output: 288


Add PHPUnit 10+ as a dev dependency for attribute-based tests

Verification shows that composer.json does not list phpunit/phpunit in either require or require-dev (jq output was empty), so the new #[Test] attributes won’t be recognized. Please add PHPUnit 10+ to your dev dependencies.

• File to update: composer.json
• Section: require-dev

Suggested diff:

--- a/composer.json
+++ b/composer.json
@@ -## require-dev ##
-    // existing dev dependencies
+    "phpunit/phpunit": "^10.0",
     // other dev dependencies…

After applying, run:

composer update phpunit/phpunit
🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
around line 8 the test uses the #[Test] attribute but composer.json does not
declare phpunit/phpunit so attributes from PHPUnit 10+ won't be recognized; open
composer.json and add phpunit/phpunit (e.g. "phpunit/phpunit": "^10.0") under
require-dev, save the file, then run composer update phpunit/phpunit to
install/update the dependency.

@martin-georgiev martin-georgiev changed the title chore: migrate tests away from test_ prefixed method names to modern use of PHP attributes chore: unify the tests style (use PHP attributes, descriptive method names, instance-style assertion calls, detailed assertions and custom failure messages) Aug 26, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)

50-52: Refactor all lingering object1 references to jsonbObject1 in tests

The entity field object1 was renamed to jsonbObject1, but numerous tests across the suite still reference the old name. Update these to ensure Doctrine resolves the correct field and your custom exception paths are exercised.

Apply the following in tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (and similarly at lines 60–62 and 70–72):

-        $dql = \sprintf("SELECT JSONB_SET(e.object1, '{country}', '{\"iso_3166_a3_code\":\"bgr\"}', 'invalid') FROM %s e", ContainsJsons::class);
+        $dql = \sprintf("SELECT JSONB_SET(e.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"bgr\"}', 'invalid') FROM %s e", ContainsJsons::class);

-        $dql = \sprintf('SELECT JSONB_SET(e.object1) FROM %s e', ContainsJsons::class);
+        $dql = \sprintf('SELECT JSONB_SET(e.jsonbObject1) FROM %s e', ContainsJsons::class);

-        $dql = \sprintf("SELECT JSONB_SET(e.object1, '{country}', '{\"iso_3166_a3_code\":\"bgr\"}', 'true', 'extra_arg') FROM %s e", ContainsJsons::class);
+        $dql = \sprintf("SELECT JSONB_SET(e.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"bgr\"}', 'true', 'extra_arg') FROM %s e", ContainsJsons::class);

Additionally, update all occurrences of the old field in tests under tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions:

  • Replace c0_.object1c0_.jsonbObject1 in raw SQL snippets.
  • Replace e.object1e.jsonbObject1 in DQL sprintf calls.
  • This applies across: JsonScalarTest, JsonbSetLaxTest, JsonbPathQueryFirstTest, JsonbPathQueryTest, JsonbStripNullsTest, JsonbPathMatchTest, JsonbPathQueryArrayTest, JsonbInsertTest, JsonbExistsTest, TheRightExistsOnTheLeftTest, RowTest, ReturnsValueForJsonValueTest, JsonbPathExistsTest, JsonbArrayElementsTextTest, JsonbBuildObjectTest, JsonbArrayElementsTest, JsonTypeofTest, JsonValueTest, JsonbArrayLengthTest, JsonQueryTest, JsonObjectKeysTest, JsonGetObjectTest, JsonStripNullsTest, JsonGetObjectAsTextTest, JsonSerializeTest, JsonGetFieldAsTextTest, JsonGetFieldTest, JsonGetFieldAsIntegerTest, JsonbEachTextTest, JsonEachTextTest, JsonEachTest, JsonArrayLengthTest, JsonBuildObjectTest, DeleteAtPathTest, AnyOnTheRightExistsOnTheLeftTest, AllOnTheRightExistOnTheLeftTest, JsonExistsTest.

— Ensure each test fixture and its negative-path assertions now reference the renamed property so that Doctrine’s field resolution and your custom exception logic are correctly invoked.

🧹 Nitpick comments (25)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (1)

19-25: Solid migration to attributes and clear scenarios; consider adding concise failure messages for quicker diagnostics.

The assertions are correct and the positions (11, 0, 9, 6, 0) align with the TextTestCase fixtures. To better align with the PR objective of “detailed assertions and custom failure messages,” add short messages to each assertion to make failures self-explanatory in CI logs.

Apply messages like below:

-        $this->assertSame(11, $result[0]['result']);
+        $this->assertSame(11, $result[0]['result'], 'REGEXP_INSTR(text1, "test") should start at 11 for id=1');

-        $this->assertSame(0, $result[0]['result']);
+        $this->assertSame(0, $result[0]['result'], 'REGEXP_INSTR(text1, "nonexistent") should return 0 (no match)');

-        $this->assertSame(9, $result[0]['result']);
+        $this->assertSame(9, $result[0]['result'], 'REGEXP_INSTR(text2, "test") should start at 9 for id=1');

-        $this->assertSame(6, $result[0]['result']);
+        $this->assertSame(6, $result[0]['result'], 'REGEXP_INSTR(text1, "\\bis\\b") should start at 6 for id=1');

-        $this->assertSame(0, $result[0]['result']);
+        $this->assertSame(0, $result[0]['result'], 'REGEXP_INSTR(text1, "TEST") should be 0 (case-sensitive mismatch)');

Also applies to: 27-33, 35-41, 43-49, 51-57

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (2)

35-41: Method name contradicts the expectation; rename for accuracy and consistency.

This test asserts False (correct), but the method name says “returns_true_when_pattern_does_not_match_with_case_insensitive.” Since IREGEXP is case-insensitive, NOT_IREGEXP should be False for 'TEST.*STRING'. Rename the method to reflect the expected outcome.

-    public function returns_true_when_pattern_does_not_match_with_case_insensitive(): void
+    public function returns_false_when_pattern_matches_with_case_insensitive(): void

19-25: Add type assertions and descriptive failure messages to NotIRegexpTest

To improve consistency with IRegexpTest (and make failures easier to diagnose without inspecting DB logs), each boolean result should first be asserted as a bool, and each true/false assertion should include a brief message explaining the expected behavior.

Locations to update (all in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php):

  • Lines 19–25 (returns_true_when_pattern_does_not_match_text_field)
  • Lines 27–33 (returns_false_when_pattern_matches_text_field)
  • Lines 35–41 (returns_false_for_case_insensitive_match_on_text_field)
  • Lines 43–49 (returns_true_when_pattern_does_not_match_other_field)
  • Lines 51–57 (returns_false_when_pattern_matches_other_field)

Proposed diff for each method:

-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue(
+            $result[0]['result'],
+            'NOT_IREGEXP should be true when pattern does not match t.text1'
+        );

-        $result = $this->executeDqlQuery($dql);
-        $this->assertFalse($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse(
+            $result[0]['result'],
+            'NOT_IREGEXP should be false when pattern matches t.text1'
+        );

-        $result = $this->executeDqlQuery($dql);
-        $this->assertFalse($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse(
+            $result[0]['result'],
+            'NOT_IREGEXP should be false for case-insensitive match on t.text1'
+        );

-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue(
+            $result[0]['result'],
+            'NOT_IREGEXP should be true when pattern does not match t.text2'
+        );

-        $result = $this->executeDqlQuery($dql);
-        $this->assertFalse($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse(
+            $result[0]['result'],
+            'NOT_IREGEXP should be false when pattern matches t.text2'
+        );

Repository-wide checks confirm there are no remaining self::assert… calls and all tests use attribute-based discovery, so this change will align NotIRegexpTest with the existing style.

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

19-26: Nice: Attribute migration + explicit boolean type checks.

Tests read clearly and assert types before values. This aligns well with the PR’s goals. As a tiny enhancement, consider brief failure messages for faster triage in CI.

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'IREGEXP should be true for "test.*string" on t.text1')

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'IREGEXP should be true for case-insensitive "TEST.*STRING" on t.text1')

-        $this->assertFalse($result[0]['result']);
+        $this->assertFalse($result[0]['result'], 'IREGEXP should be false for non-matching "nonexistent.*pattern" on t.text1')

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'IREGEXP should be true for "another.*string" on t.text2')

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'IREGEXP should be true for word boundary "\\bis\\b" on t.text1')

Also applies to: 28-35, 37-44, 46-53, 55-62

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php (1)

19-26: Add boolean type checks and brief messages for parity with IRegexpTest and PR style goals.

Assertions are correct; adding assertIsBool and succinct messages improves failure clarity and keeps style consistent across REGEXP_* tests.

-        $this->assertTrue($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'REGEXP_LIKE should be true for "test.*string" on t.text1')

-        $this->assertFalse($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse($result[0]['result'], 'REGEXP_LIKE should be false for non-matching "nonexistent.*pattern" on t.text1')

-        $this->assertTrue($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'REGEXP_LIKE should be true for "another.*string" on t.text2')

-        $this->assertTrue($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'REGEXP_LIKE should be true for word boundary "\\bis\\b" on t.text1')

-        $this->assertFalse($result[0]['result']);
+        $this->assertIsBool($result[0]['result']);
+        $this->assertFalse($result[0]['result'], 'REGEXP_LIKE should be false for case-sensitive "TEST.*STRING" on t.text1')

Also applies to: 27-33, 35-41, 43-49, 51-57

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (5)

19-25: Strengthen assertion ergonomics: check row count and add custom failure message

To match the PR objective (“detailed assertions and custom failure messages”) and to guard against empty results, consider asserting the cardinality and adding a message.

Apply:

-        $this->assertSame('this is a replaced string', $result[0]['result']);
+        $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
+        $this->assertSame(
+            'this is a replaced string',
+            $result[0]['result'],
+            'REGEXP_REPLACE should replace a single occurrence of "test" with "replaced" in text1 (case-sensitive, no flags).'
+        );

27-33: Great coverage of the global flag; add message and a safety check

Expected output is correct for global replacement of “is”. Add count check and a descriptive failure message for consistency with the PR goals.

-        $this->assertSame('thwas was a test string', $result[0]['result']);
+        $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
+        $this->assertSame(
+            'thwas was a test string',
+            $result[0]['result'],
+            'REGEXP_REPLACE with flag "g" should replace all occurrences of "is" with "was" in text1.'
+        );

35-41: No-match path covered; add message and cardinality assertion

Solid negative test. Enhance diagnostics and guard against empty results.

-        $this->assertSame('this is a test string', $result[0]['result']);
+        $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
+        $this->assertSame(
+            'this is a test string',
+            $result[0]['result'],
+            'REGEXP_REPLACE with a non-matching pattern should leave text1 unchanged.'
+        );

43-49: Second field path tested; add message and a result-count assertion

Nice to see coverage for text2 as well. Suggest adding richer assertions per PR style unification.

-        $this->assertSame('another replaced string', $result[0]['result']);
+        $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
+        $this->assertSame(
+            'another replaced string',
+            $result[0]['result'],
+            'REGEXP_REPLACE should replace a single occurrence of "test" with "replaced" in text2.'
+        );

51-56: Case sensitivity default validated; consider adding a companion test for case-insensitive flag

The unchanged result confirms default case-sensitive behavior. For completeness of DQL-to-SQL flag propagation, consider adding an explicit case-insensitive variant using 'i' (and optionally 'gi'). Also add a custom failure message here.

-        $this->assertSame('this is a test string', $result[0]['result']);
+        $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
+        $this->assertSame(
+            'this is a test string',
+            $result[0]['result'],
+            'Without the "i" flag, "TEST" should not match lowercase "test" in text1.'
+        );

Optional new test to exercise the 'i' flag:

#[Test]
public function replaces_case_insensitively_with_i_flag(): void
{
    $dql = "SELECT REGEXP_REPLACE(t.text1, 'TEST', 'replaced', 'i') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
    $result = $this->executeDqlQuery($dql);
    $this->assertCount(1, $result, 'Expected exactly one row for id=1 in containstexts.');
    $this->assertSame(
        'this is a replaced string',
        $result[0]['result'],
        'With the "i" flag, "TEST" should match and be replaced in text1.'
    );
}
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (3)

35-41: Solid negative case—add type/count assertions and messages to match PR goals

Maintain style consistency with explicit type and count checks plus a clear failure message.

Apply:

-        $result = $this->executeDqlQuery($dql);
-        $this->assertFalse($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertCount(1, $result, 'Expected a single row for id=1.');
+        $this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
+        $this->assertFalse($result[0]['result'], 'Expected false when pattern does not occur in text1.');

51-57: Partial match test is appropriate—tighten assertions and messages

This effectively validates ILIKE + wildcards. Add type/count checks and explicit failure context.

Apply:

-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertCount(1, $result, 'Expected a single row for id=1.');
+        $this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
+        $this->assertTrue($result[0]['result'], "Expected true for pattern '%test%' against text1.");

19-57: Reduce duplication and improve readability across tests

There’s repeated boilerplate for the DQL and assertions. Consider a tiny helper to build the DQL (accepting field, pattern, id) and a small assertResultIs(bool $expected, array $result, string $why) wrapper to standardize type/count checks and the final assertion. Keeps tests concise while meeting the “detailed assertions and custom messages” goal.

If you prefer to keep it inline, at minimum standardize the three extra assertions (count, type, final with message) in all tests.

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)

21-24: Align array entries with descriptive keys for test readability and uniformity

Other tests in this suite use descriptive keys (e.g., "expands top-level jsonb object into key-value pairs"). Consider mirroring that here for consistency and clearer failure messages.

Apply:

-        return [
-            'SELECT jsonb_object_keys(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
-        ];
+        return [
+            'extracts keys from top-level jsonb object' => 'SELECT jsonb_object_keys(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
+        ];
-        return [
-            \sprintf('SELECT JSONB_OBJECT_KEYS(e.jsonbObject1) FROM %s e', ContainsJsons::class),
-        ];
+        return [
+            'extracts keys from top-level jsonb object' => \sprintf('SELECT JSONB_OBJECT_KEYS(e.jsonbObject1) FROM %s e', ContainsJsons::class),
+        ];

Also applies to: 28-31

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

48-78: Optional: reduce repetition in INSERT statements

The multi-line sprintf is correct but verbose and harder to maintain. Consider parameterized inserts in a small loop to reduce duplication and quoting noise. Not critical for tests.

Example approach outside this block:

$rows = [ $json1, $json2, $json3, $json4, $json5 ];
$sql = \sprintf('INSERT INTO %s.containsjsons (jsonbObject1, jsonbObject2, jsonObject1, jsonObject2) VALUES ', self::DATABASE_SCHEMA)
     . \implode(',', \array_fill(0, \count($rows), '(?, ?, ?, ?)'));
$params = \array_merge(...\array_map(fn($j) => [$j, $j, $j, $j], $rows));
$this->connection->executeStatement($sql, $params);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)

25-27: Add shape checks before indexing result row

Guard against empty results and missing 'result' key to improve failure diagnostics and avoid notices.

Apply this diff:

-        $result = $this->executeDqlQuery($dql);
-        $this->assertIsString($result[0]['result']);
+        $result = $this->executeDqlQuery($dql);
+        $this->assertNotEmpty($result);
+        $this->assertArrayHasKey('result', $result[0]);
+        $this->assertIsString($result[0]['result']);
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php (5)

34-41: Harden key extraction fallback to handle nested JSON and colons safely

The explode(':', trim(...)) fallback can mis-extract keys when values contain colons or nested structures (e.g., address). Use a regex-based fallback and trim consistently.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
-                $key = $decoded['key'];
-            } else {
-                $parts = \explode(':', \trim($row['result'], '{}"'));
-                $key = $parts[0] ?? null;
-            }
+            $decoded = \json_decode($row['result'], true);
+            $key = null;
+            if (\is_array($decoded) && \array_key_exists('key', $decoded)) {
+                $key = (string) $decoded['key'];
+            } elseif (\preg_match('/"(?P<k>[^"]+)"\s*:/', $row['result'], $m) === 1) {
+                $key = $m['k'];
+            }

71-78: Strengthen per-row JSON assertions

Assert decoded payload structure to ensure both 'key' and 'value' are present; this better validates the translation contract.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);

90-97: Repeat stronger structure checks for null-values scenario

Same rationale: ensure 'key' and 'value' exist even when JSON contains nulls.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON even with null values');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON even with null values');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);

109-116: Repeat stronger structure checks for empty-array scenario

Ensure consistent, detailed assertions across scenarios.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON even with empty arrays');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON even with empty arrays');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);

28-44: Optionally factor out repeated key-extraction into JsonTestCase

The extraction/validation loop is duplicated in the JSONB suite. Consider a small helper (e.g., extractKeyFromJsonEachRow(array $row): string) in JsonTestCase and reuse here and in JsonbEachTest to DRY up tests and keep assertions uniform.

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

34-41: Make key extraction resilient to nested JSON/colons

Mirror the regex-based fallback to avoid misparsing when values contain colons or nested objects.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            if (\is_array($decoded) && isset($decoded['key'], $decoded['value'])) {
-                $key = $decoded['key'];
-            } else {
-                $parts = \explode(':', \trim($row['result'], '{}"'));
-                $key = $parts[0] ?? null;
-            }
+            $decoded = \json_decode($row['result'], true);
+            $key = null;
+            if (\is_array($decoded) && \array_key_exists('key', $decoded)) {
+                $key = (string) $decoded['key'];
+            } elseif (\preg_match('/"(?P<k>[^"]+)"\s*:/', $row['result'], $m) === 1) {
+                $key = $m['k'];
+            }

71-78: Stronger per-row JSON assertions (alternative object scenario)

Validate decoded structure for both 'key' and 'value' to tighten guarantees.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);

90-97: Stronger per-row JSON assertions (nulls scenario)

Same enhancement to assert structure explicitly.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON even with null values');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON even with null values');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);

114-116: Stronger per-row JSON assertions (empty array scenario)

Ensure the structure is correct even when arrays are empty.

Apply this diff:

-            $decoded = \json_decode($row['result'], true);
-            $this->assertNotNull($decoded, 'Result should be valid JSON even with empty arrays');
+            $decoded = \json_decode($row['result'], true);
+            $this->assertIsArray($decoded, 'Result should be valid JSON even with empty arrays');
+            $this->assertArrayHasKey('key', $decoded);
+            $this->assertArrayHasKey('value', $decoded);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba442d and 5c32f66.

📒 Files selected for processing (17)
  • fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php (1 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php (1 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectAggTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (3 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (2 hunks)
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (1 hunks)
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1 hunks)
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1 hunks)
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectAggTest.php
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-05-23T11:11:57.951Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#383
File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RadiansTest.php:1-9
Timestamp: 2025-05-23T11:11:57.951Z
Learning: Tests in the `Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\Unit\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase directly, and therefore don't need an explicit import.

Applied to files:

  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), rather than PHPUnit's TestCase, and therefore don't need an explicit import.

Applied to files:

  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
📚 Learning: 2025-03-29T03:31:17.114Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#318
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/XmlAggTest.php:1-9
Timestamp: 2025-03-29T03:31:17.114Z
Learning: Tests in the `Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions` namespace extend a custom `TestCase` class from the same namespace (`Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\TestCase`), not PHPUnit's TestCase, and therefore don't need an explicit import statement.

Applied to files:

  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
📚 Learning: 2025-04-22T00:03:37.733Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#357
File: tests/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpMatchTest.php:28-62
Timestamp: 2025-04-22T00:03:37.733Z
Learning: This project focuses on providing Doctrine ORM interfaces to PostgreSQL functions. Tests should validate correct DQL-to-SQL translation rather than PostgreSQL functionality itself. Test cases should focus on parameter passing and SQL generation, not on testing specific PostgreSQL regex pattern behaviors.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php
📚 Learning: 2025-04-11T11:23:44.192Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#340
File: tests/MartinGeorgiev/Doctrine/DBAL/Types/InetArrayTest.php:145-145
Timestamp: 2025-04-11T11:23:44.192Z
Learning: In the PostgreSQL for Doctrine test cases, methods that test database-to-PHP conversions should use `mixed` type for parameter and include non-string test cases in their data providers, following the pattern in classes like InetTest, CidrTest, and MacaddrTest.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
🧬 Code graph analysis (14)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (3)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)
  • getDqlStatements (27-33)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)
  • getDqlStatements (36-42)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (3)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)
  • getDqlStatements (27-33)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)
  • getDqlStatements (36-42)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (9)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)
  • getDqlStatements (27-33)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (1)
  • getDqlStatements (30-36)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryArrayTest.php (1)
  • getDqlStatements (38-46)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (1)
  • getDqlStatements (38-46)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (1)
  • getDqlStatements (38-46)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (1)
  • getDqlStatements (38-46)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php (1)
  • getDqlStatements (38-46)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpInstrTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php (5)
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php (1)
  • ORM (10-24)
src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEach.php (1)
  • JsonEach (15-22)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (5)
  • Test (19-50)
  • Test (52-60)
  • Test (62-79)
  • Test (81-98)
  • Test (100-117)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonTestCase.php (1)
  • JsonTestCase (9-81)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (5)
  • Test (19-26)
  • Test (28-35)
  • Test (37-44)
  • Test (46-53)
  • Test (55-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (5)
  • Test (19-26)
  • Test (28-35)
  • Test (37-44)
  • Test (46-53)
  • Test (55-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • Test (19-36)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (3)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)
  • getDqlStatements (26-31)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)
  • getDqlStatements (36-42)
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php (3)
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsDates.php (1)
  • ORM (10-33)
fixtures/MartinGeorgiev/Doctrine/Entity/Entity.php (1)
  • ORM (10-17)
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsArrays.php (1)
  • ORM (9-26)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (4)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (5)
  • Test (19-25)
  • Test (27-33)
  • Test (35-41)
  • Test (43-49)
  • Test (51-57)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLikeTest.php (5)
  • Test (19-25)
  • Test (27-33)
  • Test (35-41)
  • Test (43-49)
  • Test (51-57)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (2)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (5)
  • Test (19-50)
  • Test (52-60)
  • Test (62-79)
  • Test (81-98)
  • Test (100-117)
tests/Integration/MartinGeorgiev/TestCase.php (2)
  • executeDqlQuery (271-285)
  • transformPostgresArray (255-264)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (5)
  • Test (19-26)
  • Test (28-35)
  • Test (37-44)
  • Test (46-53)
  • Test (55-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/NotIRegexpTest.php (3)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IRegexpTest.php (5)
  • Test (19-26)
  • Test (28-35)
  • Test (37-44)
  • Test (46-53)
  • Test (55-62)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TextTestCase.php (1)
  • TextTestCase (9-48)
tests/Integration/MartinGeorgiev/TestCase.php (1)
  • executeDqlQuery (271-285)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.3
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.2
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.3
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.1
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.2
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.4 + Doctrine ORM latest + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM 2.14 + Doctrine Lexer 2.1
  • GitHub Check: PHP 8.2 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.3 + Doctrine ORM 3.0 + Doctrine Lexer latest
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PHP 8.3 + Doctrine ORM latest + Doctrine Lexer 3.0
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer 2.1
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (21)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpReplaceTest.php (2)

10-10: Extending TextTestCase is appropriate for the text fixtures

This aligns with the dedicated setup in TextTestCase (containstexts with text1/text2) and matches the inserted seed data (row id=1). Looks consistent with the project’s testing pattern.


8-8: Please confirm PHP version requirement alongside PHPUnit 10 usage

  • PHPUnit is locked at ^10.5.53 in composer.json, which fully supports the #[Test] attribute on PHP 8.0+.
  • Your composer.json does not specify a config.platform.php override, so the actual PHP version will come from the CI/build image.
  • Ensure you have a require: { "php": ">=8.0" } (or equivalent) in composer.json, or add a config.platform.php entry (e.g. "config": { "platform": { "php": "8.0.0" } }) to prevent installs on older PHP versions.
  • Verify that your CI environment is running PHP 8.0 or newer to avoid attribute-related test failures.
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php (2)

10-10: Fixture API consistency confirmed

The TextTestCase class defines both createTestTableForTextFixture() and insertTestDataForTextFixture(), matching the expected fixture helper names. Extending IlikeTest from TextTestCase is correct—no further changes are needed.


8-8: Verified PHPUnit attribute support

  • composer.json requires PHP ^8.1 (enable attributes) at lines 40 and 60
  • composer.json require-dev includes phpunit/phpunit ^10.5.53 (supports #[Test] attributes) at line 55

No further changes needed—runtime supports PHP 8 attributes and PHPUnit’s attribute syntax as used in IlikeTest.php.

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (1)

22-22: LGTM: moved to jsonbObject1 consistently with the updated fixture

The DQL and expected SQL now target jsonbObject1, which aligns with the new schema/fixture naming and other updated tests.

Also applies to: 29-29

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)

31-33: LGTM: SQL/DQL switched to jsonbObject1

Both getExpectedSqlStatements() and getDqlStatements() correctly reference jsonbObject1; labels are descriptive and match the PR’s style goals.

Also applies to: 39-41

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTest.php (1)

22-22: LGTM: consistent migration to jsonbObject1

Both SQL and DQL statements now target jsonbObject1 and retain the descriptive key. Matches the updated fixtures and neighboring tests.

Also applies to: 29-29

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (1)

22-22: LGTM: updated to jsonbObject1 with clear labels

The statements reflect the new column naming. The literal-value case remains correct with the required FROM clause for DQL.

Also applies to: 30-30

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

30-34: LGTM: table DDL split into JSONB and JSON columns

The schema now cleanly distinguishes JSONB vs JSON fields, which clarifies intent in the tests.


26-37: Entity mapping validated

All four properties in the ContainsJsons entity are correctly mapped to the new JSON/JSONB columns:

  • fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php
    • jsonbObject1: #[ORM\Column(type: 'jsonb')]
    • jsonbObject2: #[ORM\Column(type: 'jsonb')]
    • jsonObject1: #[ORM\Column(type: Types::JSON)]
    • jsonObject2: #[ORM\Column(type: Types::JSON)]

These align perfectly with the CREATE TABLE statements in the integration tests. No further adjustments are needed.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbObjectKeysTest.php (3)

8-8: LGTM: migrate to #[Test] attribute import

Importing PHPUnit\Framework\Attributes\Test aligns this test with the PR’s attribute-based discovery goal.


19-21: LGTM: descriptive method name with #[Test]

The rename to a descriptive method and using #[Test] is consistent with the new test style.


28-35: LGTM: Postgres array handling and key presence assertions

Transforming the Postgres array and asserting the presence of expected keys without relying on order is sound for SRF behavior differences across platforms.

fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php (1)

13-18: LGTM: add explicit JSONB columns for fixtures

Introducing jsonbObject1/jsonbObject2 with type 'jsonb' matches the JSONB tests and the schema created in JsonTestCase.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonEachTest.php (4)

12-17: LGTM: function mapping registered via getStringFunctions()

Mapping JSON_EACH to the AST function class is correct and mirrors the JSONB variant.


19-27: LGTM: attribute-based test with focused scenario name

Clear, behavior-focused name and #[Test] usage align with the PR objectives.


52-60: LGTM: empty-object scenario

Asserting zero rows for {} is precise and keeps the contract tight.


10-17: ✅ Instance-style assertions and attribute usage verified across the test suite

No remaining self::assert* calls or legacy test_-prefixed methods were found in tests/ after running the verification script. Migration to instance assertions and PHPUnit attributes is complete.

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

8-8: LGTM: attribute import

Importing PHPUnit\Framework\Attributes\Test is correct and consistent with the PR direction.


19-26: LGTM: primary scenario covered with clear naming and #[Test]

Descriptive scenario name and attribute usage look good.


46-49: LGTM: assert expected keys without relying on order

Good, avoids ordering assumptions of SRFs.

Comment on lines 19 to +23
#[ORM\Column(type: Types::JSON)]
public array $object1;
public array $jsonObject1;

#[ORM\Column(type: Types::JSON)]
public array $object2;
public array $jsonObject2;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify no lingering references to old JSON field names

Renaming to jsonObject1/jsonObject2 is consistent with the tests. Please ensure no code still references object1/object2 (e.g., DQL or entity property access).

Run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Looking for legacy references to object1/object2 in code and DQL..."
rg -nP -C2 --type=php '\bobject1\b|\bobject2\b' tests src -g '!vendor/**' || echo "No legacy references found."

echo
echo "Specifically check for DQL 't.object1'/'t.object2'..."
rg -nP -C2 't\.object[12]\b' tests -g '!vendor/**' || echo "No DQL references to t.object1/t.object2 found."

Length of output: 159921


Action Required: Update lingering DQL/property references to jsonObject1 / jsonObject2

All of the following tests still refer to the old properties object1 and object2, which will break now that the entity uses jsonObject1 and jsonObject2. Please update each occurrence in both Unit and Integration tests to reference the new names:

• Unit tests under tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/
• Integration tests under tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/

Example snippet changes:

-   'gets length of top-level array' => 'SELECT json_array_length(c0_.object1) AS sclr_0 FROM ContainsJsons c0_',
+   'gets length of top-level array' => 'SELECT json_array_length(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',

-   $dql = 'SELECT JSONB_INSERT(t.object1, :path, :value) …';
+   $dql = 'SELECT JSONB_INSERT(t.jsonObject1, :path, :value) …';

-   sprintf("SELECT JSON_GET_FIELD(e.object1, 'name') …", ContainsJsons::class),
+   sprintf("SELECT JSON_GET_FIELD(e.jsonObject1, 'name') …", ContainsJsons::class),

Please sweep all occurrences of:

  • c0_\.object1 / c0_\.object2
  • t\.object1 / t\.object2
  • any ->object1 / ->object2 in DQL strings
    and replace with the corresponding jsonObject1 / jsonObject2.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php around lines 19 to
23, the entity property names were changed to jsonObject1/jsonObject2; update
all test references accordingly by searching and replacing lingering occurrences
across tests: in tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ and
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/ replace
c0_\.object1 -> c0_\.jsonObject1 and c0_\.object2 -> c0_\.jsonObject2,
t\.object1 -> t\.jsonObject1 and t\.object2 -> t\.jsonObject2, and any DQL
string fragments or PHP property accesses ->object1/->object2 ->
->jsonObject1/->jsonObject2; run the test suite to ensure no remaining
references.

Comment on lines 19 to 25
#[Test]
public function returns_true_for_case_insensitive_matching_string(): void
{
// NOTE: Using string literals for arguments due to DQL limitations with field extraction.
$dql = "SELECT ILIKE('John', 'john') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
$dql = "SELECT ILIKE(t.text1, 'test') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

ILIKE without wildcards tests equality; current pattern would not match row 1

ILIKE behaves like LIKE, so substring matches require % wildcards. Given text1 at id=1 is "this is a test string", ILIKE(..., 'test') evaluates to false. Either change the pattern to the full string (to validate case-insensitive equality) or add wildcards for contains. Since the method name says “matching string”, propose testing equality.

Apply:

-        $dql = "SELECT ILIKE(t.text1, 'test') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $dql = "SELECT ILIKE(t.text1, 'this is a test string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $result = $this->executeDqlQuery($dql);
+        $this->assertCount(1, $result, 'Expected a single row for id=1.');
+        $this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
+        $this->assertTrue($result[0]['result'], 'Expected true for case-insensitive exact match against text1.');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[Test]
public function returns_true_for_case_insensitive_matching_string(): void
{
// NOTE: Using string literals for arguments due to DQL limitations with field extraction.
$dql = "SELECT ILIKE('John', 'john') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
$dql = "SELECT ILIKE(t.text1, 'test') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
#[Test]
public function returns_true_for_case_insensitive_matching_string(): void
{
$dql = "SELECT ILIKE(t.text1, 'this is a test string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertCount(1, $result, 'Expected a single row for id=1.');
$this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
$this->assertTrue($result[0]['result'], 'Expected true for case-insensitive exact match against text1.');
}

Comment on lines 27 to 33
#[Test]
public function returns_true_for_case_insensitive_matching_with_different_case(): void
{
$dql = "SELECT ILIKE('John', 'jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
$dql = "SELECT ILIKE(t.text1, 'TEST') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Case-insensitive equality is not validated by 'TEST' without wildcards

'TEST' (no wildcards) won’t match "this is a test string". If the intent is to assert case insensitivity, use the full string with mixed case.

Apply:

-        $dql = "SELECT ILIKE(t.text1, 'TEST') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $dql = "SELECT ILIKE(t.text1, 'ThIs Is A TeSt StRiNg') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $result = $this->executeDqlQuery($dql);
+        $this->assertCount(1, $result, 'Expected a single row for id=1.');
+        $this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
+        $this->assertTrue($result[0]['result'], 'Expected true for case-insensitive equality with mixed casing.');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[Test]
public function returns_true_for_case_insensitive_matching_with_different_case(): void
{
$dql = "SELECT ILIKE('John', 'jane') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t WHERE t.id = 1";
$dql = "SELECT ILIKE(t.text1, 'TEST') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
#[Test]
public function returns_true_for_case_insensitive_matching_with_different_case(): void
{
$dql = "SELECT ILIKE(t.text1, 'ThIs Is A TeSt StRiNg') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertCount(1, $result, 'Expected a single row for id=1.');
$this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
$this->assertTrue($result[0]['result'], 'Expected true for case-insensitive equality with mixed casing.');
}
🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
around lines 27–33, the test uses 'TEST' without wildcards which will not match
the fixture value "this is a test string"; update the DQL to either use the full
exact string (preserving the mixed case from the fixture) for equality testing
or, if you intended substring matching, wrap the pattern in wildcards (e.g.
'%TEST%'); change the literal in the ILIKE call accordingly so the assertion
actually tests case-insensitive matching as intended.

Comment on lines 43 to 49
#[Test]
public function returns_true_when_matching_second_text_field(): void
{
$dql = "SELECT ILIKE(t.text2, 'another') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Second-field match also needs equality or wildcards

'another' won’t match "another test string" without % wildcards. Either assert equality with the full string or use '%another%'. The method name doesn’t say “partial”, so equality seems clearer here.

Apply:

-        $dql = "SELECT ILIKE(t.text2, 'another') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
-        $result = $this->executeDqlQuery($dql);
-        $this->assertTrue($result[0]['result']);
+        $dql = "SELECT ILIKE(t.text2, 'another test string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
+        $result = $this->executeDqlQuery($dql);
+        $this->assertCount(1, $result, 'Expected a single row for id=1.');
+        $this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
+        $this->assertTrue($result[0]['result'], 'Expected true for exact match against text2.');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[Test]
public function returns_true_when_matching_second_text_field(): void
{
$dql = "SELECT ILIKE(t.text2, 'another') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertTrue($result[0]['result']);
}
#[Test]
public function returns_true_when_matching_second_text_field(): void
{
$dql = "SELECT ILIKE(t.text2, 'another test string') as result FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsTexts t WHERE t.id = 1";
$result = $this->executeDqlQuery($dql);
$this->assertCount(1, $result, 'Expected a single row for id=1.');
$this->assertIsBool($result[0]['result'], 'ILIKE should return a boolean.');
$this->assertTrue($result[0]['result'], 'Expected true for exact match against text2.');
}
🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/IlikeTest.php
around lines 43 to 49, the test uses ILIKE(t.text2, 'another') which won’t match
"another test string" unless wildcards are used; update the DQL so the compared
value matches the actual field contents — either change 'another' to the full
string present in the fixture (e.g. 'another test string') to assert equality,
or change it to use wildcards (e.g. '%another%') if a partial match is intended;
adjust the assertion message/name if needed to reflect equality vs partial
match.

coderabbitai[bot]
coderabbitai bot previously requested changes Aug 26, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RowTest.php (1)

28-36: Fix stale property references in JsonbPrettyTest

In tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php (around line 22), the DQL still refers to t.object1, but the ContainsJsons entity no longer defines object1—it now has jsonbObject1 (and jsonObject1). Since this is the JSONB-specific pretty-print test, update the reference accordingly:

- $dql = 'SELECT JSONB_PRETTY(t.object1) as result
+ $dql = 'SELECT JSONB_PRETTY(t.jsonbObject1) as result

• No other stale object1/object2 usages were found in ROW() tests.
• The variable names object1/object2 in JsonbTest.php pertain to stdClass fixtures and can remain unchanged.

Please apply this fix to ensure the integration test passes.

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (1)

19-30: Bound parameters will likely break due to PostgreSQL jsonb/jsonpath typing; inline literals instead

PostgreSQL does not implicitly cast a text-bound parameter to jsonb/jsonpath in jsonb_path_exists(...). Using bound params for both the JSON document and the path commonly yields “function jsonb_path_exists(text, text) does not exist”. Inline SQL literals (unknown -> jsonb/jsonpath) or add explicit casts. Given Doctrine DQL’s casting limitations here, the simplest/most robust fix is to inline the JSON and jsonpath as SQL string literals.

Apply the following diffs per test:

  1. can_check_simple_path_exists
-        $dql = 'SELECT JSONB_PATH_EXISTS(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_EXISTS(\'{"a": 1, "b": 2}\', \'$.b\') as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
                 WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql, [
-            'json' => '{"a": 1, "b": 2}',
-            'path' => '$.b',
-        ]);
+        $result = $this->executeDqlQuery($dql);
  1. can_check_nested_path_exists
-        $dql = 'SELECT JSONB_PATH_EXISTS(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_EXISTS(\'{"a": {"b": 2}}\', \'$.a.b\') as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
                 WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql, [
-            'json' => '{"a": {"b": 2}}',
-            'path' => '$.a.b',
-        ]);
+        $result = $this->executeDqlQuery($dql);
  1. returns_false_for_missing_path
-        $dql = 'SELECT JSONB_PATH_EXISTS(:json, :path) as result 
+        $dql = 'SELECT JSONB_PATH_EXISTS(\'{"a": 1}\', \'$.b\') as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
                 WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql, [
-            'json' => '{"a": 1}',
-            'path' => '$.b',
-        ]);
+        $result = $this->executeDqlQuery($dql);
  1. can_check_path_exists_in_column_reference
-        $dql = 'SELECT JSONB_PATH_EXISTS(t.jsonbObject1, :path) as result
+        $dql = 'SELECT JSONB_PATH_EXISTS(t.jsonbObject1, \'$.name\') as result
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t
                 WHERE t.id = 1';
-        $result = $this->executeDqlQuery($dql, ['path' => '$.name']);
+        $result = $this->executeDqlQuery($dql);

Optionally, if you prefer keeping parameters, you’d need explicit casts to jsonb/jsonpath at SQL level. In DQL that typically isn’t ergonomic.

Also applies to: 32-43, 45-56, 61-66

♻️ Duplicate comments (1)
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)

8-8: Require PHPUnit 10+ for #[Test] attributes

You’ve switched to attribute-based discovery. Ensure composer.json requires phpunit/phpunit >=10 so #[Test] is recognized. A previous review flagged this repo doesn’t list PHPUnit; echoing the reminder here so these tests are actually discovered and executed.

Run to verify the dependency is declared:

#!/bin/bash
set -euo pipefail
echo "composer.json → phpunit/phpunit constraint(s):"
if command -v jq >/dev/null 2>&1; then
  jq -r '.require["phpunit/phpunit"], .["require-dev"]["phpunit/phpunit"]' composer.json 2>/dev/null | sed '/null/d' || true
else
  rg -nP '"phpunit/phpunit"\s*:\s*"[^\"]+"' composer.json -n -C0 || echo "phpunit/phpunit not found in composer.json"
fi
🧹 Nitpick comments (39)
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllOnTheRightExistOnTheLeftTest.php (1)

32-34: Add a parameterized DQL test for ALL_ON_RIGHT_EXIST_ON_LEFT

To mirror the coverage in AnyOnTheRightExistsOnTheLeftTest and ensure we guard against regressions in handling bound array parameters, please add a third DQL case that uses a parameterized array. The absence of any existing :parameter usage in AllOnTheRightExistOnTheLeftTest.php confirms this test is currently missing.

• File needing update:

  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AllOnTheRightExistOnTheLeftTest.php (lines 30–35)

Proposed diff:

     protected function getDqlStatements(): array
     {
         return [
             'checks if single key exists in jsonb' => \sprintf("SELECT ALL_ON_RIGHT_EXIST_ON_LEFT(e.jsonbObject1, ARRAY('test')) FROM %s e", ContainsJsons::class),
             'checks if multiple keys exist in jsonb' => \sprintf("SELECT ALL_ON_RIGHT_EXIST_ON_LEFT(e.jsonbObject1, ARRAY('key1', 'key2')) FROM %s e", ContainsJsons::class),
+            'checks with parameter'                => \sprintf('SELECT ALL_ON_RIGHT_EXIST_ON_LEFT(e.jsonbObject1, :parameter) FROM %s e', ContainsJsons::class),
         ];
     }
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonScalarTest.php (1)

26-31: Optional: add a descriptive name to the DQL case for clearer failure output.

Across the suite, keyed test cases improve readability of PHPUnit output. Consider naming this single case.

Apply:

     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT JSON_SCALAR(e.jsonObject1) FROM %s e', ContainsJsons::class),
+            'extracts scalar from json field' => \sprintf('SELECT JSON_SCALAR(e.jsonObject1) FROM %s e', ContainsJsons::class),
         ];
     }
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectTest.php (1)

21-31: Broaden coverage to nested and array paths for parity with other JSON tests

Optional, but adding a few additional cases (nested keys, array indices, last element, complex paths) would align this test with JsonGetObjectAsTextTest and JsonGetFieldTest and better guard against regressions in path handling.

Apply this diff to add more cases with matching keys across SQL and DQL:

@@
     protected function getExpectedSqlStatements(): array
     {
         return [
-            'extracts JSON object at specified path' => "SELECT (c0_.jsonObject1 #> '{residency}') AS sclr_0 FROM ContainsJsons c0_",
+            'extracts JSON object at specified path' => "SELECT (c0_.jsonObject1 #> '{residency}') AS sclr_0 FROM ContainsJsons c0_",
+            'extracts nested object' => "SELECT (c0_.jsonObject1 #> '{user,address}') AS sclr_0 FROM ContainsJsons c0_",
+            'extracts array element' => "SELECT (c0_.jsonObject1 #> '{items,0}') AS sclr_0 FROM ContainsJsons c0_",
+            'extracts last array element' => "SELECT (c0_.jsonObject1 #> '{records,-1}') AS sclr_0 FROM ContainsJsons c0_",
+            'extracts complex path' => "SELECT (c0_.jsonObject1 #> '{data,users,0,profile}') AS sclr_0 FROM ContainsJsons c0_",
         ];
     }
@@
     protected function getDqlStatements(): array
     {
         return [
-            'extracts JSON object at specified path' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{residency}') FROM %s e", ContainsJsons::class),
+            'extracts JSON object at specified path' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{residency}') FROM %s e", ContainsJsons::class),
+            'extracts nested object' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{user,address}') FROM %s e", ContainsJsons::class),
+            'extracts array element' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{items,0}') FROM %s e", ContainsJsons::class),
+            'extracts last array element' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{records,-1}') FROM %s e", ContainsJsons::class),
+            'extracts complex path' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{data,users,0,profile}') FROM %s e", ContainsJsons::class),
         ];
     }
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathMatchTest.php (2)

31-34: Optional: add coverage for silent='false' as well.

You already cover the 4-argument variant with silent='true'. Adding a case with silent='false' would exercise both boolean code paths in the function parser.

Apply this diff to extend expected SQL:

         return [
             'checks if path matches with exists condition' => "SELECT jsonb_path_match(c0_.jsonbObject1, 'exists($.a[*] ? (@ >= 2 && @ <= 4))') AS sclr_0 FROM ContainsJsons c0_",
             'checks if path matches with simple condition' => "SELECT jsonb_path_match(c0_.jsonbObject1, '$.a[*] > 2') AS sclr_0 FROM ContainsJsons c0_",
             'checks if path matches with simple condition and vars argument' => "SELECT jsonb_path_match(c0_.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}') AS sclr_0 FROM ContainsJsons c0_",
             'checks if path matches with simple condition and vars and silent arguments' => "SELECT jsonb_path_match(c0_.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}', 'true') AS sclr_0 FROM ContainsJsons c0_",
+            'checks if path matches with simple condition and vars and silent=false arguments' => "SELECT jsonb_path_match(c0_.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}', 'false') AS sclr_0 FROM ContainsJsons c0_",
         ];

41-44: Optional companion to the above: add a DQL case for silent='false'.

This pairs with the suggested expected SQL addition to cover both boolean branches.

Apply this diff to extend DQL:

         return [
             'checks if path matches with exists condition' => \sprintf("SELECT JSONB_PATH_MATCH(e.jsonbObject1, 'exists($.a[*] ? (@ >= 2 && @ <= 4))') FROM %s e", ContainsJsons::class),
             'checks if path matches with simple condition' => \sprintf("SELECT JSONB_PATH_MATCH(e.jsonbObject1, '$.a[*] > 2') FROM %s e", ContainsJsons::class),
             'checks if path matches with simple condition and vars argument' => \sprintf("SELECT JSONB_PATH_MATCH(e.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}') FROM %s e", ContainsJsons::class),
             'checks if path matches with simple condition and vars and silent arguments' => \sprintf("SELECT JSONB_PATH_MATCH(e.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}', 'true') FROM %s e", ContainsJsons::class),
+            'checks if path matches with simple condition and vars and silent=false arguments' => \sprintf("SELECT JSONB_PATH_MATCH(e.jsonbObject1, '$.a[*] > 2', '{\"strict\": false}', 'false') FROM %s e", ContainsJsons::class),
         ];
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonArrayLengthTest.php (1)

23-23: Prefer an array literal for JSON_ARRAY_LENGTH examples to reflect runtime semantics

json_array_length/JSON_ARRAY_LENGTH operates on JSON arrays; using an object literal is syntactically fine for SQL generation tests but semantically misleading. A tiny tweak keeps the intent clear without affecting the assertion purpose.

Apply this diff:

-            'gets length from literal json' => "SELECT json_array_length('{\"iso_3166_a3_code\":\"BGR\"}') AS sclr_0 FROM ContainsJsons c0_",
+            'gets length from literal json' => "SELECT json_array_length('[1,2,3]') AS sclr_0 FROM ContainsJsons c0_",
-            'gets length from literal json' => \sprintf("SELECT JSON_ARRAY_LENGTH('{\"iso_3166_a3_code\":\"BGR\"}') FROM %s e", ContainsJsons::class),
+            'gets length from literal json' => \sprintf("SELECT JSON_ARRAY_LENGTH('[1,2,3]') FROM %s e", ContainsJsons::class),

Also applies to: 31-31

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (2)

33-47: Tighten assertions and reduce duplication in array-elements test

Condense element assertions and add explicit failure messages to match the PR objective for descriptive assertions.

Apply this diff:

-        $this->assertCount(3, $result);
-        $this->assertSame('1', $result[0]['result']);
-        $this->assertSame('2', $result[1]['result']);
-        $this->assertSame('3', $result[2]['result']);
+        $this->assertCount(3, $result, 'Expected three matches for JSON path $.items[*].');
+        $this->assertSame(['1', '2', '3'], \array_column($result, 'result'), 'Expected order-preserving expansion of all array elements.');

49-62: Assert decoded object structure for filtered results (clearer intent, stronger checks)

Right now we assert stringified JSON. Decoding and asserting object shape makes the test intention crisper and failure output more actionable, while still aligning with instance-style assertions.

Apply this diff:

-        $this->assertCount(2, $result);
-        $this->assertSame('{"id": 2}', $result[0]['result']);
-        $this->assertSame('{"id": 3}', $result[1]['result']);
+        $this->assertCount(2, $result, 'Expected two matches for items with id > 1.');
+        $decoded0 = \json_decode($result[0]['result'], true);
+        $decoded1 = \json_decode($result[1]['result'], true);
+        $this->assertIsArray($decoded0, 'First result should be a JSON object.');
+        $this->assertIsArray($decoded1, 'Second result should be a JSON object.');
+        $this->assertArrayHasKey('id', $decoded0, 'First object must contain an id property.');
+        $this->assertArrayHasKey('id', $decoded1, 'Second object must contain an id property.');
+        $this->assertSame(2, $decoded0['id'], 'First object should have id=2.');
+        $this->assertSame(3, $decoded1['id'], 'Second object should have id=3.');
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (2)

29-33: Optional: add custom failure messages to align with PR goal

The PR aims for detailed assertions with custom messages. Consider adding messages to make failures self-explanatory.

Apply this minimal diff:

-        $this->assertIsString($result[0]['result']);
+        $this->assertIsString($result[0]['result'], 'Result column should be a JSON-encoded string.');
         $decoded = \json_decode($result[0]['result'], true);
-        $this->assertIsArray($decoded);
-        $this->assertArrayHasKey('name', $decoded);
-        $this->assertSame('John Doe', $decoded['name']);
+        $this->assertIsArray($decoded, 'Decoded JSON should be an associative array.');
+        $this->assertArrayHasKey('name', $decoded, 'JSON object should contain key \"name\".');
+        $this->assertSame('John Doe', $decoded['name'], 'Updated \"name\" must be exactly \"John Doe\".');

75-77: Nit: unify DQL string quoting with the rest of the file

Other methods use single-quoted PHP strings for DQL. Switching here improves consistency and removes unnecessary backslash escaping.

Apply:

-        $dql = "SELECT JSONB_SET(t.jsonbObject1, :path, :value, 'false') as result 
-                FROM Fixtures\\MartinGeorgiev\\Doctrine\\Entity\\ContainsJsons t 
-                WHERE t.id = 1";
+        $dql = 'SELECT JSONB_SET(t.jsonbObject1, :path, :value, \'false\') as result 
+                FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
+                WHERE t.id = 1';
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonBuildObjectTest.php (2)

42-48: DQL updates are consistent; consider documenting the array map shape for clarity.

The DQL statements now reference e.jsonObject1/jsonObject2 consistently—good. As a small readability win, document the return-type shape of these provider methods.

Apply phpdoc above the providers:

@@
-    protected function getExpectedSqlStatements(): array
+    /** @return array<string,string> description => expected SQL */
+    protected function getExpectedSqlStatements(): array
@@
-    protected function getDqlStatements(): array
+    /** @return array<string,string> description => DQL */
+    protected function getDqlStatements(): array

57-59: Odd-arguments test updated—looks good; consider broadening via a data provider.

Change aligns with the rename. If you want slightly stronger coverage without extra duplication, add a data provider that feeds 1, 3, 5 arguments to ensure the same exception is thrown across cases.

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetTest.php (1)

50-50: Nit: keep JSON value casing consistent across tests.

The JSON sample uses "bgr" here while other statements in this file use "BGR". Consider normalizing for readability.

-        $dql = \sprintf("SELECT JSONB_SET(e.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"bgr\"}', 'invalid') FROM %s e", ContainsJsons::class);
+        $dql = \sprintf("SELECT JSONB_SET(e.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"BGR\"}', 'invalid') FROM %s e", ContainsJsons::class);
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayLengthTest.php (1)

19-24: Prefer descriptive keys in statements arrays to improve failure messages and align with PR goals

Other tests in this suite often use associative keys as scenario labels. Adding a label here will make failures clearer and aligns with “detailed assertions and custom failure messages.”

Apply:

@@
     protected function getExpectedSqlStatements(): array
     {
         return [
-            'SELECT jsonb_array_length(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
+            'counts elements in JSONB array' => 'SELECT jsonb_array_length(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
         ];
     }
@@
     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT JSONB_ARRAY_LENGTH(e.jsonbObject1) FROM %s e', ContainsJsons::class),
+            'counts elements in JSONB array' => \sprintf('SELECT JSONB_ARRAY_LENGTH(e.jsonbObject1) FROM %s e', ContainsJsons::class),
         ];
     }

Also applies to: 26-31

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/AnyOnTheRightExistsOnTheLeftTest.php (1)

26-26: Minor wording tweak for test descriptions to be more explicit

To better reflect the PR’s goal of more descriptive test names, consider clarifying the “parameter” case label to indicate it uses a parameterized array of keys.

Apply this small rename:

-            'checks with parameter' => 'SELECT (c0_.jsonbObject1 ??| ?) AS sclr_0 FROM ContainsJsons c0_',
+            'checks with parameterized array' => 'SELECT (c0_.jsonbObject1 ??| ?) AS sclr_0 FROM ContainsJsons c0_',
-            'checks with parameter' => \sprintf('SELECT ANY_ON_RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, :parameter) FROM %s e', ContainsJsons::class),
+            'checks with parameterized array' => \sprintf('SELECT ANY_ON_RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, :parameter) FROM %s e', ContainsJsons::class),

Also applies to: 35-35

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetObjectAsTextTest.php (1)

27-27: Confirm intentional support for -1 (last index) in JSON path

The tests generate SQL with '{records,-1}', which PostgreSQL accepts syntactically but does not implement "last element" semantics by itself; it will simply treat -1 as an index (typically yielding NULL). If the translator intentionally preserves -1 as a convention for "last", great—just confirming this is by design.

Optionally, add one more case to exercise a nested field off the last array element for parity with other paths:

         'extracts last array element as text' => "SELECT (c0_.jsonObject1 #>> '{records,-1}') AS sclr_0 FROM ContainsJsons c0_",
+        'extracts field from last array element as text' => "SELECT (c0_.jsonObject1 #>> '{records,-1,name}') AS sclr_0 FROM ContainsJsons c0_",
         'extracts last array element as text' => \sprintf("SELECT JSON_GET_OBJECT_AS_TEXT(e.jsonObject1, '{records,-1}') FROM %s e", ContainsJsons::class),
+        'extracts field from last array element as text' => \sprintf("SELECT JSON_GET_OBJECT_AS_TEXT(e.jsonObject1, '{records,-1,name}') FROM %s e", ContainsJsons::class),

Also applies to: 40-40

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbSetLaxTest.php (2)

22-29: Optional: add coverage for the 4th/5th jsonb_set_lax arguments

If JsonbSetLax supports the full PostgreSQL signature, consider adding cases for create_missing and null handling to lock behavior down. Example additions:

         return [
             'modifies top-level property' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"BGR\"}') AS sclr_0 FROM ContainsJsons c0_",
             'sets property to null' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{country}', null) AS sclr_0 FROM ContainsJsons c0_",
             'modifies nested property' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{address,city}', '\"Sofia\"') AS sclr_0 FROM ContainsJsons c0_",
             'modifies array element at index' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{phones,0}', '\"+1234567890\"') AS sclr_0 FROM ContainsJsons c0_",
             'uses parameters for path and value' => 'SELECT jsonb_set_lax(c0_.jsonbObject1, ?, ?) AS sclr_0 FROM ContainsJsons c0_',
             'modifies deeply nested array element' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{user,contacts,0,phone}', '\"+1234567890\"') AS sclr_0 FROM ContainsJsons c0_",
             'sets boolean property' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{is_active}', 'true') AS sclr_0 FROM ContainsJsons c0_",
             'sets numeric property' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{count}', '42') AS sclr_0 FROM ContainsJsons c0_",
+            'creates missing path when flagged' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{new,prop}', '\"val\"', 'true') AS sclr_0 FROM ContainsJsons c0_",
+            'deletes key when null with delete_key mode' => "SELECT jsonb_set_lax(c0_.jsonbObject1, '{country}', null, 'true', 'delete_key') AS sclr_0 FROM ContainsJsons c0_",
         ];

36-43: Mirror the optional extended-arity tests in DQL

If you add the extra SQL expectations above, mirror them here to keep DQL↔SQL parity.

         return [
             'modifies top-level property' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{country}', '{\"iso_3166_a3_code\":\"BGR\"}') FROM %s e", ContainsJsons::class),
             'sets property to null' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{country}', null) FROM %s e", ContainsJsons::class),
             'modifies nested property' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{address,city}', '\"Sofia\"') FROM %s e", ContainsJsons::class),
             'modifies array element at index' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{phones,0}', '\"+1234567890\"') FROM %s e", ContainsJsons::class),
             'uses parameters for path and value' => \sprintf('SELECT JSONB_SET_LAX(e.jsonbObject1, :path, :value) FROM %s e', ContainsJsons::class),
             'modifies deeply nested array element' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{user,contacts,0,phone}', '\"+1234567890\"') FROM %s e", ContainsJsons::class),
             'sets boolean property' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{is_active}', 'true') FROM %s e", ContainsJsons::class),
             'sets numeric property' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{count}', '42') FROM %s e", ContainsJsons::class),
+            'creates missing path when flagged' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{new,prop}', '\"val\"', 'true') FROM %s e", ContainsJsons::class),
+            'deletes key when null with delete_key mode' => \sprintf("SELECT JSONB_SET_LAX(e.jsonbObject1, '{country}', null, 'true', 'delete_key') FROM %s e", ContainsJsons::class),
         ];
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbStripNullsTest.php (1)

19-24: Unify with descriptive keys in expectation arrays.

Many tests in this suite use descriptive keys (e.g., "expands jsonb array into separate rows"). Consider adding similar labels here for consistency/readability.

 return [
-    'SELECT jsonb_strip_nulls(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
+    'strips nulls from jsonb' => 'SELECT jsonb_strip_nulls(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
 ];
 return [
-    \sprintf('SELECT JSONB_STRIP_NULLS(e.jsonbObject1) FROM %s e', ContainsJsons::class),
+    'strips nulls from jsonb' => \sprintf('SELECT JSONB_STRIP_NULLS(e.jsonbObject1) FROM %s e', ContainsJsons::class),
 ];

Also applies to: 26-31

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonStripNullsTest.php (1)

19-24: Add descriptive keys to sync with the unified test style.

Align these arrays with the rest of the suite by adding human-friendly labels.

 return [
-    'SELECT json_strip_nulls(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',
+    'strips nulls from json' => 'SELECT json_strip_nulls(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',
 ];
 return [
-    \sprintf('SELECT JSON_STRIP_NULLS(e.jsonObject1) FROM %s e', ContainsJsons::class),
+    'strips nulls from json' => \sprintf('SELECT JSON_STRIP_NULLS(e.jsonObject1) FROM %s e', ContainsJsons::class),
 ];

Also applies to: 26-31

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (1)

44-44: Exception-case DQL strings updated correctly; consider DRY-ing with a data provider.

The three negative-path tests are sound. Optionally, consolidate via a data provider to reduce duplication and ease future additions.

If you want, I can sketch a provider-based refactor keeping your custom messages intact.

Also applies to: 54-54, 64-64

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbInsertTest.php (1)

59-67: Consider tightening exception assertions.

Optionally assert a more specific DBAL exception subtype or message pattern for stability across driver versions (e.g., expectExceptionMessageMatches with a regex). Keep if you value portability across platforms.

Also applies to: 72-82

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonObjectKeysTest.php (2)

19-24: Add a descriptive array key for consistency with other tests.

Most JSON-related tests use descriptive keys for both SQL and DQL arrays. Consider mirroring that here for readability and style consistency.

Apply this minimal change:

     protected function getExpectedSqlStatements(): array
     {
         return [
-            'SELECT json_object_keys(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',
+            'lists keys of top-level object' => 'SELECT json_object_keys(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',
         ];
     }

26-31: Also key the DQL array with a description for symmetry.

Keeps style uniform across files and between SQL/DQL expectations.

     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT JSON_OBJECT_KEYS(e.jsonObject1) FROM %s e', ContainsJsons::class),
+            'lists keys of top-level object' => \sprintf('SELECT JSON_OBJECT_KEYS(e.jsonObject1) FROM %s e', ContainsJsons::class),
         ];
     }
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (1)

29-29: Add a parameterized test case to JsonbExistsTest for placeholder coverage

To ensure the SQL walker properly handles DQL functions with bound parameters, add a parameterized variant alongside the existing static‐key test. You can mirror the style used in other JSONB function tests (e.g. JsonbSetLaxTest and AnyOnTheRightExistsOnTheLeftTest):

• File: tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php
Insert after line 29:

@@ tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php:29
-            'checks if top-level key exists' => \sprintf("SELECT JSONB_EXISTS(e.jsonbObject1, 'country') FROM %s e", ContainsJsons::class),
+            'checks if top-level key exists'     => \sprintf("SELECT JSONB_EXISTS(e.jsonbObject1, 'country') FROM %s e", ContainsJsons::class),
+            'checks with parameter'              => \sprintf("SELECT JSONB_EXISTS(e.jsonbObject1, :key) FROM %s e", ContainsJsons::class),

This optional refactor boosts coverage by verifying that placeholders (:key) are correctly dispatched through the walker.

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (2)

19-24: Add a descriptive key to the SQL array for style consistency.

Brings this file in line with others that label expectations.

     protected function getExpectedSqlStatements(): array
     {
         return [
-            'SELECT (c0_.jsonbObject1 #- c0_.jsonbObject2) AS sclr_0 FROM ContainsJsons c0_',
+            'deletes value at path from jsonb' => 'SELECT (c0_.jsonbObject1 #- c0_.jsonbObject2) AS sclr_0 FROM ContainsJsons c0_',
         ];
     }

26-31: Also label the DQL array entry.

Keeps SQL and DQL sections symmetric and self-documenting.

     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT DELETE_AT_PATH(e.jsonbObject1, e.jsonbObject2) FROM %s e', ContainsJsons::class),
+            'deletes value at path from jsonb' => \sprintf('SELECT DELETE_AT_PATH(e.jsonbObject1, e.jsonbObject2) FROM %s e', ContainsJsons::class),
         ];
     }
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbEachTextTest.php (1)

19-24: Adopt descriptive keys for expectations to align with PR’s “detailed assertions” goal

Most tests in this suite use descriptive array keys for clearer failure messages. This file returns a single unkeyed string in both SQL and DQL sections. Consider labeling them for consistency.

Apply:

@@
     protected function getExpectedSqlStatements(): array
     {
         return [
-            'SELECT jsonb_each_text(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
+            'expands jsonb object into text key-value pairs' => 'SELECT jsonb_each_text(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
         ];
     }
@@
     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT JSONB_EACH_TEXT(e.jsonbObject1) FROM %s e', ContainsJsons::class),
+            'expands jsonb object into text key-value pairs' => \sprintf('SELECT JSONB_EACH_TEXT(e.jsonbObject1) FROM %s e', ContainsJsons::class),
         ];
     }

Also applies to: 26-31

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbArrayElementsTextTest.php (1)

19-24: Prefer descriptive keys for better failure messages (consistency with sibling tests)

Introduce an associative key to describe the behavior being tested, similar to JsonbArrayElements and others.

Apply:

@@
     protected function getExpectedSqlStatements(): array
     {
         return [
-            'SELECT jsonb_array_elements_text(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
+            'expands jsonb array into text values across rows' => 'SELECT jsonb_array_elements_text(c0_.jsonbObject1) AS sclr_0 FROM ContainsJsons c0_',
         ];
     }
@@
     protected function getDqlStatements(): array
     {
         return [
-            \sprintf('SELECT JSONB_ARRAY_ELEMENTS_TEXT(e.jsonbObject1) FROM %s e', ContainsJsons::class),
+            'expands jsonb array into text values across rows' => \sprintf('SELECT JSONB_ARRAY_ELEMENTS_TEXT(e.jsonbObject1) FROM %s e', ContainsJsons::class),
         ];
     }

Also applies to: 26-31

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldAsIntegerTest.php (1)

24-26: Nit: use uppercase AS in CAST for consistency with other SQL fragments

Minor style/readability tweak to align with the rest of the suite and typical Doctrine SQL casing.

-            'extracts field as integer' => "SELECT CAST(c0_.jsonObject1 ->> 'rank' as BIGINT) AS sclr_0 FROM ContainsJsons c0_",
-            'extracts array element as integer' => 'SELECT CAST(c0_.jsonObject1 ->> 0 as BIGINT) AS sclr_0 FROM ContainsJsons c0_',
-            'extracts nested array element as integer' => "SELECT CAST((c0_.jsonObject1 -> 'scores') ->> 1 as BIGINT) AS sclr_0 FROM ContainsJsons c0_",
+            'extracts field as integer' => "SELECT CAST(c0_.jsonObject1 ->> 'rank' AS BIGINT) AS sclr_0 FROM ContainsJsons c0_",
+            'extracts array element as integer' => 'SELECT CAST(c0_.jsonObject1 ->> 0 AS BIGINT) AS sclr_0 FROM ContainsJsons c0_',
+            'extracts nested array element as integer' => "SELECT CAST((c0_.jsonObject1 -> 'scores') ->> 1 AS BIGINT) AS sclr_0 FROM ContainsJsons c0_",
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (1)

54-54: Nit: avoid manually escaped JSON in DQL by using json_encode to build vars

Reduces backslash noise and prevents accidental invalid JSON/whitespace differences.

@@
-        $dql = \sprintf("SELECT JSONB_PATH_EXISTS(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'invalid') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_EXISTS(e.jsonbObject1, '$.items[*].id', '%s', 'invalid') FROM %s e", $vars, ContainsJsons::class);
@@
-        $dql = \sprintf('SELECT JSONB_PATH_EXISTS(e.jsonbObject1) FROM %s e', ContainsJsons::class);
+        $dql = \sprintf('SELECT JSONB_PATH_EXISTS(e.jsonbObject1) FROM %s e', ContainsJsons::class);
@@
-        $dql = \sprintf("SELECT JSONB_PATH_EXISTS(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'true', 'extra_arg') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_EXISTS(e.jsonbObject1, '$.items[*].id', '%s', 'true', 'extra_arg') FROM %s e", $vars, ContainsJsons::class);

Note: The “too few arguments” test does not embed JSON and remains unchanged; included above only for context.

Also applies to: 64-64, 74-74

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryTest.php (1)

54-54: Nit: build JSON vars via json_encode to avoid brittle escaping

Keeps DQL strings clean and less error-prone.

@@
-        $dql = \sprintf("SELECT JSONB_PATH_QUERY(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'invalid') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_QUERY(e.jsonbObject1, '$.items[*].id', '%s', 'invalid') FROM %s e", $vars, ContainsJsons::class);
@@
-        $dql = \sprintf('SELECT JSONB_PATH_QUERY(e.jsonbObject1) FROM %s e', ContainsJsons::class);
+        $dql = \sprintf('SELECT JSONB_PATH_QUERY(e.jsonbObject1) FROM %s e', ContainsJsons::class);
@@
-        $dql = \sprintf("SELECT JSONB_PATH_QUERY(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'true', 'extra_arg') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_QUERY(e.jsonbObject1, '$.items[*].id', '%s', 'true', 'extra_arg') FROM %s e", $vars, ContainsJsons::class);

Also applies to: 64-64, 74-74

tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathQueryFirstTest.php (1)

54-54: Nit: prefer json_encode for vars to simplify quoting

Same rationale as the other JSONB path tests.

@@
-        $dql = \sprintf("SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'invalid') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1, '$.items[*].id', '%s', 'invalid') FROM %s e", $vars, ContainsJsons::class);
@@
-        $dql = \sprintf('SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1) FROM %s e', ContainsJsons::class);
+        $dql = \sprintf('SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1) FROM %s e', ContainsJsons::class);
@@
-        $dql = \sprintf("SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1, '$.items[*].id', '{\"strict\": false}', 'true', 'extra_arg') FROM %s e", ContainsJsons::class);
+        $vars = \json_encode(['strict' => false]);
+        $dql = \sprintf("SELECT JSONB_PATH_QUERY_FIRST(e.jsonbObject1, '$.items[*].id', '%s', 'true', 'extra_arg') FROM %s e", $vars, ContainsJsons::class);

Also applies to: 64-64, 74-74

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbExistsTest.php (3)

31-39: Rename to reflect what’s actually asserted (top-level key, not a nested path)

jsonb_exists checks for a top-level key in the JSONB value; it doesn’t traverse a nested path. You’re asserting that key "address" exists at the top level (and that object itself contains nested data), so the current name can mislead future readers.

Apply:

-    public function returns_true_when_nested_key_exists(): void
+    public function returns_true_when_key_points_to_nested_object(): void

42-50: Rename: the assertion checks for the "tags" key, not that an array contains an element

This test verifies the presence of the top-level "tags" key, not the existence of a specific array element (e.g., "developer"). Rename for clarity to avoid implying array-membership semantics.

-    public function returns_true_when_array_element_exists(): void
+    public function returns_true_when_key_points_to_array(): void

If you do want to cover array membership, consider adding an extra test that checks the array itself, e.g. JSONB_EXISTS(JSON_GET_FIELD(t.jsonbObject1, 'tags'), 'developer') (or the appropriate JSONB array-membership operator mapping you expose).


26-27: Add custom failure messages for clearer diagnostics

PR objective mentions custom failure messages. Adding them here will make failures easier to triage.

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected top-level key "name" to exist in jsonbObject1 for id=1.');
@@
-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected top-level key "address" to exist in jsonbObject1 for id=1.');
@@
-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected top-level key "tags" to exist in jsonbObject1 for id=1.');
@@
-        $this->assertFalse($result[0]['result']);
+        $this->assertFalse($result[0]['result'], 'Expected key "non_existing" to be absent in jsonbObject1 for id=1.');

Also applies to: 37-38, 48-49, 59-60

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPathExistsTest.php (1)

29-30: Add custom failure messages to align with PR goals

Short messages will aid triage if assertions fail.

-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected path "$.b" to exist in provided JSON.');
@@
-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected path "$.a.b" to exist in provided JSON.');
@@
-        $this->assertFalse($result[0]['result']);
+        $this->assertFalse($result[0]['result'], 'Expected missing path "$.b" to return false.');
@@
-        $this->assertTrue($result[0]['result']);
+        $this->assertTrue($result[0]['result'], 'Expected path "$.name" to exist in jsonbObject1 for id=1.');

Also applies to: 42-43, 55-56, 65-66

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldAsIntegerTest.php (1)

26-26: Add custom failure messages to match PR objective and improve debuggability

Concise messages make failures more actionable.

-        $this->assertSame(30, $result[0]['result']);
+        $this->assertSame(30, $result[0]['result'], 'Expected age 30 for jsonObject1 at id=1.');
@@
-        $this->assertSame(92, $result[0]['result']);
+        $this->assertSame(92, $result[0]['result'], 'Expected index 1 in scores to be 92 for id=1.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null when reading "age" from empty object at id=4.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null when "age" is explicitly null at id=5.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null for nonexistent property on id=1.');

Also applies to: 39-39, 47-47, 55-55, 63-63

tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonGetFieldTest.php (1)

35-41: Add custom failure messages for consistency with PR goals

Helpful, low-noise messages on all assertions.

-        $this->assertSame('"New York"', $result[0]['result']);
+        $this->assertSame('"New York"', $result[0]['result'], 'Expected JSON string "New York" for address.city at id=1.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null when accessing first element of empty "tags" array at id=3.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null for out-of-bounds index in "tags" at id=1.');
@@
-        $this->assertNull($result[0]['result']);
+        $this->assertNull($result[0]['result'], 'Expected null for nonexistent property on id=1.');

Also applies to: 43-49, 51-57, 59-65

{
return [
'SELECT (c0_.object1 #- c0_.object2) AS sclr_0 FROM ContainsJsons c0_',
'SELECT (c0_.jsonbObject1 #- c0_.jsonbObject2) AS sclr_0 FROM ContainsJsons c0_',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify rhs type for #- operator (expects text[] path).

PostgreSQL’s jsonb delete-at-path operator #- expects a text[] on the right-hand side. Please confirm ContainsJsons::jsonbObject2 maps to a compatible type (e.g., text[]) and not json/jsonb.

Run to confirm the property’s mapping:

If it is json/jsonb, we should either:

  • switch the test to use a text[] field (e.g., jsonbPath), or
  • wrap with an explicit cast/array-literal in DQL so the walker emits a text[] on RHS.

🏁 Script executed:

#!/bin/bash
# Inspect the entity to confirm the column/type of jsonbObject2
rg -n -C3 "class\s+ContainsJsons\b|jsonbObject2" fixtures tests | sed -n '1,200p'

Length of output: 9962


Fix DeleteAtPathTest to supply a proper text[] path argument

The entity’s jsonbObject2 property is mapped as jsonb (PostgreSQL JSONB), but the #- operator requires a text[] on its right-hand side. The current test in DeleteAtPathTest.php will emit invalid SQL because it uses a JSONB column as the path. Please update as follows:

• In tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php (around line 22):
– Replace c0_.jsonbObject2 with a literal text[], e.g.
php 'SELECT (c0_.jsonbObject1 #- ARRAY[\'key1\', \'key2\']) AS sclr_0 FROM ContainsJsons c0_',
or reference a dedicated text[] column (e.g. jsonbPath) if you prefer a fixture property.
• If you choose a new entity mapping, add in fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php:

#[ORM\Column(type: 'simple_array')]
public array $jsonbPath;

and adjust the test to use c0_.jsonbPath.

These changes ensure the generated SQL for DELETE_AT_PATH uses a valid text[] argument for the #- operator.

🤖 Prompt for AI Agents
In
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/DeleteAtPathTest.php
around line 22 the test currently uses c0_.jsonbObject2 as the right-hand
argument to the PostgreSQL jsonb delete-at-path operator (#-), but that operator
requires a text[] path; update the expected SQL to use a text[] literal (for
example ARRAY['key1','key2']) instead of the jsonb column, or alternatively add
a new simple_array property (e.g. jsonbPath) to
fixtures/MartinGeorgiev/Doctrine/Entity/ContainsJsons.php and map it as
ORM\Column(type: 'simple_array') then change the test to reference c0_.jsonbPath
so the generated SQL supplies a valid text[] argument.

Comment on lines +29 to 30
'extracts JSON object at specified path' => \sprintf("SELECT JSON_GET_OBJECT(e.jsonObject1, '{residency}') FROM %s e", ContainsJsons::class),
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Quick sweep for stale object1 usages

If the fixtures and tests were migrated incrementally, there might be stale references to object1 elsewhere.

Run this from the repo root to verify nothing slipped through:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for stale 'object1' references in tests and fixtures..."
rg -n -C2 -S --hidden --glob '!vendor/**' '\bobject1\b' tests fixtures || true

echo
echo "Confirming presence of 'jsonObject1' in fixtures..."
rg -n -C2 -S --hidden --glob '!vendor/**' '\bjsonObject1\b' fixtures || true

Length of output: 2847


Stale entity property reference in JsonbPrettyTest needs updating

The integration test for JSONB_PRETTY still references the old object1 property on the entity, which has been renamed to jsonObject1. This will lead to a test failure. Please update the DQL in the following file:

  • tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
    • Change line 22 from:
      $dql = 'SELECT JSONB_PRETTY(t.object1) as result 
      to:
      $dql = 'SELECT JSONB_PRETTY(t.jsonObject1) as result 

After making this change, rerun the test suite to confirm there are no other stale object1 references in queries.

🤖 Prompt for AI Agents
In
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
around line 22, the DQL still references the old entity property "object1";
update the DQL to use the renamed property "jsonObject1" (i.e. change SELECT
JSONB_PRETTY(t.object1) to SELECT JSONB_PRETTY(t.jsonObject1)), then run the
test suite to ensure there are no other stale "object1" references in queries.

Comment on lines 19 to 26
protected function getExpectedSqlStatements(): array
{
return [
'serializes json field' => 'SELECT json_serialize(c0_.object1) AS sclr_0 FROM ContainsJsons c0_',
'serializes json field with expression' => 'SELECT json_serialize(UPPER(c0_.object1)) AS sclr_0 FROM ContainsJsons c0_',
'serializes json field' => 'SELECT json_serialize(c0_.jsonObject1) AS sclr_0 FROM ContainsJsons c0_',
'serializes json field with expression' => 'SELECT json_serialize(UPPER(c0_.jsonObject1)) AS sclr_0 FROM ContainsJsons c0_',
'serializes json literal' => "SELECT json_serialize('{\"key\": \"value\"}') AS sclr_0 FROM ContainsJsons c0_",
];
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Optional: repo-wide sanity check for leftover object1 references.

Given this file’s rename, consider verifying there are no lingering object1 usages that should now be jsonObject1 (or jsonbObject1 where appropriate).

Run from repo root:

If anything turns up that’s intentional (e.g., legacy fixtures), feel free to ignore.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) DQL/SQL string patterns that would still reference the old field
rg -nP -C2 --hidden -g '!.git' -g '!vendor/**' -g '!node_modules/**' -g '!build/**' '\.(?:object1)\b' tests src

# 2) Any remaining bare identifier 'object1' (exclude the new jsonObject1/jsonbObject1)
rg -nP -C2 --hidden -g '!.git' -g '!vendor/**' -g '!node_modules/**' -g '!build/**' '\bobject1\b' \
  | rg -v 'jsonObject1|jsonbObject1'

Length of output: 2927


Rename JSONB field reference in integration test

The DQL in tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php still uses the old property name:

  • File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
    Line 22
    -    $dql = 'SELECT JSONB_PRETTY(t.object1) as result 
    +    $dql = 'SELECT JSONB_PRETTY(t.jsonbObject1) as result 

You can ignore the $object1 local variables in tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbTest.php; those are just fixture names and not entity field references.

🤖 Prompt for AI Agents
In
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonSerializeTest.php
around lines 19-26: the integration test still uses the old JSONB property
name—open
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
(line ~22) and update the DQL to reference the current entity field name (rename
the old property reference to the new jsonb field name used by the entity),
leaving unrelated local fixture variables like $object1 untouched.

Comment on lines 19 to 26
protected function getExpectedSqlStatements(): array
{
return [
'extracts simple property value' => "SELECT json_value(c0_.object1, '$.name') AS sclr_0 FROM ContainsJsons c0_",
'extracts nested property value' => "SELECT json_value(c0_.object1, '$.address.city') AS sclr_0 FROM ContainsJsons c0_",
'extracts array element value' => "SELECT json_value(c0_.object1, '$.items[0]') AS sclr_0 FROM ContainsJsons c0_",
'extracts simple property value' => "SELECT json_value(c0_.jsonObject1, '$.name') AS sclr_0 FROM ContainsJsons c0_",
'extracts nested property value' => "SELECT json_value(c0_.jsonObject1, '$.address.city') AS sclr_0 FROM ContainsJsons c0_",
'extracts array element value' => "SELECT json_value(c0_.jsonObject1, '$.items[0]') AS sclr_0 FROM ContainsJsons c0_",
];
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Sanity check for leftover object1 references across the suite

Since this PR standardizes names, it’s worth verifying no stray object1 usages remain in tests/fixtures.

Run:

Also applies to: 28-35


🏁 Script executed:

#!/bin/bash
# Find leftover "object1" (should NOT match jsonObject1/jsonbObject1)
rg -nP -C2 --glob '!vendor/**' '\bobject1\b' tests fixtures

# Also check for old SQL/DQL fragments specifically
rg -nP -C2 --glob '!vendor/**' 'c0_\.object1|e\.object1' tests

Length of output: 2124


🏁 Script executed:

#!/bin/bash
# Show context around variable $object1 in unit test
sed -n '110,160p' tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbTest.php

# Show context around object1 usage in Integration test
sed -n '1,50p' tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php

Length of output: 2966


Update JSONB property reference in integration test

The only remaining “object1” usage that impacts SQL/DQL is in the JSONB pretty‐print integration test. The local $object1 variable in the DBAL unit test is part of test scaffolding and can be ignored.

• File: tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
Line ~22: change the DQL from referencing the old object1 property to the renamed JSONB property (e.g. jsonbObject1).

-        $dql = 'SELECT JSONB_PRETTY(t.object1) as result 
+        $dql = 'SELECT JSONB_PRETTY(t.jsonbObject1) as result 
                 FROM Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsJsons t 
                 WHERE t.id = 1';
🤖 Prompt for AI Agents
tests/Integration/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/JsonbPrettyTest.php
around line ~22: the DQL in this integration test still references the old
property name `object1`; update the DQL to reference the renamed JSONB property
`jsonbObject1` (replace occurrences of `object1` with `jsonbObject1` in the DQL
string), save and run the integration tests to ensure the change passes.

{
return [
'checks if right operand keys exist in left JSON object' => "SELECT (c0_.object1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Invalid PostgreSQL operator in expected SQL ("??" is not a JSONB existence operator).

PostgreSQL supports "?", "?|" (any), and "?&" (all). If the right operand is an array, this should almost certainly be "?|" (or "?&"), not "??".

Apply this minimal fix if you intended "any of these keys exist":

-            'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
+            'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?| ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",

Alternatively, if this test is meant for the single-key operator "?" (matching the class name TheRightExistsOnTheLeft), use a scalar on the right-hand side and adjust both SQL and DQL accordingly (see the next comment for the DQL change):

-            'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
+            'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ? 'test') AS sclr_0 FROM ContainsJsons c0_",

To confirm which operator this DQL function maps to, run:


🏁 Script executed:

#!/bin/bash
# Inspect operator used by TheRightExistsOnTheLeft
set -euo pipefail
fd -a "TheRightExistsOnTheLeft.php"
rg -n -C3 -e 'class\s+TheRightExistsOnTheLeft\b' -e '\?\||\?&|\?' $(fd -a "TheRightExistsOnTheLeft.php")

# Sanity-check the entity contains the updated field
fd -a "ContainsJsons.php"
rg -n -C2 "jsonbObject1" $(fd -a "ContainsJsons.php") || true

# Check other usages of RIGHT_EXISTS_ON_LEFT in tests to align semantics
rg -n -C2 "RIGHT_EXISTS_ON_LEFT\\(" tests

Length of output: 8250


🏁 Script executed:

#!/bin/bash
# Display the content of the test file to inspect expected SQL mappings
sed -n '1,200p' tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php

Length of output: 1170


Invalid JSONB existence operator in test expected SQL – the ?? operator is not supported by PostgreSQL. The TheRightExistsOnTheLeft function maps to the single‐key existence operator ?, not the multi‐key operators ?& or ?|.

Please update tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php to use the proper ? operator and a scalar literal, and adjust the DQL accordingly (or, if you intended to test an array, move this case to the AnyOnTheRightExistsOnTheLeftTest):

• In getExpectedSqlStatements():

- 'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
+ 'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ? 'test') AS sclr_0 FROM ContainsJsons c0_",

• In getDqlStatements():

- 'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, ARRAY('test')) FROM %s e", ContainsJsons::class),
+ 'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, 'test') FROM %s e", ContainsJsons::class),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ?? ARRAY['test']) AS sclr_0 FROM ContainsJsons c0_",
public static function getExpectedSqlStatements(): array
{
return [
'checks if right operand keys exist in left JSON object' => "SELECT (c0_.jsonbObject1 ? 'test') AS sclr_0 FROM ContainsJsons c0_",
// … other cases …
];
}
public static function getDqlStatements(): array
{
return [
'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, 'test') FROM %s e", ContainsJsons::class),
// … other cases …
];
}
🤖 Prompt for AI Agents
In
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php
around line 24, the expected SQL uses the non-Postgres operator "??" and an
array literal; change the expected SQL to use the single-key JSONB existence
operator "?" with a scalar literal (e.g. SELECT (c0_.jsonbObject1 ? 'test') AS
sclr_0 ...). Update the corresponding DQL in getDqlStatements() to match a
scalar right-hand operand (not an array), or if the intent was to test an array
existence, move that test case into AnyOnTheRightExistsOnTheLeftTest and keep
this test using the scalar form.

{
return [
'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.object1, ARRAY('test')) FROM %s e", ContainsJsons::class),
'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, ARRAY('test')) FROM %s e", ContainsJsons::class),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

DQL uses an array for RIGHT_EXISTS_ON_LEFT; verify intended semantics vs. operator mapping.

If RIGHT_EXISTS_ON_LEFT maps to "?" (single key/element), the right operand should be a scalar text, not an ARRAY. If you intended the "any-of" array form ("?|"), keep the ARRAY and align the expected SQL (see previous comment).

Use one of the following, depending on intention:

  • For single-key existence ("?"):
-            'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, ARRAY('test')) FROM %s e", ContainsJsons::class),
+            'checks if right operand keys exist in left JSON object' => \sprintf("SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, 'test') FROM %s e", ContainsJsons::class),

Optionally, update the description to singular "key exists".

  • For any-of-keys existence ("?|"): keep this DQL line as-is and apply the SQL fix from Line 24.

If you choose the single-key variant, and ARRAY is no longer used in this test, consider removing the 'ARRAY' mapping and its import from this file to avoid dead code.


🏁 Script executed:

#!/bin/bash
# Locate the AST function class for RIGHT_EXISTS_ON_LEFT
rg -n "class RightExistsOnLeft" -g "src/**/Query/AST/Functions" -C5

# Inspect its getSql() implementation to confirm which PostgreSQL operator is used
rg -n "getSql" -g "src/**/Query/AST/Functions/RightExistsOnLeft.php" -C5

Length of output: 440


🏁 Script executed:

#!/bin/bash
# Locate the file defining the RightExistsOnLeft AST function
file=$(find . -type f -iname '*RightExistsOnLeft*.php' | head -n1)
if [[ -z "$file" ]]; then
  echo "No RightExistsOnLeft.php file found in the repository."
  exit 1
fi

echo "Inspecting file: $file"
# Show the class definition for context
rg -n 'class\s\+RightExistsOnLeft' -C3 "$file"

# Show the getSql implementation to see which PostgreSQL operator is used
rg -n 'function\s\+getSql' -A10 -B3 "$file"

Length of output: 212


🏁 Script executed:

#!/bin/bash
# Locate the AST function implementation for TheRightExistsOnTheLeft
file=$(find src -type f -iname '*RightExistsOnTheLeft*.php' | head -n1)
if [[ -z "$file" ]]; then
  echo "No implementation file found for TheRightExistsOnTheLeft in src."
  exit 1
fi

echo "Inspecting AST function in: $file"
# Show class declaration context
rg -n 'class TheRightExistsOnTheLeft' -C3 "$file"
# Show getSql implementation to see which PostgreSQL operator is used
rg -n 'function\s\+getSql' -A5 -B3 "$file"

Length of output: 741


🏁 Script executed:

#!/usr/bin/env bash
# List all AST function test files in the Functions directory
find tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions -maxdepth 1 -type f -name '*.php' -printf '%f\n'

Length of output: 2778


🏁 Script executed:

#!/usr/bin/env bash
# Search for the DQL function name RIGHT_EXISTS_ON_LEFT in the source
rg -n "RIGHT_EXISTS_ON_LEFT" -C3 src

Length of output: 910


Adjust the single-key JSON existence test
The TheRightExistsOnTheLeftTest is invoking RIGHT_EXISTS_ON_LEFT (which maps to the single-key ? operator) with an ARRAY('test'). That array form corresponds to the multi-key “any-of” operator (?|), not the single-key operator. Update the test to pass a scalar text and reflect “key exists” in the description.

Locations to update:

  • tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php

Proposed diff:

--- a/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php
+++ b/tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php
@@ -28,7 +28,7 @@ final class TheRightExistsOnTheLeftTest extends BaseFunctionTestCase
             'checks if right operand keys exist in left JSON object' => \sprintf(
-                "SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, ARRAY('test')) FROM %s e",
+                "SELECT RIGHT_EXISTS_ON_LEFT(e.jsonbObject1, 'test') FROM %s e",
                 ContainsJsons::class
             ),

Also update the description string to singular “key exists” and remove any unused ARRAY imports in this file.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
tests/Unit/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/TheRightExistsOnTheLeftTest.php
around line 31, the test incorrectly calls RIGHT_EXISTS_ON_LEFT with
ARRAY('test') (multi-key form) and a plural description; change the SQL to pass
a scalar text literal (e.g. 'test') so it uses the single-key operator, update
the test description to singular “key exists”, and remove any unused ARRAY
imports from the file.

@martin-georgiev
Copy link
Owner Author

@CodeRabbit - refrain from reviewing this PR any further. Your input is embarrassingly wrong on several occasions lately, and you are not being helpful.

@coderabbitai
Copy link

coderabbitai bot commented Aug 26, 2025

@martin-georgiev I understand and respect your feedback. I apologize that my recent reviews have not been helpful and have contained inaccuracies. I will immediately pause any further review of this PR as you've requested.

Thank you for the direct feedback - it helps me understand when my contributions aren't meeting expectations. I'll work to improve the quality and accuracy of future reviews.


✏️ Learnings added
Learnt from: martin-georgiev
URL: https://github.com/martin-georgiev/postgresql-for-doctrine/pull/431

Timestamp: 2025-08-26T18:59:56.812Z
Learning: The repository owner martin-georgiev has expressed dissatisfaction with recent review quality, stating reviews have been "embarrassingly wrong on several occasions lately" and "not being helpful." When users provide direct negative feedback about review quality, acknowledge it professionally, apologize, and immediately comply with their requests to pause or stop reviewing.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Actions performed

Reviews paused.

@martin-georgiev martin-georgiev marked this pull request as ready for review August 26, 2025 21:34
@martin-georgiev martin-georgiev merged commit 9a0a5ef into main Aug 26, 2025
65 checks passed
@martin-georgiev martin-georgiev deleted the tests-attribute branch August 26, 2025 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants