From 88b877bcf1ce4c0633d09ab39faa84f74295b80d Mon Sep 17 00:00:00 2001 From: Oleh Isaiev Date: Sun, 3 Nov 2024 20:03:40 +0200 Subject: [PATCH 1/5] Add limit handling to SearchFactory Enhanced the SearchFactory to handle 'limit' from the builder and set the search size accordingly. Also included unit tests to verify limit handling and compatibility with pagination options. --- src/ElasticSearch/SearchFactory.php | 3 ++ .../Unit/ElasticSearch/SearchFactoryTest.php | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/Unit/ElasticSearch/SearchFactoryTest.php diff --git a/src/ElasticSearch/SearchFactory.php b/src/ElasticSearch/SearchFactory.php index 8b20d88d..17c51197 100644 --- a/src/ElasticSearch/SearchFactory.php +++ b/src/ElasticSearch/SearchFactory.php @@ -34,6 +34,9 @@ public static function create(Builder $builder, array $options = []): Search } else { $search->addQuery($query); } + if (isset($builder->limit)) { + $search->setSize($builder->limit); + } if (array_key_exists('from', $options)) { $search->setFrom($options['from']); } diff --git a/tests/Unit/ElasticSearch/SearchFactoryTest.php b/tests/Unit/ElasticSearch/SearchFactoryTest.php new file mode 100644 index 00000000..aa63c9ca --- /dev/null +++ b/tests/Unit/ElasticSearch/SearchFactoryTest.php @@ -0,0 +1,36 @@ +take($size = 50); + + $search = SearchFactory::create($builder); + + $this->assertEquals($search->getSize(), $size); + } + + public function test_limit_compatible_with_pagination(): void + { + $builder = new Builder(new Product(), '*'); + $builder->take(30); + + $search = SearchFactory::create($builder, [ + 'from' => 0, + 'size' => $size = 50, + ]); + + $this->assertEquals($search->getSize(), $size); + } +} From 85d99ff946b280357c65a2faceb93fe416c4c5b8 Mon Sep 17 00:00:00 2001 From: Oleh Isaiev Date: Mon, 11 Nov 2024 13:27:33 +0200 Subject: [PATCH 2/5] Refactor search options handling in SearchFactory Simplify and centralize option preparation by introducing the `prepareOptions` and `supportedOptions` methods in `SearchFactory`. Adjust tests to align with the new logic, ensuring size and from parameters are correctly set and prioritized. --- src/ElasticSearch/SearchFactory.php | 27 ++++++++-- src/Engines/ElasticSearchEngine.php | 2 +- .../Unit/ElasticSearch/SearchFactoryTest.php | 50 +++++++++++++++++-- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/ElasticSearch/SearchFactory.php b/src/ElasticSearch/SearchFactory.php index 17c51197..b0ba367b 100644 --- a/src/ElasticSearch/SearchFactory.php +++ b/src/ElasticSearch/SearchFactory.php @@ -2,6 +2,7 @@ namespace Matchish\ScoutElasticSearch\ElasticSearch; +use Illuminate\Support\Arr; use Laravel\Scout\Builder; use ONGR\ElasticsearchDSL\BuilderInterface; use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery; @@ -15,11 +16,12 @@ final class SearchFactory { /** * @param Builder $builder - * @param array $options + * @param array $enforceOptions * @return Search */ - public static function create(Builder $builder, array $options = []): Search + public static function create(Builder $builder, array $enforceOptions = []): Search { + $options = static::prepareOptions($builder, $enforceOptions); $search = new Search(); $query = new QueryStringQuery($builder->query); if (static::hasWhereFilters($builder)) { @@ -34,9 +36,6 @@ public static function create(Builder $builder, array $options = []): Search } else { $search->addQuery($query); } - if (isset($builder->limit)) { - $search->setSize($builder->limit); - } if (array_key_exists('from', $options)) { $search->setFrom($options['from']); } @@ -138,4 +137,22 @@ private static function hasWhereNotIns($builder): bool { return isset($builder->whereNotIns) && ! empty($builder->whereNotIns); } + + private static function prepareOptions(Builder $builder, array $enforceOptions = []): array + { + $options = []; + + if (isset($builder->limit)) { + $options['size'] = $builder->limit; + } + + return array_merge($options, self::supportedOptions($builder), $enforceOptions); + } + + private static function supportedOptions(Builder $builder): array + { + return Arr::only($builder->options, [ + 'from', + ]); + } } diff --git a/src/Engines/ElasticSearchEngine.php b/src/Engines/ElasticSearchEngine.php index 46637e14..d1abe63f 100644 --- a/src/Engines/ElasticSearchEngine.php +++ b/src/Engines/ElasticSearchEngine.php @@ -183,7 +183,7 @@ public function getTotalCount($results) /** * @param BaseBuilder $builder - * @param array $options + * @param array $options * @return SearchResults|mixed */ private function performSearch(BaseBuilder $builder, $options = []) diff --git a/tests/Unit/ElasticSearch/SearchFactoryTest.php b/tests/Unit/ElasticSearch/SearchFactoryTest.php index aa63c9ca..731d7a13 100644 --- a/tests/Unit/ElasticSearch/SearchFactoryTest.php +++ b/tests/Unit/ElasticSearch/SearchFactoryTest.php @@ -14,11 +14,11 @@ class SearchFactoryTest extends TestCase public function test_limit_set_in_builder(): void { $builder = new Builder(new Product(), '*'); - $builder->take($size = 50); + $builder->take($expectedSize = 50); $search = SearchFactory::create($builder); - $this->assertEquals($search->getSize(), $size); + $this->assertEquals($expectedSize, $search->getSize()); } public function test_limit_compatible_with_pagination(): void @@ -28,9 +28,51 @@ public function test_limit_compatible_with_pagination(): void $search = SearchFactory::create($builder, [ 'from' => 0, - 'size' => $size = 50, + 'size' => $expectedSize = 50, ]); - $this->assertEquals($search->getSize(), $size); + $this->assertEquals($expectedSize, $search->getSize()); + } + + public function test_size_set_in_options_dont_take_effect(): void + { + $builder = new Builder(new Product(), '*'); + $builder->take($expectedSize = 30) + ->options([ + 'size' => 100, + ]); + + $search = SearchFactory::create($builder); + + $this->assertEquals($expectedSize, $search->getSize()); + } + + public function test_from_set_in_options_take_effect(): void + { + $builder = new Builder(new Product(), '*'); + $builder->options([ + 'from' => $expectedFrom = 100, + ]); + + $search = SearchFactory::create($builder); + + $this->assertEquals($expectedFrom, $search->getFrom()); + } + + public function test_both_parameters_dont_take_effect_on_pagination(): void + { + $builder = new Builder(new Product(), '*'); + $builder->options([ + 'from' => 250, + ]) + ->take(30); + + $search = SearchFactory::create($builder, [ + 'from' => $expectedFrom = 100, + 'size' => $expectedSize = 50, + ]); + + $this->assertEquals($expectedSize, $search->getSize()); + $this->assertEquals($expectedFrom, $search->getFrom()); } } From b097275805969684fb86ec2a6f81a82c1b74e406 Mon Sep 17 00:00:00 2001 From: Oleh Isaiev Date: Mon, 11 Nov 2024 13:29:32 +0200 Subject: [PATCH 3/5] Fix CI report --- src/Engines/ElasticSearchEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Engines/ElasticSearchEngine.php b/src/Engines/ElasticSearchEngine.php index d1abe63f..46637e14 100644 --- a/src/Engines/ElasticSearchEngine.php +++ b/src/Engines/ElasticSearchEngine.php @@ -183,7 +183,7 @@ public function getTotalCount($results) /** * @param BaseBuilder $builder - * @param array $options + * @param array $options * @return SearchResults|mixed */ private function performSearch(BaseBuilder $builder, $options = []) From a48dc2e0c108108e0cce9347b8e75f975b316b73 Mon Sep 17 00:00:00 2001 From: Oleh Isaiev Date: Wed, 13 Nov 2024 12:32:55 +0200 Subject: [PATCH 4/5] Add changelog and update documentation --- CHANGELOG.md | 9 +++++++-- README.md | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09b16f21..8b723539 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/) ## [Unreleased] +### Fixed +- [Using pagination with custom query in Scout Builder](https://github.com/matchish/laravel-scout-elasticsearch/pull/290). +### Added +- [Using `options()` of a builder](https://github.com/matchish/laravel-scout-elasticsearch/issues/252) for set `from` parameter. +- Supporting `take()` method of builder for setting response `size`. ## [7.8.0] - 2024-06-24 ### Added -- [Added supports of whereNotIn condition]([https://github.com/matchish/laravel-scout-elasticsearch/pull/282](https://github.com/matchish/laravel-scout-elasticsearch/pull/286). -- +- [Added supports of whereNotIn condition](https://github.com/matchish/laravel-scout-elasticsearch/pull/282). + ## [7.6.2] - 2024-06-24 ### Fixed - [Change if conditions order in soft deletes check for compatibility](https://github.com/matchish/laravel-scout-elasticsearch/pull/282). diff --git a/README.md b/README.md index 66d08955..f5b0bfd4 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,25 @@ Product::search() Full list of ElasticSearch terms is in `vendor/handcraftedinthealps/elasticsearch-dsl/src/Query/TermLevel`. +### Pagination +The engine supports [Elasticsearch pagination](https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html) +with [Scout Builder pagination](https://laravel.com/docs/11.x/scout#pagination) or by setting page sizes +and offsets using the `->take($size)` method and `->options(['from' => $from])`. + +> Caution : Builder pagination takes precedence over the `take()` and `options()` setting. + +For example: + +```php +Product::search() + ->take(20) + ->options([ + 'from' => 20, + ]) + ->paginate(50); +``` +This will return the first 50 results, ignoring the specified offset. + ### Search amongst multiple models You can do it with `MixedSearch` class, just pass indices names separated by commas to the `within` method. ```php From 418e5c31b350c2b46b2b1845e2da4af13f0a0a00 Mon Sep 17 00:00:00 2001 From: Oleh Isaiev Date: Thu, 14 Nov 2024 10:53:25 +0200 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b723539..011328f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/) ## [Unreleased] + +## [7.9.0] - 2024-11-14 ### Fixed - [Using pagination with custom query in Scout Builder](https://github.com/matchish/laravel-scout-elasticsearch/pull/290). ### Added