-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[9.x] Add whereJsonContainsKey
to query builder
#41756
Conversation
What if the user does I believe we recently worked on a similar issue with another JSON clause builder /cc @derekmd |
TLDR; I may need to submit another PR before this one is merged. Here's a preliminary dev branch to fix Postgres support of JSON array indexes: https://github.com/laravel/framework/compare/9.x...derekmd:fix-postgres-json-paths-with-array-index?expand=1 Now this repo's GitHub Actions have Postgres & SQL Server test runs, some https://github.com/laravel/framework/tree/9.x/tests/Integration/Database cases should probably be added to execute actual database queries? My PR #38391 fixed allowing array index references: DB::table('users')
->whereJsonDoesntContainKey('options->languages[0]')
->get(); The new methods calling This isn't a huge deal since this compiles fine: DB::table('users')
->whereJsonDoesntContainKey('options->languages->0')
->get(); This PR's -- unexpected wrapping of array key inside the last segment
SELECT * FROM "users"
WHERE coalesce(("options"')::jsonb ?? 'language[0]', false) -- correct
SELECT * FROM "users"
WHERE coalesce(("options"->'language')::jsonb ?? 0, false) |
@taylorotwell I'm confused about implementing this feature for the arrays as |
Here's a sample integration test for Postgres where 3 of the 6 data sets currently don't pass: derekmd@fcb626f /**
* @dataProvider jsonContainsKeyDataProvider
*/
public function testWhereJsonContainsKey($count, $column)
{
DB::table('json_table')->insert([
['json_col' => '{"foo":{"bar":["baz"]}}'],
['json_col' => '{"foo":{"bar":false}}'],
['json_col' => '{"foo":{}}'],
]);
$this->assertSame($count, DB::table('json_table')->whereJsonContainsKey($column)->count());
}
public function jsonContainsKeyDataProvider()
{
return [
'key exists' => [3, 'json_col->foo'],
'nested key exists' => [2, 'json_col->foo->bar'],
'array key exists with arrow' => [1, 'json_col->foo->bar->0'],
'array key exists with braces' => [1, 'json_col->foo->bar[0]'],
'array key not exists' => [0, 'json_col->foo->bar[1]'],
'key not exists' => [0, 'json_col->none'],
];
}
For
|
Is it even possible to support numeric keys with this method across all drivers? |
Experimental commits with integration tests covering array integer keys: https://github.com/derekmd/framework/commits/query-where-json-contains-key MySQL/MariaDB👍 Supported and very straightforward with MySQL's SQL Server👍 Method PostgreSQL👍-ish, this is the most complicated implementation since Postgres functions differentiate between JSONB objects and arrays. Like SQL Server, the array index must be extracted from the column string. Also:
SQLite👍 Not implemented in this PR, but my branch shows SQLite is as straightforward as MySQL. |
Thanks @derekmd Getting a bit lost though, so this PR is not ready to merge? |
This PR is 80% there, I can finish the last 20% in another commit that can be merged into this. |
This PR adds a new function to the query builder to check JSON column type has the given key or not.
The syntax for keys is exactly like
whereJsonContains
.Sample codes: