Skip to content

Conversation

@martin-georgiev
Copy link
Owner

@martin-georgiev martin-georgiev commented Sep 6, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Correctly escape and quote JSON values when storing JSONB arrays, preventing malformed data.
    • Properly interpret empty database arrays as empty arrays in the application.
  • Tests

    • Added integration tests covering simple, nested, and mixed JSONB array content.
    • Updated unit tests to align with the new serialized representation of JSONB array elements.

@coderabbitai
Copy link

coderabbitai bot commented Sep 6, 2025

Warning

Rate limit exceeded

@martin-georgiev has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 16 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 32c5116 and 595edf6.

📒 Files selected for processing (3)
  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php (2 hunks)
  • src/MartinGeorgiev/Utils/PostgresJsonToPHPArrayTransformer.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php (1 hunks)

Walkthrough

Updates JsonbArray type to quote/escape JSON elements for Postgres arrays and to handle empty array literals. Parsing now delegates to PostgresArrayToPHPArrayTransformer except for {}. Adds an integration test for JSONB[] mappings and adjusts a unit test’s expected serialized Postgres value.

Changes

Cohort / File(s) Summary
JSONB[] type implementation
src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php
Import PostgresArrayToPHPArrayTransformer; update @see link; quote and escape JSON per element in transformArrayItemForPostgres; handle {} as empty array; delegate non-empty parsing to PostgresArrayToPHPArrayTransformer.
Integration tests for JSONB[]
tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php
New integration test validating JSONB[] mappings with diverse payloads via data provider and ArrayTypeTestCase.
Unit test expectation update
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTest.php
Adjust expected Postgres serialization to quoted, escaped JSON object elements within the array.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Application
  participant ORM as Doctrine DBAL
  participant Type as JsonbArray Type
  participant PG as PostgreSQL

  rect rgb(235, 245, 255)
  note over Type: Write path (PHP -> Postgres)
  App->>ORM: persist entity with PHP array of JSON-able values
  ORM->>Type: convertToDatabaseValue()
  Type->>Type: transformArrayItemForPostgres()<br/>- JSON encode<br/>- escape \" and \\<br/>- quote each element
  Type->>PG: send JSONB[] literal (e.g., {"\"{...}\"", ...})
  end

  rect rgb(245, 235, 255)
  note over Type: Read path (Postgres -> PHP)
  PG-->>ORM: returns JSONB[] text literal (e.g., {...} or {})
  ORM->>Type: convertToPHPValue()
  alt Empty array literal {}
    Type->>ORM: return []
  else Non-empty
    Type->>Type: PostgresArrayToPHPArrayTransformer::transform()
    Type->>ORM: return PHP array of decoded JSON values
  end
  ORM->>App: hydrated values
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

In curly braces, bytes now gleam,
Each JSON wrapped—an orderly dream.
I twitch my ears at brackets tight,
Empty {}? Hop—alright!
From burrowed tests to types that sing,
Escapes and quotes now do their thing. 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jsonbarray-bug

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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 (4)
src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php (3)

26-31: Escaping is correct; simplify with strtr (minor)

Functionally sound. You can trim an intermediate variable and use strtr for a tiny win.

-        $json = $this->transformToPostgresJson($item);
-        $escaped = \str_replace(['\\', '"'], ['\\\\', '\\"'], $json);
-
-        return '"'.$escaped.'"';
+        return '"'.\strtr(
+            $this->transformToPostgresJson($item),
+            ['\\' => '\\\\', '"' => '\\"']
+        ).'"';

35-41: Redundant '{}' check (optional cleanup)

PostgresArrayToPHPArrayTransformer already returns [] for '{}' (and trims/validates). You can delegate unconditionally.

-        $trimmed = \trim($postgresArray);
-        if ($trimmed === '{}') {
-            return [];
-        }
-
-        return PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresArray);
+        return PostgresArrayToPHPArrayTransformer::transformPostgresArrayToPHPArray($postgresArray);

46-49: Consider preserving big integers when decoding JSON items (consistency)

Elsewhere (PostgresArrayToPHPArrayTransformer) big ints are preserved via JSON_BIGINT_AS_STRING; here JSON decode doesn’t use it, which can coerce large numbers. If you aim for consistency across paths, enable it in PostgresJsonToPHPArrayTransformer.

Outside this file (proposal):

--- a/src/MartinGeorgiev/Utils/PostgresJsonToPHPArrayTransformer.php
+++ b/src/MartinGeorgiev/Utils/PostgresJsonToPHPArrayTransformer.php
@@ public static function transformPostgresJsonEncodedValueToPHPArray(string $postgresValue): array
-            $transformedValue = \json_decode($postgresValue, true, 512, JSON_THROW_ON_ERROR);
+            $transformedValue = \json_decode($postgresValue, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
@@ public static function transformPostgresJsonEncodedValueToPHPValue(string $postgresValue): array|bool|float|int|string|null
-            return \json_decode($postgresValue, true, 512, JSON_THROW_ON_ERROR);
+            return \json_decode($postgresValue, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php (1)

32-65: Add edge-case dataset for escaping (quotes, backslashes, braces, commas, newlines)

To lock in the fix and prevent regressions around quoting, add a dataset with tricky characters.

         return [
@@
             'jsonb array with mixed types' => ['jsonb array with mixed types', [
                 [
                     'string' => 'value',
                     'number' => 42,
                     'boolean' => false,
                     'null' => null,
                     'array' => [1, 2, 3],
                     'object' => ['a' => 1],
                 ],
                 [
                     'different' => 'structure',
                     'count' => 999,
                     'enabled' => true,
                 ],
             ]],
+            'escaping edge cases' => ['escaping edge cases', [
+                [
+                    'text' => 'quote " and backslash \\ and braces {} and comma ,',
+                    'path' => 'C:\\tmp\\file.txt',
+                    'multiline' => "line1\nline2",
+                    'json' => ['nested' => ['quote' => '"', 'backslash' => '\\']],
+                ],
+                [
+                    'raw' => '{}',
+                    'nested' => ['brace' => '{}', 'comma' => ','],
+                ],
+            ]],
         ];
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 745b269 and 32c5116.

📒 Files selected for processing (3)
  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php (2 hunks)
  • tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php (1 hunks)
  • tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTest.php (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#421
File: docs/AVAILABLE-TYPES.md:31-33
Timestamp: 2025-08-19T13:07:15.184Z
Learning: In martin-georgiev/postgresql-for-doctrine, the point[] array type should be documented as "point[]" not "_point" in the AVAILABLE-TYPES.md table, to be consistent with all other array types like text[], jsonb[], inet[], etc.
📚 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/DBAL/Types/JsonbArrayTypeTest.php
  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php
📚 Learning: 2025-08-19T13:07:15.184Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#421
File: docs/AVAILABLE-TYPES.md:31-33
Timestamp: 2025-08-19T13:07:15.184Z
Learning: In martin-georgiev/postgresql-for-doctrine, the AVAILABLE-TYPES.md documentation table's second column shows DBAL type names (what getName() method returns) not PostgreSQL internal catalogue names. Array types use the format like 'text[]', 'jsonb[]', 'inet[]' - not the underscore-prefixed PostgreSQL internal names like '_text', '_jsonb', '_inet'.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php
  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php
📚 Learning: 2025-08-19T13:07:15.184Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#421
File: docs/AVAILABLE-TYPES.md:31-33
Timestamp: 2025-08-19T13:07:15.184Z
Learning: In martin-georgiev/postgresql-for-doctrine, the AVAILABLE-TYPES.md documentation table's second column shows DBAL type names (what TYPE_NAME constants contain and getName() method returns) not PostgreSQL internal catalogue names. Array types use the format like 'text[]', 'jsonb[]', 'inet[]' - not the underscore-prefixed PostgreSQL internal names like '_text', '_jsonb', '_inet'.

Applied to files:

  • tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php
  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.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/DBAL/Types/JsonbArrayTypeTest.php
  • tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTest.php
📚 Learning: 2025-08-19T13:07:15.184Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#421
File: docs/AVAILABLE-TYPES.md:31-33
Timestamp: 2025-08-19T13:07:15.184Z
Learning: In martin-georgiev/postgresql-for-doctrine, the point[] array type should be documented as "point[]" not "_point" in the AVAILABLE-TYPES.md table, to be consistent with all other array types like text[], jsonb[], inet[], etc.

Applied to files:

  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.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:

  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php
📚 Learning: 2025-03-25T01:23:29.749Z
Learnt from: martin-georgiev
PR: martin-georgiev/postgresql-for-doctrine#304
File: src/MartinGeorgiev/Utils/DataStructure.php:152-168
Timestamp: 2025-03-25T01:23:29.749Z
Learning: In PostgreSQL text arrays, backslashes must be escaped with triple backslashes. A single backslash in PHP like 'path\to\file' becomes "path\\\to\\\file" in PostgreSQL format.

Applied to files:

  • src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php
🧬 Code graph analysis (2)
tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php (2)
tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTest.php (5)
  • DataProvider (37-42)
  • DataProvider (44-49)
  • DataProvider (90-98)
  • Test (31-35)
  • provideValidTransformations (57-88)
tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/ArrayTypeTestCase.php (2)
  • ArrayTypeTestCase (9-40)
  • can_handle_array_values (33-39)
src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php (4)
src/MartinGeorgiev/Utils/PostgresArrayToPHPArrayTransformer.php (2)
  • PostgresArrayToPHPArrayTransformer (16-250)
  • transformPostgresArrayToPHPArray (29-90)
src/MartinGeorgiev/Utils/PostgresJsonToPHPArrayTransformer.php (2)
  • PostgresJsonToPHPArrayTransformer (17-65)
  • transformPostgresArrayToPHPArray (21-34)
src/MartinGeorgiev/Doctrine/DBAL/Types/JsonTransformer.php (1)
  • transformToPostgresJson (24-33)
src/MartinGeorgiev/Doctrine/DBAL/Types/BaseArray.php (1)
  • transformPostgresArrayToPHPArray (127-135)
⏰ 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: sloth
  • GitHub Check: PHP 8.2 + Doctrine ORM 2.14 + Doctrine Lexer latest
  • GitHub Check: PHP 8.1 + Doctrine ORM 2.18 + Doctrine Lexer latest
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.2
  • GitHub Check: PostgreSQL 16 + PostGIS 3.5 + PHP 8.3
  • 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.4 + PHP 8.3
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 17 + PostGIS 3.4 + PHP 8.4
  • GitHub Check: PostgreSQL 17 + PostGIS 3.5 + PHP 8.2
  • 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.1
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.2
  • GitHub Check: PostgreSQL 16 + PostGIS 3.4 + PHP 8.1
  • GitHub Check: wait-for-tests-worflows-before-upload
🔇 Additional comments (5)
src/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArray.php (2)

7-7: Right import to fix parsing path

Delegating array shell parsing to PostgresArrayToPHPArrayTransformer is the correct move and resolves the brittle split logic.


13-13: Doc link is helpful and accurate

The arrays doc reference is appropriate here.

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

85-85: Expected postgres literal now matches quoted/escaped element semantics

This aligns with the new per-element quoting. Looks good.

tests/Integration/MartinGeorgiev/Doctrine/DBAL/Types/JsonbArrayTypeTest.php (2)

17-20: Type name casing

'JSONB[]' is fine (PostgreSQL is case-insensitive). If other array tests use uppercase, keep as-is for consistency.


22-27: Round-trip hook looks good

Delegating to parent test ensures the canonical round trip for values.

coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 6, 2025
@coveralls
Copy link

coveralls commented Sep 6, 2025

Coverage Status

coverage: 95.39% (+0.007%) from 95.383%
when pulling 595edf6 on jsonbarray-bug
into 745b269 on main.

@martin-georgiev martin-georgiev changed the title fix: address fundamentally broken JsonbArray parsing fix: address broken escaping of PHP array items for JsonbArray and preserve integer values as strings if they are outside PHP integer range Sep 6, 2025
@martin-georgiev martin-georgiev changed the title fix: address broken escaping of PHP array items for JsonbArray and preserve integer values as strings if they are outside PHP integer range fix: address broken escaping of array items for JsonbArray and preserve integer values as strings if they are outside PHP integer range Sep 6, 2025
@martin-georgiev martin-georgiev merged commit d213967 into main Sep 6, 2025
65 of 66 checks passed
@martin-georgiev martin-georgiev deleted the jsonbarray-bug branch September 6, 2025 12:35
@github-actions github-actions bot mentioned this pull request Sep 6, 2025
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