From edd08715a0dd64bab9fd1194e70fface09e02900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 12 Jul 2023 14:54:16 +0200 Subject: [PATCH] PHPORM-46 Throw an exception when Query\Builder::orderBy() is used with invalid direction (#7) * Convert only strings, let the driver fail for int values * Add more tests on Builder::orderBy --- src/Query/Builder.php | 7 +++- tests/Query/BuilderTest.php | 82 +++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/Query/Builder.php b/src/Query/Builder.php index 22d933fea..78aabffeb 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -513,11 +513,16 @@ public function distinct($column = false) /** * @inheritdoc + * @param int|string|array $direction */ public function orderBy($column, $direction = 'asc') { if (is_string($direction)) { - $direction = (strtolower($direction) == 'asc' ? 1 : -1); + $direction = match ($direction) { + 'asc', 'ASC' => 1, + 'desc', 'DESC' => -1, + default => throw new \InvalidArgumentException('Order direction must be "asc" or "desc".'), + }; } if ($column == 'natural') { diff --git a/tests/Query/BuilderTest.php b/tests/Query/BuilderTest.php index 17ce184b5..b06a89f8e 100644 --- a/tests/Query/BuilderTest.php +++ b/tests/Query/BuilderTest.php @@ -5,6 +5,7 @@ namespace Jenssegers\Mongodb\Tests\Query; use DateTimeImmutable; +use Illuminate\Tests\Database\DatabaseQueryBuilderTest; use Jenssegers\Mongodb\Connection; use Jenssegers\Mongodb\Query\Builder; use Jenssegers\Mongodb\Query\Processor; @@ -63,6 +64,66 @@ public static function provideQueryBuilderToMql(): iterable fn (Builder $builder) => $builder->limit(10)->offset(5)->select('foo', 'bar'), ]; + /** @see DatabaseQueryBuilderTest::testOrderBys() */ + yield 'orderBy multiple columns' => [ + ['find' => [[], ['sort' => ['email' => 1, 'age' => -1]]]], + fn (Builder $builder) => $builder + ->orderBy('email') + ->orderBy('age', 'desc'), + ]; + + yield 'orders = null' => [ + ['find' => [[], []]], + function (Builder $builder) { + $builder->orders = null; + + return $builder; + }, + ]; + + yield 'orders = []' => [ + ['find' => [[], []]], + function (Builder $builder) { + $builder->orders = []; + + return $builder; + }, + ]; + + yield 'multiple orders with direction' => [ + ['find' => [[], ['sort' => ['email' => -1, 'age' => 1]]]], + fn (Builder $builder) => $builder + ->orderBy('email', -1) + ->orderBy('age', 1), + ]; + + yield 'orderByDesc' => [ + ['find' => [[], ['sort' => ['email' => -1]]]], + fn (Builder $builder) => $builder->orderByDesc('email'), + ]; + + /** @see DatabaseQueryBuilderTest::testReorder() */ + yield 'reorder reset' => [ + ['find' => [[], []]], + fn (Builder $builder) => $builder->orderBy('name')->reorder(), + ]; + + yield 'reorder column' => [ + ['find' => [[], ['sort' => ['name' => -1]]]], + fn (Builder $builder) => $builder->orderBy('name')->reorder('name', 'desc'), + ]; + + /** @link https://www.mongodb.com/docs/manual/reference/method/cursor.sort/#text-score-metadata-sort */ + yield 'orderBy array meta' => [ + ['find' => [ + ['$text' => ['$search' => 'operating']], + ['sort' => ['score' => ['$meta' => 'textScore']]], + ]], + fn (Builder $builder) => $builder + ->where('$text', ['$search' => 'operating']) + ->orderBy('score', ['$meta' => 'textScore']), + ]; + yield 'distinct' => [ ['distinct' => ['foo', [], []]], fn (Builder $builder) => $builder->distinct('foo'), @@ -74,6 +135,27 @@ public static function provideQueryBuilderToMql(): iterable ]; } + /** + * @dataProvider provideExceptions + */ + public function testException($class, $message, \Closure $build): void + { + $builder = self::getBuilder(); + + $this->expectException($class); + $this->expectExceptionMessage($message); + $build($builder); + } + + public static function provideExceptions(): iterable + { + yield 'orderBy invalid direction' => [ + \InvalidArgumentException::class, + 'Order direction must be "asc" or "desc"', + fn (Builder $builder) => $builder->orderBy('_id', 'dasc'), + ]; + } + private static function getBuilder(): Builder { $connection = m::mock(Connection::class);