From e5bcccadbb77f3639af97d21cbdc9acd04a8ce10 Mon Sep 17 00:00:00 2001 From: mvelimir Date: Thu, 9 Mar 2023 16:17:42 +0100 Subject: [PATCH] Add type parameter to ElasticQuery and propagate it through existing code --- .../example/RepositoriesElasticsearch.scala | 4 +- .../main/scala/example/api/Repositories.scala | 7 +- .../main/scala/zio/elasticsearch/Boost.scala | 51 ++-- .../zio/elasticsearch/CaseInsensitive.scala | 26 +- .../zio/elasticsearch/ElasticQuery.scala | 174 ++++++----- .../zio/elasticsearch/ElasticRequest.scala | 8 +- .../main/scala/zio/elasticsearch/Field.scala | 2 +- .../zio/elasticsearch/IgnoreUnmapped.scala | 12 +- .../scala/zio/elasticsearch/ScoreMode.scala | 12 +- .../zio/elasticsearch/QueryDSLSpec.scala | 279 +++++++++++------- 10 files changed, 334 insertions(+), 241 deletions(-) diff --git a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala index 8a84df0d1..6cd70c7b5 100644 --- a/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala +++ b/modules/example/src/main/scala/example/RepositoriesElasticsearch.scala @@ -74,7 +74,7 @@ final case class RepositoriesElasticsearch(elasticsearch: Elasticsearch) { res <- elasticsearch.execute(ElasticRequest.deleteById(Index, DocumentId(id)).routing(routing).refreshFalse) } yield res - def search(query: ElasticQuery[_]): Task[List[GitHubRepo]] = + def search(query: ElasticQuery[_, _]): Task[List[GitHubRepo]] = elasticsearch.execute(ElasticRequest.search[GitHubRepo](Index, query)) private def routingOf(value: String): IO[IllegalArgumentException, Routing.Type] = @@ -102,7 +102,7 @@ object RepositoriesElasticsearch { def remove(organization: String, id: String): RIO[RepositoriesElasticsearch, DeletionOutcome] = ZIO.serviceWithZIO[RepositoriesElasticsearch](_.remove(organization, id)) - def search(query: ElasticQuery[_]): RIO[RepositoriesElasticsearch, List[GitHubRepo]] = + def search(query: ElasticQuery[_, _]): RIO[RepositoriesElasticsearch, List[GitHubRepo]] = ZIO.serviceWithZIO[RepositoriesElasticsearch](_.search(query)) lazy val live: URLayer[Elasticsearch, RepositoriesElasticsearch] = diff --git a/modules/example/src/main/scala/example/api/Repositories.scala b/modules/example/src/main/scala/example/api/Repositories.scala index 48b0b3665..322b9466c 100644 --- a/modules/example/src/main/scala/example/api/Repositories.scala +++ b/modules/example/src/main/scala/example/api/Repositories.scala @@ -18,7 +18,6 @@ package example.api import example.{GitHubRepo, RepositoriesElasticsearch} import zio.ZIO -import zio.elasticsearch.ElasticQuery.boolQuery import zio.elasticsearch._ import zio.http._ import zio.http.model.Method @@ -120,12 +119,12 @@ object Repositories { .orDie } - private def createElasticQuery(query: Criteria): ElasticQuery[_] = + private def createElasticQuery(query: Criteria): ElasticQuery[_, _] = query match { case CompoundCriteria(operator, filters) => operator match { - case And => boolQuery.must(filters.map(createElasticQuery): _*) - case Or => boolQuery.should(filters.map(createElasticQuery): _*) + case And => ElasticQuery.must(filters.map(createElasticQuery): _*) + case Or => ElasticQuery.should(filters.map(createElasticQuery): _*) } case DateCriteria(field, operator, value) => operator match { diff --git a/modules/library/src/main/scala/zio/elasticsearch/Boost.scala b/modules/library/src/main/scala/zio/elasticsearch/Boost.scala index 132e1ec27..ad7f0819d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/Boost.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/Boost.scala @@ -22,35 +22,48 @@ import zio.elasticsearch.ElasticQueryType.{Bool, MatchAll, Range, Term, Wildcard object Boost { trait WithBoost[EQT <: ElasticQueryType] { - def withBoost(query: ElasticQuery[EQT], value: Double): ElasticQuery[EQT] + def withBoost[S](query: ElasticQuery[S, EQT], value: Double): ElasticQuery[S, EQT] } object WithBoost { - implicit val boolWithBoost: WithBoost[Bool] = (query: ElasticQuery[Bool], value: Double) => - query match { - case q: BoolQuery => q.copy(boost = Some(value)) + implicit val boolWithBoost: WithBoost[Bool] = + new WithBoost[Bool] { + def withBoost[S](query: ElasticQuery[S, Bool], value: Double): ElasticQuery[S, Bool] = + query match { + case q: BoolQuery[S] => q.copy(boost = Some(value)) + } } - implicit val matchAllWithBoost: WithBoost[MatchAll] = (query: ElasticQuery[MatchAll], value: Double) => - query match { - case q: MatchAllQuery => q.copy(boost = Some(value)) + implicit val matchAllWithBoost: WithBoost[MatchAll] = + new WithBoost[MatchAll] { + def withBoost[S](query: ElasticQuery[S, MatchAll], value: Double): ElasticQuery[S, MatchAll] = + query match { + case q: MatchAllQuery => q.copy(boost = Some(value)) + } } implicit def rangeWithBoost[A, LB <: LowerBound, UB <: UpperBound]: WithBoost[Range[A, LB, UB]] = - (query: ElasticQuery[Range[A, LB, UB]], value: Double) => - query match { - case q: RangeQuery[A, LB, UB] => q.copy(boost = Some(value)) - } + new WithBoost[Range[A, LB, UB]] { + def withBoost[S](query: ElasticQuery[S, Range[A, LB, UB]], value: Double): ElasticQuery[S, Range[A, LB, UB]] = + query match { + case q: RangeQuery[_, A, LB, UB] => q.copy(boost = Some(value)) + } + } implicit def termWithBoost[A: ElasticPrimitive]: WithBoost[Term[A]] = - (query: ElasticQuery[Term[A]], value: Double) => - query match { - case q: TermQuery[A] => q.copy(boost = Some(value)) - } - - implicit val wildcardWithBoost: WithBoost[Wildcard] = (query: ElasticQuery[Wildcard], value: Double) => - query match { - case q: WildcardQuery => q.copy(boost = Some(value)) + new WithBoost[Term[A]] { + def withBoost[S](query: ElasticQuery[S, Term[A]], value: Double): ElasticQuery[S, Term[A]] = + query match { + case q: TermQuery[_, A] => q.copy(boost = Some(value)) + } + } + + implicit val wildcardWithBoost: WithBoost[Wildcard] = + new WithBoost[Wildcard] { + def withBoost[S](query: ElasticQuery[S, Wildcard], value: Double): ElasticQuery[S, Wildcard] = + query match { + case q: WildcardQuery[_] => q.copy(boost = Some(value)) + } } } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/CaseInsensitive.scala b/modules/library/src/main/scala/zio/elasticsearch/CaseInsensitive.scala index a8a360425..22b17252c 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/CaseInsensitive.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/CaseInsensitive.scala @@ -22,20 +22,26 @@ import zio.elasticsearch.ElasticQueryType.{Term, Wildcard} object CaseInsensitive { trait WithCaseInsensitive[EQT <: ElasticQueryType] { - def withCaseInsensitive(query: ElasticQuery[EQT], value: Boolean): ElasticQuery[EQT] + def withCaseInsensitive[S](query: ElasticQuery[S, EQT], value: Boolean): ElasticQuery[S, EQT] } object WithCaseInsensitive { implicit val termWithCaseInsensitiveString: WithCaseInsensitive[Term[String]] = - (query: ElasticQuery[Term[String]], value: Boolean) => - query match { - case q: TermQuery[String] => q.copy(caseInsensitive = Some(value)) - } - + new WithCaseInsensitive[Term[String]] { + def withCaseInsensitive[S]( + query: ElasticQuery[S, Term[String]], + value: Boolean + ): ElasticQuery[S, Term[String]] = + query match { + case q: TermQuery[S, String] => q.copy(caseInsensitive = Some(value)) + } + } implicit val wildcardWithCaseInsensitiveString: WithCaseInsensitive[Wildcard] = - (query: ElasticQuery[Wildcard], value: Boolean) => - query match { - case q: WildcardQuery => q.copy(caseInsensitive = Some(value)) - } + new WithCaseInsensitive[Wildcard] { + def withCaseInsensitive[S](query: ElasticQuery[S, Wildcard], value: Boolean): ElasticQuery[S, Wildcard] = + query match { + case q: WildcardQuery[S] => q.copy(caseInsensitive = Some(value)) + } + } } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index d36822ca7..a17552d12 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -26,34 +26,34 @@ import zio.json.ast.Json.{Arr, Num, Obj, Str} import scala.annotation.unused -sealed trait ElasticQuery[EQT <: ElasticQueryType] { self => +sealed trait ElasticQuery[-S, EQT <: ElasticQueryType] { self => - def paramsToJson: Json + def paramsToJson(fieldPath: Option[String]): Json - final def toJson: Json = Obj("query" -> self.paramsToJson) + final def toJson: Json = Obj("query" -> self.paramsToJson(None)) - final def boost(value: Double)(implicit wb: WithBoost[EQT]): ElasticQuery[EQT] = + final def boost(value: Double)(implicit wb: WithBoost[EQT]): ElasticQuery[S, EQT] = wb.withBoost(query = self, value = value) - final def caseInsensitive(value: Boolean)(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[EQT] = + final def caseInsensitive(value: Boolean)(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[S, EQT] = wci.withCaseInsensitive(query = self, value = value) - final def caseInsensitiveFalse(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[EQT] = + final def caseInsensitiveFalse(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[S, EQT] = caseInsensitive(value = false) - final def caseInsensitiveTrue(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[EQT] = + final def caseInsensitiveTrue(implicit wci: WithCaseInsensitive[EQT]): ElasticQuery[S, EQT] = caseInsensitive(value = true) - final def ignoreUnmapped(value: Boolean)(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[EQT] = + final def ignoreUnmapped(value: Boolean)(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[S, EQT] = wiu.withIgnoreUnmapped(query = self, value = value) - final def ignoreUnmappedFalse(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[EQT] = + final def ignoreUnmappedFalse(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[S, EQT] = ignoreUnmapped(value = false) - final def ignoreUnmappedTrue(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[EQT] = + final def ignoreUnmappedTrue(implicit wiu: WithIgnoreUnmapped[EQT]): ElasticQuery[S, EQT] = ignoreUnmapped(value = true) - final def scoreMode(scoreMode: ScoreMode)(implicit wsm: WithScoreMode[EQT]): ElasticQuery[EQT] = + final def scoreMode(scoreMode: ScoreMode)(implicit wsm: WithScoreMode[EQT]): ElasticQuery[S, EQT] = wsm.withScoreMode(query = self, scoreMode = scoreMode) } @@ -85,49 +85,56 @@ object ElasticQuery { def toJson(implicit EP: ElasticPrimitive[A]): Json = EP.toJson(value) } - def boolQuery: BoolQuery = BoolQuery.empty - - def contains(field: String, value: String): ElasticQuery[Wildcard] = + def contains(field: String, value: String): ElasticQuery[Any, Wildcard] = WildcardQuery(field = field, value = s"*$value*", boost = None, caseInsensitive = None) - def exists(field: Field[_, _]): ElasticQuery[Exists] = ExistsQuery(field.toString) + def exists[S](field: Field[S, _]): ElasticQuery[S, Exists] = ExistsQuery(field.toString) + + def exists(field: String): ElasticQuery[Any, Exists] = ExistsQuery(field) - def exists(field: String): ElasticQuery[Exists] = ExistsQuery(field) + def filter[S](queries: ElasticQuery[S, _]*): BoolQuery[S] = + BoolQuery[S](filter = queries.toList, must = Nil, should = Nil, boost = None) - def matchAll: ElasticQuery[MatchAll] = MatchAllQuery(boost = None) + def matchAll: ElasticQuery[Any, MatchAll] = MatchAllQuery(boost = None) - def matches[A: ElasticPrimitive]( - field: Field[_, A], + def matches[S, A: ElasticPrimitive]( + field: Field[S, A], multiField: Option[String] = None, value: A - ): ElasticQuery[Match] = + ): ElasticQuery[S, Match] = MatchQuery(field.toString ++ multiField.map("." ++ _).getOrElse(""), value) - def matches[A: ElasticPrimitive](field: String, value: A): ElasticQuery[Match] = + def matches[A: ElasticPrimitive](field: String, value: A): ElasticQuery[Any, Match] = MatchQuery(field, value) - def nested(path: Field[_, _], query: ElasticQuery[_]): ElasticQuery[Nested] = + def must[S](queries: ElasticQuery[S, _]*): BoolQuery[S] = + BoolQuery[S](filter = Nil, must = queries.toList, should = Nil, boost = None) + + def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A, _]): ElasticQuery[S, Nested] = NestedQuery(path.toString, query, None, None) - def nested(path: String, query: ElasticQuery[_]): ElasticQuery[Nested] = + def nested(path: String, query: ElasticQuery[_, _]): ElasticQuery[Any, Nested] = NestedQuery(path, query, None, None) - def range[A]( - field: Field[_, A], + def range[S, A]( + field: Field[S, A], multiField: Option[String] = None - ): RangeQuery[A, Unbounded.type, Unbounded.type] = + ): RangeQuery[S, A, Unbounded.type, Unbounded.type] = RangeQuery.empty(field.toString ++ multiField.map("." ++ _).getOrElse("")) - def range(field: String): RangeQuery[Any, Unbounded.type, Unbounded.type] = RangeQuery.empty[Any](field) + def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = RangeQuery.empty[Any, Any](field) + + def should[S](queries: ElasticQuery[S, _]*): BoolQuery[S] = + BoolQuery[S](filter = Nil, must = Nil, should = queries.toList, boost = None) - def startsWith(field: String, value: String): ElasticQuery[Wildcard] = + def startsWith(field: String, value: String): ElasticQuery[Any, Wildcard] = WildcardQuery(field = field, value = s"$value*", boost = None, caseInsensitive = None) - def term[A: ElasticPrimitive]( - field: Field[_, A], + def term[S, A: ElasticPrimitive]( + field: Field[S, A], multiField: Option[String] = None, value: A - ): ElasticQuery[Term[A]] = + ): ElasticQuery[S, Term[A]] = TermQuery( field = field.toString ++ multiField.map("." ++ _).getOrElse(""), value = value, @@ -135,66 +142,69 @@ object ElasticQuery { caseInsensitive = None ) - def term[A: ElasticPrimitive](field: String, value: A): ElasticQuery[Term[A]] = + def term[A: ElasticPrimitive](field: String, value: A): ElasticQuery[Any, Term[A]] = TermQuery(field = field, value = value, boost = None, caseInsensitive = None) - def wildcard(field: String, value: String): ElasticQuery[Wildcard] = + def wildcard(field: String, value: String): ElasticQuery[Any, Wildcard] = WildcardQuery(field = field, value = value, boost = None, caseInsensitive = None) - private[elasticsearch] final case class BoolQuery( - filter: List[ElasticQuery[_]], - must: List[ElasticQuery[_]], - should: List[ElasticQuery[_]], + private[elasticsearch] final case class BoolQuery[S]( + filter: List[ElasticQuery[S, _]], + must: List[ElasticQuery[S, _]], + should: List[ElasticQuery[S, _]], boost: Option[Double] - ) extends ElasticQuery[Bool] { self => + ) extends ElasticQuery[S, Bool] { self => - def filter(queries: ElasticQuery[_]*): BoolQuery = + def filter(queries: ElasticQuery[S, _]*): BoolQuery[S] = self.copy(filter = filter ++ queries) - def must(queries: ElasticQuery[_]*): BoolQuery = + def must(queries: ElasticQuery[S, _]*): BoolQuery[S] = self.copy(must = must ++ queries) - def paramsToJson: Json = { + def paramsToJson(fieldPath: Option[String]): Json = { val boolFields = - Some("filter" -> Arr(filter.map(_.paramsToJson): _*)) ++ - Some("must" -> Arr(must.map(_.paramsToJson): _*)) ++ - Some("should" -> Arr(should.map(_.paramsToJson): _*)) ++ + Some("filter" -> Arr(filter.map(_.paramsToJson(fieldPath)): _*)) ++ + Some("must" -> Arr(must.map(_.paramsToJson(fieldPath)): _*)) ++ + Some("should" -> Arr(should.map(_.paramsToJson(fieldPath)): _*)) ++ boost.map("boost" -> Num(_)) Obj("bool" -> Obj(boolFields.toList: _*)) } - def should(queries: ElasticQuery[_]*): BoolQuery = + def should(queries: ElasticQuery[S, _]*): BoolQuery[S] = self.copy(should = should ++ queries) } - private[elasticsearch] object BoolQuery { - def empty: BoolQuery = BoolQuery(filter = Nil, must = Nil, should = Nil, boost = None) - } - - private[elasticsearch] final case class ExistsQuery private (field: String) extends ElasticQuery[Exists] { - def paramsToJson: Json = Obj("exists" -> Obj("field" -> field.toJson)) + private[elasticsearch] final case class ExistsQuery[S](field: String) extends ElasticQuery[S, Exists] { + def paramsToJson(fieldPath: Option[String]): Json = Obj( + "exists" -> Obj("field" -> (fieldPath.getOrElse("") ++ field).toJson) + ) } - private[elasticsearch] final case class MatchQuery[A: ElasticPrimitive](field: String, value: A) - extends ElasticQuery[Match] { - def paramsToJson: Json = Obj("match" -> Obj(field -> value.toJson)) + private[elasticsearch] final case class MatchQuery[S, A: ElasticPrimitive](field: String, value: A) + extends ElasticQuery[S, Match] { + def paramsToJson(fieldPath: Option[String]): Json = Obj( + "match" -> Obj(fieldPath.getOrElse("") ++ field -> value.toJson) + ) } - private[elasticsearch] final case class MatchAllQuery(boost: Option[Double]) extends ElasticQuery[MatchAll] { - def paramsToJson: Json = Obj("match_all" -> Obj(boost.map("boost" -> Num(_)).toList: _*)) + private[elasticsearch] final case class MatchAllQuery(boost: Option[Double]) extends ElasticQuery[Any, MatchAll] { + def paramsToJson(fieldPath: Option[String]): Json = Obj("match_all" -> Obj(boost.map("boost" -> Num(_)).toList: _*)) } - private[elasticsearch] final case class NestedQuery( + private[elasticsearch] final case class NestedQuery[S]( path: String, - query: ElasticQuery[_], + query: ElasticQuery[_, _], scoreMode: Option[ScoreMode], ignoreUnmapped: Option[Boolean] - ) extends ElasticQuery[Nested] { - def paramsToJson: Json = Obj( + ) extends ElasticQuery[S, Nested] { + def paramsToJson(fieldPath: Option[String]): Json = Obj( "nested" -> Obj( - Chunk("path" -> Str(path), "query" -> query.paramsToJson) ++ scoreMode.map(scoreMode => - "score_mode" -> Str(scoreMode.toString.toLowerCase) - ) ++ ignoreUnmapped.map("ignore_unmapped" -> Json.Bool(_)) + Chunk( + "path" -> Str(path), + "query" -> query.paramsToJson(fieldPath.map(_ + path).orElse(Some(path))) + ) ++ scoreMode.map(scoreMode => "score_mode" -> Str(scoreMode.toString.toLowerCase)) ++ ignoreUnmapped.map( + "ignore_unmapped" -> Json.Bool(_) + ) ) ) } @@ -227,42 +237,44 @@ object ElasticQuery { def toJson: Option[(String, Json)] = None } - private[elasticsearch] final case class RangeQuery[A, LB <: LowerBound, UB <: UpperBound] private ( + private[elasticsearch] final case class RangeQuery[S, A, LB <: LowerBound, UB <: UpperBound] private ( field: String, lower: LB, upper: UB, boost: Option[Double] - ) extends ElasticQuery[Range[A, LB, UB]] { self => + ) extends ElasticQuery[S, Range[A, LB, UB]] { self => def gt[B <: A: ElasticPrimitive](value: B)(implicit @unused ev: LB =:= Unbounded.type - ): RangeQuery[B, GreaterThan[B], UB] = + ): RangeQuery[S, B, GreaterThan[B], UB] = self.copy(lower = GreaterThan(value)) def gte[B <: A: ElasticPrimitive](value: B)(implicit @unused ev: LB =:= Unbounded.type - ): RangeQuery[B, GreaterThanOrEqualTo[B], UB] = + ): RangeQuery[S, B, GreaterThanOrEqualTo[B], UB] = self.copy(lower = GreaterThanOrEqualTo(value)) def lt[B <: A: ElasticPrimitive](value: B)(implicit @unused ev: UB =:= Unbounded.type - ): RangeQuery[B, LB, LessThan[B]] = + ): RangeQuery[S, B, LB, LessThan[B]] = self.copy(upper = LessThan(value)) def lte[B <: A: ElasticPrimitive](value: B)(implicit @unused ev: UB =:= Unbounded.type - ): RangeQuery[B, LB, LessThanOrEqualTo[B]] = + ): RangeQuery[S, B, LB, LessThanOrEqualTo[B]] = self.copy(upper = LessThanOrEqualTo(value)) - def paramsToJson: Json = { - val rangeFields = Some(field -> Obj(List(lower.toJson, upper.toJson).flatten: _*)) ++ boost.map("boost" -> Num(_)) + def paramsToJson(fieldPath: Option[String]): Json = { + val rangeFields = Some( + fieldPath.getOrElse("") ++ field -> Obj(List(lower.toJson, upper.toJson).flatten: _*) + ) ++ boost.map("boost" -> Num(_)) Obj("range" -> Obj(rangeFields.toList: _*)) } } private[elasticsearch] object RangeQuery { - def empty[A](field: String): RangeQuery[A, Unbounded.type, Unbounded.type] = - RangeQuery[A, Unbounded.type, Unbounded.type]( + def empty[S, A](field: String): RangeQuery[S, A, Unbounded.type, Unbounded.type] = + RangeQuery[S, A, Unbounded.type, Unbounded.type]( field = field, lower = Unbounded, upper = Unbounded, @@ -270,31 +282,31 @@ object ElasticQuery { ) } - private[elasticsearch] final case class TermQuery[A: ElasticPrimitive]( + private[elasticsearch] final case class TermQuery[S, A: ElasticPrimitive]( field: String, value: A, boost: Option[Double], caseInsensitive: Option[Boolean] - ) extends ElasticQuery[Term[A]] { self => - def paramsToJson: Json = { + ) extends ElasticQuery[S, Term[A]] { self => + def paramsToJson(fieldPath: Option[String]): Json = { val termFields = Some("value" -> value.toJson) ++ boost.map("boost" -> Num(_)) ++ caseInsensitive.map( "case_insensitive" -> Json.Bool(_) ) - Obj("term" -> Obj(field -> Obj(termFields.toList: _*))) + Obj("term" -> Obj(fieldPath.getOrElse("") ++ field -> Obj(termFields.toList: _*))) } } - private[elasticsearch] final case class WildcardQuery( + private[elasticsearch] final case class WildcardQuery[S]( field: String, value: String, boost: Option[Double], caseInsensitive: Option[Boolean] - ) extends ElasticQuery[Wildcard] { self => - def paramsToJson: Json = { + ) extends ElasticQuery[S, Wildcard] { self => + def paramsToJson(fieldPath: Option[String]): Json = { val wildcardFields = Some("value" -> value.toJson) ++ boost.map("boost" -> Num(_)) ++ caseInsensitive.map( "case_insensitive" -> Json.Bool(_) ) - Obj("wildcard" -> Obj(field -> Obj(wildcardFields.toList: _*))) + Obj("wildcard" -> Obj(fieldPath.getOrElse("") ++ field -> Obj(wildcardFields.toList: _*))) } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala index 4ece49d9f..1de63d8fe 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala @@ -64,7 +64,7 @@ object ElasticRequest { def deleteById(index: IndexName, id: DocumentId): ElasticRequest[DeletionOutcome, DeleteById] = DeleteByIdRequest(index = index, id = id, refresh = false, routing = None) - def deleteByQuery(index: IndexName, query: ElasticQuery[_]): ElasticRequest[DeletionOutcome, DeleteByQuery] = + def deleteByQuery(index: IndexName, query: ElasticQuery[_, _]): ElasticRequest[DeletionOutcome, DeleteByQuery] = DeleteByQueryRequest(index = index, query = query, refresh = false, routing = None) def deleteIndex(name: IndexName): ElasticRequest[DeletionOutcome, DeleteIndex] = @@ -84,7 +84,7 @@ object ElasticRequest { Right(None) } - def search[A](index: IndexName, query: ElasticQuery[_])(implicit + def search[A](index: IndexName, query: ElasticQuery[_, _])(implicit schema: Schema[A] ): ElasticRequest[List[A], GetByQuery] = GetByQueryRequest(index = index, query = query, routing = None).map { response => @@ -184,7 +184,7 @@ object ElasticRequest { private[elasticsearch] final case class DeleteByQueryRequest( index: IndexName, - query: ElasticQuery[_], + query: ElasticQuery[_, _], refresh: Boolean, routing: Option[Routing] ) extends ElasticRequest[DeletionOutcome, DeleteByQuery] @@ -206,7 +206,7 @@ object ElasticRequest { private[elasticsearch] final case class GetByQueryRequest( index: IndexName, - query: ElasticQuery[_], + query: ElasticQuery[_, _], routing: Option[Routing] ) extends ElasticRequest[ElasticQueryResponse, GetByQuery] diff --git a/modules/library/src/main/scala/zio/elasticsearch/Field.scala b/modules/library/src/main/scala/zio/elasticsearch/Field.scala index d687c31bf..95e3c4b2c 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/Field.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/Field.scala @@ -20,7 +20,7 @@ import zio.schema.{AccessorBuilder, Schema} import scala.annotation.tailrec -private[elasticsearch] final case class Field[S, A](parent: Option[Field[S, _]], name: String) { self => +private[elasticsearch] final case class Field[-S, +A](parent: Option[Field[S, _]], name: String) { self => def /[B](that: Field[A, B]): Field[S, B] = Field(that.parent.map(self / _).orElse(Some(self)), that.name) diff --git a/modules/library/src/main/scala/zio/elasticsearch/IgnoreUnmapped.scala b/modules/library/src/main/scala/zio/elasticsearch/IgnoreUnmapped.scala index 2e7e3d9e3..2b64961e2 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/IgnoreUnmapped.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/IgnoreUnmapped.scala @@ -22,14 +22,16 @@ import zio.elasticsearch.ElasticQueryType.Nested object IgnoreUnmapped { trait WithIgnoreUnmapped[EQT <: ElasticQueryType] { - def withIgnoreUnmapped(query: ElasticQuery[EQT], value: Boolean): ElasticQuery[EQT] + def withIgnoreUnmapped[S](query: ElasticQuery[S, EQT], value: Boolean): ElasticQuery[S, EQT] } object WithIgnoreUnmapped { implicit val nestedWithIgnoreUnmapped: WithIgnoreUnmapped[Nested] = - (query: ElasticQuery[Nested], value: Boolean) => - query match { - case q: NestedQuery => q.copy(ignoreUnmapped = Some(value)) - } + new WithIgnoreUnmapped[Nested] { + def withIgnoreUnmapped[S](query: ElasticQuery[S, Nested], value: Boolean): ElasticQuery[S, Nested] = + query match { + case q: NestedQuery[S] => q.copy(ignoreUnmapped = Some(value)) + } + } } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/ScoreMode.scala b/modules/library/src/main/scala/zio/elasticsearch/ScoreMode.scala index 240ae7040..30a5193ba 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ScoreMode.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ScoreMode.scala @@ -30,14 +30,16 @@ object ScoreMode { final case object Sum extends ScoreMode trait WithScoreMode[EQT <: ElasticQueryType] { - def withScoreMode(query: ElasticQuery[EQT], scoreMode: ScoreMode): ElasticQuery[EQT] + def withScoreMode[S](query: ElasticQuery[S, EQT], scoreMode: ScoreMode): ElasticQuery[S, EQT] } object WithScoreMode { implicit val nestedWithScoreMode: WithScoreMode[Nested] = - (query: ElasticQuery[Nested], scoreMode: ScoreMode) => - query match { - case q: NestedQuery => q.copy(scoreMode = Some(scoreMode)) - } + new WithScoreMode[Nested] { + def withScoreMode[S](query: ElasticQuery[S, Nested], scoreMode: ScoreMode): ElasticQuery[S, Nested] = + query match { + case q: NestedQuery[S] => q.copy(scoreMode = Some(scoreMode)) + } + } } } diff --git a/modules/library/src/test/scala/zio/elasticsearch/QueryDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/QueryDSLSpec.scala index 07ed06575..bee6851fe 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/QueryDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/QueryDSLSpec.scala @@ -28,14 +28,21 @@ import zio.test._ object QueryDSLSpec extends ZIOSpecDefault { - final case class UserDocument(id: String, name: String, address: String, balance: Double, age: Int) + final case class UserDocument( + id: String, + name: String, + address: String, + balance: Double, + age: Int, + items: List[String] + ) object UserDocument { - implicit val schema: Schema.CaseClass5[String, String, String, Double, Int, UserDocument] = + implicit val schema: Schema.CaseClass6[String, String, String, Double, Int, List[String], UserDocument] = DeriveSchema.gen[UserDocument] - val (id, name, address, balance, age) = schema.makeAccessors(ElasticQueryAccessorBuilder) + val (id, name, address, balance, age, items) = schema.makeAccessors(ElasticQueryAccessorBuilder) } override def spec: Spec[Environment with TestEnvironment with Scope, Any] = @@ -46,37 +53,31 @@ object QueryDSLSpec extends ZIOSpecDefault { val queryBool = matches(field = "day_of_week", value = true) val queryLong = matches(field = "day_of_week", value = 1L) - assert(queryString)(equalTo(MatchQuery(field = "day_of_week", value = "Monday"))) && - assert(queryBool)(equalTo(MatchQuery(field = "day_of_week", value = true))) && - assert(queryLong)(equalTo(MatchQuery(field = "day_of_week", value = 1))) + assert(queryString)(equalTo(MatchQuery[Any, String](field = "day_of_week", value = "Monday"))) && + assert(queryBool)(equalTo(MatchQuery[Any, Boolean](field = "day_of_week", value = true))) && + assert(queryLong)(equalTo(MatchQuery[Any, Long](field = "day_of_week", value = 1))) }, test("successfully create type-safe Match query using `matches` method") { val queryString = matches(field = UserDocument.name, value = "Name") val queryInt = matches(field = UserDocument.age, value = 39) - assert(queryString)(equalTo(MatchQuery(field = "name", value = "Name"))) && - assert(queryInt)(equalTo(MatchQuery(field = "age", value = 39))) + assert(queryString)(equalTo(MatchQuery[Any, String](field = "name", value = "Name"))) && + assert(queryInt)(equalTo(MatchQuery[Any, Int](field = "age", value = 39))) }, test("successfully create type-safe Match query with multi-field using `matches` method") { val query = matches(field = UserDocument.name, multiField = Some("keyword"), value = "Name") - assert(query)(equalTo(MatchQuery(field = "name.keyword", value = "Name"))) - }, - test("successfully create Bool Query with boost") { - val query = boolQuery.boost(1.0) - - assert(query)(equalTo(BoolQuery(filter = Nil, must = Nil, should = Nil, boost = Some(1.0)))) + assert(query)(equalTo(MatchQuery[UserDocument, String](field = "name.keyword", value = "Name"))) }, test("successfully create `Filter` query from two Match queries") { - val query = boolQuery - .filter( - matches(field = "day_of_week", value = "Monday"), - matches(field = "customer_gender", value = "MALE") - ) + val query = filter( + matches(field = "day_of_week", value = "Monday"), + matches(field = "customer_gender", value = "MALE") + ) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = List( MatchQuery(field = "day_of_week", value = "Monday"), MatchQuery(field = "customer_gender", value = "MALE") @@ -88,13 +89,33 @@ object QueryDSLSpec extends ZIOSpecDefault { ) ) }, + test("successfully create `Filter` query with boost from two Match queries") { + val query = filter( + matches(field = "day_of_week", value = "Monday"), + matches(field = "customer_gender", value = "MALE") + ).boost(1.0) + + assert(query)( + equalTo( + BoolQuery[Any]( + filter = List( + MatchQuery(field = "day_of_week", value = "Monday"), + MatchQuery(field = "customer_gender", value = "MALE") + ), + must = Nil, + should = Nil, + boost = Some(1.0) + ) + ) + ) + }, test("successfully create `Must` query from two Match queries") { - val query = boolQuery - .must(matches(field = "day_of_week", value = "Monday"), matches(field = "customer_gender", value = "MALE")) + val query = + must(matches(field = "day_of_week", value = "Monday"), matches(field = "customer_gender", value = "MALE")) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = Nil, must = List( MatchQuery(field = "day_of_week", value = "Monday"), @@ -107,15 +128,14 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create `Should` query from two Match queries") { - val query = boolQuery - .should( - matches(field = "day_of_week", value = "Monday"), - matches(field = "customer_gender", value = "MALE") - ) + val query = should( + matches(field = "day_of_week", value = "Monday"), + matches(field = "customer_gender", value = "MALE") + ) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = Nil, must = Nil, should = List( @@ -128,17 +148,16 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create `Filter/Must/Should` mixed query with Filter containing two Match queries") { - val query = boolQuery - .filter( - matches(field = "day_of_week", value = "Monday"), - matches(field = "customer_gender", value = "MALE") - ) + val query = filter( + matches(field = "day_of_week", value = "Monday"), + matches(field = "customer_gender", value = "MALE") + ) .must(matches(field = "customer_age", value = 23)) .should(matches(field = "customer_id", value = 1)) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = List( MatchQuery(field = "day_of_week", value = "Monday"), MatchQuery(field = "customer_gender", value = "MALE") @@ -151,14 +170,13 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create `Filter/Must/Should` mixed query with Must containing two Match queries") { - val query = boolQuery - .filter(matches(field = "customer_id", value = 1)) + val query = filter(matches(field = "customer_id", value = 1)) .must(matches(field = "day_of_week", value = "Monday"), matches(field = "customer_gender", value = "MALE")) .should(matches(field = "customer_age", value = 23)) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = List(MatchQuery(field = "customer_id", value = 1)), must = List( MatchQuery(field = "day_of_week", value = "Monday"), @@ -171,8 +189,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create `Filter/Must/Should` mixed query with Should containing two Match queries") { - val query = boolQuery - .filter(matches(field = "customer_id", value = 1)) + val query = filter(matches(field = "customer_id", value = 1)) .must(matches(field = "customer_age", value = 23)) .should( matches(field = "day_of_week", value = "Monday"), @@ -181,7 +198,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = List(MatchQuery(field = "customer_id", value = 1)), must = List(MatchQuery(field = "customer_age", value = 23)), should = List( @@ -194,15 +211,14 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create `Filter/Must/Should` mixed query with boost") { - val query = boolQuery - .filter(matches(field = "customer_id", value = 1)) + val query = filter(matches(field = "customer_id", value = 1)) .must(matches(field = "customer_age", value = 23)) .should(matches(field = "day_of_week", value = "Monday")) .boost(1.0) assert(query)( equalTo( - BoolQuery( + BoolQuery[Any]( filter = List(MatchQuery(field = "customer_id", value = 1)), must = List(MatchQuery(field = "customer_age", value = 23)), should = List(MatchQuery(field = "day_of_week", value = "Monday")), @@ -214,12 +230,12 @@ object QueryDSLSpec extends ZIOSpecDefault { test("successfully create Exists Query") { val query = exists(field = "day_of_week") - assert(query)(equalTo(ExistsQuery(field = "day_of_week"))) + assert(query)(equalTo(ExistsQuery[Any](field = "day_of_week"))) }, test("successfully create Exists Query with accessor") { val query = exists(field = UserDocument.name) - assert(query)(equalTo(ExistsQuery(field = "name"))) + assert(query)(equalTo(ExistsQuery[Any](field = "name"))) }, test("successfully create MatchAll Query") { val query = matchAll @@ -236,7 +252,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = None, @@ -246,12 +262,12 @@ object QueryDSLSpec extends ZIOSpecDefault { ) }, test("successfully create type-safe Nested Query with MatchAll Query") { - val query = nested(path = UserDocument.address, query = matchAll) + val query = nested(path = UserDocument.items, query = matchAll) assert(query)( equalTo( - NestedQuery( - path = "address", + NestedQuery[UserDocument]( + path = "items", query = MatchAllQuery(boost = None), scoreMode = None, ignoreUnmapped = None @@ -268,7 +284,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(queryAvg)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.Avg), @@ -278,7 +294,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) && assert(queryMax)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.Max), @@ -288,7 +304,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) && assert(queryMin)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.Min), @@ -298,7 +314,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) && assert(queryNone)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.None), @@ -308,7 +324,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) && assert(querySum)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.Sum), @@ -322,7 +338,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = None, @@ -336,7 +352,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - NestedQuery( + NestedQuery[Any]( path = "customer", query = MatchAllQuery(boost = None), scoreMode = Some(ScoreMode.Avg), @@ -350,7 +366,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Any, Unbounded.type, Unbounded.type]( + RangeQuery[Any, Any, Unbounded.type, Unbounded.type]( field = "customer_age", lower = Unbounded, upper = Unbounded, @@ -365,7 +381,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(queryString)( equalTo( - RangeQuery[String, Unbounded.type, Unbounded.type]( + RangeQuery[UserDocument, String, Unbounded.type, Unbounded.type]( field = "name", lower = Unbounded, upper = Unbounded, @@ -375,7 +391,7 @@ object QueryDSLSpec extends ZIOSpecDefault { ) && assert(queryInt)( equalTo( - RangeQuery[Int, Unbounded.type, Unbounded.type]( + RangeQuery[UserDocument, Int, Unbounded.type, Unbounded.type]( field = "age", lower = Unbounded, upper = Unbounded, @@ -389,7 +405,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[String, Unbounded.type, Unbounded.type]( + RangeQuery[UserDocument, String, Unbounded.type, Unbounded.type]( field = "name.keyword", lower = Unbounded, upper = Unbounded, @@ -403,7 +419,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Int, Unbounded.type, LessThan[Int]]( + RangeQuery[Any, Int, Unbounded.type, LessThan[Int]]( field = "customer_age", lower = Unbounded, upper = LessThan(23), @@ -417,7 +433,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Int, GreaterThan[Int], Unbounded.type]( + RangeQuery[Any, Int, GreaterThan[Int], Unbounded.type]( field = "customer_age", lower = GreaterThan(23), upper = Unbounded, @@ -431,7 +447,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Int, Unbounded.type, LessThanOrEqualTo[Int]]( + RangeQuery[Any, Int, Unbounded.type, LessThanOrEqualTo[Int]]( field = "customer_age", lower = Unbounded, upper = LessThanOrEqualTo(23), @@ -445,7 +461,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Int, GreaterThanOrEqualTo[Int], Unbounded.type]( + RangeQuery[Any, Int, GreaterThanOrEqualTo[Int], Unbounded.type]( field = "customer_age", lower = GreaterThanOrEqualTo(23), upper = Unbounded, @@ -459,7 +475,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query)( equalTo( - RangeQuery[Int, GreaterThanOrEqualTo[Int], LessThan[Int]]( + RangeQuery[Any, Int, GreaterThanOrEqualTo[Int], LessThan[Int]]( field = "customer_age", lower = GreaterThanOrEqualTo(23), upper = LessThan(50), @@ -475,30 +491,45 @@ object QueryDSLSpec extends ZIOSpecDefault { val queryLong = term(field = "day_of_week", value = 1L) assert(queryInt)( - equalTo(TermQuery(field = "day_of_week", value = 1, boost = None, caseInsensitive = None)) + equalTo(TermQuery[Any, Int](field = "day_of_week", value = 1, boost = None, caseInsensitive = None)) ) && assert(queryString)( - equalTo(TermQuery(field = "day_of_week", value = "Monday", boost = None, caseInsensitive = None)) + equalTo( + TermQuery[Any, String](field = "day_of_week", value = "Monday", boost = None, caseInsensitive = None) + ) ) && assert(queryBool)( - equalTo(TermQuery(field = "day_of_week", value = true, boost = None, caseInsensitive = None)) + equalTo(TermQuery[Any, Boolean](field = "day_of_week", value = true, boost = None, caseInsensitive = None)) ) && - assert(queryLong)(equalTo(TermQuery(field = "day_of_week", value = 1L, boost = None, caseInsensitive = None))) + assert(queryLong)( + equalTo(TermQuery[Any, Long](field = "day_of_week", value = 1L, boost = None, caseInsensitive = None)) + ) }, test("successfully create type-safe Term Query") { val queryString = term(field = UserDocument.name, value = "Name") val queryInt = term(field = UserDocument.age, value = 39) assert(queryString)( - equalTo(TermQuery(field = "name", value = "Name", boost = None, caseInsensitive = None)) + equalTo( + TermQuery[UserDocument, String](field = "name", value = "Name", boost = None, caseInsensitive = None) + ) ) && - assert(queryInt)(equalTo(TermQuery(field = "age", value = 39, boost = None, caseInsensitive = None))) + assert(queryInt)( + equalTo(TermQuery[UserDocument, Int](field = "age", value = 39, boost = None, caseInsensitive = None)) + ) }, test("successfully create type-safe Term Query with multi-field") { val query = term(field = UserDocument.name, multiField = Some("keyword"), value = "Name") assert(query)( - equalTo(TermQuery(field = "name.keyword", value = "Name", boost = None, caseInsensitive = None)) + equalTo( + TermQuery[UserDocument, String]( + field = "name.keyword", + value = "Name", + boost = None, + caseInsensitive = None + ) + ) ) }, test("successfully create Term Query with boost") { @@ -508,30 +539,48 @@ object QueryDSLSpec extends ZIOSpecDefault { val queryLong = term(field = "day_of_week", value = 1L).boost(1.0) assert(queryInt)( - equalTo(TermQuery(field = "day_of_week", value = 1, boost = Some(1.0), caseInsensitive = None)) + equalTo(TermQuery[Any, Int](field = "day_of_week", value = 1, boost = Some(1.0), caseInsensitive = None)) ) && assert(queryString)( - equalTo(TermQuery(field = "day_of_week", value = "Monday", boost = Some(1.0), caseInsensitive = None)) + equalTo( + TermQuery[Any, String](field = "day_of_week", value = "Monday", boost = Some(1.0), caseInsensitive = None) + ) ) && assert(queryBool)( - equalTo(TermQuery(field = "day_of_week", value = true, boost = Some(1.0), caseInsensitive = None)) + equalTo( + TermQuery[Any, Boolean](field = "day_of_week", value = true, boost = Some(1.0), caseInsensitive = None) + ) ) && assert(queryLong)( - equalTo(TermQuery(field = "day_of_week", value = 1L, boost = Some(1.0), caseInsensitive = None)) + equalTo(TermQuery[Any, Long](field = "day_of_week", value = 1L, boost = Some(1.0), caseInsensitive = None)) ) }, test("successfully create case insensitive Term Query") { val queryString = term(field = "day_of_week", value = "Monday").caseInsensitiveTrue assert(queryString)( - equalTo(TermQuery(field = "day_of_week", value = "Monday", boost = None, caseInsensitive = Some(true))) + equalTo( + TermQuery[Any, String]( + field = "day_of_week", + value = "Monday", + boost = None, + caseInsensitive = Some(true) + ) + ) ) }, test("successfully create case insensitive Term Query with boost") { val queryString = term(field = "day_of_week", value = "Monday").boost(1.0).caseInsensitiveTrue assert(queryString)( - equalTo(TermQuery(field = "day_of_week", value = "Monday", boost = Some(1.0), caseInsensitive = Some(true))) + equalTo( + TermQuery[Any, String]( + field = "day_of_week", + value = "Monday", + boost = Some(1.0), + caseInsensitive = Some(true) + ) + ) ) }, test("successfully create Wildcard Query") { @@ -540,13 +589,13 @@ object QueryDSLSpec extends ZIOSpecDefault { val wildcardQuery3 = wildcard(field = "day_of_week", value = "M*") assert(wildcardQuery1)( - equalTo(WildcardQuery(field = "day_of_week", value = "*M*", boost = None, caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "*M*", boost = None, caseInsensitive = None)) ) && assert(wildcardQuery2)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = None, caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = None, caseInsensitive = None)) ) && assert(wildcardQuery3)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = None, caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = None, caseInsensitive = None)) ) }, test("successfully create Wildcard Query with boost") { @@ -555,13 +604,13 @@ object QueryDSLSpec extends ZIOSpecDefault { val wildcardQuery3 = wildcard(field = "day_of_week", value = "M*").boost(1.0) assert(wildcardQuery1)( - equalTo(WildcardQuery(field = "day_of_week", value = "*M*", boost = Some(1.0), caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "*M*", boost = Some(1.0), caseInsensitive = None)) ) && assert(wildcardQuery2)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = None)) ) && assert(wildcardQuery3)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = None)) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = None)) ) }, test("successfully create case insensitive Wildcard Query") { @@ -570,13 +619,15 @@ object QueryDSLSpec extends ZIOSpecDefault { val wildcardQuery3 = wildcard(field = "day_of_week", value = "M*").caseInsensitiveTrue assert(wildcardQuery1)( - equalTo(WildcardQuery(field = "day_of_week", value = "*M*", boost = None, caseInsensitive = Some(true))) + equalTo( + WildcardQuery[Any](field = "day_of_week", value = "*M*", boost = None, caseInsensitive = Some(true)) + ) ) && assert(wildcardQuery2)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = None, caseInsensitive = Some(true))) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = None, caseInsensitive = Some(true))) ) && assert(wildcardQuery3)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = None, caseInsensitive = Some(true))) + equalTo(WildcardQuery[Any](field = "day_of_week", value = "M*", boost = None, caseInsensitive = Some(true))) ) }, test("successfully create case insensitive Wildcard Query with boost") { @@ -586,14 +637,18 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(wildcardQuery1)( equalTo( - WildcardQuery(field = "day_of_week", value = "*M*", boost = Some(1.0), caseInsensitive = Some(true)) + WildcardQuery[Any](field = "day_of_week", value = "*M*", boost = Some(1.0), caseInsensitive = Some(true)) ) ) && assert(wildcardQuery2)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = Some(true))) + equalTo( + WildcardQuery[Any](field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = Some(true)) + ) ) && assert(wildcardQuery3)( - equalTo(WildcardQuery(field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = Some(true))) + equalTo( + WildcardQuery[Any](field = "day_of_week", value = "M*", boost = Some(1.0), caseInsensitive = Some(true)) + ) ) } ), @@ -613,17 +668,22 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, - test("properly encode Bool Query with boost") { - val query = boolQuery.boost(1.0) + test("properly encode Bool Query with Filter containing `Match` leaf query") { + val query = filter(matches(field = "day_of_week", value = "Monday")) val expected = """ |{ | "query": { | "bool": { - | "filter": [], + | "filter": [ + | { + | "match": { + | "day_of_week": "Monday" + | } + | } + | ], | "must": [], - | "should": [], - | "boost": 1.0 + | "should": [] | } | } |} @@ -631,14 +691,14 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, - test("properly encode Bool Query with Filter containing `Match` leaf query") { - val query = boolQuery.filter(matches(field = "day_of_week", value = "Monday")) + test("properly encode Bool Query with Filter containing `Match` leaf query with boost") { + val query = filter(matches(field = "day_of_week", value = "Monday")).boost(1.0) val expected = """ |{ | "query": { | "bool": { - | "filter": [ + | "filter": [ | { | "match": { | "day_of_week": "Monday" @@ -646,7 +706,8 @@ object QueryDSLSpec extends ZIOSpecDefault { | } | ], | "must": [], - | "should": [] + | "should": [], + | "boost": 1.0 | } | } |} @@ -655,7 +716,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, test("properly encode Bool Query with Must containing `Match` leaf query") { - val query = boolQuery.must(matches(field = "day_of_week", value = "Monday")) + val query = must(matches(field = "day_of_week", value = "Monday")) val expected = """ |{ @@ -678,7 +739,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, test("properly encode Bool Query with Should containing `Match` leaf query") { - val query = boolQuery.should(matches(field = "day_of_week", value = "Monday")) + val query = should(matches(field = "day_of_week", value = "Monday")) val expected = """ |{ @@ -701,8 +762,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, test("properly encode Bool Query with Filter, Must and Should containing `Match` leaf query") { - val query = boolQuery - .filter(matches(field = "customer_age", value = 23)) + val query = filter(matches(field = "customer_age", value = 23)) .must(matches(field = "customer_id", value = 1)) .should(matches(field = "day_of_week", value = "Monday")) val expected = @@ -739,8 +799,7 @@ object QueryDSLSpec extends ZIOSpecDefault { assert(query.toJson)(equalTo(expected.toJson)) }, test("properly encode Bool Query with Filter, Must and Should containing `Match` leaf query and with boost") { - val query = boolQuery - .filter(matches(field = "customer_age", value = 23)) + val query = filter(matches(field = "customer_age", value = 23)) .must(matches(field = "customer_id", value = 1)) .should(matches(field = "day_of_week", value = "Monday")) .boost(1.0) @@ -1250,7 +1309,7 @@ object QueryDSLSpec extends ZIOSpecDefault { test("properly encode Bulk request body") { val bulkQuery = IndexName.make("users").map { index => val user = - UserDocument(id = "WeeMwR5d5", name = "Name", address = "Address", balance = 1000, age = 24) + UserDocument(id = "WeeMwR5d5", name = "Name", address = "Address", balance = 1000, age = 24, items = Nil) val req1 = ElasticRequest .create[UserDocument](index, DocumentId("ETux1srpww2ObCx"), user.copy(age = 39)) @@ -1270,11 +1329,11 @@ object QueryDSLSpec extends ZIOSpecDefault { val expectedBody = """|{ "create" : { "_index" : "users", "_id" : "ETux1srpww2ObCx", "routing" : "WeeMwR5d5" } } - |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":1000.0,"age":39} + |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":1000.0,"age":39,"items":[]} |{ "create" : { "_index" : "users", "routing" : "WeeMwR5d5" } } - |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":1000.0,"age":24} + |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":1000.0,"age":24,"items":[]} |{ "index" : { "_index" : "users", "_id" : "yMyEG8iFL5qx", "routing" : "WeeMwR5d5" } } - |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":3000.0,"age":24} + |{"id":"WeeMwR5d5","name":"Name","address":"Address","balance":3000.0,"age":24,"items":[]} |{ "delete" : { "_index" : "users", "_id" : "1VNzFt2XUFZfXZheDc", "routing" : "WeeMwR5d5" } } |""".stripMargin