From cb586b51879c93bf3f7571d500fed4849495f5a8 Mon Sep 17 00:00:00 2001 From: Javier Date: Mon, 8 Mar 2021 08:55:52 +0100 Subject: [PATCH 1/4] [WIP] Add flexibility to handle arrays as argument while using where clause and add ranges method --- src/Builder.php | 35 +++++++++++++++++++++++++++++ src/Engines/ElasticSearchEngine.php | 18 ++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Builder.php b/src/Builder.php index 90f4bc3..68cf935 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -45,6 +45,11 @@ class Builder */ public $wheres = []; + /** + * @var array + */ + public $ranges = []; + /** * The "limit" that should be applied to the search. * @@ -128,6 +133,36 @@ public function where($field, $value) return $this; } + /** + * Add a range for a single field with one or more operators + * + * @param string $field + * @param array $ranges + * + * @return $this + */ + public function ranges($field, array $ranges) + { + $validOperators = ['gt', 'gte', 'lt', 'lte']; + $selectedOperators = array_keys($ranges); + + foreach ($selectedOperators as $selectedOperator) { + $isValidOperator = in_array($selectedOperator, $validOperators); + if ($isValidOperator) { + continue; + } + + throw new \InvalidArgumentException("Invalid operator {$selectedOperator}"); + } + + $this->ranges[$field] = array_merge( + $this->ranges[$field] ?? [], + $ranges + ); + + return $this; + } + /** * Set the "limit" for the search query. * diff --git a/src/Engines/ElasticSearchEngine.php b/src/Engines/ElasticSearchEngine.php index d557451..56d3f70 100644 --- a/src/Engines/ElasticSearchEngine.php +++ b/src/Engines/ElasticSearchEngine.php @@ -266,6 +266,20 @@ protected function filters(Builder $builder) })->values()->all(); } + /** + * @param Builder $builder + * @return array + */ + protected function ranges(Builder $builder) + { + $ranges = $builder->ranges; + + $field = key($ranges); + return [ + $field => $ranges + ]; + } + /** * Perform the given search on the engine for all indices * @@ -297,8 +311,10 @@ public function searchAll(AllBuilder $builder) } foreach ($this->filters($builder) as $field => $value) { + $queryParameter = is_array($value) ? 'terms' : 'term'; + $params['body']['filter']['bool']['must'] = [ - 'term' => [$field => $value] + $queryParameter => [$field => $value] ]; } From 716719819f7fb76d73d7f0e453f7776c9ebb072c Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 9 Mar 2021 15:25:01 +0100 Subject: [PATCH 2/4] Fix query parameters --- src/Engines/ElasticSearchEngine.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Engines/ElasticSearchEngine.php b/src/Engines/ElasticSearchEngine.php index 56d3f70..08c2137 100644 --- a/src/Engines/ElasticSearchEngine.php +++ b/src/Engines/ElasticSearchEngine.php @@ -261,9 +261,7 @@ protected function performSearch(Builder $builder, array $filters = []) */ protected function filters(Builder $builder) { - return collect($builder->wheres)->map(function ($value, $key) { - return [$key => $value]; - })->values()->all(); + return $builder->wheres; } /** @@ -294,13 +292,17 @@ public function searchAll(AllBuilder $builder) 'from' => $builder->offset, 'body' => [ 'query' => [ - 'query_string' => [ - 'query' => $builder->query, - 'type' => 'phrase', - 'default_operator' => 'and', + 'bool' => [ + 'must' => [ + 'query_string' => [ + 'query' => $builder->query, + 'type' => 'phrase', + 'default_operator' => 'and', + ], + ], ], - ] - ] + ], + ], ]; if (empty($builder->query)) { @@ -313,7 +315,7 @@ public function searchAll(AllBuilder $builder) foreach ($this->filters($builder) as $field => $value) { $queryParameter = is_array($value) ? 'terms' : 'term'; - $params['body']['filter']['bool']['must'] = [ + $params['body']['query']['bool']['filter'] = [ $queryParameter => [$field => $value] ]; } From e8f702b1ec8bfa2e5581602c7be40bd531006b62 Mon Sep 17 00:00:00 2001 From: Javier Date: Tue, 9 Mar 2021 15:31:12 +0100 Subject: [PATCH 3/4] Add Laravel helpers package since the source code contains it --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index af3c7eb..e1b6e5f 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "keywords": ["Laravel", "laravel-search"], "require": { "elasticsearch/elasticsearch": "^7.8", - "illuminate/support": "~5|~6|~7|~8" + "illuminate/support": "~5|~6|~7|~8", + "laravel/helpers": "^1.4" }, "require-dev": { "phpunit/phpunit": "^9.3", From d8cfcb2df74f51b04ae8692f4d5974f14791ba30 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 10 Mar 2021 09:17:32 +0100 Subject: [PATCH 4/4] Make ranges and empty search term to work in conjunction with other filters applied --- src/Engines/ElasticSearchEngine.php | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Engines/ElasticSearchEngine.php b/src/Engines/ElasticSearchEngine.php index 08c2137..d1ab501 100644 --- a/src/Engines/ElasticSearchEngine.php +++ b/src/Engines/ElasticSearchEngine.php @@ -270,12 +270,7 @@ protected function filters(Builder $builder) */ protected function ranges(Builder $builder) { - $ranges = $builder->ranges; - - $field = key($ranges); - return [ - $field => $ranges - ]; + return $builder->ranges; } /** @@ -294,22 +289,21 @@ public function searchAll(AllBuilder $builder) 'query' => [ 'bool' => [ 'must' => [ - 'query_string' => [ - 'query' => $builder->query, - 'type' => 'phrase', - 'default_operator' => 'and', - ], + [ + 'query_string' => [ + 'query' => $builder->query, + 'type' => 'phrase', + 'default_operator' => 'and', + ], + ] ], ], ], ], ]; - if (empty($builder->query)) { - $params['body']['query'] = [ - 'match_all' => (object)null - ]; - + foreach ($this->ranges($builder) as $field => $ranges) { + $params['body']['query']['bool']['must'][]['range'][$field] = $ranges; } foreach ($this->filters($builder) as $field => $value) { @@ -320,6 +314,18 @@ public function searchAll(AllBuilder $builder) ]; } + if (empty($builder->query)) { + $queryContainsFilters = $this->filters($builder); + + if (! $queryContainsFilters) { + $params['body']['query'] = [ + 'match_all' => (object)null + ]; + } else { + $params['body']['query']['bool']['must']['match_all'] = (object)null; + } + } + if ($sort = $builder->sort) { $params['body']['sort'] = $sort; }