Skip to content

Commit 0f046b4

Browse files
committed
#111039 add collapsing by field
1 parent 0f4af3a commit 0f046b4

File tree

15 files changed

+246
-6
lines changed

15 files changed

+246
-6
lines changed

composer.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/elastic-query-specification.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
'sort' => 'sort',
1010
'aggregate' => 'aggregate',
1111
'facet' => 'facet',
12+
'collapse' => 'collapse',
1213
],
1314
];

src/Collapsing/AllowedCollapse.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuerySpecification\Collapsing;
4+
5+
use Ensi\LaravelElasticQuerySpecification\Contracts\Collapse;
6+
use Ensi\LaravelElasticQuery\Contracts\CollapsibleQuery;
7+
use Webmozart\Assert\Assert;
8+
9+
class AllowedCollapse implements Collapse
10+
{
11+
private string $name;
12+
13+
protected string $field;
14+
15+
public function __construct(string $name, ?string $field = null)
16+
{
17+
Assert::stringNotEmpty($name);
18+
Assert::nullOrStringNotEmpty($field);
19+
20+
$this->name = $name;
21+
$this->field = $field ?? $this->name;
22+
}
23+
24+
public function __invoke(CollapsibleQuery $query): void
25+
{
26+
$query->collapse($this->field);
27+
}
28+
29+
public function name(): string
30+
{
31+
return $this->name;
32+
}
33+
34+
public static function field(string $name, ?string $field = null): self
35+
{
36+
return new static($name, $field);
37+
}
38+
39+
public static function wrap(self|string $source): self
40+
{
41+
return $source instanceof self
42+
? $source
43+
: self::field($source);
44+
}
45+
}

src/Concerns/ExtractsQueryParameters.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ public function facets(): Collection
3737
return $this->extractNames($key);
3838
}
3939

40+
public function collapse(): ?string
41+
{
42+
$key = $this->config('collapse');
43+
$result = $this->extract($key);
44+
45+
if (!is_string($result) || empty(trim($result))) {
46+
return null;
47+
}
48+
49+
return trim($result);
50+
}
51+
4052
protected function extractNames(string $key): Collection
4153
{
4254
return collect($this->extractArray($key))

src/Contracts/Collapse.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuerySpecification\Contracts;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\CollapsibleQuery;
6+
7+
interface Collapse
8+
{
9+
public function __invoke(CollapsibleQuery $query): void;
10+
}

src/Contracts/QueryParameters.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ public function sorts(): Collection;
1313
public function aggregates(): Collection;
1414

1515
public function facets(): Collection;
16+
17+
public function collapse(): ?string;
1618
}

src/Exceptions/InvalidQueryException.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ public static function notAllowedFacets(Collection $facets): self
4040
return new self(Response::HTTP_BAD_REQUEST, $message);
4141
}
4242

43+
public static function notAllowedCollapse(string $collapse): self
44+
{
45+
$message = "Requested collapse \"$collapse\" are not allowed";
46+
47+
return new self(Response::HTTP_BAD_REQUEST, $message);
48+
}
49+
4350
public static function notSupportMultipleValues(string $filter): self
4451
{
4552
return new self(
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Ensi\LaravelElasticQuerySpecification\Processors;
4+
5+
use Ensi\LaravelElasticQuery\Contracts\CollapsibleQuery;
6+
use Ensi\LaravelElasticQuerySpecification\Exceptions\InvalidQueryException;
7+
use Ensi\LaravelElasticQuerySpecification\Specification\Specification;
8+
use Ensi\LaravelElasticQuerySpecification\Specification\Visitor;
9+
use Illuminate\Support\Collection;
10+
11+
class CollapseProcessor implements Visitor
12+
{
13+
private ?string $collapseField;
14+
private Collection $allowedCollapses;
15+
16+
public function __construct(private CollapsibleQuery $query, ?string $field)
17+
{
18+
$this->collapseField = $field;
19+
$this->allowedCollapses = new Collection();
20+
}
21+
22+
public function visitRoot(Specification $specification): void
23+
{
24+
$this->allowedCollapses = $specification->collapses();
25+
}
26+
27+
public function visitNested(string $field, Specification $specification): void
28+
{
29+
}
30+
31+
public function done(): void
32+
{
33+
$field = $this->collapseField;
34+
35+
if ($field === null) {
36+
return;
37+
}
38+
39+
$isAllowedCollapse = $this->allowedCollapses->has($field);
40+
41+
if (!$isAllowedCollapse) {
42+
throw InvalidQueryException::notAllowedCollapse($field);
43+
}
44+
45+
$this->allowedCollapses[$field]($this->query);
46+
}
47+
}

src/SearchQueryBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Ensi\LaravelElasticQuerySpecification;
44

55
use Ensi\LaravelElasticQuery\Search\SearchQuery;
6+
use Ensi\LaravelElasticQuerySpecification\Processors\CollapseProcessor;
67
use Ensi\LaravelElasticQuerySpecification\Processors\ConstraintProcessor;
78
use Ensi\LaravelElasticQuerySpecification\Processors\FilterProcessor;
89
use Ensi\LaravelElasticQuerySpecification\Processors\SortProcessor;
@@ -19,5 +20,6 @@ protected function processors(): Generator
1920
yield new FilterProcessor($this->parameters->filters());
2021
yield new ConstraintProcessor($this->query);
2122
yield new SortProcessor($this->query, $this->parameters->sorts());
23+
yield new CollapseProcessor($this->query, $this->parameters->collapse());
2224
}
2325
}

src/Specification/Specification.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Closure;
66
use Ensi\LaravelElasticQuery\Contracts\BoolQuery;
77
use Ensi\LaravelElasticQuerySpecification\Agregating\AllowedAggregate;
8+
use Ensi\LaravelElasticQuerySpecification\Collapsing\AllowedCollapse;
89
use Ensi\LaravelElasticQuerySpecification\Contracts\Constraint;
910
use Ensi\LaravelElasticQuerySpecification\Exceptions\ComponentExistsException;
1011
use Ensi\LaravelElasticQuerySpecification\Faceting\AllowedFacet;
@@ -30,6 +31,9 @@ class Specification
3031
/** @var array|AllowedFacet[] */
3132
protected array $facets = [];
3233

34+
/** @var array|AllowedCollapse[] */
35+
protected array $collapses = [];
36+
3337
public static function new(): static
3438
{
3539
return new static();
@@ -194,6 +198,27 @@ public function activeFacets(): Collection
194198
}
195199
//endregion
196200

201+
//region Collapse
202+
public function allowedCollapses(array $collapses): static
203+
{
204+
foreach ($collapses as $collapse) {
205+
$collapse = AllowedCollapse::wrap($collapse);
206+
207+
$this->addComponent($this->collapses, $collapse->name(), $collapse, 'collapse');
208+
}
209+
210+
return $this;
211+
}
212+
213+
/**
214+
* @return Collection<int,AllowedCollapse>
215+
*/
216+
public function collapses(): Collection
217+
{
218+
return new Collection($this->collapses);
219+
}
220+
//endregion
221+
197222
private function addComponent(array &$target, string $name, mixed $component, string $type): void
198223
{
199224
if (array_key_exists($name, $target)) {

0 commit comments

Comments
 (0)