From 20684dfaf3bb8a1729fd376aa62594770b054751 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 17 Oct 2024 11:51:29 +1100 Subject: [PATCH 1/3] Revert "Ensure where with array respects boolean (#53147)" This reverts commit d62e92d781327bc2d272724f9f4be9dd62d5bceb. --- src/Illuminate/Database/Query/Builder.php | 2 +- tests/Database/DatabaseQueryBuilderTest.php | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index ff5c7be04605..49a68820ed9c 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -926,7 +926,7 @@ protected function addArrayOfWheres($column, $boolean, $method = 'where') return $this->whereNested(function ($query) use ($column, $method, $boolean) { foreach ($column as $key => $value) { if (is_numeric($key) && is_array($value)) { - $query->{$method}(...array_values($value), boolean: $boolean); + $query->{$method}(...array_values($value)); } else { $query->{$method}($key, '=', $value, $boolean); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index d635a7e2efc3..18ab730f2f69 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2323,30 +2323,15 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); - $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - $builder = $this->getBuilder(); $builder->select('*')->from('users')->where(['foo' => 1, 'bar' => 2]); $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where(['foo' => 1, 'bar' => 2], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); - $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]]); $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = ? or "bar" < ?)', $builder->toSql()); - $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); } public function testNestedWheres() From 14db3bbeeaac48adfe48dcdeb968df60db39f896 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 17 Oct 2024 11:56:16 +1100 Subject: [PATCH 2/3] Improve tests --- tests/Database/DatabaseQueryBuilderTest.php | 334 ++++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 18ab730f2f69..05bac123c3c8 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2316,22 +2316,356 @@ public function testWhereShortcut() $this->assertEquals([0 => 1, 1 => 'foo'], $builder->getBindings()); } + public function testItHasInconsistentResultsForOrWhereWithArray() + { + $queries = []; + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere(['foo' => 1, 'bar' => 2]); + $queries[] = $builder->toSql(); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', 2]]); + $queries[] = $builder->toSql(); + + $this->assertSame([ + 'select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', + 'select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" = ?)', + ], $queries); + + $queries = []; + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereColumn(['foo' => '_foo', 'bar' => '_bar']); + $queries[] = $builder->toSql(); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereColumn([['foo', '_foo'], ['bar', '_bar']]); + $queries[] = $builder->toSql(); + + $this->assertSame([ + 'select * from "users" where "xxxx" = ? or ("foo" = "_foo" or "bar" = "_bar")', + 'select * from "users" where "xxxx" = ? or ("foo" = "_foo" and "bar" = "_bar")', + ], $queries); + } + public function testWhereWithArrayConditions() { + /* + * where(key, value) + */ + $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]]); $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + $builder = $this->getBuilder(); $builder->select('*')->from('users')->where(['foo' => 1, 'bar' => 2]); $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where(['foo' => 1, 'bar' => 2], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where(['foo' => 1, 'bar' => 2], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + /* + * where(key, <, value) + */ + $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]]); $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + /* + * whereNot(key, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', 2]]); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', 2]], boolean: 'or'); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', 2]], boolean: 'and'); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot(['foo' => 1, 'bar' => 2]); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot(['foo' => 1, 'bar' => 2], boolean: 'or'); + $this->assertSame('select * from "users" where not (("foo" = ? or "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot(['foo' => 1, 'bar' => 2], boolean: 'and'); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + /* + * whereNot(key, <, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', '<', 2]]); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', '<', 2]], boolean: 'or'); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', '<', 2]], boolean: 'and'); + $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); + + /* + * whereColumn(col1, col2) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '_bar']]); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '_bar']], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '_bar']], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn(['foo' => '_foo', 'bar' => '_bar']); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn(['foo' => '_foo', 'bar' => '_bar'], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = "_foo" or "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn(['foo' => '_foo', 'bar' => '_bar'], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + /* + * whereColumn(col1, <, col2) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '<', '_bar']]); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + // boolean is not respected + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '<', '_bar']], boolean: 'or'); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '<', '_bar']], boolean: 'and'); + $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + + /* + * whereAll([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereAll(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereAll(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + /* + * whereAny([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereAny(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereAny(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + /* + * whereNone([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNone(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where not ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereNone(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where not ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 2, 1 => 2], $builder->getBindings()); + + /* + * where()->orWhere(key, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', 2]]); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere(['foo' => 1, 'bar' => 2]); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhere(key, <, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', '<', 2]]); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" < ?)', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereColumn(col1, col2) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereColumn([['foo', '_foo'], ['bar', '_bar']]); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([0 => "xxxx"], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereColumn(['foo' => '_foo', 'bar' => '_bar']); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = "_foo" or "bar" = "_bar")', $builder->toSql()); + $this->assertEquals([0 => "xxxx"], $builder->getBindings()); + + /* + * where()->orWhere(key, <, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhere([['foo', 1], ['bar', '<', 2]]); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" < ?)', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereNot(key, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNot([['foo', 1], ['bar', 2]]); + $this->assertSame('select * from "users" where "xxxx" = ? or not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNot(['foo' => 1, 'bar' => 2]); + $this->assertSame('select * from "users" where "xxxx" = ? or not (("foo" = ? or "bar" = ?))', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereNot(key, <, value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNot([['foo', 1], ['bar', '<', 2]]); + $this->assertSame('select * from "users" where "xxxx" = ? or not (("foo" = ? and "bar" < ?))', $builder->toSql()); + $this->assertEquals([0 => "xxxx", 1 => 1, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereAll([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAll(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAll(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereAny([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAny(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereAny(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); + + /* + * where()->orWhereNone([...keys], value) + */ + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNone(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or not ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); + + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('xxxx', 'xxxx')->orWhereNone(['foo', 'bar'], 2); + $this->assertSame('select * from "users" where "xxxx" = ? or not ("foo" = ? or "bar" = ?)', $builder->toSql()); + $this->assertEquals([0 => 'xxxx', 1 => 2, 2 => 2], $builder->getBindings()); } public function testNestedWheres() From 43a7098879d20aaa9fbb0ba8e97e97a143019608 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 17 Oct 2024 12:19:41 +1100 Subject: [PATCH 3/3] Respect boolean when using array syntax --- src/Illuminate/Database/Query/Builder.php | 21 ++++++++++++++++++--- tests/Database/DatabaseQueryBuilderTest.php | 18 ++++++------------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 49a68820ed9c..6f3e266e7a6f 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -919,19 +919,20 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' * @param array $column * @param string $boolean * @param string $method + * @param string|null $outerBoolean * @return $this */ - protected function addArrayOfWheres($column, $boolean, $method = 'where') + protected function addArrayOfWheres($column, $boolean, $method = 'where', $outerBoolean = null) { return $this->whereNested(function ($query) use ($column, $method, $boolean) { foreach ($column as $key => $value) { if (is_numeric($key) && is_array($value)) { - $query->{$method}(...array_values($value)); + $query->{$method}(...array_values($value), boolean: $boolean); } else { $query->{$method}($key, '=', $value, $boolean); } } - }, $boolean); + }, $outerBoolean ?? $boolean); } /** @@ -1004,6 +1005,10 @@ protected function isBitwiseOperator($operator) */ public function orWhere($column, $operator = null, $value = null) { + if (is_array($column)) { + return $this->addArrayOfWheres($column, array_is_list($column) ? 'and' : 'or', outerBoolean: 'or'); + } + [$value, $operator] = $this->prepareValueAndOperator( $value, $operator, func_num_args() === 2 ); @@ -1041,6 +1046,12 @@ public function whereNot($column, $operator = null, $value = null, $boolean = 'a */ public function orWhereNot($column, $operator = null, $value = null) { + if (is_array($column)) { + return $this->whereNested(function ($query) use ($column, $operator, $value) { + $query->where($column, $operator, $value, array_is_list($column) ? 'and' : 'or'); + }, 'or not'); + } + return $this->whereNot($column, $operator, $value, 'or'); } @@ -1091,6 +1102,10 @@ public function whereColumn($first, $operator = null, $second = null, $boolean = */ public function orWhereColumn($first, $operator = null, $second = null) { + if (is_array($first)) { + return $this->addArrayOfWheres($first, array_is_list($first) ? 'and' : 'or', 'whereColumn', outerBoolean: 'or'); + } + return $this->whereColumn($first, $operator, $second, 'or'); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 05bac123c3c8..b18ba296a504 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2358,10 +2358,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = ? and "bar" = ?)', $builder->toSql()); + $this->assertSame('select * from "users" where ("foo" = ? or "bar" = ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); $builder = $this->getBuilder(); @@ -2393,10 +2392,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->where([['foo', 1], ['bar', '<', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = ? and "bar" < ?)', $builder->toSql()); + $this->assertSame('select * from "users" where ("foo" = ? or "bar" < ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); $builder = $this->getBuilder(); @@ -2413,10 +2411,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where not (("foo" = ? and "bar" = ?))', $builder->toSql()); + $this->assertSame('select * from "users" where not (("foo" = ? or "bar" = ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); $builder = $this->getBuilder(); @@ -2448,10 +2445,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereNot([['foo', 1], ['bar', '<', 2]], boolean: 'or'); - $this->assertSame('select * from "users" where not (("foo" = ? and "bar" < ?))', $builder->toSql()); + $this->assertSame('select * from "users" where not (("foo" = ? or "bar" < ?))', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2], $builder->getBindings()); $builder = $this->getBuilder(); @@ -2468,10 +2464,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '_bar']], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" = "_bar")', $builder->toSql()); + $this->assertSame('select * from "users" where ("foo" = "_foo" or "bar" = "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); $builder = $this->getBuilder(); @@ -2503,10 +2498,9 @@ public function testWhereWithArrayConditions() $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); - // boolean is not respected $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereColumn([['foo', '_foo'], ['bar', '<', '_bar']], boolean: 'or'); - $this->assertSame('select * from "users" where ("foo" = "_foo" and "bar" < "_bar")', $builder->toSql()); + $this->assertSame('select * from "users" where ("foo" = "_foo" or "bar" < "_bar")', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); $builder = $this->getBuilder();