diff --git a/src/Aggregating/Bucket/FiltersAggregation.php b/src/Aggregating/Bucket/FiltersAggregation.php index d51cc94..dc697ac 100644 --- a/src/Aggregating/Bucket/FiltersAggregation.php +++ b/src/Aggregating/Bucket/FiltersAggregation.php @@ -2,10 +2,12 @@ namespace Ensi\LaravelElasticQuery\Aggregating\Bucket; +use Ensi\LaravelElasticQuery\Aggregating\AggregationCollection; use Ensi\LaravelElasticQuery\Aggregating\BucketCollection; use Ensi\LaravelElasticQuery\Aggregating\FiltersCollection; use Ensi\LaravelElasticQuery\Aggregating\Result; use Ensi\LaravelElasticQuery\Contracts\Aggregation; +use Illuminate\Support\Collection; use Webmozart\Assert\Assert; class FiltersAggregation implements Aggregation @@ -13,7 +15,7 @@ class FiltersAggregation implements Aggregation public function __construct( private string $name, private FiltersCollection $filters, - private ?Aggregation $composite = null, + private Aggregation|AggregationCollection|null $composite = null, private ?string $otherBucketKey = null, ) { Assert::stringNotEmpty(trim($name)); @@ -45,6 +47,7 @@ public function parseResults(array $response): array $buckets = array_map( function (mixed $key, array $bucket) { $values = $this->isComposite() ? $this->composite->parseResults($bucket) : []; + $values = $values instanceof Collection ? $values->toArray() : $values; return Result::parseBucketWithKey($key, $bucket, $values); }, diff --git a/src/Aggregating/Bucket/TermsAggregation.php b/src/Aggregating/Bucket/TermsAggregation.php index 9c39151..d8b2d49 100644 --- a/src/Aggregating/Bucket/TermsAggregation.php +++ b/src/Aggregating/Bucket/TermsAggregation.php @@ -2,10 +2,13 @@ namespace Ensi\LaravelElasticQuery\Aggregating\Bucket; +use Ensi\LaravelElasticQuery\Aggregating\AggregationCollection; use Ensi\LaravelElasticQuery\Aggregating\BucketCollection; use Ensi\LaravelElasticQuery\Aggregating\Result; use Ensi\LaravelElasticQuery\Contracts\Aggregation; use Ensi\LaravelElasticQuery\Search\Sorting\Sort; +use Ensi\LaravelElasticQuery\Search\Sorting\SortCollection; +use Illuminate\Support\Collection; use Webmozart\Assert\Assert; class TermsAggregation implements Aggregation @@ -14,8 +17,8 @@ public function __construct( private string $name, private string $field, private ?int $size = null, - private ?Sort $sort = null, - private ?Aggregation $composite = null, + private Sort|SortCollection|null $sort = null, + private Aggregation|AggregationCollection|null $composite = null, ) { Assert::stringNotEmpty(trim($name)); Assert::stringNotEmpty(trim($field)); @@ -57,6 +60,7 @@ public function parseResults(array $response): array $buckets = array_map( function (array $bucket) { $values = $this->isComposite() ? $this->composite->parseResults($bucket) : []; + $values = $values instanceof Collection ? $values->toArray() : $values; return Result::parseBucket($bucket, $values); }, diff --git a/src/Aggregating/Metrics/MaxAggregation.php b/src/Aggregating/Metrics/MaxAggregation.php new file mode 100644 index 0000000..59313cd --- /dev/null +++ b/src/Aggregating/Metrics/MaxAggregation.php @@ -0,0 +1,42 @@ +name; + } + + public function toDSL(): array + { + $body['field'] = $this->field; + + if ($this->missing) { + $body['missing'] = $this->missing; + } + + return [ + $this->name => ['max' => $body], + ]; + } + + public function parseResults(array $response): array + { + return [$this->name => Result::parseValue($response[$this->name]) ?? 0]; + } +} diff --git a/src/Aggregating/Metrics/MinAggregation.php b/src/Aggregating/Metrics/MinAggregation.php new file mode 100644 index 0000000..e9da92f --- /dev/null +++ b/src/Aggregating/Metrics/MinAggregation.php @@ -0,0 +1,42 @@ +name; + } + + public function toDSL(): array + { + $body['field'] = $this->field; + + if ($this->missing) { + $body['missing'] = $this->missing; + } + + return [ + $this->name => ['min' => $body], + ]; + } + + public function parseResults(array $response): array + { + return [$this->name => Result::parseValue($response[$this->name]) ?? 0]; + } +} diff --git a/src/Concerns/ConstructsAggregations.php b/src/Concerns/ConstructsAggregations.php index 33adca7..d59ce53 100644 --- a/src/Concerns/ConstructsAggregations.php +++ b/src/Concerns/ConstructsAggregations.php @@ -11,12 +11,15 @@ use Ensi\LaravelElasticQuery\Aggregating\CompositeAggregationBuilder; use Ensi\LaravelElasticQuery\Aggregating\FiltersCollection; use Ensi\LaravelElasticQuery\Aggregating\Metrics\CardinalityAggregation; +use Ensi\LaravelElasticQuery\Aggregating\Metrics\MaxAggregation; +use Ensi\LaravelElasticQuery\Aggregating\Metrics\MinAggregation; use Ensi\LaravelElasticQuery\Aggregating\Metrics\MinMaxAggregation; use Ensi\LaravelElasticQuery\Aggregating\Metrics\ValueCountAggregation; use Ensi\LaravelElasticQuery\Contracts\Aggregation; use Ensi\LaravelElasticQuery\Contracts\Criteria; use Ensi\LaravelElasticQuery\Filtering\BoolQueryBuilder; use Ensi\LaravelElasticQuery\Search\Sorting\Sort; +use Ensi\LaravelElasticQuery\Search\Sorting\SortCollection; trait ConstructsAggregations { @@ -30,8 +33,8 @@ public function terms( string $name, string $field, ?int $size = null, - ?Sort $sort = null, - ?Aggregation $composite = null, + Sort|SortCollection|null $sort = null, + Aggregation|AggregationCollection|null $composite = null, ): static { $this->aggregations->add(new TermsAggregation($name, $this->absolutePath($field), $size, $sort, $composite)); @@ -48,7 +51,7 @@ public function filter(string $name, Criteria $criteria, AggregationCollection $ public function filters( string $name, FiltersCollection $filters, - ?Aggregation $composite = null, + Aggregation|AggregationCollection|null $composite = null, ?string $otherBucketKey = null, ): static { $this->aggregations->add(new FiltersAggregation($name, $filters, $composite, $otherBucketKey)); @@ -63,6 +66,20 @@ public function minmax(string $name, string $field): static return $this; } + public function min(string $name, string $field, mixed $missing = null): static + { + $this->aggregations->add(new MinAggregation($name, $this->absolutePath($field), $missing)); + + return $this; + } + + public function max(string $name, string $field, mixed $missing = null): static + { + $this->aggregations->add(new MaxAggregation($name, $this->absolutePath($field), $missing)); + + return $this; + } + public function count(string $name, string $field): static { $this->aggregations->add(new ValueCountAggregation($name, $this->absolutePath($field))); diff --git a/src/Contracts/AggregationsBuilder.php b/src/Contracts/AggregationsBuilder.php index 9de49a8..6f4b100 100644 --- a/src/Contracts/AggregationsBuilder.php +++ b/src/Contracts/AggregationsBuilder.php @@ -10,6 +10,10 @@ public function terms(string $name, string $field, ?int $size = null): static; public function minmax(string $name, string $field): static; + public function min(string $name, string $field, mixed $missing = null): static; + + public function max(string $name, string $field, mixed $missing = null): static; + public function count(string $path, string $field): static; public function nested(string $path, Closure $callback): static; diff --git a/tests/IntegrationTests/AggregationQueryIntegrationTest.php b/tests/IntegrationTests/AggregationQueryIntegrationTest.php index ab64ddb..5040f5a 100644 --- a/tests/IntegrationTests/AggregationQueryIntegrationTest.php +++ b/tests/IntegrationTests/AggregationQueryIntegrationTest.php @@ -28,7 +28,11 @@ ->count('product_count', 'product_id') ->nested( 'offers', - fn (AggregationsBuilder $builder) => $builder->where('seller_id', 10)->minmax('price', 'price') + fn (AggregationsBuilder $builder) => $builder + ->where('seller_id', 10) + ->minmax('price', 'price') + ->min('min_price', 'price') + ->max('max_price', 'price') ) ->get(); @@ -38,6 +42,9 @@ ); assertEquals(new MinMax(168.0, 611.0), $results->get('price')); + assertEquals(168.0, $results->get('min_price')); + assertEquals(611.0, $results->get('max_price')); + assertEquals(2, $results->get('product_count')); });