From 705bfcc346e540a5308734a5d0155a43e130a372 Mon Sep 17 00:00:00 2001 From: Ryan Bibby Date: Fri, 13 Jan 2023 11:11:41 +0000 Subject: [PATCH] Allow more than one sort to be applied --- README.md | 5 +++ src/Sieve.php | 29 ++++++++++-------- tests/SieveTest.php | 74 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1d22e7b..fac95d8 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,11 @@ Sieve will also allow consumers of your API to specify sort order. You can do th * `sort=age:asc` * `sort=id:desc` +If you do not specify a direction (for instance `sort=age`) then the sorting will be carried out in ascending order. + +You can specify more than one column to sort by as a comma separated list. These will be applied in the order given. +For instance `sort=age:asc,name:asc` will return people in age order, then alphabetically. + By default, MySQL will sort `null` values first for ascending sorts and last for descending sorts. Depending on the context of the column this may not be the desired functionality. You can change this using the following URL queries: diff --git a/src/Sieve.php b/src/Sieve.php index 136b099..b3d8827 100644 --- a/src/Sieve.php +++ b/src/Sieve.php @@ -72,22 +72,25 @@ public function apply($queryBuilder) continue; } - if ($this->getSort() == "$property:desc") { - $queryBuilder->orderBy($column, "desc"); - } + $sorts = explode(',', $this->getSort()); + foreach ($sorts as $sort) { + if ($sort == "$property:desc") { + $queryBuilder->orderBy($column, "desc"); + } - if ($this->getSort() == "$property:asc") { - $queryBuilder->orderBy($column, "asc"); - } + if ($sort == "$property:asc" || $sort == $property) { + $queryBuilder->orderBy($column, "asc"); + } - if ($this->getSort() == "$property:asc_nulls_last") { - $queryBuilder->orderByRaw("ISNULL($column) asc") - ->orderBy($column, 'asc'); - } + if ($sort == "$property:asc_nulls_last") { + $queryBuilder->orderByRaw("ISNULL($column) asc") + ->orderBy($column, 'asc'); + } - if ($this->getSort() == "$property:desc_nulls_first") { - $queryBuilder->orderByRaw("ISNULL($column) desc") - ->orderBy($column, 'desc'); + if ($sort == "$property:desc_nulls_first") { + $queryBuilder->orderByRaw("ISNULL($column) desc") + ->orderBy($column, 'desc'); + } } } diff --git a/tests/SieveTest.php b/tests/SieveTest.php index 6e7f5b5..0b23a59 100644 --- a/tests/SieveTest.php +++ b/tests/SieveTest.php @@ -50,6 +50,30 @@ public function set_default_sort_filter() $this->assertEquals($sieve->getSort(), 'name:desc'); } + /** + * @test + */ + public function applies_sieve_sorts_to_a_query_builder_asc_by_default() + { + $request = Request::create('/', 'GET', [ + 'sort' => 'name', + ]); + + $seive = new Sieve($request); + $seive->addFilter('name', new StringFilter); + + /** @var Builder */ + $builder = $this->app->make(Builder::class); + $builder->from('pets'); + + $seive->apply($builder); + + $this->assertEquals( + 'select * from "pets" order by "name" asc', + $builder->toSql() + ); + } + /** * @test */ @@ -122,6 +146,56 @@ public function applies_sieve_sorts_to_a_query_builder_desc_nulls_first() ); } + /** + * @test + */ + public function allows_multiple_columns_to_be_ordered() + { + $request = Request::create('/', 'GET', [ + 'sort' => 'type:asc,name:desc', + ]); + + $seive = new Sieve($request); + $seive->addFilter('type', new StringFilter); + $seive->addFilter('name', new StringFilter); + + /** @var Builder */ + $builder = $this->app->make(Builder::class); + $builder->from('pets'); + + $seive->apply($builder); + + $this->assertEquals( + 'select * from "pets" order by "type" asc, "name" desc', + $builder->toSql() + ); + } + + /** + * @test + */ + public function allows_multiple_columns_to_be_ordered_including_a_null_column() + { + $request = Request::create('/', 'GET', [ + 'sort' => 'type:asc,name:desc_nulls_first', + ]); + + $seive = new Sieve($request); + $seive->addFilter('type', new StringFilter); + $seive->addFilter('name', new StringFilter); + + /** @var Builder */ + $builder = $this->app->make(Builder::class); + $builder->from('pets'); + + $seive->apply($builder); + + $this->assertEquals( + 'select * from "pets" order by "type" asc, ISNULL(name) desc, "name" desc', + $builder->toSql() + ); + } + /** * @test */