From 93e325c35dbc0b7c9d7424b188956c0741f60185 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 28 Apr 2023 15:27:44 +0200 Subject: [PATCH 1/5] Support Max Aggregation --- .../example/RepositoriesElasticsearch.scala | 18 ++++++++++- .../elasticsearch/ElasticAggregation.scala | 28 ++++++++++++++++- .../aggregation/Aggregations.scala | 20 ++++++++++-- .../aggregation/options/HasMissing.scala | 31 +++++++++++++++++++ .../elasticsearch/executor/HttpExecutor.scala | 2 ++ .../response/AggregationResponse.scala | 12 +++++++ .../SearchWithAggregationsResponse.scala | 3 ++ 7 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala diff --git a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala index 28ab974da..e9f23deb1 100644 --- a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala +++ b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala @@ -17,6 +17,7 @@ package example import zio._ +import zio.elasticsearch.ElasticAggregation.{maxAggregation, termsAggregation} import zio.elasticsearch.ElasticQuery.matchAll import zio.elasticsearch._ import zio.elasticsearch.query.ElasticQuery @@ -24,9 +25,24 @@ import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} final case class RepositoriesElasticsearch(elasticsearch: Elasticsearch) { - def findAll(): Task[List[GitHubRepo]] = + def findAll(): Task[List[GitHubRepo]] = { elasticsearch.execute(ElasticRequest.search(Index, matchAll)).documentAs[GitHubRepo] + for { + x <- elasticsearch + .execute( + ElasticRequest.aggregate( + Index, + termsAggregation("aggrTerms", GitHubRepo.organization) + .withSubAgg(maxAggregation("aggMax", GitHubRepo.forks).missing(10.24)) + ) + ) + .aggregations + _ = println(x) + } yield (List()) + + } + def findById(organization: String, id: String): Task[Option[GitHubRepo]] = for { routing <- routingOf(organization) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticAggregation.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticAggregation.scala index c441750f9..ca16b5e1d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticAggregation.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticAggregation.scala @@ -50,11 +50,37 @@ object ElasticAggregation { * @param name * aggregation name * @param field - * field for which terms aggregation will be executed + * the field for which terms aggregation will be executed * @return * an instance of [[zio.elasticsearch.aggregation.TermsAggregation]] that represents terms aggregation to be * performed. */ final def termsAggregation(name: String, field: String): TermsAggregation = Terms(name = name, field = field, order = Set.empty, subAggregations = Nil, size = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.aggregation.MaxAggregation]] using the specified parameters. + * + * @param name + * aggregation name + * @param field + * the type-safe field for which max aggregation will be executed + * @return + * an instance of [[zio.elasticsearch.aggregation.MaxAggregation]] that represents max aggregation to be performed. + */ + final def maxAggregation(name: String, field: Field[_, Any]): MaxAggregation = + Max(name = name, field = field.toString, missing = None) + + /** + * Constructs an instance of [[zio.elasticsearch.aggregation.MaxAggregation]] using the specified parameters. + * + * @param name + * aggregation name + * @param field + * the field for which max aggregation will be executed + * @return + * an instance of [[zio.elasticsearch.aggregation.MaxAggregation]] that represents max aggregation to be performed. + */ + final def maxAggregation(name: String, field: String): MaxAggregation = + Max(name = name, field = field, missing = None) } diff --git a/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala b/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala index ed9a659fc..3fbe16e0f 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala @@ -31,6 +31,22 @@ sealed trait ElasticAggregation { self => sealed trait SingleElasticAggregation extends ElasticAggregation +sealed trait MaxAggregation extends SingleElasticAggregation with HasMissing[MaxAggregation] with WithAgg + +final case class Max(name: String, field: String, missing: Option[Double]) extends MaxAggregation { self => + def missing(value: Double): MaxAggregation = + self.copy(missing = Some(value)) + + def withAgg(agg: SingleElasticAggregation): MultipleAggregations = + multipleAggregations.aggregations(self, agg) + + private[elasticsearch] def paramsToJson: Json = { + val missingJson: Json = missing.fold(Obj())(m => Obj("missing" -> m.toJson)) + + Obj(name -> Obj("max" -> (Obj("field" -> field.toJson) merge missingJson))) + } +} + sealed trait MultipleAggregations extends ElasticAggregation with WithAgg { def aggregations(aggregations: SingleElasticAggregation*): MultipleAggregations } @@ -40,7 +56,7 @@ private[elasticsearch] final case class Multiple(aggregations: List[SingleElasti def aggregations(aggregations: SingleElasticAggregation*): MultipleAggregations = self.copy(aggregations = self.aggregations ++ aggregations) - def paramsToJson: Json = + private[elasticsearch] def paramsToJson: Json = aggregations.map(_.paramsToJson).reduce(_ merge _) def withAgg(agg: SingleElasticAggregation): MultipleAggregations = @@ -75,7 +91,7 @@ private[elasticsearch] final case class Terms( def orderBy(order: AggregationOrder, orders: AggregationOrder*): TermsAggregation = self.copy(order = self.order + order ++ orders.toSet) - def paramsToJson: Json = + private[elasticsearch] def paramsToJson: Json = Obj(name -> paramsToJsonHelper) def size(value: Int): TermsAggregation = diff --git a/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala b/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala new file mode 100644 index 000000000..ca70ab8b3 --- /dev/null +++ b/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala @@ -0,0 +1,31 @@ +/* + * Copyright 2022 LambdaWorks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package zio.elasticsearch.aggregation.options + +private[elasticsearch] trait HasMissing[A <: HasMissing[A]] { + + /** + * Sets the `missing` parameter for the [[zio.elasticsearch.aggregation.ElasticAggregation]]. The`Missing` parameter + * provides a value to use when a document is missing the field that the aggregation is running on. + * + * @param value + * the value to use for missing documents + * @return + * an instance of the [[zio.elasticsearch.aggregation.ElasticAggregation]] enriched with the `missing` parameter. + */ + def missing(value: Double): A +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala index bf52b548b..54c81b237 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala @@ -115,6 +115,8 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig .contentType(ApplicationJson) .body(r.aggregation.toJson) ).flatMap { response => + println(r.aggregation.toJson) + println(response.body) response.code match { case HttpOk => response.body.fold( diff --git a/modules/library/src/main/scala/zio/elasticsearch/executor/response/AggregationResponse.scala b/modules/library/src/main/scala/zio/elasticsearch/executor/response/AggregationResponse.scala index 5924fd83d..12383303a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/executor/response/AggregationResponse.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/executor/response/AggregationResponse.scala @@ -22,6 +22,12 @@ import zio.json.{DeriveJsonDecoder, JsonDecoder, jsonField} sealed trait AggregationResponse +private[elasticsearch] final case class MaxAggregationResponse(value: Double) extends AggregationResponse + +private[elasticsearch] object MaxAggregationResponse { + implicit val decoder: JsonDecoder[MaxAggregationResponse] = DeriveJsonDecoder.gen[MaxAggregationResponse] +} + private[elasticsearch] final case class TermsAggregationResponse( @jsonField("doc_count_error_upper_bound") docErrorCount: Int, @@ -65,6 +71,10 @@ private[elasticsearch] object TermsAggregationBucket { .map(_.unsafeAs[TermsAggregationBucket](TermsAggregationBucket.decoder)) ) ) + case str if str.contains("max#") => + Some( + field -> MaxAggregationResponse(value = objFields("value").unsafeAs[Double]) + ) } } }.toMap @@ -76,6 +86,8 @@ private[elasticsearch] object TermsAggregationBucket { (field: @unchecked) match { case str if str.contains("terms#") => (field.split("#")(1), data.asInstanceOf[TermsAggregationResponse]) + case str if str.contains("max#") => + (field.split("#")(1), data.asInstanceOf[MaxAggregationResponse]) } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/executor/response/SearchWithAggregationsResponse.scala b/modules/library/src/main/scala/zio/elasticsearch/executor/response/SearchWithAggregationsResponse.scala index 4e2c6f112..38b2b3810 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/executor/response/SearchWithAggregationsResponse.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/executor/response/SearchWithAggregationsResponse.scala @@ -75,6 +75,9 @@ private[elasticsearch] final case class SearchWithAggregationsResponse( TermsAggregationResponse.decoder .decodeJson(data.toString) .map(field.split("#")(1) -> _) + case str if str.contains("max#") => + MaxAggregationResponse.decoder.decodeJson(data.toString).map(field.split("#")(1) -> _) + } ) } From d600d12d51f646527c82cab974be26c7c97d18da Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 28 Apr 2023 16:11:37 +0200 Subject: [PATCH 2/5] Add tests for Max Aggregations --- .../example/RepositoriesElasticsearch.scala | 18 +- .../zio/elasticsearch/HttpExecutorSpec.scala | 41 +- .../elasticsearch/executor/HttpExecutor.scala | 2 - .../zio/elasticsearch/AggregationSpec.scala | 512 ++++++++++++++++++ .../ElasticAggregationSpec.scala | 126 +++-- 5 files changed, 635 insertions(+), 64 deletions(-) create mode 100644 modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala diff --git a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala index e9f23deb1..28ab974da 100644 --- a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala +++ b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala @@ -17,7 +17,6 @@ package example import zio._ -import zio.elasticsearch.ElasticAggregation.{maxAggregation, termsAggregation} import zio.elasticsearch.ElasticQuery.matchAll import zio.elasticsearch._ import zio.elasticsearch.query.ElasticQuery @@ -25,24 +24,9 @@ import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} final case class RepositoriesElasticsearch(elasticsearch: Elasticsearch) { - def findAll(): Task[List[GitHubRepo]] = { + def findAll(): Task[List[GitHubRepo]] = elasticsearch.execute(ElasticRequest.search(Index, matchAll)).documentAs[GitHubRepo] - for { - x <- elasticsearch - .execute( - ElasticRequest.aggregate( - Index, - termsAggregation("aggrTerms", GitHubRepo.organization) - .withSubAgg(maxAggregation("aggMax", GitHubRepo.forks).missing(10.24)) - ) - ) - .aggregations - _ = println(x) - } yield (List()) - - } - def findById(organization: String, id: String): Task[Option[GitHubRepo]] = for { routing <- routingOf(organization) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index 886a61428..f691b5833 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -17,12 +17,13 @@ package zio.elasticsearch import zio.Chunk -import zio.elasticsearch.ElasticAggregation.{multipleAggregations, termsAggregation} +import zio.elasticsearch.ElasticAggregation.{maxAggregation, multipleAggregations, termsAggregation} import zio.elasticsearch.ElasticHighlight.highlight import zio.elasticsearch.ElasticQuery._ import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.domain.{TestDocument, TestSubDocument} import zio.elasticsearch.executor.Executor +import zio.elasticsearch.executor.response.MaxAggregationResponse import zio.elasticsearch.query.sort.SortMode.Max import zio.elasticsearch.query.sort.SortOrder._ import zio.elasticsearch.query.sort.SourceType.NumberType @@ -44,6 +45,30 @@ object HttpExecutorSpec extends IntegrationSpec { suite("Executor")( suite("HTTP Executor")( suite("aggregation")( + test("aggregate using max aggregation") { + checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { + (firstDocumentId, firstDocument, secondDocumentId, secondDocument) => + for { + _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) + _ <- Executor.execute( + ElasticRequest + .upsert[TestDocument](firstSearchIndex, firstDocumentId, firstDocument.copy(intField = 20)) + ) + _ <- Executor.execute( + ElasticRequest + .upsert[TestDocument](firstSearchIndex, secondDocumentId, secondDocument.copy(intField = 10)) + .refreshTrue + ) + aggregation = maxAggregation(name = "aggregationInt", field = TestDocument.intField) + aggsRes <- Executor + .execute(ElasticRequest.aggregate(index = firstSearchIndex, aggregation = aggregation)) + .aggregations + } yield assert(aggsRes.head)(equalTo("aggregationInt", MaxAggregationResponse(20.0))) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), test("aggregate using terms aggregation") { checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { (firstDocumentId, firstDocument, secondDocumentId, secondDocument) => @@ -58,15 +83,9 @@ object HttpExecutorSpec extends IntegrationSpec { .refreshTrue ) aggregation = - termsAggregation( - name = "aggregationString", - field = TestDocument.stringField.keyword - ) + termsAggregation(name = "aggregationString", field = TestDocument.stringField.keyword) aggsRes <- Executor - .execute( - ElasticRequest - .aggregate(index = firstSearchIndex, aggregation = aggregation) - ) + .execute(ElasticRequest.aggregate(index = firstSearchIndex, aggregation = aggregation)) .aggregations } yield assert(aggsRes)(isNonEmpty) } @@ -106,7 +125,7 @@ object HttpExecutorSpec extends IntegrationSpec { Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie ), - test("aggregate using terms aggregation with nested terms aggregation") { + test("aggregate using terms aggregation with nested max aggregation") { checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { (firstDocumentId, firstDocument, secondDocumentId, secondDocument) => for { @@ -123,7 +142,7 @@ object HttpExecutorSpec extends IntegrationSpec { name = "aggregationString", field = TestDocument.stringField.keyword ) - .withSubAgg(termsAggregation(name = "aggregationInt", field = "intField.keyword")) + .withSubAgg(maxAggregation(name = "aggregationInt", field = "intField")) aggsRes <- Executor .execute( ElasticRequest diff --git a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala index 54c81b237..bf52b548b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala @@ -115,8 +115,6 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig .contentType(ApplicationJson) .body(r.aggregation.toJson) ).flatMap { response => - println(r.aggregation.toJson) - println(response.body) response.code match { case HttpOk => response.body.fold( diff --git a/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala new file mode 100644 index 000000000..c9313c58a --- /dev/null +++ b/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala @@ -0,0 +1,512 @@ +package zio.elasticsearch + +import zio.Scope +import zio.elasticsearch.ElasticAggregation.{maxAggregation, multipleAggregations, termsAggregation} +import zio.elasticsearch.aggregation._ +import zio.elasticsearch.domain.TestSubDocument +import zio.elasticsearch.query.sort.SortOrder.{Asc, Desc} +import zio.elasticsearch.utils._ +import zio.test.Assertion.equalTo +import zio.test._ + +object AggregationSpec extends ZIOSpecDefault { + def spec: Spec[Environment with TestEnvironment with Scope, Any] = + suite("Aggregations")( + suite("creating ElasticAggregation")( + test("successfully create Max aggregation using `maxAggregation` method") { + val aggregation = maxAggregation(name = "aggregation", field = "day_of_month") + + assert(aggregation)( + equalTo( + Max(name = "aggregation", field = "day_of_month", missing = None) + ) + ) + }, + test("successfully create type-safe Max aggregation using `maxAggregation` method") { + val aggregation = maxAggregation(name = "aggregation", field = TestSubDocument.intField) + + assert(aggregation)( + equalTo( + Max(name = "aggregation", field = "intField", missing = None) + ) + ) + }, + test("successfully create type-safe Max aggregation using `maxAggregation` method with `missing` parameter") { + val aggregation = maxAggregation(name = "aggregation", field = TestSubDocument.intField).missing(20) + + assert(aggregation)( + equalTo( + Max(name = "aggregation", field = "intField", missing = Some(20)) + ) + ) + }, + test("successfully create Multiple Aggregations using two `maxAggregation` methods") { + val aggregation = maxAggregation(name = "aggregation1", field = TestSubDocument.intField) + .withAgg(maxAggregation("aggregation2", TestSubDocument.intFieldList)) + + assert(aggregation)( + equalTo( + Multiple(aggregations = + List( + Max(name = "aggregation1", field = "intField", None), + Max(name = "aggregation2", field = "intFieldList", None) + ) + ) + ) + ) + }, + test("successfully create Terms aggregation using `termsAggregation` method") { + val aggregation = termsAggregation(name = "aggregation", field = "day_of_week") + + assert(aggregation)( + equalTo( + Terms(name = "aggregation", field = "day_of_week", order = Set.empty, subAggregations = Nil, size = None) + ) + ) + }, + test("successfully create type-safe Terms aggregation using `termsAggregation` method") { + val aggregation = termsAggregation(name = "aggregation", field = TestSubDocument.stringField) + + assert(aggregation)( + equalTo( + Terms(name = "aggregation", field = "stringField", order = Set.empty, subAggregations = Nil, size = None) + ) + ) + }, + test("successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method") { + val aggregation = + termsAggregation(name = "aggregation", field = TestSubDocument.stringField.keyword) + + assert(aggregation)( + equalTo( + Terms( + name = "aggregation", + field = "stringField.keyword", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ) + ) + }, + test( + "successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method and `order` parameter" + ) { + val aggregation = + termsAggregation( + name = "aggregation", + field = TestSubDocument.stringField.keyword + ).orderByKeyDesc.orderByCountAsc + + assert(aggregation)( + equalTo( + Terms( + name = "aggregation", + field = "stringField.keyword", + order = Set(AggregationOrder("_key", Desc), AggregationOrder("_count", Asc)), + subAggregations = Nil, + size = None + ) + ) + ) + }, + test( + "successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method and `size` parameter" + ) { + val aggregation = + termsAggregation(name = "aggregation", field = TestSubDocument.stringField.keyword) + .size(5) + + assert(aggregation)( + equalTo( + Terms( + name = "aggregation", + field = "stringField.keyword", + order = Set.empty, + subAggregations = Nil, + size = Some(5) + ) + ) + ) + }, + test( + "successfully create type-safe Terms aggregation with multi-field with all params" + ) { + val aggregation = + termsAggregation( + name = "aggregation", + field = TestSubDocument.stringField.keyword + ).orderByCountDesc.orderByKeyAsc + .size(5) + + assert(aggregation)( + equalTo( + Terms( + name = "aggregation", + field = "stringField.keyword", + order = Set(AggregationOrder("_count", Desc), AggregationOrder("_key", Asc)), + subAggregations = Nil, + size = Some(5) + ) + ) + ) + }, + test( + "successfully create Multiple aggregations using `multipleAggregations` method with two `termsAggregation`" + ) { + val aggregation = multipleAggregations.aggregations( + termsAggregation(name = "firstAggregation", field = "day_of_week"), + termsAggregation(name = "secondAggregation", field = "customer_age") + ) + + assert(aggregation)( + equalTo( + Multiple( + List( + Terms( + name = "firstAggregation", + field = "day_of_week", + order = Set.empty, + subAggregations = Nil, + size = None + ), + Terms( + name = "secondAggregation", + field = "customer_age", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ) + ) + ) + ) + }, + test("successfully create Multiple aggregations using `withAgg`") { + val aggregation1 = termsAggregation(name = "firstAggregation", field = "day_of_week") + .withAgg(termsAggregation(name = "secondAggregation", field = "customer_age")) + val aggregation2 = multipleAggregations + .aggregations( + termsAggregation(name = "firstAggregation", field = "day_of_week"), + termsAggregation(name = "secondAggregation", field = "customer_age") + ) + .withAgg(termsAggregation(name = "thirdAggregation", field = "day_of_month")) + + assert(aggregation1)( + equalTo( + Multiple( + List( + Terms( + name = "firstAggregation", + field = "day_of_week", + order = Set.empty, + subAggregations = Nil, + size = None + ), + Terms( + name = "secondAggregation", + field = "customer_age", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ) + ) + ) + ) && assert(aggregation2)( + equalTo( + Multiple( + List( + Terms( + name = "thirdAggregation", + field = "day_of_month", + order = Set.empty, + subAggregations = Nil, + size = None + ), + Terms( + name = "firstAggregation", + field = "day_of_week", + order = Set.empty, + subAggregations = Nil, + size = None + ), + Terms( + name = "secondAggregation", + field = "customer_age", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ) + ) + ) + ) + }, + test("successfully create nested aggregation using `withSubAgg`") { + val aggregation1 = termsAggregation(name = "firstAggregation", field = "day_of_week").withSubAgg( + termsAggregation(name = "secondAggregation", field = "customer_age") + ) + val aggregation2 = multipleAggregations + .aggregations( + termsAggregation(name = "firstAggregation", field = "day_of_week") + .withSubAgg(maxAggregation(name = "fourthAggregation", field = "age")), + termsAggregation(name = "secondAggregation", field = "customer_age").withSubAgg( + termsAggregation(name = "thirdAggregation", field = "day_of_month") + ) + ) + + assert(aggregation1)( + equalTo( + Terms( + name = "firstAggregation", + field = "day_of_week", + order = Set.empty, + subAggregations = List( + Terms( + name = "secondAggregation", + field = "customer_age", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ), + size = None + ) + ) + ) && assert(aggregation2)( + equalTo( + Multiple( + List( + Terms( + name = "firstAggregation", + field = "day_of_week", + order = Set.empty, + subAggregations = List(Max(name = "fourthAggregation", field = "age", missing = None)), + size = None + ), + Terms( + name = "secondAggregation", + field = "customer_age", + order = Set.empty, + subAggregations = List( + Terms( + name = "thirdAggregation", + field = "day_of_month", + order = Set.empty, + subAggregations = Nil, + size = None + ) + ), + size = None + ) + ) + ) + ) + ) + } + ), + suite("encoding ElasticAggregation as JSON")( + test("properly encode Max aggregation") { + val aggregation = maxAggregation(name = "aggregation", field = "day_of_month") + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "max": { + | "field": "day_of_month" + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Max aggregation with `missing") { + val aggregation = maxAggregation(name = "aggregation", field = "day_of_month").missing(20) + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "max": { + | "field": "day_of_month", + | "missing": 20.0 + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Terms aggregation") { + val aggregation = termsAggregation(name = "aggregation", field = "day_of_week") + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "terms": { + | "field": "day_of_week" + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Terms aggregation with `order`") { + val aggregation = + termsAggregation(name = "aggregation", field = "day_of_week").orderBy(AggregationOrder("_key", Desc)) + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "terms": { + | "field": "day_of_week", + | "order": { + | "_key": "desc" + | } + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Terms aggregation with `size`") { + val aggregation = termsAggregation(name = "aggregation", field = "day_of_week").size(5) + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "terms": { + | "field": "day_of_week", + | "size": 5 + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Multiple aggregations with two Terms aggregations") { + val aggregation = multipleAggregations.aggregations( + termsAggregation(name = "firstAggregation", field = "day_of_week"), + termsAggregation(name = "secondAggregation", field = "customer_age") + ) + val expected = + """ + |{ + | "aggs": { + | "firstAggregation": { + | "terms": { + | "field": "day_of_week" + | } + | }, + | "secondAggregation": { + | "terms": { + | "field": "customer_age" + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode Multiple aggregations with Terms aggregation and Max aggregation") { + val aggregation = multipleAggregations.aggregations( + termsAggregation(name = "firstAggregation", field = "day_of_week"), + maxAggregation(name = "secondAggregation", field = "customer_age") + ) + val expected = + """ + |{ + | "aggs": { + | "firstAggregation": { + | "terms": { + | "field": "day_of_week" + | } + | }, + | "secondAggregation": { + | "max": { + | "field": "customer_age" + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode nested aggregation") { + val aggregation = termsAggregation(name = "firstAggregation", field = "day_of_week").withSubAgg( + maxAggregation(name = "secondAggregation", field = "customer_age") + ) + val expected = + """ + |{ + | "aggs": { + | "firstAggregation": { + | "terms": { + | "field": "day_of_week" + | }, + | "aggs": { + | "secondAggregation": { + | "max": { + | "field": "customer_age" + | } + | } + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + }, + test("properly encode multiple aggregation with nested aggregation") { + val aggregation = termsAggregation(name = "firstAggregation", field = "day_of_week") + .withSubAgg( + termsAggregation(name = "secondAggregation", field = "customer_age") + ) + .withAgg(termsAggregation(name = "thirdAggregation", field = "day_of_month")) + val expected = + """ + |{ + | "aggs": { + | "firstAggregation": { + | "terms": { + | "field": "day_of_week" + | }, + | "aggs": { + | "secondAggregation": { + | "terms": { + | "field": "customer_age" + | } + | } + | } + | }, + | "thirdAggregation": { + | "terms": { + | "field": "day_of_month" + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) + } + ) + ) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticAggregationSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticAggregationSpec.scala index b5d338939..9187c578b 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticAggregationSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticAggregationSpec.scala @@ -1,6 +1,6 @@ package zio.elasticsearch -import zio.elasticsearch.ElasticAggregation.{multipleAggregations, termsAggregation} +import zio.elasticsearch.ElasticAggregation.{maxAggregation, multipleAggregations, termsAggregation} import zio.elasticsearch.aggregation._ import zio.elasticsearch.domain.{TestDocument, TestSubDocument} import zio.elasticsearch.query.sort.SortOrder @@ -13,15 +13,28 @@ object ElasticAggregationSpec extends ZIOSpecDefault { def spec: Spec[TestEnvironment, Any] = suite("ElasticAggregation")( suite("constructing")( + test("max") { + val aggregation = maxAggregation("aggregation", "testField") + val aggregationTs = maxAggregation("aggregation", TestSubDocument.intField) + val aggregationTsRaw = maxAggregation("aggregation", TestSubDocument.intField.raw) + val aggregationWithMissing = maxAggregation("aggregation", TestSubDocument.intField).missing(20.0) + + assert(aggregation)(equalTo(Max(name = "aggregation", field = "testField", missing = None))) && + assert(aggregationTs)(equalTo(Max(name = "aggregation", field = "intField", missing = None))) && + assert(aggregationTsRaw)(equalTo(Max(name = "aggregation", field = "intField.raw", missing = None))) && + assert(aggregationWithMissing)( + equalTo(Max(name = "aggregation", field = "intField", missing = Some(20.0))) + ) + }, test("multiple") { val aggregation = multipleAggregations.aggregations( termsAggregation("first", TestDocument.stringField).orderByKeyDesc, - termsAggregation("second", "testField").size(5) + maxAggregation("second", "testField").missing(20.0) ) val aggregationWithSubAggregation = termsAggregation("first", "testField") - .withSubAgg(termsAggregation("second", TestSubDocument.stringField.raw)) + .withSubAgg(maxAggregation("second", TestSubDocument.intField.raw)) .withAgg(termsAggregation("third", TestDocument.stringField)) assert(aggregation)( @@ -35,13 +48,7 @@ object ElasticAggregationSpec extends ZIOSpecDefault { subAggregations = Nil, size = None ), - Terms( - name = "second", - field = "testField", - order = Set.empty, - subAggregations = Nil, - size = Some(5) - ) + Max(name = "second", field = "testField", missing = Some(20.0)) ) ) ) @@ -55,12 +62,10 @@ object ElasticAggregationSpec extends ZIOSpecDefault { field = "testField", order = Set.empty, subAggregations = List( - Terms( + Max( name = "second", - field = "stringField.raw", - order = Set.empty, - subAggregations = Nil, - size = None + field = "intField.raw", + missing = None ) ), size = None @@ -78,11 +83,13 @@ object ElasticAggregationSpec extends ZIOSpecDefault { ) }, test("subAggregation") { - val aggregation1 = termsAggregation("first", TestDocument.stringField).withSubAgg( - termsAggregation("second", TestSubDocument.stringField.raw) + val aggregation1 = termsAggregation(name = "first", field = TestDocument.stringField).withSubAgg( + termsAggregation(name = "second", field = TestSubDocument.stringField.raw) ) - val aggregation2 = termsAggregation("first", TestDocument.stringField).withAgg( - termsAggregation("second", "testField").withSubAgg(termsAggregation("third", "anotherTestField")) + val aggregation2 = termsAggregation(name = "first", field = TestDocument.stringField).withAgg( + termsAggregation(name = "second", field = "testField").withSubAgg( + maxAggregation("third", "anotherTestField") + ) ) assert(aggregation1)( @@ -119,12 +126,10 @@ object ElasticAggregationSpec extends ZIOSpecDefault { field = "testField", order = Set.empty, subAggregations = List( - Terms( + Max( name = "third", field = "anotherTestField", - order = Set.empty, - subAggregations = Nil, - size = None + missing = None ) ), size = None @@ -211,15 +216,64 @@ object ElasticAggregationSpec extends ZIOSpecDefault { } ), suite("encoding as JSON")( + test("max") { + val aggregation = maxAggregation("aggregation", "testField") + val aggregationTs = maxAggregation("aggregation", TestDocument.intField) + val aggregationWithMissing = maxAggregation("aggregation", TestDocument.intField).missing(20.0) + + val expected = + """ + |{ + | "aggs": { + | "aggregation": { + | "max": { + | "field": "testField" + | } + | } + | } + |} + |""".stripMargin + + val expectedTs = + """ + |{ + | "aggs": { + | "aggregation": { + | "max": { + | "field": "intField" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithMissing = + """ + |{ + | "aggs": { + | "aggregation": { + | "max": { + | "field": "intField", + | "missing": 20.0 + | } + | } + | } + |} + |""".stripMargin + + assert(aggregation.toJson)(equalTo(expected.toJson)) && + assert(aggregationTs.toJson)(equalTo(expectedTs.toJson)) && + assert(aggregationWithMissing.toJson)(equalTo(expectedWithMissing.toJson)) + }, test("multiple") { val aggregation = multipleAggregations.aggregations( - termsAggregation("first", TestDocument.stringField), - termsAggregation("second", "testField") + termsAggregation("first", TestDocument.stringField).orderByKeyDesc, + maxAggregation("second", "testField").missing(20.0) ) val aggregationWithSubAggregation = termsAggregation("first", "testField") - .withSubAgg(termsAggregation("second", TestSubDocument.stringField.raw)) + .withSubAgg(maxAggregation("second", TestSubDocument.intField.raw)) .withAgg(termsAggregation("third", TestDocument.stringField)) val expected = @@ -228,12 +282,16 @@ object ElasticAggregationSpec extends ZIOSpecDefault { | "aggs": { | "first": { | "terms": { - | "field": "stringField" + | "field": "stringField", + | "order": { + | "_key": "desc" + | } | } | }, | "second": { - | "terms": { - | "field": "testField" + | "max": { + | "field": "testField", + | "missing": 20.0 | } | } | } @@ -250,8 +308,8 @@ object ElasticAggregationSpec extends ZIOSpecDefault { | }, | "aggs": { | "second": { - | "terms": { - | "field": "stringField.raw" + | "max": { + | "field": "intField.raw" | } | } | } @@ -271,7 +329,7 @@ object ElasticAggregationSpec extends ZIOSpecDefault { test("subAggregation") { val aggregation = termsAggregation("first", TestDocument.stringField) - .withSubAgg(termsAggregation("second", TestSubDocument.stringField.keyword)) + .withSubAgg(maxAggregation("second", TestSubDocument.intField)) val expected = """ @@ -283,8 +341,8 @@ object ElasticAggregationSpec extends ZIOSpecDefault { | }, | "aggs": { | "second": { - | "terms": { - | "field": "stringField.keyword" + | "max": { + | "field": "intField" | } | } | } From c08748197d579db5fb24cfc7fd1821a57b713daa Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Fri, 28 Apr 2023 16:27:05 +0200 Subject: [PATCH 3/5] Fix tests for scala 2.12 --- .../src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala index f691b5833..dbf20747d 100644 --- a/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/library/src/it/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -46,6 +46,7 @@ object HttpExecutorSpec extends IntegrationSpec { suite("HTTP Executor")( suite("aggregation")( test("aggregate using max aggregation") { + val expectedResponse = ("aggregationInt", MaxAggregationResponse(20.0)) checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { (firstDocumentId, firstDocument, secondDocumentId, secondDocument) => for { @@ -63,7 +64,7 @@ object HttpExecutorSpec extends IntegrationSpec { aggsRes <- Executor .execute(ElasticRequest.aggregate(index = firstSearchIndex, aggregation = aggregation)) .aggregations - } yield assert(aggsRes.head)(equalTo("aggregationInt", MaxAggregationResponse(20.0))) + } yield assert(aggsRes.head)(equalTo(expectedResponse)) } } @@ around( Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), From 83164fb0aa73392c0b790d8e851562befd99847c Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 2 May 2023 17:51:20 +0200 Subject: [PATCH 4/5] Fix code remarks --- .../scala/zio/elasticsearch/aggregation/Aggregations.scala | 3 ++- .../zio/elasticsearch/aggregation/options/HasMissing.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala b/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala index 3fbe16e0f..3b3341c0c 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/aggregation/Aggregations.scala @@ -33,7 +33,8 @@ sealed trait SingleElasticAggregation extends ElasticAggregation sealed trait MaxAggregation extends SingleElasticAggregation with HasMissing[MaxAggregation] with WithAgg -final case class Max(name: String, field: String, missing: Option[Double]) extends MaxAggregation { self => +private[elasticsearch] final case class Max(name: String, field: String, missing: Option[Double]) + extends MaxAggregation { self => def missing(value: Double): MaxAggregation = self.copy(missing = Some(value)) diff --git a/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala b/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala index ca70ab8b3..9d90a50d3 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/aggregation/options/HasMissing.scala @@ -19,7 +19,7 @@ package zio.elasticsearch.aggregation.options private[elasticsearch] trait HasMissing[A <: HasMissing[A]] { /** - * Sets the `missing` parameter for the [[zio.elasticsearch.aggregation.ElasticAggregation]]. The`Missing` parameter + * Sets the `missing` parameter for the [[zio.elasticsearch.aggregation.ElasticAggregation]]. The`missing` parameter * provides a value to use when a document is missing the field that the aggregation is running on. * * @param value From 4d3c520edc973a353c4b7119d405bd778f6ea2fe Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 2 May 2023 18:14:38 +0200 Subject: [PATCH 5/5] Remove unused file --- .../zio/elasticsearch/AggregationSpec.scala | 512 ------------------ 1 file changed, 512 deletions(-) delete mode 100644 modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala diff --git a/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala deleted file mode 100644 index c9313c58a..000000000 --- a/modules/library/src/test/scala/zio/elasticsearch/AggregationSpec.scala +++ /dev/null @@ -1,512 +0,0 @@ -package zio.elasticsearch - -import zio.Scope -import zio.elasticsearch.ElasticAggregation.{maxAggregation, multipleAggregations, termsAggregation} -import zio.elasticsearch.aggregation._ -import zio.elasticsearch.domain.TestSubDocument -import zio.elasticsearch.query.sort.SortOrder.{Asc, Desc} -import zio.elasticsearch.utils._ -import zio.test.Assertion.equalTo -import zio.test._ - -object AggregationSpec extends ZIOSpecDefault { - def spec: Spec[Environment with TestEnvironment with Scope, Any] = - suite("Aggregations")( - suite("creating ElasticAggregation")( - test("successfully create Max aggregation using `maxAggregation` method") { - val aggregation = maxAggregation(name = "aggregation", field = "day_of_month") - - assert(aggregation)( - equalTo( - Max(name = "aggregation", field = "day_of_month", missing = None) - ) - ) - }, - test("successfully create type-safe Max aggregation using `maxAggregation` method") { - val aggregation = maxAggregation(name = "aggregation", field = TestSubDocument.intField) - - assert(aggregation)( - equalTo( - Max(name = "aggregation", field = "intField", missing = None) - ) - ) - }, - test("successfully create type-safe Max aggregation using `maxAggregation` method with `missing` parameter") { - val aggregation = maxAggregation(name = "aggregation", field = TestSubDocument.intField).missing(20) - - assert(aggregation)( - equalTo( - Max(name = "aggregation", field = "intField", missing = Some(20)) - ) - ) - }, - test("successfully create Multiple Aggregations using two `maxAggregation` methods") { - val aggregation = maxAggregation(name = "aggregation1", field = TestSubDocument.intField) - .withAgg(maxAggregation("aggregation2", TestSubDocument.intFieldList)) - - assert(aggregation)( - equalTo( - Multiple(aggregations = - List( - Max(name = "aggregation1", field = "intField", None), - Max(name = "aggregation2", field = "intFieldList", None) - ) - ) - ) - ) - }, - test("successfully create Terms aggregation using `termsAggregation` method") { - val aggregation = termsAggregation(name = "aggregation", field = "day_of_week") - - assert(aggregation)( - equalTo( - Terms(name = "aggregation", field = "day_of_week", order = Set.empty, subAggregations = Nil, size = None) - ) - ) - }, - test("successfully create type-safe Terms aggregation using `termsAggregation` method") { - val aggregation = termsAggregation(name = "aggregation", field = TestSubDocument.stringField) - - assert(aggregation)( - equalTo( - Terms(name = "aggregation", field = "stringField", order = Set.empty, subAggregations = Nil, size = None) - ) - ) - }, - test("successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method") { - val aggregation = - termsAggregation(name = "aggregation", field = TestSubDocument.stringField.keyword) - - assert(aggregation)( - equalTo( - Terms( - name = "aggregation", - field = "stringField.keyword", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ) - ) - }, - test( - "successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method and `order` parameter" - ) { - val aggregation = - termsAggregation( - name = "aggregation", - field = TestSubDocument.stringField.keyword - ).orderByKeyDesc.orderByCountAsc - - assert(aggregation)( - equalTo( - Terms( - name = "aggregation", - field = "stringField.keyword", - order = Set(AggregationOrder("_key", Desc), AggregationOrder("_count", Asc)), - subAggregations = Nil, - size = None - ) - ) - ) - }, - test( - "successfully create type-safe Terms aggregation with multi-field using `termsAggregation` method and `size` parameter" - ) { - val aggregation = - termsAggregation(name = "aggregation", field = TestSubDocument.stringField.keyword) - .size(5) - - assert(aggregation)( - equalTo( - Terms( - name = "aggregation", - field = "stringField.keyword", - order = Set.empty, - subAggregations = Nil, - size = Some(5) - ) - ) - ) - }, - test( - "successfully create type-safe Terms aggregation with multi-field with all params" - ) { - val aggregation = - termsAggregation( - name = "aggregation", - field = TestSubDocument.stringField.keyword - ).orderByCountDesc.orderByKeyAsc - .size(5) - - assert(aggregation)( - equalTo( - Terms( - name = "aggregation", - field = "stringField.keyword", - order = Set(AggregationOrder("_count", Desc), AggregationOrder("_key", Asc)), - subAggregations = Nil, - size = Some(5) - ) - ) - ) - }, - test( - "successfully create Multiple aggregations using `multipleAggregations` method with two `termsAggregation`" - ) { - val aggregation = multipleAggregations.aggregations( - termsAggregation(name = "firstAggregation", field = "day_of_week"), - termsAggregation(name = "secondAggregation", field = "customer_age") - ) - - assert(aggregation)( - equalTo( - Multiple( - List( - Terms( - name = "firstAggregation", - field = "day_of_week", - order = Set.empty, - subAggregations = Nil, - size = None - ), - Terms( - name = "secondAggregation", - field = "customer_age", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ) - ) - ) - ) - }, - test("successfully create Multiple aggregations using `withAgg`") { - val aggregation1 = termsAggregation(name = "firstAggregation", field = "day_of_week") - .withAgg(termsAggregation(name = "secondAggregation", field = "customer_age")) - val aggregation2 = multipleAggregations - .aggregations( - termsAggregation(name = "firstAggregation", field = "day_of_week"), - termsAggregation(name = "secondAggregation", field = "customer_age") - ) - .withAgg(termsAggregation(name = "thirdAggregation", field = "day_of_month")) - - assert(aggregation1)( - equalTo( - Multiple( - List( - Terms( - name = "firstAggregation", - field = "day_of_week", - order = Set.empty, - subAggregations = Nil, - size = None - ), - Terms( - name = "secondAggregation", - field = "customer_age", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ) - ) - ) - ) && assert(aggregation2)( - equalTo( - Multiple( - List( - Terms( - name = "thirdAggregation", - field = "day_of_month", - order = Set.empty, - subAggregations = Nil, - size = None - ), - Terms( - name = "firstAggregation", - field = "day_of_week", - order = Set.empty, - subAggregations = Nil, - size = None - ), - Terms( - name = "secondAggregation", - field = "customer_age", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ) - ) - ) - ) - }, - test("successfully create nested aggregation using `withSubAgg`") { - val aggregation1 = termsAggregation(name = "firstAggregation", field = "day_of_week").withSubAgg( - termsAggregation(name = "secondAggregation", field = "customer_age") - ) - val aggregation2 = multipleAggregations - .aggregations( - termsAggregation(name = "firstAggregation", field = "day_of_week") - .withSubAgg(maxAggregation(name = "fourthAggregation", field = "age")), - termsAggregation(name = "secondAggregation", field = "customer_age").withSubAgg( - termsAggregation(name = "thirdAggregation", field = "day_of_month") - ) - ) - - assert(aggregation1)( - equalTo( - Terms( - name = "firstAggregation", - field = "day_of_week", - order = Set.empty, - subAggregations = List( - Terms( - name = "secondAggregation", - field = "customer_age", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ), - size = None - ) - ) - ) && assert(aggregation2)( - equalTo( - Multiple( - List( - Terms( - name = "firstAggregation", - field = "day_of_week", - order = Set.empty, - subAggregations = List(Max(name = "fourthAggregation", field = "age", missing = None)), - size = None - ), - Terms( - name = "secondAggregation", - field = "customer_age", - order = Set.empty, - subAggregations = List( - Terms( - name = "thirdAggregation", - field = "day_of_month", - order = Set.empty, - subAggregations = Nil, - size = None - ) - ), - size = None - ) - ) - ) - ) - ) - } - ), - suite("encoding ElasticAggregation as JSON")( - test("properly encode Max aggregation") { - val aggregation = maxAggregation(name = "aggregation", field = "day_of_month") - val expected = - """ - |{ - | "aggs": { - | "aggregation": { - | "max": { - | "field": "day_of_month" - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Max aggregation with `missing") { - val aggregation = maxAggregation(name = "aggregation", field = "day_of_month").missing(20) - val expected = - """ - |{ - | "aggs": { - | "aggregation": { - | "max": { - | "field": "day_of_month", - | "missing": 20.0 - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Terms aggregation") { - val aggregation = termsAggregation(name = "aggregation", field = "day_of_week") - val expected = - """ - |{ - | "aggs": { - | "aggregation": { - | "terms": { - | "field": "day_of_week" - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Terms aggregation with `order`") { - val aggregation = - termsAggregation(name = "aggregation", field = "day_of_week").orderBy(AggregationOrder("_key", Desc)) - val expected = - """ - |{ - | "aggs": { - | "aggregation": { - | "terms": { - | "field": "day_of_week", - | "order": { - | "_key": "desc" - | } - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Terms aggregation with `size`") { - val aggregation = termsAggregation(name = "aggregation", field = "day_of_week").size(5) - val expected = - """ - |{ - | "aggs": { - | "aggregation": { - | "terms": { - | "field": "day_of_week", - | "size": 5 - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Multiple aggregations with two Terms aggregations") { - val aggregation = multipleAggregations.aggregations( - termsAggregation(name = "firstAggregation", field = "day_of_week"), - termsAggregation(name = "secondAggregation", field = "customer_age") - ) - val expected = - """ - |{ - | "aggs": { - | "firstAggregation": { - | "terms": { - | "field": "day_of_week" - | } - | }, - | "secondAggregation": { - | "terms": { - | "field": "customer_age" - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode Multiple aggregations with Terms aggregation and Max aggregation") { - val aggregation = multipleAggregations.aggregations( - termsAggregation(name = "firstAggregation", field = "day_of_week"), - maxAggregation(name = "secondAggregation", field = "customer_age") - ) - val expected = - """ - |{ - | "aggs": { - | "firstAggregation": { - | "terms": { - | "field": "day_of_week" - | } - | }, - | "secondAggregation": { - | "max": { - | "field": "customer_age" - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode nested aggregation") { - val aggregation = termsAggregation(name = "firstAggregation", field = "day_of_week").withSubAgg( - maxAggregation(name = "secondAggregation", field = "customer_age") - ) - val expected = - """ - |{ - | "aggs": { - | "firstAggregation": { - | "terms": { - | "field": "day_of_week" - | }, - | "aggs": { - | "secondAggregation": { - | "max": { - | "field": "customer_age" - | } - | } - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - }, - test("properly encode multiple aggregation with nested aggregation") { - val aggregation = termsAggregation(name = "firstAggregation", field = "day_of_week") - .withSubAgg( - termsAggregation(name = "secondAggregation", field = "customer_age") - ) - .withAgg(termsAggregation(name = "thirdAggregation", field = "day_of_month")) - val expected = - """ - |{ - | "aggs": { - | "firstAggregation": { - | "terms": { - | "field": "day_of_week" - | }, - | "aggs": { - | "secondAggregation": { - | "terms": { - | "field": "customer_age" - | } - | } - | } - | }, - | "thirdAggregation": { - | "terms": { - | "field": "day_of_month" - | } - | } - | } - |} - |""".stripMargin - - assert(aggregation.toJson)(equalTo(expected.toJson)) - } - ) - ) -}