Skip to content

Commit

Permalink
fix(Database): OrderByValuesScope is now from ASC to DESC order of gi…
Browse files Browse the repository at this point in the history
…ven values

BREAKING CHANGE: Values must be ordered from prefered order to last wanted order (now it was incorrectly used)
  • Loading branch information
pionl committed Nov 22, 2023
1 parent ce32947 commit dcb79f3
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 6 deletions.
13 changes: 11 additions & 2 deletions src/Database/Scopes/OrderByValuesScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,33 @@

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;

class OrderByValuesScope extends AbstractScope
{
private readonly string $direction;

/**
* @param array<string|int> $values
*/
public function __construct(
private readonly array $values,
private readonly string $column
private readonly string $column,
string $direction = 'ASC'
) {
$this->direction = strtoupper((string) $direction);

if ($this->direction !== 'ASC' && $this->direction !== 'DESC') {
throw new InvalidArgumentException('Direction must be ASC or DESC');
}
}

public function apply(Builder $builder, Model $model): void
{
$placeholders = array_map(static fn () => '?', $this->values);

$builder->orderByRaw(
'FIELD(`' . $this->column . '`, ' . implode(', ', $placeholders) . ') DESC',
'FIELD(`' . $this->column . '`, ' . implode(', ', $placeholders) . ') ' . $this->direction,
$this->values
);
}
Expand Down
83 changes: 79 additions & 4 deletions tests/Feature/Database/Scopes/OrderByValuesScopeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,99 @@

namespace Tests\LaraStrict\Feature\Database\Scopes;

use Closure;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use LaraStrict\Database\Scopes\OrderByValuesScope;
use Tests\LaraStrict\Feature\Database\Models\Test;
use Tests\LaraStrict\Feature\TestCase;

class OrderByValuesScopeTest extends TestCase
{
public function testApply(): void
/**
* @return array<string|int, array{0: Closure(static):void}>
*/
public function data(): array
{
return [
[
static fn (self $self) => $self->assert(direction: 'ASC', expectedDirection: 'ASC'),
],
[
static fn (self $self) => $self->assert(direction: 'DESC', expectedDirection: 'DESC'),
],
[
static fn (self $self) => $self->assert(direction: 'desc', expectedDirection: 'DESC'),
],
[
static fn (self $self) => $self->assert(direction: 'asc', expectedDirection: 'ASC'),
],
[
static fn (self $self) => $self->assert(direction: null, expectedDirection: 'ASC'),
],
];
}

/**
* @param Closure(static):void $assert
*
* @dataProvider data
*/
public function test(Closure $assert): void
{
$assert($this);
}

public function assert(?string $direction, string $expectedDirection): void
{
$values = ['1', 2, 's33'];
$scope = $direction === null
? new OrderByValuesScope($values, Test::AttributeTest)
: new OrderByValuesScope($values, Test::AttributeTest, $direction);

$query = Test::query()
->withoutGlobalScope(new SoftDeletingScope())
->withGlobalScope('test', new OrderByValuesScope(['1', 2, 's33'], Test::AttributeTest));
->withGlobalScope('test', $scope);

$this->assertEquals(
expected: 'select * from "tests" order by FIELD(`test`, ?, ?, ?) DESC',
expected: 'select * from "tests" order by FIELD(`test`, ?, ?, ?) ' . $expectedDirection,
actual: $query->toSql()
);

$this->assertEquals(expected: ['1', 2, 's33'], actual: $query->getBindings());
$this->assertEquals(expected: $values, actual: $query->getBindings());
}

/**
* @return array<string|int, array{0: Closure(static):void}>
*/
public function dataInvalid(): array
{
return [
[
static fn (self $self) => $self->assertInvalid(direction: 'invalid'),
],
[
static fn (self $self) => $self->assertInvalid(direction: 'asio'),
],

[
static fn (self $self) => $self->assertInvalid(direction: 'descio'),
],
];
}

/**
* @param Closure(static):void $assert
*
* @dataProvider dataInvalid
*/
public function testInvalid(Closure $assert): void
{
$assert($this);
}

public function assertInvalid(string $direction): void
{
$this->expectExceptionMessage('Direction must be ASC or DESC');
new OrderByValuesScope([], Test::AttributeTest, $direction);
}
}

0 comments on commit dcb79f3

Please sign in to comment.