From 04771b338e225b913cd94aa33f4f8845ac175602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 12 Jul 2023 16:42:18 +0200 Subject: [PATCH 1/8] PHPORM-47 Improve Builder::whereBetween to support CarbonPeriod and reject invalid array --- src/Query/Builder.php | 32 ++++++-- tests/Query/BuilderTest.php | 143 ++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index b5141a0..3c0c788 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -2,6 +2,7 @@ namespace Jenssegers\Mongodb\Query; +use Carbon\CarbonPeriod; use Closure; use DateTimeInterface; use Illuminate\Database\Query\Builder as BaseBuilder; @@ -554,11 +555,25 @@ public function whereAll($column, array $values, $boolean = 'and', $not = false) /** * @inheritdoc + * @param array{mixed, mixed}|CarbonPeriod $values */ public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { $type = 'between'; + if ($values instanceof Collection) { + $values = $values->all(); + } + + if (is_array($values)) { + if (! array_is_list($values)) { + throw new \InvalidArgumentException('Between array must a list with 2 elements: [min, max]'); + } + if (count($values) !== 2) { + throw new \InvalidArgumentException('Between array must have 2 elements: [min, max]'); + } + } + $this->wheres[] = compact('column', 'type', 'boolean', 'values', 'not'); return $this; @@ -995,11 +1010,18 @@ protected function compileWheres(): array } } } elseif (isset($where['values'])) { - array_walk_recursive($where['values'], function (&$item, $key) { - if ($item instanceof DateTimeInterface) { - $item = new UTCDateTime($item); - } - }); + if (is_array($where['values'])) { + array_walk_recursive($where['values'], function (&$item, $key) { + if ($item instanceof DateTimeInterface) { + $item = new UTCDateTime($item); + } + }); + } elseif ($where['values'] instanceof CarbonPeriod) { + $where['values'] = [ + new UTCDateTime($where['values']->getStartDate()), + new UTCDateTime($where['values']->getEndDate()), + ]; + } } // The next item in a "chain" of wheres devices the boolean of the diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index f7d12ad..ae3b8d4 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -5,6 +5,7 @@ namespace Jenssegers\Mongodb\Tests\Query; use DateTimeImmutable; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Tests\Database\DatabaseQueryBuilderTest; use Jenssegers\Mongodb\Connection; use Jenssegers\Mongodb\Query\Builder; @@ -124,6 +125,122 @@ function (Builder $builder) { ->orderBy('score', ['$meta' => 'textScore']), ]; + /** @see DatabaseQueryBuilderTest::testWhereBetweens() */ + yield 'whereBetween array of numbers' => [ + ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []]], + fn (Builder $builder) => $builder->whereBetween('id', [1, 2]), + ]; + + /* + yield 'whereBetween excessive nested array of numbers' => [ + ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []], + fn (Builder $builder) => $builder->whereBetween('id', [[1, 2, 3]]), + ]; + + yield 'whereBetween nested array of numbers' => [ + ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []]], + fn (Builder $builder) => $builder->whereBetween('id', [[1], [2, 3]]), + ]; + */ + + yield 'whereNotBetween array of numbers' => [ + ['find' => [['$or' => [['id' => ['$lte' => 1]], ['id' => ['$gte' => 2]]]], []]], + fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]), + ]; + + $period = now()->toPeriod(now()->addDay()); + yield 'whereBetween CarbonPeriod' => [ + ['find' => [['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], []]], + fn (Builder $builder) => $builder->whereBetween('created_at', $period), + ]; + + $period = now()->toPeriod(now()->addMonth()); + yield 'custom long carbon period date' => [ + ['find' => [['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], []]], + fn (Builder $builder) => $builder->whereBetween('created_at', $period), + ]; + + yield 'whereBetween collection' => [ + ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []]], + fn (Builder $builder) => $builder->whereBetween('id', collect([1, 2])), + ]; + + /** @see DatabaseQueryBuilderTest::testOrWhereBetween() */ + yield 'whereBetween array numbers' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]], []]], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereBetween('id', [3, 5]), + ]; + + /* + yield 'whereBetween excessive nested array numbers' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]], []], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereBetween('id', [[3, 4, 5]]), + ]; + + yield 'orWhereBetween nested array numbers' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]], []], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereBetween('id', [[3, 5]]), + ]; + + yield 'orWhereBetween nested excessive array numbers' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 4, '$lte' => 6]]]], []], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereBetween('id', [[4], [6, 8]]), + ]; + */ + + yield 'orWhereBetween collection' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]], []]], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereBetween('id', collect([3, 4])), + ]; + + /** @see DatabaseQueryBuilderTest::testOrWhereNotBetween() */ + yield 'orWhereNotBetween array of numbers' => [ + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]], []]], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereNotBetween('id', [3, 5]), + ]; + + /* + yield 'orWhereNotBetween excessive array of numbers' => [ + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]], []], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereNotBetween('id', [[3, 4, 5]]), + ]; + + yield 'orWhereNotBetween nested array of numbers' => [ + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]], []], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereNotBetween('id', [[3, 5]]), + ]; + */ + + yield 'orWhereNotBetween excessive nested array of numbers' => [ + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [4]]], ['id' => ['$gte' => [6, 8]]]]]]]]], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereNotBetween('id', [[4], [6, 8]]), + ]; + + yield 'orWhereNotBetween collection' => [ + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]], []]], + fn (Builder $builder) => $builder + ->where('id', '=', 1) + ->orWhereNotBetween('id', collect([3, 4])), + ]; + yield 'distinct' => [ ['distinct' => ['foo', [], []]], fn (Builder $builder) => $builder->distinct('foo'), @@ -154,6 +271,32 @@ public static function provideExceptions(): iterable 'Order direction must be "asc" or "desc"', fn (Builder $builder) => $builder->orderBy('_id', 'dasc'), ]; + + /** @see DatabaseQueryBuilderTest::testWhereBetweens */ + yield 'whereBetween array too short' => [ + \InvalidArgumentException::class, + 'Between array must have 2 elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', [1]), + ]; + + yield 'whereBetween array too long' => [ + \InvalidArgumentException::class, + 'Between array must have 2 elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', [1, 2, 3]), + ]; + + yield 'whereBetween collection too long' => [ + \InvalidArgumentException::class, + 'Between array must have 2 elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', new Collection([1, 2, 3])), + ]; + + yield 'whereBetween array is not a list' => [ + \InvalidArgumentException::class, + 'Between array must a list with 2 elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]), + ]; + } /** @dataProvider getEloquentMethodsNotSupported */ From 1628a68388f9031fa9eaea186a0aefd4ed2b2e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 12 Jul 2023 20:28:34 +0200 Subject: [PATCH 2/8] wording for exception message --- src/Query/Builder.php | 4 ++-- tests/Query/BuilderTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 3c0c788..61d90b5 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -567,10 +567,10 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not = if (is_array($values)) { if (! array_is_list($values)) { - throw new \InvalidArgumentException('Between array must a list with 2 elements: [min, max]'); + throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]'); } if (count($values) !== 2) { - throw new \InvalidArgumentException('Between array must have 2 elements: [min, max]'); + throw new \InvalidArgumentException('Between $values must have exactly two elements: [min, max]'); } } diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index ae3b8d4..12c5e21 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -275,25 +275,25 @@ public static function provideExceptions(): iterable /** @see DatabaseQueryBuilderTest::testWhereBetweens */ yield 'whereBetween array too short' => [ \InvalidArgumentException::class, - 'Between array must have 2 elements: [min, max]', + 'Between $values must have exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [1]), ]; yield 'whereBetween array too long' => [ \InvalidArgumentException::class, - 'Between array must have 2 elements: [min, max]', + 'Between $values must have exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [1, 2, 3]), ]; yield 'whereBetween collection too long' => [ \InvalidArgumentException::class, - 'Between array must have 2 elements: [min, max]', + 'Between $values must have exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', new Collection([1, 2, 3])), ]; yield 'whereBetween array is not a list' => [ \InvalidArgumentException::class, - 'Between array must a list with 2 elements: [min, max]', + 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]), ]; From c5c3cd034f2e465543ec808794356a90e5a7278b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 12 Jul 2023 20:57:07 +0200 Subject: [PATCH 3/8] Add tests on between array values https://www.mongodb.com/docs/manual/reference/method/cursor.sort/#text-score-metadata-sort --- tests/Query/BuilderTest.php | 50 +++++++++---------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 12c5e21..87dddd8 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -131,17 +131,10 @@ function (Builder $builder) { fn (Builder $builder) => $builder->whereBetween('id', [1, 2]), ]; - /* - yield 'whereBetween excessive nested array of numbers' => [ - ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []], - fn (Builder $builder) => $builder->whereBetween('id', [[1, 2, 3]]), - ]; - yield 'whereBetween nested array of numbers' => [ - ['find' => [['id' => ['$gte' => 1, '$lte' => 2]], []]], + ['find' => [['id' => ['$gte' => [1], '$lte' => [2, 3]]], []]], fn (Builder $builder) => $builder->whereBetween('id', [[1], [2, 3]]), ]; - */ yield 'whereNotBetween array of numbers' => [ ['find' => [['$or' => [['id' => ['$lte' => 1]], ['id' => ['$gte' => 2]]]], []]], @@ -173,28 +166,13 @@ function (Builder $builder) { ->orWhereBetween('id', [3, 5]), ]; - /* - yield 'whereBetween excessive nested array numbers' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]], []], - fn (Builder $builder) => $builder - ->where('id', '=', 1) - ->orWhereBetween('id', [[3, 4, 5]]), - ]; - - yield 'orWhereBetween nested array numbers' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]], []], - fn (Builder $builder) => $builder - ->where('id', '=', 1) - ->orWhereBetween('id', [[3, 5]]), - ]; - - yield 'orWhereBetween nested excessive array numbers' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 4, '$lte' => 6]]]], []], + /** @link https://www.mongodb.com/docs/manual/reference/bson-type-comparison-order/#arrays */ + yield 'orWhereBetween nested array of numbers' => [ + ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => [4], '$lte' => [6, 8]]]]], []]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereBetween('id', [[4], [6, 8]]), ]; - */ yield 'orWhereBetween collection' => [ ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]], []]], @@ -211,24 +189,15 @@ function (Builder $builder) { ->orWhereNotBetween('id', [3, 5]), ]; - /* - yield 'orWhereNotBetween excessive array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]], []], - fn (Builder $builder) => $builder - ->where('id', '=', 1) - ->orWhereNotBetween('id', [[3, 4, 5]]), - ]; - yield 'orWhereNotBetween nested array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]], []], + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [2, 3]]], ['id' => ['$gte' => [5]]]]]]], []]], fn (Builder $builder) => $builder ->where('id', '=', 1) - ->orWhereNotBetween('id', [[3, 5]]), + ->orWhereNotBetween('id', [[2, 3], [5]]), ]; - */ yield 'orWhereNotBetween excessive nested array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [4]]], ['id' => ['$gte' => [6, 8]]]]]]]]], + ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [4]]], ['id' => ['$gte' => [6, 8]]]]]]], []]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereNotBetween('id', [[4], [6, 8]]), @@ -297,6 +266,11 @@ public static function provideExceptions(): iterable fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]), ]; + yield 'whereBetween nested' => [ + \InvalidArgumentException::class, + 'Between $values must have exactly two elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', [[1, 2]]), + ]; } /** @dataProvider getEloquentMethodsNotSupported */ From 20ec87c35d519f79e7ca39b5aee1023df31af38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 13 Jul 2023 10:02:07 +0200 Subject: [PATCH 4/8] Use assert for exception --- src/Query/Builder.php | 9 +--- tests/Query/BuilderTest.php | 102 ++++++++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 28 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 61d90b5..9d2c3bf 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -565,13 +565,8 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not = $values = $values->all(); } - if (is_array($values)) { - if (! array_is_list($values)) { - throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]'); - } - if (count($values) !== 2) { - throw new \InvalidArgumentException('Between $values must have exactly two elements: [min, max]'); - } + if (is_array($values) && (! array_is_list($values) || count($values) !== 2)) { + throw new \InvalidArgumentException('Between $values must be a list with exactly two elements: [min, max]'); } $this->wheres[] = compact('column', 'type', 'boolean', 'values', 'not'); diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 87dddd8..531c8dd 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -137,19 +137,22 @@ function (Builder $builder) { ]; yield 'whereNotBetween array of numbers' => [ - ['find' => [['$or' => [['id' => ['$lte' => 1]], ['id' => ['$gte' => 2]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => ['$lte' => 1]], + ['id' => ['$gte' => 2]], + ]], + [], // options + ]], fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]), ]; - $period = now()->toPeriod(now()->addDay()); - yield 'whereBetween CarbonPeriod' => [ - ['find' => [['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], []]], - fn (Builder $builder) => $builder->whereBetween('created_at', $period), - ]; - $period = now()->toPeriod(now()->addMonth()); - yield 'custom long carbon period date' => [ - ['find' => [['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], []]], + yield 'whereBetween CarbonPeriod' => [ + ['find' => [ + ['created_at' => ['$gte' => new UTCDateTime($period->start), '$lte' => new UTCDateTime($period->end)]], + [], // options + ]], fn (Builder $builder) => $builder->whereBetween('created_at', $period), ]; @@ -160,7 +163,13 @@ function (Builder $builder) { /** @see DatabaseQueryBuilderTest::testOrWhereBetween() */ yield 'whereBetween array numbers' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 5]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['id' => ['$gte' => 3, '$lte' => 5]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereBetween('id', [3, 5]), @@ -168,14 +177,26 @@ function (Builder $builder) { /** @link https://www.mongodb.com/docs/manual/reference/bson-type-comparison-order/#arrays */ yield 'orWhereBetween nested array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => [4], '$lte' => [6, 8]]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['id' => ['$gte' => [4], '$lte' => [6, 8]]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereBetween('id', [[4], [6, 8]]), ]; yield 'orWhereBetween collection' => [ - ['find' => [['$or' => [['id' => 1], ['id' => ['$gte' => 3, '$lte' => 4]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['id' => ['$gte' => 3, '$lte' => 4]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereBetween('id', collect([3, 4])), @@ -183,28 +204,64 @@ function (Builder $builder) { /** @see DatabaseQueryBuilderTest::testOrWhereNotBetween() */ yield 'orWhereNotBetween array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 5]]]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['$or' => [ + ['id' => ['$lte' => 3]], + ['id' => ['$gte' => 5]], + ]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereNotBetween('id', [3, 5]), ]; yield 'orWhereNotBetween nested array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [2, 3]]], ['id' => ['$gte' => [5]]]]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['$or' => [ + ['id' => ['$lte' => [2, 3]]], + ['id' => ['$gte' => [5]]], + ]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereNotBetween('id', [[2, 3], [5]]), ]; yield 'orWhereNotBetween excessive nested array of numbers' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => [4]]], ['id' => ['$gte' => [6, 8]]]]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['$or' => [ + ['id' => ['$lte' => [4]]], + ['id' => ['$gte' => [6, 8]]], + ]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereNotBetween('id', [[4], [6, 8]]), ]; yield 'orWhereNotBetween collection' => [ - ['find' => [['$or' => [['id' => 1], ['$or' => [['id' => ['$lte' => 3]], ['id' => ['$gte' => 4]]]]]], []]], + ['find' => [ + ['$or' => [ + ['id' => 1], + ['$or' => [ + ['id' => ['$lte' => 3]], + ['id' => ['$gte' => 4]], + ]], + ]], + [], // options + ]], fn (Builder $builder) => $builder ->where('id', '=', 1) ->orWhereNotBetween('id', collect([3, 4])), @@ -216,7 +273,10 @@ function (Builder $builder) { ]; yield 'groupBy' => [ - ['aggregate' => [[['$group' => ['_id' => ['foo' => '$foo'], 'foo' => ['$last' => '$foo']]]], []]], + ['aggregate' => [ + [['$group' => ['_id' => ['foo' => '$foo'], 'foo' => ['$last' => '$foo']]]], + [], // options + ]], fn (Builder $builder) => $builder->groupBy('foo'), ]; } @@ -244,19 +304,19 @@ public static function provideExceptions(): iterable /** @see DatabaseQueryBuilderTest::testWhereBetweens */ yield 'whereBetween array too short' => [ \InvalidArgumentException::class, - 'Between $values must have exactly two elements: [min, max]', + 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [1]), ]; yield 'whereBetween array too long' => [ \InvalidArgumentException::class, - 'Between $values must have exactly two elements: [min, max]', + 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [1, 2, 3]), ]; yield 'whereBetween collection too long' => [ \InvalidArgumentException::class, - 'Between $values must have exactly two elements: [min, max]', + 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', new Collection([1, 2, 3])), ]; @@ -268,7 +328,7 @@ public static function provideExceptions(): iterable yield 'whereBetween nested' => [ \InvalidArgumentException::class, - 'Between $values must have exactly two elements: [min, max]', + 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [[1, 2]]), ]; } From 812d8d94b6c68adb9eedafdacede8fc494fa4ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 13 Jul 2023 21:13:29 +0200 Subject: [PATCH 5/8] Update tests/Query/BuilderTest.php Co-authored-by: Jeremy Mikola --- tests/Query/BuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 531c8dd..ad0185c 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -326,7 +326,7 @@ public static function provideExceptions(): iterable fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]), ]; - yield 'whereBetween nested' => [ + yield 'whereBetween array too short (nested)' => [ \InvalidArgumentException::class, 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', [[1, 2]]), From c3959c435ac0c456ae1f80e36caad674a50b5177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 13 Jul 2023 21:13:40 +0200 Subject: [PATCH 6/8] Update tests/Query/BuilderTest.php Co-authored-by: Jeremy Mikola --- tests/Query/BuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index ad0185c..cc7d410 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -162,7 +162,7 @@ function (Builder $builder) { ]; /** @see DatabaseQueryBuilderTest::testOrWhereBetween() */ - yield 'whereBetween array numbers' => [ + yield 'orWhereBetween array of numbers' => [ ['find' => [ ['$or' => [ ['id' => 1], From abee0cb16ad81f85989b3d363205cecd5fdd7910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 17 Jul 2023 11:08:13 +0200 Subject: [PATCH 7/8] Remove useless test case --- tests/Query/BuilderTest.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index cc7d410..4706ea5 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -235,22 +235,6 @@ function (Builder $builder) { ->orWhereNotBetween('id', [[2, 3], [5]]), ]; - yield 'orWhereNotBetween excessive nested array of numbers' => [ - ['find' => [ - ['$or' => [ - ['id' => 1], - ['$or' => [ - ['id' => ['$lte' => [4]]], - ['id' => ['$gte' => [6, 8]]], - ]], - ]], - [], // options - ]], - fn (Builder $builder) => $builder - ->where('id', '=', 1) - ->orWhereNotBetween('id', [[4], [6, 8]]), - ]; - yield 'orWhereNotBetween collection' => [ ['find' => [ ['$or' => [ From 3d152435b0a5e1a6719dba414a38e4ee5a12c2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 19 Jul 2023 10:36:50 +0200 Subject: [PATCH 8/8] review --- src/Query/Builder.php | 2 +- tests/Query/BuilderTest.php | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 9d2c3bf..b6924bb 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -555,7 +555,7 @@ public function whereAll($column, array $values, $boolean = 'and', $not = false) /** * @inheritdoc - * @param array{mixed, mixed}|CarbonPeriod $values + * @param list{mixed, mixed}|CarbonPeriod $values */ public function whereBetween($column, iterable $values, $boolean = 'and', $not = false) { diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 4706ea5..f600fa7 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -136,17 +136,6 @@ function (Builder $builder) { fn (Builder $builder) => $builder->whereBetween('id', [[1], [2, 3]]), ]; - yield 'whereNotBetween array of numbers' => [ - ['find' => [ - ['$or' => [ - ['id' => ['$lte' => 1]], - ['id' => ['$gte' => 2]], - ]], - [], // options - ]], - fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]), - ]; - $period = now()->toPeriod(now()->addMonth()); yield 'whereBetween CarbonPeriod' => [ ['find' => [ @@ -202,6 +191,17 @@ function (Builder $builder) { ->orWhereBetween('id', collect([3, 4])), ]; + yield 'whereNotBetween array of numbers' => [ + ['find' => [ + ['$or' => [ + ['id' => ['$lte' => 1]], + ['id' => ['$gte' => 2]], + ]], + [], // options + ]], + fn (Builder $builder) => $builder->whereNotBetween('id', [1, 2]), + ]; + /** @see DatabaseQueryBuilderTest::testOrWhereNotBetween() */ yield 'orWhereNotBetween array of numbers' => [ ['find' => [ @@ -292,6 +292,12 @@ public static function provideExceptions(): iterable fn (Builder $builder) => $builder->whereBetween('id', [1]), ]; + yield 'whereBetween array too short (nested)' => [ + \InvalidArgumentException::class, + 'Between $values must be a list with exactly two elements: [min, max]', + fn (Builder $builder) => $builder->whereBetween('id', [[1, 2]]), + ]; + yield 'whereBetween array too long' => [ \InvalidArgumentException::class, 'Between $values must be a list with exactly two elements: [min, max]', @@ -309,12 +315,6 @@ public static function provideExceptions(): iterable 'Between $values must be a list with exactly two elements: [min, max]', fn (Builder $builder) => $builder->whereBetween('id', ['min' => 1, 'max' => 2]), ]; - - yield 'whereBetween array too short (nested)' => [ - \InvalidArgumentException::class, - 'Between $values must be a list with exactly two elements: [min, max]', - fn (Builder $builder) => $builder->whereBetween('id', [[1, 2]]), - ]; } /** @dataProvider getEloquentMethodsNotSupported */