Skip to content

Commit fec0f86

Browse files
committed
Add orderByNullsFirst method
1 parent 0d1a0f0 commit fec0f86

File tree

6 files changed

+87
-27
lines changed

6 files changed

+87
-27
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ phpunit
22
vendor
33
.php-cs-fixer.php
44
.php-cs-fixer.cache
5-
.phpunit.result.cache
5+
.phpunit.cache
66
composer.lock
77
phpunit.xml
88
phpstan.neon

phpstan-baseline.neon

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,6 @@ parameters:
55
count: 1
66
path: src/Mixins/CollectionMixin.php
77

8-
-
9-
message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<TModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\|Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:getAttributes\\(\\)\\.$#"
10-
count: 4
11-
path: src/Mixins/Creation.php
12-
13-
-
14-
message: "#^Call to an undefined method Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<TModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\|Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:newCollection\\(\\)\\.$#"
15-
count: 1
16-
path: src/Mixins/Creation.php
17-
188
-
199
message: "#^Call to protected method addTimestampsToUpsertValues\\(\\) of class Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<TModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\.$#"
2010
count: 2
@@ -31,7 +21,7 @@ parameters:
3121
path: src/Mixins/Misc.php
3222

3323
-
34-
message: "#^Call to protected method callScope\\(\\) of class Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\.$#"
24+
message: "#^Call to protected method callScope\\(\\) of class Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<mixed\\>\\.$#"
3525
count: 1
3626
path: src/Mixins/Ordering.php
3727

@@ -72,12 +62,7 @@ parameters:
7262

7363
-
7464
message: "#^Method Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Ordering\\:\\:preventInvalidDirection\\(\\) invoked with 1 parameter, 0 required\\.$#"
75-
count: 2
76-
path: src/Mixins/Ordering.php
77-
78-
-
79-
message: "#^Offset 0 does not exist on array\\|null\\.$#"
80-
count: 1
65+
count: 3
8166
path: src/Mixins/Ordering.php
8267

8368
-
@@ -91,7 +76,7 @@ parameters:
9176
path: src/Mixins/Ordering.php
9277

9378
-
94-
message: "#^Parameter \\#2 \\$parentQuery of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\:\\:getRelationExistenceQuery\\(\\) expects Illuminate\\\\Database\\\\Eloquent\\\\Builder, \\$this\\(Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Ordering\\) given\\.$#"
79+
message: "#^Parameter \\#2 \\$parentQuery of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation\\<\\*\\>\\:\\:getRelationExistenceQuery\\(\\) expects Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>, \\$this\\(Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Ordering\\) given\\.$#"
9580
count: 1
9681
path: src/Mixins/Ordering.php
9782

@@ -116,7 +101,7 @@ parameters:
116101
path: src/Mixins/Select.php
117102

118103
-
119-
message: "#^Call to protected method callScope\\(\\) of class Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\.$#"
104+
message: "#^Call to protected method callScope\\(\\) of class Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<mixed\\>\\.$#"
120105
count: 1
121106
path: src/Mixins/Select.php
122107

@@ -135,11 +120,6 @@ parameters:
135120
count: 2
136121
path: src/Mixins/Select.php
137122

138-
-
139-
message: "#^Offset 0 does not exist on array\\|null\\.$#"
140-
count: 1
141-
path: src/Mixins/Select.php
142-
143123
-
144124
message: "#^Parameter \\#1 \\$query of method Soyhuce\\\\EloquentExtended\\\\Aggregates\\\\Contracts\\\\AggregateFunction\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\:\\:apply\\(\\) expects Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>, \\$this\\(Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Select\\<TModelClass of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\) given\\.$#"
145125
count: 1
@@ -161,7 +141,7 @@ parameters:
161141
path: src/Mixins/Select.php
162142

163143
-
164-
message: "#^Parameter \\#2 \\$parentQuery of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation\\<Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\:\\:getRelationExistenceQuery\\(\\) expects Illuminate\\\\Database\\\\Eloquent\\\\Builder, \\$this\\(Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Select\\<TModelClass of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\) given\\.$#"
144+
message: "#^Parameter \\#2 \\$parentQuery of method Illuminate\\\\Database\\\\Eloquent\\\\Relations\\\\Relation\\<\\*\\>\\:\\:getRelationExistenceQuery\\(\\) expects Illuminate\\\\Database\\\\Eloquent\\\\Builder\\<TDeclaringModel of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>, \\$this\\(Soyhuce\\\\EloquentExtended\\\\Mixins\\\\Select\\<TModelClass of Illuminate\\\\Database\\\\Eloquent\\\\Model\\>\\) given\\.$#"
165145
count: 1
166146
path: src/Mixins/Select.php
167147

src/Aggregates/AnyExists.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Database\Query\Builder as QueryBuilder;
77
use Illuminate\Support\Collection;
88
use Soyhuce\EloquentExtended\Aggregates\Contracts\MultiRelationAggregate;
9+
use function sprintf;
910

1011
/**
1112
* @template TModelClass of \Illuminate\Database\Eloquent\Model

src/Mixins/Ordering.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use InvalidArgumentException;
88
use function count;
99
use function in_array;
10+
use function sprintf;
1011

1112
/**
1213
* @mixin \Illuminate\Database\Eloquent\Builder
@@ -44,6 +45,28 @@ public function orderByRawNullsLast(): Closure
4445
};
4546
}
4647

48+
public function orderByNullsFirst(): Closure
49+
{
50+
return function (string $column, string $direction = 'asc'): self {
51+
$this->preventInvalidDirection($direction);
52+
53+
$column = $this->getGrammar()->wrap($column);
54+
55+
$this->orderByRaw("{$column} {$direction} nulls first");
56+
57+
return $this;
58+
};
59+
}
60+
61+
public function orderByRawNullsFirst(): Closure
62+
{
63+
return function (string $sql): self {
64+
$this->orderByRaw("{$sql} nulls first");
65+
66+
return $this;
67+
};
68+
}
69+
4770
public function orderByAggregate(): Closure
4871
{
4972
return function (

src/NextIdeHelper/Extension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public function execute(Model $model): void
3030
"{$builderClass} withImplode(array|string \$relations, string \$column, string \$glue, ?string \$orderBy = null, string \$direction = 'asc')",
3131
"{$builderClass} orderByNullsLast(string \$column, string \$direction = 'asc')",
3232
"{$builderClass} orderByRawNullsLast(string \$sql)",
33+
"{$builderClass} orderByNullsFirst(string \$column, string \$direction = 'asc')",
34+
"{$builderClass} orderByRawNullsFirst(string \$sql)",
3335
"{$builderClass} orderByAggregate(string \$relationName, string \$column, string \$direction = 'asc', ?string \$function = null, ?\\Closure \$constraints = null)",
3436
"{$builderClass} orderByExists(string \$relation, ?\\Closure \$constraints = null, string \$direction = 'asc')",
3537
"{$builderClass} orderByExistsDesc(string \$relation, ?\\Closure \$constraints = null)",

tests/OrderingTest.php

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function otherDirectionIsInvalid(): void
4040
* @test
4141
* @covers ::orderByNullsLast
4242
*/
43-
public function orderByNullLast(): void
43+
public function orderByNullsLast(): void
4444
{
4545
$sqliteVersion = User::query()->getConnection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
4646

@@ -90,6 +90,60 @@ public function orderByRawNullsLast(): void
9090
);
9191
}
9292

93+
/**
94+
* @test
95+
* @covers ::orderByNullsLast
96+
*/
97+
public function orderByNullsFirst(): void
98+
{
99+
$sqliteVersion = User::query()->getConnection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
100+
101+
if (version_compare($sqliteVersion, '3.31', '<')) {
102+
$this->markTestSkipped('Sqlite < 3.31 does not support nulls last');
103+
}
104+
105+
$admin = User::factory()->createOne(['role' => 'admin']);
106+
$user = User::factory()->createOne(['role' => 'user']);
107+
$none = User::factory()->createOne(['role' => null]);
108+
109+
$this->assertEquals(
110+
[$none->id, $admin->id, $user->id],
111+
User::query()->orderByNullsFirst('role')->pluck('id')->all()
112+
);
113+
114+
$this->assertEquals(
115+
[$none->id, $user->id, $admin->id],
116+
User::query()->orderByNullsFirst('role', 'desc')->pluck('id')->all()
117+
);
118+
}
119+
120+
/**
121+
* @test
122+
* @covers ::orderByRawNullsLast
123+
*/
124+
public function orderByRawNullsFirst(): void
125+
{
126+
$sqliteVersion = User::query()->getConnection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
127+
128+
if (version_compare($sqliteVersion, '3.31', '<')) {
129+
$this->markTestSkipped('Sqlite < 3.31 does not support nulls last');
130+
}
131+
132+
$admin = User::factory()->createOne(['role' => 'admin']);
133+
$user = User::factory()->createOne(['role' => 'user']);
134+
$none = User::factory()->createOne(['role' => null]);
135+
136+
$this->assertEquals(
137+
[$none->id, $admin->id, $user->id],
138+
User::query()->orderByRawNullsFirst('UPPER("role")')->pluck('id')->all()
139+
);
140+
141+
$this->assertEquals(
142+
[$none->id, $user->id, $admin->id],
143+
User::query()->orderByRawNullsFirst('UPPER("role") desc')->pluck('id')->all()
144+
);
145+
}
146+
93147
/**
94148
* @test
95149
* @covers ::orderByExists

0 commit comments

Comments
 (0)