Skip to content

Commit

Permalink
add sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeroen-G committed Oct 31, 2020
1 parent 587a768 commit 36f7d02
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Also do not forget to follow the [installation instructions for Laravel Scout](h
- [Quickstart](quickstart.md)
- [Mapping properties in Elasticsearch](mapping.md)
- [Advanced queries](advanced-queries.md)
- [Sorting search results](sorting.md)

[ico-version]: https://img.shields.io/packagist/v/jeroen-g/explorer.svg?style=flat-square
[ico-actions]: https://img.shields.io/github/workflow/status/Jeroen-G/explorer/CI?label=CI%2FCD&style=flat-square
Expand Down
23 changes: 23 additions & 0 deletions docs/sorting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Sorting

By default, your search results will be sorted by their score according to Elasticsearch.
If you want to step in and influence the sorting you may do so using a simplified implementation in Explorer.
Currently it is only possible to define one sort order.

```php
use App\Models\Post;
use \JeroenG\Explorer\Domain\Syntax\Sort;

$results = Post::search('Self-steering')
->sort(new Sort('published_at'))
->get();
```

The first parameter of a `Sort()` object is the name of the field, an optional second parameter is for the order.

```php
use \JeroenG\Explorer\Domain\Syntax\Sort;

new Sort('id', Sort::ASCENDING); // the default
new Sort('id', Sort::DESCENDING);
```
23 changes: 23 additions & 0 deletions src/Application/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace JeroenG\Explorer\Application;

use JeroenG\Explorer\Domain\Syntax\Sort;
use Laravel\Scout\Builder;
use Webmozart\Assert\Assert;

Expand All @@ -25,6 +26,8 @@ class BuildCommand

private ?int $limit = null;

private ?Sort $sort = null;

public static function wrap(Builder $builder): BuildCommand
{
$normalizedBuilder = new self();
Expand All @@ -34,6 +37,7 @@ public static function wrap(Builder $builder): BuildCommand
$normalizedBuilder->setFilter($builder->filter ?? []);
$normalizedBuilder->setWhere($builder->where ?? []);
$normalizedBuilder->setQuery($builder->query ?? '');
$normalizedBuilder->setSort($builder->sort ?? null);

$index = $builder->index ?: $builder->model->searchableAs();

Expand Down Expand Up @@ -83,6 +87,20 @@ public function getLimit(): ?int
return $this->limit;
}

public function hasSort(): bool
{
return !is_null($this->sort);
}

public function getSort(): array
{
if ($this->hasSort()) {
return $this->sort->build();
}

return [];
}

public function setMust(array $must): void
{
$this->must = $must;
Expand Down Expand Up @@ -122,4 +140,9 @@ public function setLimit(?int $limit): void
{
$this->limit = $limit;
}

public function setSort(?Sort $sort = null): void
{
$this->sort = $sort;
}
}
4 changes: 4 additions & 0 deletions src/Application/Finder.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public function find(): Results
$query['size'] = $this->builder->getLimit();
}

if ($this->builder->hasSort()) {
$query['body']['sort'] = $this->builder->getSort();
}

$rawResults = $this->client->search($query);

return new Results($rawResults);
Expand Down
30 changes: 30 additions & 0 deletions src/Domain/Syntax/Sort.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace JeroenG\Explorer\Domain\Syntax;

use Webmozart\Assert\Assert;

class Sort implements SyntaxInterface
{
public const ASCENDING = 'asc';

public const DESCENDING = 'desc';

private string $field;

private string $order;

public function __construct(string $field, string $order = self::ASCENDING)
{
$this->field = $field;
$this->order = $order;
Assert::inArray($order, [self::ASCENDING, self::DESCENDING]);
}

public function build(): array
{
return [$this->field => $this->order];
}
}
5 changes: 5 additions & 0 deletions src/ExplorerServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function boot(): void
$this->filters[] = $filter;
return $this;
});

Builder::macro('sort', function ($sort) {
$this->sort = $sort;
return $this;
});
}

public function register(): void
Expand Down
40 changes: 40 additions & 0 deletions tests/Unit/BuildCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
namespace JeroenG\Explorer\Tests\Unit;

use Illuminate\Database\Eloquent\Model;
use InvalidArgumentException;
use JeroenG\Explorer\Application\BuildCommand;
use JeroenG\Explorer\Domain\Syntax\Sort;
use JeroenG\Explorer\Domain\Syntax\Term;
use Laravel\Scout\Builder;
use Mockery;
Expand Down Expand Up @@ -88,4 +90,42 @@ public function buildCommandProvider(): array
['Query', 'Lorem Ipsum'],
];
}

public function test_it_can_set_the_sort_order(): void
{
$command = new BuildCommand();

self::assertFalse($command->hasSort());

$command->setSort(new Sort('id'));

self::assertTrue($command->hasSort());
self::assertSame(['id' => 'asc'], $command->getSort());

$command->setSort(null);

self::assertFalse($command->hasSort());
self::assertSame([], $command->getSort());

$command->setSort(new Sort('id', 'desc'));

self::assertTrue($command->hasSort());
self::assertSame(['id' => 'desc'], $command->getSort());

$this->expectException(InvalidArgumentException::class);
$command->setSort(new Sort('id', 'invalid'));
}

public function test_it_can_get_the_sorting_from_the_scout_builder(): void
{
$builder = Mockery::mock(Builder::class);
$builder->model = Mockery::mock(Model::class);

$builder->index = self::TEST_INDEX;
$builder->sort = new Sort('id');

$subject = BuildCommand::wrap($builder);

self::assertSame(['id' => 'asc'], $subject->getSort());
}
}

0 comments on commit 36f7d02

Please sign in to comment.