diff --git a/src/Concerns/DecoratesBoolQuery.php b/src/Concerns/DecoratesBoolQuery.php index ab0754c..439b010 100644 --- a/src/Concerns/DecoratesBoolQuery.php +++ b/src/Concerns/DecoratesBoolQuery.php @@ -4,14 +4,13 @@ use Closure; use Ensi\LaravelElasticQuery\Contracts\DSLAware; -use Ensi\LaravelElasticQuery\Contracts\FunctionScoreItem; -use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions; use Ensi\LaravelElasticQuery\Contracts\MatchOptions; use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions; use Ensi\LaravelElasticQuery\Contracts\MoreLikeThis; use Ensi\LaravelElasticQuery\Contracts\MultiMatchOptions; use Ensi\LaravelElasticQuery\Contracts\WildcardOptions; use Ensi\LaravelElasticQuery\Filtering\BoolQueryBuilder; +use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScore; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Support\Traits\ForwardsCalls; @@ -161,12 +160,7 @@ public function whereBetween(string $field, mixed $from, mixed $to): static return $this; } - /** - * @param array $functions - * @param ?DSLAware $query - * @param ?FunctionScoreOptions $options - */ - public function addFunctionScore(array $functions, ?DSLAware $query = null, ?FunctionScoreOptions $options = null): static + public function orFunctionScore(FunctionScore $functionScore): static { $this->forwardCallTo($this->boolQuery(), __FUNCTION__, func_get_args()); diff --git a/src/Contracts/BoolQuery.php b/src/Contracts/BoolQuery.php index 6029468..4dca250 100644 --- a/src/Contracts/BoolQuery.php +++ b/src/Contracts/BoolQuery.php @@ -3,6 +3,7 @@ namespace Ensi\LaravelElasticQuery\Contracts; use Closure; +use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScore; use Illuminate\Contracts\Support\Arrayable; interface BoolQuery @@ -47,12 +48,7 @@ public function whereMoreLikeThis(array $fields, MoreLikeThis $likeThis, ?MoreLi public function whereBetween(string $field, mixed $from, mixed $to): static; - /** - * @param array $functions - * @param ?DSLAware $query - * @param ?FunctionScoreOptions $options - */ - public function addFunctionScore(array $functions, ?DSLAware $query = null, ?FunctionScoreOptions $options = null): static; + public function orFunctionScore(FunctionScore $functionScore): static; public function pinned(array $ids, ?DSLAware $query = null): static; } diff --git a/src/Contracts/FunctionScoreItem.php b/src/Contracts/FunctionScoreItem.php index 836a526..8f7b580 100644 --- a/src/Contracts/FunctionScoreItem.php +++ b/src/Contracts/FunctionScoreItem.php @@ -7,16 +7,16 @@ class FunctionScoreItem implements Arrayable { public function __construct( - private int $weight, - private Criteria $filter, + protected int $weight, + protected Criteria $filter, ) { } public function toArray(): array { return [ - 'weight' => $this->weight, 'filter' => $this->filter->toDSL(), + 'weight' => $this->weight, ]; } } diff --git a/src/Contracts/FunctionScoreOptions.php b/src/Contracts/FunctionScoreOptions.php index 6c8176f..4e87c70 100644 --- a/src/Contracts/FunctionScoreOptions.php +++ b/src/Contracts/FunctionScoreOptions.php @@ -7,7 +7,7 @@ class FunctionScoreOptions implements Arrayable { - public function __construct(private array $options = []) + public function __construct(protected array $options = []) { } diff --git a/src/Contracts/FunctionScoreScript.php b/src/Contracts/FunctionScoreScript.php new file mode 100644 index 0000000..198109e --- /dev/null +++ b/src/Contracts/FunctionScoreScript.php @@ -0,0 +1,20 @@ + array_filter([ + 'source' => $this->source, + 'params' => $this->params, + ])]; + } +} diff --git a/src/Filtering/BoolQueryBuilder.php b/src/Filtering/BoolQueryBuilder.php index d848506..b68b0e8 100644 --- a/src/Filtering/BoolQueryBuilder.php +++ b/src/Filtering/BoolQueryBuilder.php @@ -7,8 +7,6 @@ use Ensi\LaravelElasticQuery\Contracts\BoolQuery; use Ensi\LaravelElasticQuery\Contracts\Criteria; use Ensi\LaravelElasticQuery\Contracts\DSLAware; -use Ensi\LaravelElasticQuery\Contracts\FunctionScoreItem; -use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions; use Ensi\LaravelElasticQuery\Contracts\MatchOptions; use Ensi\LaravelElasticQuery\Contracts\MoreLikeOptions; use Ensi\LaravelElasticQuery\Contracts\MoreLikeThis; @@ -268,14 +266,9 @@ public function whereBetween(string $field, mixed $from, mixed $to): static return $this; } - /** - * @param array $functions - * @param ?DSLAware $query - * @param ?FunctionScoreOptions $options - */ - public function addFunctionScore(array $functions, ?DSLAware $query = null, ?FunctionScoreOptions $options = null): static + public function orFunctionScore(FunctionScore $functionScore): static { - $this->should->add(new FunctionScore($functions, $query, $options)); + $this->should->add($functionScore); return $this; } diff --git a/src/Filtering/Criterias/FunctionScore.php b/src/Filtering/Criterias/FunctionScore.php index 71f060a..8ecabfd 100644 --- a/src/Filtering/Criterias/FunctionScore.php +++ b/src/Filtering/Criterias/FunctionScore.php @@ -6,6 +6,7 @@ use Ensi\LaravelElasticQuery\Contracts\DSLAware; use Ensi\LaravelElasticQuery\Contracts\FunctionScoreItem; use Ensi\LaravelElasticQuery\Contracts\FunctionScoreOptions; +use Ensi\LaravelElasticQuery\Contracts\FunctionScoreScript; use stdClass; use Webmozart\Assert\Assert; @@ -13,23 +14,35 @@ class FunctionScore implements Criteria { /** * @param array $functions - * @param FunctionScoreOptions|null $options */ public function __construct( - private array $functions, - private ?DSLAware $query = null, - private ?FunctionScoreOptions $options = null, + protected ?DSLAware $query = null, + protected ?FunctionScoreOptions $options = null, + protected array $functions = [], + protected ?FunctionScoreScript $scriptScore = null, + protected ?float $weight = null, ) { - array_map(fn ($function) => Assert::isInstanceOfAny($function, [FunctionScoreItem::class]), $functions); + Assert::allIsInstanceOfAny($functions, [FunctionScoreItem::class]); } public function toDSL(): array { $body = [ 'query' => $this->query?->toDSL() ?? ['match_all' => new stdClass()], - 'functions' => array_map(fn (FunctionScoreItem $function) => $function->toArray(), $this->functions), ]; + if ($this->functions) { + $body['functions'] = array_map(fn (FunctionScoreItem $function) => $function->toArray(), $this->functions); + } + + if ($this->scriptScore) { + $body['script_score'] = $this->scriptScore->toDSL(); + } + + if (!is_null($this->weight)) { + $body['weight'] = $this->weight; + } + if ($this->options) { $body = array_merge($this->options->toArray(), $body); } diff --git a/tests/IntegrationTests/Search/SearchQueryIntegrationTest.php b/tests/IntegrationTests/Search/SearchQueryIntegrationTest.php index b062cc2..05902eb 100644 --- a/tests/IntegrationTests/Search/SearchQueryIntegrationTest.php +++ b/tests/IntegrationTests/Search/SearchQueryIntegrationTest.php @@ -8,6 +8,7 @@ use Ensi\LaravelElasticQuery\Contracts\MoreLikeThis; use Ensi\LaravelElasticQuery\Contracts\ScoreMode; use Ensi\LaravelElasticQuery\Contracts\SortableQuery; +use Ensi\LaravelElasticQuery\Filtering\Criterias\FunctionScore; use Ensi\LaravelElasticQuery\Filtering\Criterias\Terms; use Ensi\LaravelElasticQuery\Tests\Data\Models\ProductsIndex; use Ensi\LaravelElasticQuery\Tests\IntegrationTestCase; @@ -148,21 +149,19 @@ /** @var SearchIntegrationTestCase $this */ $result = ProductsIndex::query() - ->addFunctionScore( - [ - new FunctionScoreItem( - weight: 10, - filter: new Terms( - field: "tags", - values: ["drinks"], - ), - ), - ], + ->orFunctionScore(new FunctionScore( options: FunctionScoreOptions::make( scoreMode: ScoreMode::SUM, boostMode: BoostMode::SUM - ) - ) + ), + functions: [new FunctionScoreItem( + weight: 10, + filter: new Terms( + field: "tags", + values: ["drinks"], + ), + )], + )) ->get(); assertCount(6, $result);