Skip to content

Commit 46f4f16

Browse files
committed
Sorting with NULL as highest, instead of lowest
This allow to sort by a field as ASC but get all null values at the end instead of a the begining. This would typically be achieved like so: ```graphql query { posts(sorting: [ {field: title, order: ASC, nullAsHighest: true}, {field: title, order: ASC} ]) { title } } ```
1 parent 6e3b88b commit 46f4f16

File tree

7 files changed

+69
-2
lines changed

7 files changed

+69
-2
lines changed

src/Definition/SortingOrderType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use GraphQL\Type\Definition\EnumType;
88

99
/**
10-
* An enum for join types to be used in DQL
10+
* An enum for sorting order to be used in DQL
1111
*/
1212
final class SortingOrderType extends EnumType
1313
{

src/Factory/FilteredQueryBuilderFactory.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,14 @@ private function applySorting(ClassMetadata $metadata, string $className, array
176176
if ($customSort) {
177177
$customSort($this->uniqueNameFactory, $metadata, $this->queryBuilder, $alias, $sort['order']);
178178
} else {
179-
$this->queryBuilder->addOrderBy($alias . '.' . $sort['field'], $sort['order']);
179+
$sortingField = $alias . '.' . $sort['field'];
180+
if ($sort['nullAsHighest'] ?? false) {
181+
$expression = 'CASE WHEN ' . $sortingField . ' IS NULL THEN 1 ELSE 0 END';
182+
$sortingField = $this->uniqueNameFactory->createAliasName('sorting');
183+
$this->queryBuilder->addSelect($expression . ' AS HIDDEN ' . $sortingField);
184+
}
185+
186+
$this->queryBuilder->addOrderBy($sortingField, $sort['order']);
180187
}
181188
}
182189
}

src/Factory/Type/SortingTypeFactory.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ public function create(string $className, string $typeName): Type
5151
'name' => 'field',
5252
'type' => Type::nonNull($fieldsEnum),
5353
],
54+
[
55+
'name' => 'nullAsHighest',
56+
'type' => Type::boolean(),
57+
'description' => 'If true `NULL` values will be considered as the highest value, so appearing last in a `ASC` order, and first in a `DESC` order.',
58+
'defaultValue' => false,
59+
],
5460
[
5561
'name' => 'order',
5662
'type' => $this->types->get('SortingOrder'),

tests/data/ModelWithTraitsSorting.graphqls

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ schema {
44

55
input ModelWithTraitsSorting {
66
field: ModelWithTraitsSortingField!
7+
8+
"""
9+
If true `NULL` values will be considered as the highest value, so appearing
10+
last in a `ASC` order, and first in a `DESC` order.
11+
"""
12+
nullAsHighest: Boolean = false
713
order: SortingOrder = ASC
814
}
915

tests/data/PostSorting.graphqls

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ schema {
44

55
input PostSorting {
66
field: PostSortingField!
7+
8+
"""
9+
If true `NULL` values will be considered as the highest value, so appearing
10+
last in a `ASC` order, and first in a `DESC` order.
11+
"""
12+
nullAsHighest: Boolean = false
713
order: SortingOrder = ASC
814
}
915

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// all posts sorted by reversed title but with null title first
6+
return [
7+
'SELECT post1, CASE WHEN post1.title IS NULL THEN 1 ELSE 0 END AS HIDDEN sorting1 FROM GraphQLTests\Doctrine\Blog\Model\Post post1 ORDER BY sorting1 DESC, post1.title DESC',
8+
\GraphQLTests\Doctrine\Blog\Model\Post::class,
9+
[],
10+
[
11+
[
12+
'field' => 'title',
13+
'nullAsHighest' => true,
14+
'order' => 'DESC',
15+
],
16+
[
17+
'field' => 'title',
18+
'order' => 'DESC',
19+
],
20+
],
21+
];
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// all posts sorted by title but with null title last
6+
return [
7+
'SELECT post1, CASE WHEN post1.title IS NULL THEN 1 ELSE 0 END AS HIDDEN sorting1 FROM GraphQLTests\Doctrine\Blog\Model\Post post1 ORDER BY sorting1 ASC, post1.title ASC',
8+
\GraphQLTests\Doctrine\Blog\Model\Post::class,
9+
[],
10+
[
11+
[
12+
'field' => 'title',
13+
'nullAsHighest' => true,
14+
'order' => 'ASC',
15+
],
16+
[
17+
'field' => 'title',
18+
'order' => 'ASC',
19+
],
20+
],
21+
];

0 commit comments

Comments
 (0)