From 00cb3d2c68ab144536ff0ec12b8a64dafd7582e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 18 Sep 2023 21:41:59 +0200 Subject: [PATCH 1/2] PHPORM-90 Fix whereNot to use $nor --- src/Query/Builder.php | 3 +- tests/Query/BuilderTest.php | 58 +++++++++++++++++++++---------------- tests/QueryTest.php | 39 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 1494a7345..a145ecb3e 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -1053,8 +1053,9 @@ protected function compileWheres(): array $method = 'compileWhere' . $where['type']; $result = $this->{$method}($where); + // Negate the expression if (str_ends_with($where['boolean'], 'not')) { - $result = ['$not' => $result]; + $result = ['$nor' => [$result]]; } // Wrap the where with an $or operator. diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 556239afc..2bfc03515 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -195,8 +195,8 @@ public static function provideQueryBuilderToMql(): iterable 'find' => [ [ '$and' => [ - ['$not' => ['name' => 'foo']], - ['$not' => ['name' => ['$ne' => 'bar']]], + ['$nor' => [['name' => 'foo']]], + ['$nor' => [['name' => ['$ne' => 'bar']]]], ], ], [], // options @@ -231,8 +231,8 @@ public static function provideQueryBuilderToMql(): iterable 'find' => [ [ '$or' => [ - ['$not' => ['name' => 'foo']], - ['$not' => ['name' => ['$ne' => 'bar']]], + ['$nor' => [['name' => 'foo']]], + ['$nor' => [['name' => ['$ne' => 'bar']]]], ], ], [], // options @@ -248,7 +248,7 @@ public static function provideQueryBuilderToMql(): iterable 'find' => [ [ '$or' => [ - ['$not' => ['name' => 'foo']], + ['$nor' => [['name' => 'foo']]], ['name' => ['$ne' => 'bar']], ], ], @@ -264,7 +264,7 @@ public static function provideQueryBuilderToMql(): iterable yield 'whereNot callable' => [ [ 'find' => [ - ['$not' => ['name' => 'foo']], + ['$nor' => [['name' => 'foo']]], [], // options ], ], @@ -278,7 +278,7 @@ public static function provideQueryBuilderToMql(): iterable [ '$and' => [ ['name' => 'bar'], - ['$not' => ['email' => 'foo']], + ['$nor' => [['email' => 'foo']]], ], ], [], // options @@ -295,10 +295,12 @@ public static function provideQueryBuilderToMql(): iterable [ 'find' => [ [ - '$not' => [ - '$and' => [ - ['name' => 'foo'], - ['$not' => ['email' => ['$ne' => 'bar']]], + '$nor' => [ + [ + '$and' => [ + ['name' => 'foo'], + ['$nor' => [['email' => ['$ne' => 'bar']]]], + ], ], ], ], @@ -318,7 +320,7 @@ public static function provideQueryBuilderToMql(): iterable [ '$or' => [ ['name' => 'bar'], - ['$not' => ['email' => 'foo']], + ['$nor' => [['email' => 'foo']]], ], ], [], // options @@ -337,7 +339,7 @@ public static function provideQueryBuilderToMql(): iterable [ '$or' => [ ['name' => 'bar'], - ['$not' => ['email' => 'foo']], + ['$nor' => [['email' => 'foo']]], ], ], [], // options @@ -353,10 +355,12 @@ public static function provideQueryBuilderToMql(): iterable [ 'find' => [ [ - '$not' => [ - '$and' => [ - ['foo' => 1], - ['bar' => 2], + '$nor' => [ + [ + '$and' => [ + ['foo' => 1], + ['bar' => 2], + ], ], ], ], @@ -371,10 +375,12 @@ public static function provideQueryBuilderToMql(): iterable [ 'find' => [ [ - '$not' => [ - '$and' => [ - ['foo' => 1], - ['bar' => 2], + '$nor' => [ + [ + '$and' => [ + ['foo' => 1], + ['bar' => 2], + ], ], ], ], @@ -389,10 +395,12 @@ public static function provideQueryBuilderToMql(): iterable [ 'find' => [ [ - '$not' => [ - '$and' => [ - ['foo' => 1], - ['bar' => ['$lt' => 2]], + '$nor' => [ + [ + '$and' => [ + ['foo' => 1], + ['bar' => ['$lt' => 2]], + ], ], ], ], diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 3d1df99f0..46056b797 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -6,6 +6,8 @@ use DateTimeImmutable; use LogicException; +use MongoDB\BSON\Regex; +use MongoDB\Laravel\Eloquent\Builder; use MongoDB\Laravel\Tests\Models\Birthday; use MongoDB\Laravel\Tests\Models\Scoped; use MongoDB\Laravel\Tests\Models\User; @@ -154,6 +156,43 @@ public function testSelect(): void $this->assertNull($user->age); } + public function testWhereNot(): void + { + // implicit equality operator + $users = User::whereNot('title', 'admin')->get(); + $this->assertCount(6, $users); + + // nested query + $users = User::whereNot(fn (Builder $builder) => $builder->where('title', 'admin'))->get(); + $this->assertCount(6, $users); + + // double negation + $users = User::whereNot('title', '!=', 'admin')->get(); + $this->assertCount(3, $users); + + // explicit equality operator + $users = User::whereNot('title', '=', 'admin')->get(); + $this->assertCount(6, $users); + + // custom query operator + $users = User::whereNot('title', ['$eq' => 'admin'])->get(); + $this->assertCount(6, $users); + + // regex + $users = User::whereNot('title', new Regex('^admin$'))->get(); + $this->assertCount(6, $users); + + // equals null + $users = User::whereNot('title', null)->get(); + $this->assertCount(8, $users); + + // nested $or + $users = User::whereNot(fn (Builder $builder) => $builder + ->where('title', 'admin') + ->orWhere('age', 35))->get(); + $this->assertCount(5, $users); + } + public function testOrWhere(): void { $users = User::where('age', 13)->orWhere('title', 'admin')->get(); From 3d29332d333157814e77a829d803a5639537c80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 19 Sep 2023 09:34:19 +0200 Subject: [PATCH 2/2] add double negation nested test --- tests/QueryTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 46056b797..a5e834e53 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -170,12 +170,17 @@ public function testWhereNot(): void $users = User::whereNot('title', '!=', 'admin')->get(); $this->assertCount(3, $users); + // nested negation + $users = User::whereNot(fn (Builder $builder) => $builder + ->whereNot('title', 'admin'))->get(); + $this->assertCount(3, $users); + // explicit equality operator $users = User::whereNot('title', '=', 'admin')->get(); $this->assertCount(6, $users); // custom query operator - $users = User::whereNot('title', ['$eq' => 'admin'])->get(); + $users = User::whereNot('title', ['$in' => ['admin']])->get(); $this->assertCount(6, $users); // regex