From 5d9cf9ca81f5985b90dcbaa4a9a3f81c2f471e7a Mon Sep 17 00:00:00 2001 From: Daniele Ambrosino Date: Sat, 16 Dec 2023 17:47:47 +0100 Subject: [PATCH] Add SQLite support for `whereJsonContains` method (#49401) --- .../Database/Query/Grammars/SQLiteGrammar.php | 25 +++++++++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 18 ++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index 8bf7d39f6935..b628d70d2b02 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -146,6 +146,31 @@ protected function compileJsonLength($column, $operator, $value) return 'json_array_length('.$field.$path.') '.$operator.' '.$value; } + /** + * Compile a "JSON contains" statement into SQL. + * + * @param string $column + * @param mixed $value + * @return string + */ + protected function compileJsonContains($column, $value) + { + [$field, $path] = $this->wrapJsonFieldAndPath($column); + + return 'exists (select 1 from json_each('.$field.$path.') where '.$this->wrap('json_each.value').' is '.$value.')'; + } + + /** + * Prepare the binding for a "JSON contains" statement. + * + * @param mixed $binding + * @return mixed + */ + public function prepareBindingForJsonContains($binding) + { + return $binding; + } + /** * Compile a "JSON contains key" statement into SQL. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index b05798eca8a7..011e22c99afb 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -5192,10 +5192,15 @@ public function testWhereJsonContainsPostgres() public function testWhereJsonContainsSqlite() { - $this->expectException(RuntimeException::class); + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->whereJsonContains('options', 'en')->toSql(); + $this->assertSame('select * from "users" where exists (select 1 from json_each("options") where "json_each"."value" is ?)', $builder->toSql()); + $this->assertEquals(['en'], $builder->getBindings()); $builder = $this->getSQLiteBuilder(); - $builder->select('*')->from('users')->whereJsonContains('options->languages', ['en'])->toSql(); + $builder->select('*')->from('users')->whereJsonContains('users.options->language', 'en')->toSql(); + $this->assertSame('select * from "users" where exists (select 1 from json_each("users"."options", \'$."language"\') where "json_each"."value" is ?)', $builder->toSql()); + $this->assertEquals(['en'], $builder->getBindings()); } public function testWhereJsonContainsSqlServer() @@ -5244,10 +5249,15 @@ public function testWhereJsonDoesntContainPostgres() public function testWhereJsonDoesntContainSqlite() { - $this->expectException(RuntimeException::class); + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->whereJsonDoesntContain('options', 'en')->toSql(); + $this->assertSame('select * from "users" where not exists (select 1 from json_each("options") where "json_each"."value" is ?)', $builder->toSql()); + $this->assertEquals(['en'], $builder->getBindings()); $builder = $this->getSQLiteBuilder(); - $builder->select('*')->from('users')->whereJsonDoesntContain('options->languages', ['en'])->toSql(); + $builder->select('*')->from('users')->whereJsonDoesntContain('users.options->language', 'en')->toSql(); + $this->assertSame('select * from "users" where not exists (select 1 from json_each("users"."options", \'$."language"\') where "json_each"."value" is ?)', $builder->toSql()); + $this->assertEquals(['en'], $builder->getBindings()); } public function testWhereJsonDoesntContainSqlServer()