feat: Port whereJsonContainsKey methods + CompilesJsonPaths from Laravel#7699
Merged
limingxinleo merged 14 commits intohyperf:masterfrom Jan 25, 2026
Merged
Conversation
Add whereJsonContainsKey, orWhereJsonContainsKey, whereJsonDoesntContainKey, and orWhereJsonDoesntContainKey methods to Query Builder.
Add compileJsonContainsKey method to base Grammar (throws by default) and implement for MySQL, PostgreSQL, and SQLite drivers.
Add tests for MySQL, PostgreSQL, and SQLite grammars covering whereJsonContainsKey, orWhereJsonContainsKey, whereJsonDoesntContainKey, and orWhereJsonDoesntContainKey methods.
- Rename ContainerStub to SwooleExtContainerStub (tests deprecated extension) - Rename DatabasePostgresBuilderTest to DatabasePostgresSwooleExtQueryBuilderTest - Create new ContainerStub for PDO driver - Create new DatabasePostgresQueryBuilderTest for PDO driver tests - Rename DatabaseSQLiteQueryGrammarTest to DatabaseSQLiteQueryBuilderTest The old names were inconsistent with the database package naming. Schema Builder tests use "BuilderTest", Query Builder tests use "QueryBuilderTest".
Rename query builder test classes to match SchemaBuilderTest naming: - DatabasePostgresQueryBuilderTest → QueryBuilderTest - DatabasePostgresSwooleExtQueryBuilderTest → SwooleExtQueryBuilderTest - DatabaseSQLiteQueryBuilderTest → QueryBuilderTest
…BuilderTest Consistent with database and database-pgsql packages.
…SwooleExtContainerStub
…sQueryGrammarTest
whereJsonContainsKey methods from Laravel + fix PostgreSQL / SQLite test structurewhereJsonContainsKey methods from Laravel + fix wrapJsonPath
…dex support - Update Grammar::wrapJsonPath() + add wrapJsonPathSegment() to properly parse array indices (e.g., `foo[0]` → `"foo"[0]` instead of `"foo[0]"`) - Update PostgresGrammar::wrapJsonPathAttributes() + add parseJsonPathArrayKeys() - Fix incorrect test expectation for array indices to match Laravel behavior - Add array index tests for MySQL, PostgreSQL, and SQLite Reference: laravel/framework DatabaseQueryBuilderTest.php:6682-6683
whereJsonContainsKey methods from Laravel + fix wrapJsonPathwhereJsonContainsKey methods + CompilesJsonPaths from Laravel
…pilation Port Laravel's CompilesJsonPaths trait pattern to eliminate code duplication between Query Grammar and Schema Grammar classes. - Create CompilesJsonPaths trait with wrapJsonFieldAndPath, wrapJsonPath, and wrapJsonPathSegment methods - Use trait in Query Grammar (removes 51 lines of duplicated code) - Use trait in Schema Grammar base class - Remove duplicated methods from SQLite Schema Grammar (46 lines) - Remove unused Str import from SQLite Schema Grammar
…ssing tests - Fix compileJsonUpdateColumn to use wrapJsonPathAttributes for proper array index parsing in UPDATE queries - Cast $i to int in compileJsonContainsKey for strict_types compatibility - Add testMySqlUpdateWrappingJsonPathArrayIndex test - Add testJsonPathEscaping test - Add testPostgresUpdateWrappingJsonPathArrayIndex test - Add testSQLiteUpdateWrappingJsonPathArrayIndex test - Add PostgreSQL negative array index tests ([-1]) for whereJsonContainsKey and whereJsonDoesntContainKey
Member
|
周末处理 |
limingxinleo
approved these changes
Jan 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds 4 missing Query Builder methods for checking if a JSON path exists:
whereJsonContainsKey()orWhereJsonContainsKey()whereJsonDoesntContainKey()orWhereJsonDoesntContainKey()These methods exist in Laravel but were missing from Hyperf.
Changes
1. New Builder Methods
Added to
src/database/src/Query/Builder.php:2. Grammar Support
Each database has different SQL syntax for this operation:
ifnull(json_contains_path(column, 'one', path), 0)coalesce((column)::jsonb ?? 'key', false)json_type(column, path) is not null3.
CompilesJsonPathsTraitPorted Laravel's new
CompilesJsonPathstrait to share improved JSON path compilation logic between Query Grammar and Schema Grammar classes.Why this was needed:
Hyperf's
wrapJsonPath(base Grammar) andwrapJsonPathAttributes(Postgres) were outdated and didn't handle array indices in JSON paths. For example,options->languages[0][1]was incorrectly treated as a single quoted key"languages[0][1]"instead of being parsed as"languages"[0][1].The fix required updating these methods, but they were duplicated across Query Grammar and SQLite Schema Grammar. Laravel solves this with a shared trait.
Changes:
CompilesJsonPathstrait insrc/database/src/Concerns/(matches Laravel's architecture)PostgresGrammar.php: UpdatedwrapJsonPathAttributes()+ addedparseJsonPathArrayKeys()The trait contains:
wrapJsonFieldAndPath()- splits JSON selector into field and pathwrapJsonPath()- wraps JSON path with proper array index handlingwrapJsonPathSegment()- parses individual path segments including array indicesTest fix:
The existing MySQL test in
QueryBuilderTest.phphad an incorrect expectation that matched the buggy behavior:Laravel's test confirms the correct expectation: DatabaseQueryBuilderTest.php:6682-6683
4. PostgreSQL / SQLite Test Structure Fix
The
database-pgsqlanddatabase-sqlitetest files had two problems:Problem 1: Class names
The old names were not consistent. I renamed them to match Laravel's class names:
database-pgsql(old)SchemaBuilderTest❌DatabasePostgresBuilderTest❌database-pgsql(new)DatabasePostgresSchemaBuilderTest✓DatabasePostgresQueryBuilderTest✓database-sqlite(old)DatabaseSQLiteBuilderTest❌DatabaseSQLiteQueryGrammarTest❌database-sqlite(new)DatabaseSQLiteSchemaBuilderTest✓DatabaseSQLiteQueryBuilderTest✓I also removed a duplicate test class.
Problem 2: Postgres tests used deprecated Swoole extension
The main
ContainerStubandDatabasePostgresBuilderTesttest files used the deprecatedpgsql-swooledriver:Hyperf now uses PDO for PostgreSQL. The tests only run on Swoole < 6.0.
Solution:
Renamed old files to clearly show they test the deprecated extension:
ContainerStub.php→SwooleExtContainerStub.phpDatabasePostgresBuilderTest.php→DatabasePostgresSwooleExtQueryBuilderTest.phpCreated new files for PDO driver:
ContainerStub.php- usespgsqldriver with PDODatabasePostgresQueryBuilderTest.php- pure unit tests like Laravel (no database needed)Files Changed
New trait + JSON path fixes:
src/database/src/Concerns/CompilesJsonPaths.php- new trait (matches Laravel's architecture)src/database/src/Query/Grammars/Grammar.php- uses CompilesJsonPaths trait + new compile methodsrc/database/src/Schema/Grammars/Grammar.php- uses CompilesJsonPaths traitsrc/database-pgsql/src/Query/Grammars/PostgresGrammar.php- new compile method + wrapJsonPathAttributes improvementssrc/database-sqlite/src/Query/Grammars/SQLiteGrammar.php- new compile methodsrc/database-sqlite/src/Schema/Grammars/SQLiteGrammar.php- removed duplicate methods (now inherited via trait)New Builder methods:
src/database/src/Query/Builder.php- new whereJsonContainsKey methodssrc/database/src/Query/Grammars/MySqlGrammar.php- new compile methodTests:
src/database/tests/QueryBuilderTest.php- MySQL tests + fixed array index expectationsrc/database-pgsql/tests/Cases/DatabasePostgresQueryBuilderTest.php- new file with array index testssrc/database-sqlite/tests/DatabaseSQLiteQueryBuilderTest.php- renamed + array index tests