From 861a98682d7b0b4f994b038f457125a23784e771 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 12 Jun 2025 15:24:01 +0200 Subject: [PATCH 01/41] Done: matches case for IntervalQuery --- .../zio/elasticsearch/ElasticQuery.scala | 236 ++++++++++++++ .../zio/elasticsearch/query/Queries.scala | 302 +++++++++++++++++- .../zio/elasticsearch/ElasticQuerySpec.scala | 64 ++++ 3 files changed, 588 insertions(+), 14 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 7b1472988..9a593cb2a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -21,8 +21,11 @@ import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.query._ import zio.elasticsearch.script.Script +import zio.json.ast.Json import zio.schema.Schema +import javax.management.Query + object ElasticQuery { /** @@ -548,6 +551,239 @@ object ElasticQuery { final def ids(value: String, values: String*): IdsQuery[Any] = Ids(values = Chunk.fromIterable(value +: values)) + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalMatch]] interval query. + * + * This query matches analyzed text within specified intervals based on the provided query string. + * + * @param query + * the text to match in the intervals. + * @return + * an instance of [[zio.elasticsearch.query.IntervalMatch]] that represents the `match` interval query. + */ + + final def intervalMatch(query: String): IntervalMatch = + IntervalMatch( + query = query, + analyzer = None, + useField = None, + maxGaps = None, + ordered = None, + filter = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalPrefix]] interval query. + * + * This query matches terms that start with the specified prefix in the intervals. + * + * @param prefix + * the prefix string to match. + * @return + * an instance of [[zio.elasticsearch.query.IntervalPrefix]] that represents the `prefix` interval query. + */ + + final def intervalPrefix(prefix: String): IntervalPrefix = + IntervalPrefix(prefix = prefix, analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalRegexp]] interval query. + * + * This query matches terms that follow the specified regular expression pattern within the intervals. + * + * @param pattern + * the regular expression pattern to match. + * @return + * an instance of [[zio.elasticsearch.query.IntervalRegexp]] that represents the `regexp` interval query. + */ + + final def intervalRegexp(pattern: String): IntervalRegexp = + IntervalRegexp(pattern = pattern, analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalWildcard]] interval query. + * + * This query matches terms in the intervals based on the specified wildcard pattern. + * + * @param pattern + * the wildcard pattern to match. + * @return + * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query. + */ + + final def intervalWildcard(pattern: String): IntervalWildcard = + IntervalWildcard(pattern = pattern, analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalAllOf]] interval query. + * + * This query matches analyzed text where all specified intervals are found, optionally ordered and/or filtered. + * + * @param intervals + * the list of sub-intervals that all must match. + * @param maxGaps + * optional maximum number of allowed gaps between intervals. + * @param ordered + * optional flag to enforce ordered appearance. + * @param filter + * optional filter to further restrict results. + * @return + * an instance of [[zio.elasticsearch.query.IntervalAllOf]] that represents the `all_of` interval query. + */ + + final def intervalAllOf( + intervals: Chunk[IntervalQuery], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalQuery] + ): IntervalAllOf = + IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalAnyOf]] interval query. + * + * This query matches documents that contain any of the specified interval queries. + * + * @param intervals + * a list of interval queries where any can match. + * @param filter + * optional filter to further restrict results. + * @return + * an instance of [[zio.elasticsearch.query.IntervalAnyOf]] that represents the `any_of` interval query. + */ + + final def intervalAnyOf( + intervals: Chunk[IntervalQuery], + filter: Option[IntervalQuery] + ): IntervalAnyOf = + IntervalAnyOf(intervals, filter = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalFuzzy]] interval query. + * + * This query returns documents that match terms similar to the specified term using fuzzy logic. + * + * @param term + * the term to match using fuzzy logic. + * @return + * an instance of [[zio.elasticsearch.query.IntervalFuzzy]] that represents the `fuzzy` interval query. + */ + + final def intervalFuzzy(term: String): IntervalFuzzy = + IntervalFuzzy( + term = term, + prefixLength = None, + transpositions = None, + fuzziness = None, + analyzer = None, + useField = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalRange]] interval query. + * + * This query matches documents containing terms within the specified string range constraints. + * + * @param gt + * optional exclusive lower bound. + * @param gte + * optional inclusive lower bound. + * @param lt + * optional exclusive upper bound. + * @param lte + * optional inclusive upper bound. + * @param analyzer + * optional analyzer to use for the range terms. + * @param useField + * optional alternative field to use. + * @return + * an instance of [[zio.elasticsearch.query.IntervalRange]] that represents the `range` interval query. + */ + + final def intervalRange( + gt: Option[String], + gte: Option[String], + lt: Option[String], + lte: Option[String], + analyzer: Option[String], + useField: Option[String] + ): IntervalRange = + IntervalRange(gt = None, gte = None, lt = None, lte = None, analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] interval filter. + * + * This filter allows further refinement of interval queries using a custom script. + * + * @param source + * the source of the script used for filtering. + * @return + * an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] representing the script filter. + */ + // final def intervalScriptFilter( + // after: Option[Query], + // before: Option[Query] , + // contained_by: Option[Query] , + // containing: Option[Query] , + // not_contained_by: Option[Query] , + // not_containing: Option[Query], + // not_overlapping: Option[Query], + // overlapping: Option[Query] , + // script: Option[Json] + // ): IntervalScriptFilter = + // IntervalScriptFilter( + // after= None, + // before= None, + // contained_by= None, + // containing= None, + // not_contained_by= None, + // not_containing= None, + // not_overlapping= None, + // overlapping= None, + // script= None + // ) + + /** + * Constructs an intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given field in the intervals query structure. + * + * @param field + * the name of the field to be queried. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalQuery]] representing the interval query rule. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals( + field: String, + rule: IntervalQuery + ): ElasticQuery[Any] = + Intervals(field, rule) + + /** + * Constructs a type-safe intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given type-safe field in the intervals query + * structure. + * + * @param field + * the type-safe field on which the query is executed. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalQuery]] representing the interval query rule. + * @tparam S + * the document type for which the query is defined. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals[S]( + field: Field[S, _], + rule: IntervalQuery + ): ElasticQuery[S] = + Intervals(field.toString, rule) + /** * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index ca62ebdb2..98bd34609 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -21,10 +21,13 @@ import zio.elasticsearch.ElasticPrimitive._ import zio.elasticsearch.Field import zio.elasticsearch.query.options._ import zio.elasticsearch.query.sort.options.HasFormat +import zio.json.{DeriveJsonEncoder, JsonEncoder} import zio.json.ast.Json -import zio.json.ast.Json.{Arr, Obj} +import zio.json.ast.Json.{Arr, Num, Obj, Str} import zio.schema.Schema +import javax.management.Query + sealed trait ElasticQuery[-S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json } @@ -528,7 +531,7 @@ sealed trait GeoDistanceQuery[S] extends ElasticQuery[S] { * incorrect coordinates. * * @param value - * defines how to handle invalid latitude nad longitude: + * defines how to handle invalid latitude and longitude: * - [[zio.elasticsearch.query.ValidationMethod.Strict]]: Default method * - [[zio.elasticsearch.query.ValidationMethod.IgnoreMalformed]]: Accepts geo points with invalid latitude or * longitude @@ -569,7 +572,6 @@ private[elasticsearch] final case class GeoDistance[S]( ).flatten: _* ) ) - } sealed trait GeoPolygonQuery[S] extends ElasticQuery[S] { @@ -590,7 +592,7 @@ sealed trait GeoPolygonQuery[S] extends ElasticQuery[S] { * incorrect coordinates. * * @param value - * defines how to handle invalid latitude nad longitude: + * defines how to handle invalid latitude and longitude: * - [[zio.elasticsearch.query.ValidationMethod.Strict]]: Default method * - [[zio.elasticsearch.query.ValidationMethod.IgnoreMalformed]]: Accepts geo points with invalid latitude or * longitude @@ -782,6 +784,268 @@ private[elasticsearch] final case class Ids[S](values: Chunk[String]) extends Id Obj("ids" -> Obj("values" -> Arr(values.map(_.toJson)))) } +sealed trait IntervalQuery { + private[elasticsearch] def toJson: Json +} + +/** + * Represents a `match` interval query. Matches analyzed text within intervals. + * + * @param query + * The text to match. + * @param analyzer + * Optional analyzer to use for this query. + * @param useField + * Optional alternative field used for term extraction. + */ + +/** `match` interval-query */ +private[elasticsearch] final case class IntervalMatch( + query: String, + analyzer: Option[String], + useField: Option[String], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalQuery] +) extends IntervalQuery { self => + + def withAnalyzer(a: String) = copy(analyzer = Some(a)) + def withUseField(f: String) = copy(useField = Some(f)) + def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) + def withOrdered(o: Boolean) = copy(ordered = Some(o)) + def withFilter(f: IntervalQuery) = copy(filter = Some(f)) + + override private[elasticsearch] def toJson: Json = + Obj( + "match" -> Obj( + Chunk( + Some("query" -> Str(query)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalPrefix( + prefix: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalQuery { + + override private[elasticsearch] def toJson: Json = + Obj( + "prefix" -> Obj( + Chunk( + Some("prefix" -> Str(prefix)), + analyzer.map(a => "analyzer" -> Str(a)), + useField.map(u => "use_field" -> Str(u)) + ).flatten: _* + ) + ) +} + +/** + * Represents a `prefix` interval query. Matches terms with the given prefix. + * + * @param prefix + * The prefix string. + * @param analyzer + * Optional analyzer to apply. + * @param useField + * Optional alternative field used for term extraction. + */ + +final case class IntervalRegexp( + pattern: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "regexp" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +/** + * Represents a `wildcard` interval query. Matches terms using wildcard syntax. + * + * @param pattern + * The wildcard pattern. + * @param analyzer + * Optional analyzer to apply. + * @param useField + * Optional alternative field used for term extraction. + */ +private[elasticsearch] final case class IntervalWildcard( + pattern: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "wildcard" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +/** + * Represents an `all_of` interval query. Matches documents that contain all specified intervals. + * + * @param intervals + * List of interval queries to match. + * @param maxGaps + * Optional maximum allowed gaps between intervals. + * @param ordered + * Optional flag indicating if intervals should be in order. + * @param filter + * Optional filter interval query that restricts matches. + */ +private[elasticsearch] final case class IntervalAllOf( + intervals: Chunk[IntervalQuery], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalQuery] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "all_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +/** + * Represents an `any_of` interval query. Matches documents that contain any of the specified intervals. + * + * @param intervals + * List of interval queries to match. + */ +private[elasticsearch] final case class IntervalAnyOf( + intervals: Chunk[IntervalQuery], + filter: Option[IntervalQuery] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "any_of" -> Obj( + "intervals" -> Arr(intervals.map(_.toJson): _*) + ) + ) +} + +private[elasticsearch] final case class IntervalFuzzy( + term: String, + prefixLength: Option[Int], + transpositions: Option[Boolean], + fuzziness: Option[String], + analyzer: Option[String], + useField: Option[String] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "fuzzy" -> Obj( + Chunk( + Some("term" -> term.toJson), + prefixLength.map("prefix_length" -> _.toJson), + transpositions.map("transpositions" -> _.toJson), + fuzziness.map("fuzziness" -> _.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +/** + */ + +private[elasticsearch] final case class IntervalRange( + gt: Option[String], + gte: Option[String], + lt: Option[String], + lte: Option[String], + analyzer: Option[String], + useField: Option[String] +) extends IntervalQuery { + private[elasticsearch] def toJson: Json = + Obj( + "range" -> Obj( + Chunk( + gt.map("gt" -> _.toJson), + gte.map("gte" -> _.toJson), + lt.map("lt" -> _.toJson), + lte.map("lte" -> _.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +//private[elasticsearch] final case class IntervalScriptFilter( +// after: Option[Query] = None, +// before: Option[Query] = None, +// contained_by: Option[Query] = None, +// containing: Option[Query] = None, +// not_contained_by: Option[Query] = None, +// not_containing: Option[Query] = None, +// not_overlapping: Option[Query] = None, +// overlapping: Option[Query] = None, +// script: Option[Json] = None +// ) extends IntervalQuery { +// private[elasticsearch] def toJson: Json = +// Obj( +// "filter" -> Obj( +// Chunk( +// after.map("after" -> _.toJson), +// before.map("before" -> _.toJson), +// contained_by.map("contained_by" -> _.toJson), +// containing.map("containing" -> _.toJson), +// not_contained_by.map("not_contained_by" -> _.toJson), +// not_containing.map("not_containing" -> _.toJson), +// not_overlapping.map("not_overlapping" -> _.toJson), +// overlapping.map("overlapping" -> _.toJson), +// script.map("script" -> _) +// ).flatten: _* +// ) +// ) +//} + +sealed trait IntervalsQuery[S] extends ElasticQuery[S] + +private[elasticsearch] final case class Intervals[S]( + field: String, + query: IntervalQuery +) extends IntervalsQuery[S] { + self => + + private[elasticsearch] def toJson(fieldPath: Option[String]): Json = + Obj( + "intervals" -> Obj( + fieldPath.getOrElse(field) -> query.toJson + ) + ) +} + sealed trait MatchQuery[S] extends ElasticQuery[S] private[elasticsearch] final case class Match[S, A: ElasticPrimitive](field: String, value: A) extends MatchQuery[S] { @@ -906,7 +1170,8 @@ private[elasticsearch] final case class MultiMatch[S]( boost: Option[Double], matchingType: Option[MultiMatchType], minimumShouldMatch: Option[Int] -) extends MultiMatchQuery[S] { self => +) extends MultiMatchQuery[S] { + self => def boost(boost: Double): MultiMatchQuery[S] = self.copy(boost = Some(boost)) @@ -949,7 +1214,8 @@ private[elasticsearch] final case class Nested[S]( ignoreUnmapped: Option[Boolean], innerHitsField: Option[InnerHits], scoreMode: Option[ScoreMode] -) extends NestedQuery[S] { self => +) extends NestedQuery[S] { + self => def ignoreUnmapped(value: Boolean): NestedQuery[S] = self.copy(ignoreUnmapped = Some(value)) @@ -1020,7 +1286,8 @@ private[elasticsearch] final case class Prefix[S]( field: String, value: String, caseInsensitive: Option[Boolean] -) extends PrefixQuery[S] { self => +) extends PrefixQuery[S] { + self => def caseInsensitive(value: Boolean): PrefixQuery[S] = self.copy(caseInsensitive = Some(value)) @@ -1102,7 +1369,8 @@ private[elasticsearch] final case class Range[S, A, LB <: LowerBound, UB <: Uppe upper: UB, boost: Option[Double], format: Option[String] -) extends RangeQuery[S, A, LB, UB] { self => +) extends RangeQuery[S, A, LB, UB] { + self => def boost(value: Double): RangeQuery[S, A, LB, UB] = self.copy(boost = Some(value)) @@ -1162,7 +1430,8 @@ private[elasticsearch] final case class Regexp[S]( field: String, value: String, caseInsensitive: Option[Boolean] -) extends RegexpQuery[S] { self => +) extends RegexpQuery[S] { + self => def caseInsensitive(value: Boolean): RegexpQuery[S] = self.copy(caseInsensitive = Some(value)) @@ -1177,7 +1446,8 @@ private[elasticsearch] final case class Regexp[S]( sealed trait ScriptQuery extends ElasticQuery[Any] with HasBoost[ScriptQuery] private[elasticsearch] final case class Script(script: zio.elasticsearch.script.Script, boost: Option[Double]) - extends ScriptQuery { self => + extends ScriptQuery { + self => def boost(value: Double): ScriptQuery = self.copy(boost = Some(value)) @@ -1193,7 +1463,8 @@ private[elasticsearch] final case class Term[S, A: ElasticPrimitive]( value: A, boost: Option[Double], caseInsensitive: Option[Boolean] -) extends TermQuery[S] { self => +) extends TermQuery[S] { + self => def boost(value: Double): TermQuery[S] = self.copy(boost = Some(value)) @@ -1216,7 +1487,8 @@ private[elasticsearch] final case class Terms[S, A: ElasticPrimitive]( field: String, values: Chunk[A], boost: Option[Double] -) extends TermsQuery[S] { self => +) extends TermsQuery[S] { + self => def boost(value: Double): TermsQuery[S] = self.copy(boost = Some(value)) @@ -1237,7 +1509,8 @@ private[elasticsearch] final case class TermsSet[S, A: ElasticPrimitive]( boost: Option[Double], minimumShouldMatchField: Option[String], minimumShouldMatchScript: Option[zio.elasticsearch.script.Script] -) extends TermsSetQuery[S] { self => +) extends TermsSetQuery[S] { + self => def boost(value: Double): TermsSetQuery[S] = self.copy(boost = Some(value)) @@ -1262,7 +1535,8 @@ private[elasticsearch] final case class Wildcard[S]( value: String, boost: Option[Double], caseInsensitive: Option[Boolean] -) extends WildcardQuery[S] { self => +) extends WildcardQuery[S] { + self => def boost(value: Double): WildcardQuery[S] = self.copy(boost = Some(value)) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index da509a1e2..c628e6880 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1074,6 +1074,70 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) ) }, + test("intervalsQuery") { + val intervalNoOptions = intervalMatch("lambda works") + + val intervalWithOptions = intervalMatch("lambda works") + .withOrdered(true) + .withMaxGaps(2) + .withAnalyzer("standard") + + val queryWithStringField = intervals("content", intervalWithOptions) + + val typedField: Field[TestDocument, String] = Field(None, "content") + val queryWithTypedField = intervals(typedField, intervalWithOptions) + + val expectedNoOptions = + """ + |{ + | "intervals": { + | "content": { + | "match": { + | "query": "lambda works" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithOptions = + """ + |{ + | "intervals": { + | "content": { + | "match": { + | "query": "lambda works", + | "ordered": true, + | "max_gaps": 2, + | "analyzer": "standard" + | } + | } + | } + |} + |""".stripMargin + + assert(intervalNoOptions)( + equalTo( + IntervalMatch( + query = "lambda works", + analyzer = None, + useField = None, + maxGaps = None, + ordered = None, + filter = None + ) + ) + ) && + assert(intervals("content", intervalNoOptions).toJson(None))( + equalTo(expectedNoOptions.toJson) + ) && + assert(queryWithStringField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithTypedField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) + }, test("kNN") { val queryString = kNN("stringField", 5, 10, Chunk(1.1, 2.2, 3.3)) val queryBool = kNN("boolField", 5, 10, Chunk(1.1, 2.2, 3.3)) From 7bb2df645e42518ee07ae1c8777fae89fc0eff5e Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 13 Jun 2025 13:04:13 +0200 Subject: [PATCH 02/41] Disable empty chunk in interval allof, Wildcard (with cointains, startwith, endwith), Regex instead of String in intervalRegexp, remove useless imports --- .../zio/elasticsearch/ElasticQuery.scala | 109 ++++++--- .../zio/elasticsearch/query/Queries.scala | 139 +++++------- .../zio/elasticsearch/ElasticQuerySpec.scala | 213 +++++++++++++++++- 3 files changed, 327 insertions(+), 134 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 9a593cb2a..5d6620ea9 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -16,7 +16,7 @@ package zio.elasticsearch -import zio.Chunk +import zio.{Chunk, NonEmptyChunk} import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.query._ @@ -562,7 +562,7 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalMatch]] that represents the `match` interval query. */ - final def intervalMatch(query: String): IntervalMatch = + final def intervalMatch(query: String): IntervalMatch[String] = IntervalMatch( query = query, analyzer = None, @@ -597,7 +597,7 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalRegexp]] that represents the `regexp` interval query. */ - final def intervalRegexp(pattern: String): IntervalRegexp = + final def intervalRegexp(pattern: Regexp[Any]): IntervalRegexp[Any] = IntervalRegexp(pattern = pattern, analyzer = None, useField = None) /** @@ -611,7 +611,48 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query. */ - final def intervalWildcard(pattern: String): IntervalWildcard = + /** + * Matches any term that contains the provided substring. + * + * @param pattern + * the pattern that should be contained + * @return + * an instance of IntervalWildcard that represents the `wildcard` interval query with contains pattern. + */ + final def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + /** + * Matches any term that starts with the provided substring. + * + * @param pattern + * the pattern that should be at the beginning + * @return + * an instance of IntervalWildcard that represents the `wildcard` interval query with startsWith pattern. + */ + final def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + /** + * Matches any term that ends with the provided substring. + * + * @param pattern + * the pattern that should be at the end + * @return + * an instance of IntervalWildcard that represents the `wildcard` interval query with endsWith pattern. + */ + final def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + /** + * Matches any term that matches the exact pattern. + * + * @param pattern + * wildcard pattern + * @return + * an instance of IntervalWildcard that represents the `wildcard` interval query. + */ + final def intervalWildcard[S](pattern: String): IntervalWildcard[S] = IntervalWildcard(pattern = pattern, analyzer = None, useField = None) /** @@ -631,13 +672,13 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalAllOf]] that represents the `all_of` interval query. */ - final def intervalAllOf( - intervals: Chunk[IntervalQuery], + final def intervalAllOf[S]( + intervals: NonEmptyChunk[IntervalQuery], maxGaps: Option[Int], ordered: Option[Boolean], - filter: Option[IntervalQuery] - ): IntervalAllOf = - IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + filter: Option[IntervalFilter[S]] + ): IntervalAllOf[Any] = + IntervalAllOf(intervals.toChunk, maxGaps = None, ordered = None, filter = None) /** * Constructs an instance of [[zio.elasticsearch.query.IntervalAnyOf]] interval query. @@ -652,10 +693,10 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalAnyOf]] that represents the `any_of` interval query. */ - final def intervalAnyOf( + final def intervalAnyOf[S]( intervals: Chunk[IntervalQuery], - filter: Option[IntervalQuery] - ): IntervalAnyOf = + filter: Option[IntervalFilter[S]] + ): IntervalAnyOf[S] = IntervalAnyOf(intervals, filter = None) /** @@ -720,28 +761,28 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] representing the script filter. */ - // final def intervalScriptFilter( - // after: Option[Query], - // before: Option[Query] , - // contained_by: Option[Query] , - // containing: Option[Query] , - // not_contained_by: Option[Query] , - // not_containing: Option[Query], - // not_overlapping: Option[Query], - // overlapping: Option[Query] , - // script: Option[Json] - // ): IntervalScriptFilter = - // IntervalScriptFilter( - // after= None, - // before= None, - // contained_by= None, - // containing= None, - // not_contained_by= None, - // not_containing= None, - // not_overlapping= None, - // overlapping= None, - // script= None - // ) + final def intervalFilter[S]( + after: Option[IntervalQuery] = None, + before: Option[IntervalQuery] = None, + containedBy: Option[IntervalQuery] = None, + containing: Option[IntervalQuery] = None, + notContainedBy: Option[IntervalQuery] = None, + notContaining: Option[IntervalQuery] = None, + notOverlapping: Option[IntervalQuery] = None, + overlapping: Option[IntervalQuery] = None, + script: Option[Json] = None + ): IntervalFilter[S] = + IntervalFilter( + after = after, + before = before, + containedBy = containedBy, + containing = containing, + notContainedBy = notContainedBy, + notContaining = notContaining, + notOverlapping = notOverlapping, + overlapping = overlapping, + script = script + ) /** * Constructs an intervals query by combining a field and an interval query. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 98bd34609..9bf35c93d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -21,13 +21,10 @@ import zio.elasticsearch.ElasticPrimitive._ import zio.elasticsearch.Field import zio.elasticsearch.query.options._ import zio.elasticsearch.query.sort.options.HasFormat -import zio.json.{DeriveJsonEncoder, JsonEncoder} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Num, Obj, Str} import zio.schema.Schema -import javax.management.Query - sealed trait ElasticQuery[-S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json } @@ -800,20 +797,20 @@ sealed trait IntervalQuery { */ /** `match` interval-query */ -private[elasticsearch] final case class IntervalMatch( +private[elasticsearch] final case class IntervalMatch[S]( query: String, analyzer: Option[String], useField: Option[String], maxGaps: Option[Int], ordered: Option[Boolean], - filter: Option[IntervalQuery] + filter: Option[IntervalFilter[S]] ) extends IntervalQuery { self => - def withAnalyzer(a: String) = copy(analyzer = Some(a)) - def withUseField(f: String) = copy(useField = Some(f)) - def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) - def withOrdered(o: Boolean) = copy(ordered = Some(o)) - def withFilter(f: IntervalQuery) = copy(filter = Some(f)) + def withAnalyzer(a: String) = copy(analyzer = Some(a)) + def withUseField(f: String) = copy(useField = Some(f)) + def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) + def withOrdered(o: Boolean) = copy(ordered = Some(o)) + def withFilter(f: IntervalFilter[S]) = copy(filter = Some(f)) override private[elasticsearch] def toJson: Json = Obj( @@ -836,6 +833,9 @@ private[elasticsearch] final case class IntervalPrefix( useField: Option[String] ) extends IntervalQuery { + def withAnalyzer(a: String) = copy(analyzer = Some(a)) + def withUseField(f: String) = copy(useField = Some(f)) + override private[elasticsearch] def toJson: Json = Obj( "prefix" -> Obj( @@ -848,19 +848,8 @@ private[elasticsearch] final case class IntervalPrefix( ) } -/** - * Represents a `prefix` interval query. Matches terms with the given prefix. - * - * @param prefix - * The prefix string. - * @param analyzer - * Optional analyzer to apply. - * @param useField - * Optional alternative field used for term extraction. - */ - -final case class IntervalRegexp( - pattern: String, +private[elasticsearch] final case class IntervalRegexp[S]( + pattern: Regexp[S], analyzer: Option[String], useField: Option[String] ) extends IntervalQuery { @@ -868,7 +857,7 @@ final case class IntervalRegexp( Obj( "regexp" -> Obj( Chunk( - Some("pattern" -> pattern.toJson), + Some("pattern" -> pattern.toJson(None)), analyzer.map("analyzer" -> _.toJson), useField.map("use_field" -> _.toJson) ).flatten: _* @@ -876,21 +865,18 @@ final case class IntervalRegexp( ) } -/** - * Represents a `wildcard` interval query. Matches terms using wildcard syntax. - * - * @param pattern - * The wildcard pattern. - * @param analyzer - * Optional analyzer to apply. - * @param useField - * Optional alternative field used for term extraction. - */ -private[elasticsearch] final case class IntervalWildcard( +private[elasticsearch] final case class IntervalWildcard[S]( pattern: String, analyzer: Option[String], useField: Option[String] ) extends IntervalQuery { + + def withAnalyzer(a: String): IntervalWildcard[S] = + copy(analyzer = Some(a)) + + def withUseField(f: String): IntervalWildcard[S] = + copy(useField = Some(f)) + private[elasticsearch] def toJson: Json = Obj( "wildcard" -> Obj( @@ -903,23 +889,11 @@ private[elasticsearch] final case class IntervalWildcard( ) } -/** - * Represents an `all_of` interval query. Matches documents that contain all specified intervals. - * - * @param intervals - * List of interval queries to match. - * @param maxGaps - * Optional maximum allowed gaps between intervals. - * @param ordered - * Optional flag indicating if intervals should be in order. - * @param filter - * Optional filter interval query that restricts matches. - */ -private[elasticsearch] final case class IntervalAllOf( +private[elasticsearch] final case class IntervalAllOf[S]( intervals: Chunk[IntervalQuery], maxGaps: Option[Int], ordered: Option[Boolean], - filter: Option[IntervalQuery] + filter: Option[IntervalFilter[S]] ) extends IntervalQuery { private[elasticsearch] def toJson: Json = Obj( @@ -934,15 +908,9 @@ private[elasticsearch] final case class IntervalAllOf( ) } -/** - * Represents an `any_of` interval query. Matches documents that contain any of the specified intervals. - * - * @param intervals - * List of interval queries to match. - */ -private[elasticsearch] final case class IntervalAnyOf( +private[elasticsearch] final case class IntervalAnyOf[S]( intervals: Chunk[IntervalQuery], - filter: Option[IntervalQuery] + filter: Option[IntervalFilter[S]] ) extends IntervalQuery { private[elasticsearch] def toJson: Json = Obj( @@ -975,9 +943,6 @@ private[elasticsearch] final case class IntervalFuzzy( ) } -/** - */ - private[elasticsearch] final case class IntervalRange( gt: Option[String], gte: Option[String], @@ -1001,34 +966,32 @@ private[elasticsearch] final case class IntervalRange( ) } -//private[elasticsearch] final case class IntervalScriptFilter( -// after: Option[Query] = None, -// before: Option[Query] = None, -// contained_by: Option[Query] = None, -// containing: Option[Query] = None, -// not_contained_by: Option[Query] = None, -// not_containing: Option[Query] = None, -// not_overlapping: Option[Query] = None, -// overlapping: Option[Query] = None, -// script: Option[Json] = None -// ) extends IntervalQuery { -// private[elasticsearch] def toJson: Json = -// Obj( -// "filter" -> Obj( -// Chunk( -// after.map("after" -> _.toJson), -// before.map("before" -> _.toJson), -// contained_by.map("contained_by" -> _.toJson), -// containing.map("containing" -> _.toJson), -// not_contained_by.map("not_contained_by" -> _.toJson), -// not_containing.map("not_containing" -> _.toJson), -// not_overlapping.map("not_overlapping" -> _.toJson), -// overlapping.map("overlapping" -> _.toJson), -// script.map("script" -> _) -// ).flatten: _* -// ) -// ) -//} +private[elasticsearch] final case class IntervalFilter[S]( + after: Option[IntervalQuery] = None, + before: Option[IntervalQuery] = None, + containedBy: Option[IntervalQuery] = None, + containing: Option[IntervalQuery] = None, + notContainedBy: Option[IntervalQuery] = None, + notContaining: Option[IntervalQuery] = None, + notOverlapping: Option[IntervalQuery] = None, + overlapping: Option[IntervalQuery] = None, + script: Option[Json] = None +) { + private[elasticsearch] def toJson: Json = + Obj( + Chunk( + after.map("after" -> _.toJson), + before.map("before" -> _.toJson), + containedBy.map("contained_by" -> _.toJson), + containing.map("containing" -> _.toJson), + notContainedBy.map("not_contained_by" -> _.toJson), + notContaining.map("not_containing" -> _.toJson), + notOverlapping.map("not_overlapping" -> _.toJson), + overlapping.map("overlapping" -> _.toJson), + script.map("script" -> _) + ).flatten: _* + ) +} sealed trait IntervalsQuery[S] extends ElasticQuery[S] diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index c628e6880..0b8562b73 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1074,24 +1074,34 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) ) }, - test("intervalsQuery") { - val intervalNoOptions = intervalMatch("lambda works") + test("intervalsMatchQuery") { + val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") - val intervalWithOptions = intervalMatch("lambda works") + val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") .withOrdered(true) .withMaxGaps(2) .withAnalyzer("standard") - val queryWithStringField = intervals("content", intervalWithOptions) + val filter = IntervalFilter[String]( + before = Some(intervalMatch("before_term")), + after = Some(intervalMatch("after_term")) + ) + + val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") + .withOrdered(true) + .withMaxGaps(2) + .withAnalyzer("standard") + .withFilter(filter) - val typedField: Field[TestDocument, String] = Field(None, "content") - val queryWithTypedField = intervals(typedField, intervalWithOptions) + val queryWithStringField = intervals("stringField", intervalWithOptions) + val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) + val queryWithFilter = intervals("stringField", intervalWithFilter) val expectedNoOptions = """ |{ | "intervals": { - | "content": { + | "stringField": { | "match": { | "query": "lambda works" | } @@ -1104,12 +1114,40 @@ object ElasticQuerySpec extends ZIOSpecDefault { """ |{ | "intervals": { - | "content": { + | "stringField": { | "match": { | "query": "lambda works", - | "ordered": true, + | "analyzer": "standard", | "max_gaps": 2, - | "analyzer": "standard" + | "ordered": true + | } + | } + | } + |} + |""".stripMargin + + val expectedWithFilter = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works", + | "analyzer": "standard", + | "max_gaps": 2, + | "ordered": true, + | "filter": { + | "before": { + | "match": { + | "query": "before_term" + | } + | }, + | "after": { + | "match": { + | "query": "after_term" + | } + | } + | } | } | } | } @@ -1118,7 +1156,7 @@ object ElasticQuerySpec extends ZIOSpecDefault { assert(intervalNoOptions)( equalTo( - IntervalMatch( + IntervalMatch[String]( query = "lambda works", analyzer = None, useField = None, @@ -1128,7 +1166,7 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) ) ) && - assert(intervals("content", intervalNoOptions).toJson(None))( + assert(intervals("stringField", intervalNoOptions).toJson(None))( equalTo(expectedNoOptions.toJson) ) && assert(queryWithStringField.toJson(None))( @@ -1136,8 +1174,159 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) && assert(queryWithTypedField.toJson(None))( equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithFilter.toJson(None))( + equalTo(expectedWithFilter.toJson) ) }, + test("intervalsPrefixQuery") { + val intervalNoOptions: IntervalPrefix = intervalPrefix("lambda") + + val intervalWithOptions: IntervalPrefix = intervalPrefix("lambda") + .withAnalyzer("standard") + .withUseField("text") + + val queryWithStringField = intervals("stringField", intervalWithOptions) + val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) + + val expectedNoOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "prefix": { + | "prefix": "lambda" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "prefix": { + | "prefix": "lambda", + | "analyzer": "standard", + | "use_field": "text" + | } + | } + | } + |} + |""".stripMargin + + assert(intervalNoOptions)( + equalTo( + IntervalPrefix( + prefix = "lambda", + analyzer = None, + useField = None + ) + ) + ) && + assert(intervals("stringField", intervalNoOptions).toJson(None))( + equalTo(expectedNoOptions.toJson) + ) && + assert(queryWithStringField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithTypedField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) + }, + test("intervalWildcard") { + val wildcardExact: IntervalWildcard[String] = + intervalWildcard("la*mb?da") + + val wildcardContains: IntervalWildcard[String] = + intervalContains("lambda") + + val wildcardStartsWith: IntervalWildcard[String] = + intervalStartsWith("lambda") + + val wildcardEndsWith: IntervalWildcard[String] = + intervalEndsWith("lambda") + + val queryExact: Intervals[String] = + Intervals("stringField", wildcardExact) + + val queryContains: Intervals[String] = + Intervals("stringField", wildcardContains) + + val queryStartsWith: Intervals[String] = + Intervals("stringField", wildcardStartsWith) + + val queryEndsWith: Intervals[String] = + Intervals("stringField", wildcardEndsWith) + + val expectedExact = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "la*mb?da" + | } + | } + | } + |} + |""".stripMargin + + val expectedContains = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda*" + | } + | } + | } + |} + |""".stripMargin + + val expectedStartsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "lambda*" + | } + | } + | } + |} + |""".stripMargin + + val expectedEndsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda" + | } + | } + | } + |} + |""".stripMargin + + assert(wildcardExact)( + equalTo( + IntervalWildcard[String]( + pattern = "la*mb?da", + analyzer = None, + useField = None + ) + ) + ) && + assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && + assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && + assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && + assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) + }, test("kNN") { val queryString = kNN("stringField", 5, 10, Chunk(1.1, 2.2, 3.3)) val queryBool = kNN("boolField", 5, 10, Chunk(1.1, 2.2, 3.3)) From 907980b820c1e438c8e8428aec8a431ebad5c130 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 13 Jun 2025 14:36:34 +0200 Subject: [PATCH 03/41] Implement IntervalRange test --- .../zio/elasticsearch/ElasticQuery.scala | 17 ++--- .../zio/elasticsearch/query/Queries.scala | 28 ++++--- .../zio/elasticsearch/ElasticQuerySpec.scala | 75 +++++++++++++------ 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 5d6620ea9..df07511a7 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -24,8 +24,6 @@ import zio.elasticsearch.script.Script import zio.json.ast.Json import zio.schema.Schema -import javax.management.Query - object ElasticQuery { /** @@ -710,7 +708,7 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalFuzzy]] that represents the `fuzzy` interval query. */ - final def intervalFuzzy(term: String): IntervalFuzzy = + final def intervalFuzzy[S](term: String): IntervalFuzzy[S] = IntervalFuzzy( term = term, prefixLength = None, @@ -740,16 +738,13 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.IntervalRange]] that represents the `range` interval query. */ - - final def intervalRange( - gt: Option[String], - gte: Option[String], - lt: Option[String], - lte: Option[String], + def intervalRange[S]( + lower: Option[Either[String, String]], + upper: Option[Either[String, String]], analyzer: Option[String], useField: Option[String] - ): IntervalRange = - IntervalRange(gt = None, gte = None, lt = None, lte = None, analyzer = None, useField = None) + ): IntervalRange[S] = + IntervalRange(lower, upper, analyzer, useField) /** * Constructs an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] interval filter. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 9bf35c93d..20eea0f46 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -920,7 +920,7 @@ private[elasticsearch] final case class IntervalAnyOf[S]( ) } -private[elasticsearch] final case class IntervalFuzzy( +private[elasticsearch] final case class IntervalFuzzy[S]( term: String, prefixLength: Option[Int], transpositions: Option[Boolean], @@ -943,27 +943,33 @@ private[elasticsearch] final case class IntervalFuzzy( ) } -private[elasticsearch] final case class IntervalRange( - gt: Option[String], - gte: Option[String], - lt: Option[String], - lte: Option[String], +private[elasticsearch] final case class IntervalRange[S]( + lower: Option[Either[String, String]], + upper: Option[Either[String, String]], analyzer: Option[String], useField: Option[String] ) extends IntervalQuery { - private[elasticsearch] def toJson: Json = + private[elasticsearch] def toJson: Json = { + val lowerJson = lower.map { + case Left(gt) => "gt" -> gt.toJson + case Right(gte) => "gte" -> gte.toJson + } + val upperJson = upper.map { + case Left(lt) => "lt" -> lt.toJson + case Right(lte) => "lte" -> lte.toJson + } + Obj( "range" -> Obj( Chunk( - gt.map("gt" -> _.toJson), - gte.map("gte" -> _.toJson), - lt.map("lt" -> _.toJson), - lte.map("lte" -> _.toJson), + lowerJson, + upperJson, analyzer.map("analyzer" -> _.toJson), useField.map("use_field" -> _.toJson) ).flatten: _* ) ) + } } private[elasticsearch] final case class IntervalFilter[S]( diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 0b8562b73..92a8c9a6b 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1179,61 +1179,92 @@ object ElasticQuerySpec extends ZIOSpecDefault { equalTo(expectedWithFilter.toJson) ) }, - test("intervalsPrefixQuery") { - val intervalNoOptions: IntervalPrefix = intervalPrefix("lambda") + test("intervalRange") { + val intervalNoBounds = ElasticQuery.intervalRange( + lower = None, + upper = None, + analyzer = None, + useField = None + ) - val intervalWithOptions: IntervalPrefix = intervalPrefix("lambda") - .withAnalyzer("standard") - .withUseField("text") + val intervalWithBounds = ElasticQuery.intervalRange( + lower = Some(Left("10")), + upper = Some(Right("20")), + analyzer = Some("standard"), + useField = Some("otherField") + ) - val queryWithStringField = intervals("stringField", intervalWithOptions) - val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) + val intervalWithOnlyGt = ElasticQuery.intervalRange( + lower = Some(Left("10")), + upper = None, + analyzer = Some("standard"), + useField = Some("otherField") + ) - val expectedNoOptions = + val queryWithStringField = intervals("stringField", intervalWithBounds) + val queryWithTypedField = intervals(TestDocument.stringField, intervalWithBounds) + val queryWithOnlyGt = intervals("stringField", intervalWithOnlyGt) + + val expectedNoBounds = + """ + |{ + | "intervals": { + | "stringField": { + | "range": {} + | } + | } + |} + |""".stripMargin + + val expectedWithBounds = """ |{ | "intervals": { | "stringField": { - | "prefix": { - | "prefix": "lambda" + | "range": { + | "gt": "10", + | "lte": "20", + | "analyzer": "standard", + | "use_field": "otherField" | } | } | } |} |""".stripMargin - val expectedWithOptions = + val expectedWithOnlyGt = """ |{ | "intervals": { | "stringField": { - | "prefix": { - | "prefix": "lambda", + | "range": { + | "gt": "10", | "analyzer": "standard", - | "use_field": "text" + | "use_field": "otherField" | } | } | } |} |""".stripMargin - assert(intervalNoOptions)( + assert(intervalNoBounds)( equalTo( - IntervalPrefix( - prefix = "lambda", + IntervalRange( + lower = None, + upper = None, analyzer = None, useField = None ) ) ) && - assert(intervals("stringField", intervalNoOptions).toJson(None))( - equalTo(expectedNoOptions.toJson) - ) && assert(queryWithStringField.toJson(None))( - equalTo(expectedWithOptions.toJson) + equalTo(expectedWithBounds.toJson) ) && assert(queryWithTypedField.toJson(None))( - equalTo(expectedWithOptions.toJson) + equalTo(expectedWithBounds.toJson) + ) && + assert(queryWithOnlyGt.toJson(None))( + equalTo(expectedWithOnlyGt.toJson) ) }, test("intervalWildcard") { From 3b978323cd7b8c140fbdca61769022e56a848e7b Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 13 Jun 2025 16:58:24 +0200 Subject: [PATCH 04/41] Implement: export methods from Queries.scala to ElasticIntervalQuery.scala --- .../zio/elasticsearch/ElasticQuery.scala | 42 ++-- .../query/ElasticIntervalQuery.scala | 212 ++++++++++++++++ .../zio/elasticsearch/query/Queries.scala | 226 +----------------- 3 files changed, 236 insertions(+), 244 deletions(-) create mode 100644 modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index df07511a7..da02f8495 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -671,10 +671,10 @@ object ElasticQuery { */ final def intervalAllOf[S]( - intervals: NonEmptyChunk[IntervalQuery], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] + intervals: NonEmptyChunk[IntervalRule], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] ): IntervalAllOf[Any] = IntervalAllOf(intervals.toChunk, maxGaps = None, ordered = None, filter = None) @@ -692,8 +692,8 @@ object ElasticQuery { */ final def intervalAnyOf[S]( - intervals: Chunk[IntervalQuery], - filter: Option[IntervalFilter[S]] + intervals: Chunk[IntervalRule], + filter: Option[IntervalFilter[S]] ): IntervalAnyOf[S] = IntervalAnyOf(intervals, filter = None) @@ -757,15 +757,15 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] representing the script filter. */ final def intervalFilter[S]( - after: Option[IntervalQuery] = None, - before: Option[IntervalQuery] = None, - containedBy: Option[IntervalQuery] = None, - containing: Option[IntervalQuery] = None, - notContainedBy: Option[IntervalQuery] = None, - notContaining: Option[IntervalQuery] = None, - notOverlapping: Option[IntervalQuery] = None, - overlapping: Option[IntervalQuery] = None, - script: Option[Json] = None + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None ): IntervalFilter[S] = IntervalFilter( after = after, @@ -785,16 +785,16 @@ object ElasticQuery { * The resulting query wraps the specified interval query under the given field in the intervals query structure. * * @param field - * the name of the field to be queried. + * the name of the field to be queried. * @param rule - * an instance of [[zio.elasticsearch.query.IntervalQuery]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. * @return * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ final def intervals( field: String, - rule: IntervalQuery + rule: IntervalRule ): ElasticQuery[Any] = Intervals(field, rule) @@ -805,9 +805,9 @@ object ElasticQuery { * structure. * * @param field - * the type-safe field on which the query is executed. + * the type-safe field on which the query is executed. * @param rule - * an instance of [[zio.elasticsearch.query.IntervalQuery]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. * @tparam S * the document type for which the query is defined. * @return @@ -816,7 +816,7 @@ object ElasticQuery { final def intervals[S]( field: Field[S, _], - rule: IntervalQuery + rule: IntervalRule ): ElasticQuery[S] = Intervals(field.toString, rule) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala new file mode 100644 index 000000000..9a56cd675 --- /dev/null +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -0,0 +1,212 @@ +package zio.elasticsearch.query + +import zio.Chunk +import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps +import zio.json.ast.Json +import zio.json.ast.Json.{Arr, Obj, Str} + +sealed trait IntervalRule { + private[elasticsearch] def toJson: Json +} + +private[elasticsearch] final case class IntervalAllOf[S]( + intervals: Chunk[IntervalRule], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { + private[elasticsearch] def toJson: Json = + Obj( + "all_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalAnyOf[S]( + intervals: Chunk[IntervalRule], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { + private[elasticsearch] def toJson: Json = + Obj( + "any_of" -> Obj( + "intervals" -> Arr(intervals.map(_.toJson): _*) + ) + ) +} + +private[elasticsearch] final case class IntervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None +) { + private[elasticsearch] def toJson: Json = + Obj( + Chunk( + after.map("after" -> _.toJson), + before.map("before" -> _.toJson), + containedBy.map("contained_by" -> _.toJson), + containing.map("containing" -> _.toJson), + notContainedBy.map("not_contained_by" -> _.toJson), + notContaining.map("not_containing" -> _.toJson), + notOverlapping.map("not_overlapping" -> _.toJson), + overlapping.map("overlapping" -> _.toJson), + script.map("script" -> _) + ).flatten: _* + ) +} + +private[elasticsearch] final case class IntervalFuzzy[S]( + term: String, + prefixLength: Option[Int], + transpositions: Option[Boolean], + fuzziness: Option[String], + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule { + private[elasticsearch] def toJson: Json = + Obj( + "fuzzy" -> Obj( + Chunk( + Some("term" -> term.toJson), + prefixLength.map("prefix_length" -> _.toJson), + transpositions.map("transpositions" -> _.toJson), + fuzziness.map("fuzziness" -> _.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalMatch[S]( + query: String, + analyzer: Option[String], + useField: Option[String], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { self => + + def withAnalyzer(a: String) = copy(analyzer = Some(a)) + def withUseField(f: String) = copy(useField = Some(f)) + def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) + def withOrdered(o: Boolean) = copy(ordered = Some(o)) + def withFilter(f: IntervalFilter[S]) = copy(filter = Some(f)) + + override private[elasticsearch] def toJson: Json = + Obj( + "match" -> Obj( + Chunk( + Some("query" -> Str(query)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalPrefix( + prefix: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule { + + def withAnalyzer(a: String) = copy(analyzer = Some(a)) + def withUseField(f: String) = copy(useField = Some(f)) + + override private[elasticsearch] def toJson: Json = + Obj( + "prefix" -> Obj( + Chunk( + Some("prefix" -> Str(prefix)), + analyzer.map(a => "analyzer" -> Str(a)), + useField.map(u => "use_field" -> Str(u)) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalRange[S]( + lower: Option[Either[String, String]], + upper: Option[Either[String, String]], + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule { + private[elasticsearch] def toJson: Json = { + val lowerJson = lower.map { + case Left(gt) => "gt" -> gt.toJson + case Right(gte) => "gte" -> gte.toJson + } + val upperJson = upper.map { + case Left(lt) => "lt" -> lt.toJson + case Right(lte) => "lte" -> lte.toJson + } + + Obj( + "range" -> Obj( + Chunk( + lowerJson, + upperJson, + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) + } +} + +private[elasticsearch] final case class IntervalRegexp[S]( + pattern: Regexp[S], + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule { + private[elasticsearch] def toJson: Json = + Obj( + "regexp" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson(None)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalWildcard[S]( + pattern: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule { + + def withAnalyzer(a: String): IntervalWildcard[S] = + copy(analyzer = Some(a)) + + def withUseField(f: String): IntervalWildcard[S] = + copy(useField = Some(f)) + + private[elasticsearch] def toJson: Json = + Obj( + "wildcard" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 20eea0f46..f81e4c4cf 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -781,231 +781,12 @@ private[elasticsearch] final case class Ids[S](values: Chunk[String]) extends Id Obj("ids" -> Obj("values" -> Arr(values.map(_.toJson)))) } -sealed trait IntervalQuery { - private[elasticsearch] def toJson: Json -} - -/** - * Represents a `match` interval query. Matches analyzed text within intervals. - * - * @param query - * The text to match. - * @param analyzer - * Optional analyzer to use for this query. - * @param useField - * Optional alternative field used for term extraction. - */ - -/** `match` interval-query */ -private[elasticsearch] final case class IntervalMatch[S]( - query: String, - analyzer: Option[String], - useField: Option[String], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalQuery { self => - - def withAnalyzer(a: String) = copy(analyzer = Some(a)) - def withUseField(f: String) = copy(useField = Some(f)) - def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) - def withOrdered(o: Boolean) = copy(ordered = Some(o)) - def withFilter(f: IntervalFilter[S]) = copy(filter = Some(f)) - - override private[elasticsearch] def toJson: Json = - Obj( - "match" -> Obj( - Chunk( - Some("query" -> Str(query)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalPrefix( - prefix: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalQuery { - - def withAnalyzer(a: String) = copy(analyzer = Some(a)) - def withUseField(f: String) = copy(useField = Some(f)) - - override private[elasticsearch] def toJson: Json = - Obj( - "prefix" -> Obj( - Chunk( - Some("prefix" -> Str(prefix)), - analyzer.map(a => "analyzer" -> Str(a)), - useField.map(u => "use_field" -> Str(u)) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalRegexp[S]( - pattern: Regexp[S], - analyzer: Option[String], - useField: Option[String] -) extends IntervalQuery { - private[elasticsearch] def toJson: Json = - Obj( - "regexp" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson(None)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalWildcard[S]( - pattern: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalQuery { - - def withAnalyzer(a: String): IntervalWildcard[S] = - copy(analyzer = Some(a)) - - def withUseField(f: String): IntervalWildcard[S] = - copy(useField = Some(f)) - - private[elasticsearch] def toJson: Json = - Obj( - "wildcard" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalAllOf[S]( - intervals: Chunk[IntervalQuery], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalQuery { - private[elasticsearch] def toJson: Json = - Obj( - "all_of" -> Obj( - Chunk( - Some("intervals" -> Arr(intervals.map(_.toJson): _*)), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalAnyOf[S]( - intervals: Chunk[IntervalQuery], - filter: Option[IntervalFilter[S]] -) extends IntervalQuery { - private[elasticsearch] def toJson: Json = - Obj( - "any_of" -> Obj( - "intervals" -> Arr(intervals.map(_.toJson): _*) - ) - ) -} - -private[elasticsearch] final case class IntervalFuzzy[S]( - term: String, - prefixLength: Option[Int], - transpositions: Option[Boolean], - fuzziness: Option[String], - analyzer: Option[String], - useField: Option[String] -) extends IntervalQuery { - private[elasticsearch] def toJson: Json = - Obj( - "fuzzy" -> Obj( - Chunk( - Some("term" -> term.toJson), - prefixLength.map("prefix_length" -> _.toJson), - transpositions.map("transpositions" -> _.toJson), - fuzziness.map("fuzziness" -> _.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalRange[S]( - lower: Option[Either[String, String]], - upper: Option[Either[String, String]], - analyzer: Option[String], - useField: Option[String] -) extends IntervalQuery { - private[elasticsearch] def toJson: Json = { - val lowerJson = lower.map { - case Left(gt) => "gt" -> gt.toJson - case Right(gte) => "gte" -> gte.toJson - } - val upperJson = upper.map { - case Left(lt) => "lt" -> lt.toJson - case Right(lte) => "lte" -> lte.toJson - } - - Obj( - "range" -> Obj( - Chunk( - lowerJson, - upperJson, - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) - } -} - -private[elasticsearch] final case class IntervalFilter[S]( - after: Option[IntervalQuery] = None, - before: Option[IntervalQuery] = None, - containedBy: Option[IntervalQuery] = None, - containing: Option[IntervalQuery] = None, - notContainedBy: Option[IntervalQuery] = None, - notContaining: Option[IntervalQuery] = None, - notOverlapping: Option[IntervalQuery] = None, - overlapping: Option[IntervalQuery] = None, - script: Option[Json] = None -) { - private[elasticsearch] def toJson: Json = - Obj( - Chunk( - after.map("after" -> _.toJson), - before.map("before" -> _.toJson), - containedBy.map("contained_by" -> _.toJson), - containing.map("containing" -> _.toJson), - notContainedBy.map("not_contained_by" -> _.toJson), - notContaining.map("not_containing" -> _.toJson), - notOverlapping.map("not_overlapping" -> _.toJson), - overlapping.map("overlapping" -> _.toJson), - script.map("script" -> _) - ).flatten: _* - ) -} - sealed trait IntervalsQuery[S] extends ElasticQuery[S] private[elasticsearch] final case class Intervals[S]( field: String, - query: IntervalQuery -) extends IntervalsQuery[S] { - self => + query: IntervalRule +) extends IntervalsQuery[S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json = Obj( @@ -1255,8 +1036,7 @@ private[elasticsearch] final case class Prefix[S]( field: String, value: String, caseInsensitive: Option[Boolean] -) extends PrefixQuery[S] { - self => +) extends PrefixQuery[S] { self => def caseInsensitive(value: Boolean): PrefixQuery[S] = self.copy(caseInsensitive = Some(value)) From ee269c23f7faba14cd121528ecede53e738a19b6 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 13 Jun 2025 17:29:26 +0200 Subject: [PATCH 05/41] Implement: documentation in ElasticQuery.scala --- .../zio/elasticsearch/ElasticQuery.scala | 304 +++++++++--------- 1 file changed, 152 insertions(+), 152 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index da02f8495..3a2e7e1b2 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -549,110 +549,6 @@ object ElasticQuery { final def ids(value: String, values: String*): IdsQuery[Any] = Ids(values = Chunk.fromIterable(value +: values)) - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalMatch]] interval query. - * - * This query matches analyzed text within specified intervals based on the provided query string. - * - * @param query - * the text to match in the intervals. - * @return - * an instance of [[zio.elasticsearch.query.IntervalMatch]] that represents the `match` interval query. - */ - - final def intervalMatch(query: String): IntervalMatch[String] = - IntervalMatch( - query = query, - analyzer = None, - useField = None, - maxGaps = None, - ordered = None, - filter = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalPrefix]] interval query. - * - * This query matches terms that start with the specified prefix in the intervals. - * - * @param prefix - * the prefix string to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalPrefix]] that represents the `prefix` interval query. - */ - - final def intervalPrefix(prefix: String): IntervalPrefix = - IntervalPrefix(prefix = prefix, analyzer = None, useField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalRegexp]] interval query. - * - * This query matches terms that follow the specified regular expression pattern within the intervals. - * - * @param pattern - * the regular expression pattern to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalRegexp]] that represents the `regexp` interval query. - */ - - final def intervalRegexp(pattern: Regexp[Any]): IntervalRegexp[Any] = - IntervalRegexp(pattern = pattern, analyzer = None, useField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalWildcard]] interval query. - * - * This query matches terms in the intervals based on the specified wildcard pattern. - * - * @param pattern - * the wildcard pattern to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query. - */ - - /** - * Matches any term that contains the provided substring. - * - * @param pattern - * the pattern that should be contained - * @return - * an instance of IntervalWildcard that represents the `wildcard` interval query with contains pattern. - */ - final def intervalContains[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) - - /** - * Matches any term that starts with the provided substring. - * - * @param pattern - * the pattern that should be at the beginning - * @return - * an instance of IntervalWildcard that represents the `wildcard` interval query with startsWith pattern. - */ - final def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"$pattern*", analyzer = None, useField = None) - - /** - * Matches any term that ends with the provided substring. - * - * @param pattern - * the pattern that should be at the end - * @return - * an instance of IntervalWildcard that represents the `wildcard` interval query with endsWith pattern. - */ - final def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - - /** - * Matches any term that matches the exact pattern. - * - * @param pattern - * wildcard pattern - * @return - * an instance of IntervalWildcard that represents the `wildcard` interval query. - */ - final def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern = pattern, analyzer = None, useField = None) - /** * Constructs an instance of [[zio.elasticsearch.query.IntervalAllOf]] interval query. * @@ -669,12 +565,11 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.IntervalAllOf]] that represents the `all_of` interval query. */ - final def intervalAllOf[S]( - intervals: NonEmptyChunk[IntervalRule], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] + intervals: NonEmptyChunk[IntervalRule], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] ): IntervalAllOf[Any] = IntervalAllOf(intervals.toChunk, maxGaps = None, ordered = None, filter = None) @@ -690,13 +585,73 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.IntervalAnyOf]] that represents the `any_of` interval query. */ - final def intervalAnyOf[S]( - intervals: Chunk[IntervalRule], - filter: Option[IntervalFilter[S]] + intervals: Chunk[IntervalRule], + filter: Option[IntervalFilter[S]] ): IntervalAnyOf[S] = IntervalAnyOf(intervals, filter = None) + /** + * Matches any term that contains the provided substring. + * + * @param pattern + * the pattern that should be contained. + * @return + * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with + * contains pattern. + */ + final def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalFilter]] for advanced filtering logic. + * + * This filter allows further refinement of interval queries based on spatial relationships or custom scripts. + * + * @param after + * matches intervals that are after the given rule. + * @param before + * matches intervals that are before the given rule. + * @param containedBy + * matches intervals that are contained by the given rule. + * @param containing + * matches intervals that contain the given rule. + * @param notContainedBy + * matches intervals not contained by the given rule. + * @param notContaining + * matches intervals that do not contain the given rule. + * @param notOverlapping + * matches intervals that do not overlap with the given rule. + * @param overlapping + * matches intervals that overlap with the given rule. + * @param script + * optional custom script to further filter intervals. + * @return + * an instance of [[zio.elasticsearch.query.IntervalFilter]] that applies filtering to interval queries. + */ + final def intervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None + ): IntervalFilter[S] = + IntervalFilter( + after = after, + before = before, + containedBy = containedBy, + containing = containing, + notContainedBy = notContainedBy, + notContaining = notContaining, + notOverlapping = notOverlapping, + overlapping = overlapping, + script = script + ) + /** * Constructs an instance of [[zio.elasticsearch.query.IntervalFuzzy]] interval query. * @@ -707,7 +662,6 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.IntervalFuzzy]] that represents the `fuzzy` interval query. */ - final def intervalFuzzy[S](term: String): IntervalFuzzy[S] = IntervalFuzzy( term = term, @@ -718,19 +672,48 @@ object ElasticQuery { useField = None ) + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalMatch]] interval query. + * + * This query matches analyzed text within specified intervals based on the provided query string. + * + * @param query + * the text to match in the intervals. + * @return + * an instance of [[zio.elasticsearch.query.IntervalMatch]] that represents the `match` interval query. + */ + final def intervalMatch(query: String): IntervalMatch[String] = + IntervalMatch( + query = query, + analyzer = None, + useField = None, + maxGaps = None, + ordered = None, + filter = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalPrefix]] interval query. + * + * This query matches terms that start with the specified prefix in the intervals. + * + * @param prefix + * the prefix string to match. + * @return + * an instance of [[zio.elasticsearch.query.IntervalPrefix]] that represents the `prefix` interval query. + */ + final def intervalPrefix(prefix: String): IntervalPrefix = + IntervalPrefix(prefix = prefix, analyzer = None, useField = None) + /** * Constructs an instance of [[zio.elasticsearch.query.IntervalRange]] interval query. * * This query matches documents containing terms within the specified string range constraints. * - * @param gt - * optional exclusive lower bound. - * @param gte - * optional inclusive lower bound. - * @param lt - * optional exclusive upper bound. - * @param lte - * optional inclusive upper bound. + * @param lower + * optional lower bound (exclusive or inclusive). + * @param upper + * optional upper bound (exclusive or inclusive). * @param analyzer * optional analyzer to use for the range terms. * @param useField @@ -747,37 +730,54 @@ object ElasticQuery { IntervalRange(lower, upper, analyzer, useField) /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] interval filter. + * Constructs an instance of [[zio.elasticsearch.query.IntervalRegexp]] interval query. * - * This filter allows further refinement of interval queries using a custom script. + * This query matches terms that follow the specified regular expression pattern within the intervals. * - * @param source - * the source of the script used for filtering. + * @param pattern + * the regular expression pattern to match. * @return - * an instance of [[zio.elasticsearch.query.IntervalScriptFilter]] representing the script filter. + * an instance of [[zio.elasticsearch.query.IntervalRegexp]] that represents the `regexp` interval query. */ - final def intervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None - ): IntervalFilter[S] = - IntervalFilter( - after = after, - before = before, - containedBy = containedBy, - containing = containing, - notContainedBy = notContainedBy, - notContaining = notContaining, - notOverlapping = notOverlapping, - overlapping = overlapping, - script = script - ) + final def intervalRegexp(pattern: Regexp[Any]): IntervalRegexp[Any] = + IntervalRegexp(pattern = pattern, analyzer = None, useField = None) + + /** + * Matches any term that starts with the provided substring. + * + * @param pattern + * the pattern that should be at the beginning. + * @return + * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with + * startsWith pattern. + */ + final def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + /** + * Matches any term that ends with the provided substring. + * + * @param pattern + * the pattern that should be at the end. + * @return + * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with + * endsWith pattern. + */ + final def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IntervalWildcard]] interval query. + * + * This query matches terms in the intervals based on the specified wildcard pattern. + * + * @param pattern + * the wildcard pattern to match. + * @return + * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query. + */ + final def intervalWildcard[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(pattern = pattern, analyzer = None, useField = None) /** * Constructs an intervals query by combining a field and an interval query. @@ -785,9 +785,9 @@ object ElasticQuery { * The resulting query wraps the specified interval query under the given field in the intervals query structure. * * @param field - * the name of the field to be queried. + * the name of the field to be queried. * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. * @return * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ @@ -805,9 +805,9 @@ object ElasticQuery { * structure. * * @param field - * the type-safe field on which the query is executed. + * the type-safe field on which the query is executed. * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. * @tparam S * the document type for which the query is defined. * @return From 441fe9f6d947b5db7799c57f50f20738e9820488 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 09:02:22 +0200 Subject: [PATCH 06/41] Implement: move methods to another file, fix tests --- .../zio/elasticsearch/ElasticQuery.scala | 229 ------------------ .../query/ElasticIntervalQuery.scala | 55 ++++- .../zio/elasticsearch/ElasticQuerySpec.scala | 14 +- 3 files changed, 63 insertions(+), 235 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 3a2e7e1b2..93cfbd124 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -549,235 +549,6 @@ object ElasticQuery { final def ids(value: String, values: String*): IdsQuery[Any] = Ids(values = Chunk.fromIterable(value +: values)) - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalAllOf]] interval query. - * - * This query matches analyzed text where all specified intervals are found, optionally ordered and/or filtered. - * - * @param intervals - * the list of sub-intervals that all must match. - * @param maxGaps - * optional maximum number of allowed gaps between intervals. - * @param ordered - * optional flag to enforce ordered appearance. - * @param filter - * optional filter to further restrict results. - * @return - * an instance of [[zio.elasticsearch.query.IntervalAllOf]] that represents the `all_of` interval query. - */ - final def intervalAllOf[S]( - intervals: NonEmptyChunk[IntervalRule], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] - ): IntervalAllOf[Any] = - IntervalAllOf(intervals.toChunk, maxGaps = None, ordered = None, filter = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalAnyOf]] interval query. - * - * This query matches documents that contain any of the specified interval queries. - * - * @param intervals - * a list of interval queries where any can match. - * @param filter - * optional filter to further restrict results. - * @return - * an instance of [[zio.elasticsearch.query.IntervalAnyOf]] that represents the `any_of` interval query. - */ - final def intervalAnyOf[S]( - intervals: Chunk[IntervalRule], - filter: Option[IntervalFilter[S]] - ): IntervalAnyOf[S] = - IntervalAnyOf(intervals, filter = None) - - /** - * Matches any term that contains the provided substring. - * - * @param pattern - * the pattern that should be contained. - * @return - * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with - * contains pattern. - */ - final def intervalContains[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalFilter]] for advanced filtering logic. - * - * This filter allows further refinement of interval queries based on spatial relationships or custom scripts. - * - * @param after - * matches intervals that are after the given rule. - * @param before - * matches intervals that are before the given rule. - * @param containedBy - * matches intervals that are contained by the given rule. - * @param containing - * matches intervals that contain the given rule. - * @param notContainedBy - * matches intervals not contained by the given rule. - * @param notContaining - * matches intervals that do not contain the given rule. - * @param notOverlapping - * matches intervals that do not overlap with the given rule. - * @param overlapping - * matches intervals that overlap with the given rule. - * @param script - * optional custom script to further filter intervals. - * @return - * an instance of [[zio.elasticsearch.query.IntervalFilter]] that applies filtering to interval queries. - */ - final def intervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None - ): IntervalFilter[S] = - IntervalFilter( - after = after, - before = before, - containedBy = containedBy, - containing = containing, - notContainedBy = notContainedBy, - notContaining = notContaining, - notOverlapping = notOverlapping, - overlapping = overlapping, - script = script - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalFuzzy]] interval query. - * - * This query returns documents that match terms similar to the specified term using fuzzy logic. - * - * @param term - * the term to match using fuzzy logic. - * @return - * an instance of [[zio.elasticsearch.query.IntervalFuzzy]] that represents the `fuzzy` interval query. - */ - final def intervalFuzzy[S](term: String): IntervalFuzzy[S] = - IntervalFuzzy( - term = term, - prefixLength = None, - transpositions = None, - fuzziness = None, - analyzer = None, - useField = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalMatch]] interval query. - * - * This query matches analyzed text within specified intervals based on the provided query string. - * - * @param query - * the text to match in the intervals. - * @return - * an instance of [[zio.elasticsearch.query.IntervalMatch]] that represents the `match` interval query. - */ - final def intervalMatch(query: String): IntervalMatch[String] = - IntervalMatch( - query = query, - analyzer = None, - useField = None, - maxGaps = None, - ordered = None, - filter = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalPrefix]] interval query. - * - * This query matches terms that start with the specified prefix in the intervals. - * - * @param prefix - * the prefix string to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalPrefix]] that represents the `prefix` interval query. - */ - final def intervalPrefix(prefix: String): IntervalPrefix = - IntervalPrefix(prefix = prefix, analyzer = None, useField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalRange]] interval query. - * - * This query matches documents containing terms within the specified string range constraints. - * - * @param lower - * optional lower bound (exclusive or inclusive). - * @param upper - * optional upper bound (exclusive or inclusive). - * @param analyzer - * optional analyzer to use for the range terms. - * @param useField - * optional alternative field to use. - * @return - * an instance of [[zio.elasticsearch.query.IntervalRange]] that represents the `range` interval query. - */ - def intervalRange[S]( - lower: Option[Either[String, String]], - upper: Option[Either[String, String]], - analyzer: Option[String], - useField: Option[String] - ): IntervalRange[S] = - IntervalRange(lower, upper, analyzer, useField) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalRegexp]] interval query. - * - * This query matches terms that follow the specified regular expression pattern within the intervals. - * - * @param pattern - * the regular expression pattern to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalRegexp]] that represents the `regexp` interval query. - */ - final def intervalRegexp(pattern: Regexp[Any]): IntervalRegexp[Any] = - IntervalRegexp(pattern = pattern, analyzer = None, useField = None) - - /** - * Matches any term that starts with the provided substring. - * - * @param pattern - * the pattern that should be at the beginning. - * @return - * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with - * startsWith pattern. - */ - final def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"$pattern*", analyzer = None, useField = None) - - /** - * Matches any term that ends with the provided substring. - * - * @param pattern - * the pattern that should be at the end. - * @return - * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query with - * endsWith pattern. - */ - final def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IntervalWildcard]] interval query. - * - * This query matches terms in the intervals based on the specified wildcard pattern. - * - * @param pattern - * the wildcard pattern to match. - * @return - * an instance of [[zio.elasticsearch.query.IntervalWildcard]] that represents the `wildcard` interval query. - */ - final def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern = pattern, analyzer = None, useField = None) /** * Constructs an intervals query by combining a field and an interval query. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala index 9a56cd675..7d87cbd0b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -31,11 +31,17 @@ private[elasticsearch] final case class IntervalAllOf[S]( private[elasticsearch] final case class IntervalAnyOf[S]( intervals: Chunk[IntervalRule], filter: Option[IntervalFilter[S]] -) extends IntervalRule { - private[elasticsearch] def toJson: Json = +) extends IntervalRule { self => + + def withFilter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) + + override private[elasticsearch] def toJson: Json = Obj( "any_of" -> Obj( - "intervals" -> Arr(intervals.map(_.toJson): _*) + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + filter.map("filter" -> _.toJson) + ).flatten: _* ) ) } @@ -210,3 +216,46 @@ private[elasticsearch] final case class IntervalWildcard[S]( ) ) } +object ElasticIntervalQuery { + + def intervalAllOf[S](intervals: Chunk[IntervalRule]): IntervalAllOf[S] = + IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + + def intervalAnyOf[S](intervals: Chunk[IntervalRule]): IntervalAnyOf[S] = + IntervalAnyOf(intervals, filter = None) + + def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + def intervalFilter[S](): IntervalFilter[S] = + IntervalFilter() + + def intervalFuzzy[S](term: String): IntervalFuzzy[S] = + IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) + + def intervalMatch[S](query: String): IntervalMatch[S] = + IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) + + def intervalPrefix[S](prefix: String): IntervalPrefix = + IntervalPrefix(prefix, analyzer = None, useField = None) + + def intervalRange[S]( + lower: Option[Either[String, String]] = None, + upper: Option[Either[String, String]] = None, + analyzer: Option[String] = None, + useField: Option[String] = None + ): IntervalRange[S] = + IntervalRange(lower, upper, analyzer, useField) + + def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = + IntervalRegexp(pattern, analyzer = None, useField = None) + + def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + def intervalWildcard[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(pattern, analyzer = None, useField = None) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 92a8c9a6b..7ee2e766b 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -23,6 +23,14 @@ import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain._ import zio.elasticsearch.query.DistanceType.Plane import zio.elasticsearch.query.DistanceUnit.Kilometers +import zio.elasticsearch.query.ElasticIntervalQuery.{ + intervalContains, + intervalEndsWith, + intervalMatch, + intervalRange, + intervalStartsWith, + intervalWildcard +} import zio.elasticsearch.query.FunctionScoreFunction._ import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.MultiValueMode.Max @@ -1180,21 +1188,21 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) }, test("intervalRange") { - val intervalNoBounds = ElasticQuery.intervalRange( + val intervalNoBounds = intervalRange( lower = None, upper = None, analyzer = None, useField = None ) - val intervalWithBounds = ElasticQuery.intervalRange( + val intervalWithBounds = intervalRange( lower = Some(Left("10")), upper = Some(Right("20")), analyzer = Some("standard"), useField = Some("otherField") ) - val intervalWithOnlyGt = ElasticQuery.intervalRange( + val intervalWithOnlyGt = intervalRange( lower = Some(Left("10")), upper = None, analyzer = Some("standard"), From af9b2fe7d5ed1f94ce70c30a9bd0433749af14f2 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 10:21:18 +0200 Subject: [PATCH 07/41] Fix formater bug, create ElasticIntervalQuerySpec --- .../zio/elasticsearch/ElasticQuery.scala | 2628 ++++++++--------- .../zio/elasticsearch/query/Queries.scala | 28 +- .../ElasticIntervalQuerySpec.scala | 310 ++ .../zio/elasticsearch/ElasticQuerySpec.scala | 287 +- 4 files changed, 1638 insertions(+), 1615 deletions(-) create mode 100644 modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 93cfbd124..fc1c42d40 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,1315 +1,1313 @@ -/* - * 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 - -import zio.{Chunk, NonEmptyChunk} -import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.query._ -import zio.elasticsearch.script.Script -import zio.json.ast.Json -import zio.schema.Schema - -object ElasticQuery { - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting[S: Schema]( - negativeBoost: Float, - negativeQuery: ElasticQuery[S], - positiveQuery: ElasticQuery[S] - ): BoostingQuery[S] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting( - negativeBoost: Float, - negativeQuery: ElasticQuery[Any], - positiveQuery: ElasticQuery[Any] - ): BoostingQuery[Any] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @tparam S - * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = - ConstantScore[S](query = query, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = - ConstantScore[Any](query = query, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = - DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = - DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, - * using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists[S](field: Field[S, _]): ExistsQuery[S] = - Exists(field = field.toString, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the - * specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists(field: String): ExistsQuery[Any] = - Exists(field = field, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore[S: Schema]( - functions: FunctionScoreFunction[S]* - ): FunctionScoreQuery[S] = - FunctionScore[S]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore( - functions: FunctionScoreFunction[Any]* - ): FunctionScoreQuery[Any] = - FunctionScore[Any]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = - Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy(field: String, value: String): FuzzyQuery[Any] = - Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe GeoPoint field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = - GeoPolygon( - field = field.toString, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = - GeoPolygon( - field = field, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of - * the child `type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child - * `type` field - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of - * the `parent_type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the - * `parent_type` field - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param value - * value that will be used for the query - * @param values - * array of optional values that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. - */ - final def ids(value: String, values: String*): IdsQuery[Any] = - Ids(values = Chunk.fromIterable(value +: values)) - - - /** - * Constructs an intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given field in the intervals query structure. - * - * @param field - * the name of the field to be queried. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals( - field: String, - rule: IntervalRule - ): ElasticQuery[Any] = - Intervals(field, rule) - - /** - * Constructs a type-safe intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given type-safe field in the intervals query - * structure. - * - * @param field - * the type-safe field on which the query is executed. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @tparam S - * the document type for which the query is defined. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals[S]( - field: Field[S, _], - rule: IntervalRule - ): ElasticQuery[S] = - Intervals(field.toString, rule) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the type-safe field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = - KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = - KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. - * - * @return - * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. - */ - final def matchAll: MatchAllQuery = - MatchAll(boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = - MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = - MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = - Match(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = - Match(field = field, value = value) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = - MatchPhrase(field = field.toString, value = value, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = - MatchPhrase(field = field, value = value, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a - * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching - * any words that begin with that term. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the text value to be matched - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = - MatchPhrasePrefix(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in - * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that - * begin with that term. - * - * @param field - * the field for which query is specified for - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = - MatchPhrasePrefix(field = field, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. - * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. - * - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. - */ - final def multiMatch(value: String): MultiMatchQuery[Any] = - MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria - * using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the type-safe path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = - Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = - Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = - Prefix(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix(field: String, value: String): Prefix[Any] = - Prefix(field = field, value = value, caseInsensitive = None) - - /** - * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = - Range.empty(field.toString) - - /** - * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = - Range.empty[Any, Any](field = field) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * regular expression that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = - Regexp(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the field for which query is specified for - * @param value - * regular expression that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp(field: String, value: String): RegexpQuery[Any] = - Regexp(field = field, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. - * @param script - * the script that is used by the query - * @return - * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. - */ - final def script(script: Script): ScriptQuery = - query.Script(script = script, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = - Term(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = - Term(field = field, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the type-safe field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = - Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = - Terms(field = field, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the type-safe field representing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchField: Field[S, _], - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField.toString), - minimumShouldMatchScript = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[A: ElasticPrimitive]( - field: String, - minimumShouldMatchField: String, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField), - minimumShouldMatchScript = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[A: ElasticPrimitive]( - field: String, - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = value, boost = None, caseInsensitive = None) - -} +/* + * 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 + +import zio.Chunk +import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.query._ +import zio.elasticsearch.script.Script +import zio.schema.Schema + +object ElasticQuery { + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting[S: Schema]( + negativeBoost: Float, + negativeQuery: ElasticQuery[S], + positiveQuery: ElasticQuery[S] + ): BoostingQuery[S] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting( + negativeBoost: Float, + negativeQuery: ElasticQuery[Any], + positiveQuery: ElasticQuery[Any] + ): BoostingQuery[Any] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @tparam S + * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = + ConstantScore[S](query = query, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = + ConstantScore[Any](query = query, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = + DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = + DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, + * using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists[S](field: Field[S, _]): ExistsQuery[S] = + Exists(field = field.toString, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the + * specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists(field: String): ExistsQuery[Any] = + Exists(field = field, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore[S: Schema]( + functions: FunctionScoreFunction[S]* + ): FunctionScoreQuery[S] = + FunctionScore[S]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore( + functions: FunctionScoreFunction[Any]* + ): FunctionScoreQuery[Any] = + FunctionScore[Any]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = + Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy(field: String, value: String): FuzzyQuery[Any] = + Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe GeoPoint field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = + GeoPolygon( + field = field.toString, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = + GeoPolygon( + field = field, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of + * the child `type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child + * `type` field + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of + * the `parent_type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the + * `parent_type` field + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param value + * value that will be used for the query + * @param values + * array of optional values that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. + */ + final def ids(value: String, values: String*): IdsQuery[Any] = + Ids(values = Chunk.fromIterable(value +: values)) + + /** + * Constructs an intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given field in the intervals query structure. + * + * @param field + * the name of the field to be queried. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals( + field: String, + rule: IntervalRule + ): ElasticQuery[Any] = + Intervals(field, rule) + + /** + * Constructs a type-safe intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given type-safe field in the intervals query + * structure. + * + * @param field + * the type-safe field on which the query is executed. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @tparam S + * the document type for which the query is defined. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals[S]( + field: Field[S, _], + rule: IntervalRule + ): ElasticQuery[S] = + Intervals(field.toString, rule) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the type-safe field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = + KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = + KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. + * + * @return + * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. + */ + final def matchAll: MatchAllQuery = + MatchAll(boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = + MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = + MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = + Match(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = + Match(field = field, value = value) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = + MatchPhrase(field = field.toString, value = value, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = + MatchPhrase(field = field, value = value, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a + * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching + * any words that begin with that term. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the text value to be matched + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = + MatchPhrasePrefix(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in + * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that + * begin with that term. + * + * @param field + * the field for which query is specified for + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = + MatchPhrasePrefix(field = field, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. + * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. + * + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. + */ + final def multiMatch(value: String): MultiMatchQuery[Any] = + MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria + * using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the type-safe path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = + Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = + Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = + Prefix(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix(field: String, value: String): Prefix[Any] = + Prefix(field = field, value = value, caseInsensitive = None) + + /** + * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = + Range.empty(field.toString) + + /** + * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = + Range.empty[Any, Any](field = field) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * regular expression that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = + Regexp(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the field for which query is specified for + * @param value + * regular expression that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp(field: String, value: String): RegexpQuery[Any] = + Regexp(field = field, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. + * @param script + * the script that is used by the query + * @return + * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. + */ + final def script(script: Script): ScriptQuery = + query.Script(script = script, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = + Term(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = + Term(field = field, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the type-safe field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = + Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = + Terms(field = field, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the type-safe field representing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchField: Field[S, _], + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField.toString), + minimumShouldMatchScript = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[A: ElasticPrimitive]( + field: String, + minimumShouldMatchField: String, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField), + minimumShouldMatchScript = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[A: ElasticPrimitive]( + field: String, + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = value, boost = None, caseInsensitive = None) + +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index f81e4c4cf..67e04af94 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -1,12 +1,15 @@ /* * 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. @@ -22,7 +25,7 @@ import zio.elasticsearch.Field import zio.elasticsearch.query.options._ import zio.elasticsearch.query.sort.options.HasFormat import zio.json.ast.Json -import zio.json.ast.Json.{Arr, Num, Obj, Str} +import zio.json.ast.Json.{Arr, Obj} import zio.schema.Schema sealed trait ElasticQuery[-S] { self => @@ -791,7 +794,7 @@ private[elasticsearch] final case class Intervals[S]( private[elasticsearch] def toJson(fieldPath: Option[String]): Json = Obj( "intervals" -> Obj( - fieldPath.getOrElse(field) -> query.toJson + field -> query.toJson ) ) } @@ -920,8 +923,7 @@ private[elasticsearch] final case class MultiMatch[S]( boost: Option[Double], matchingType: Option[MultiMatchType], minimumShouldMatch: Option[Int] -) extends MultiMatchQuery[S] { - self => +) extends MultiMatchQuery[S] { self => def boost(boost: Double): MultiMatchQuery[S] = self.copy(boost = Some(boost)) @@ -1118,8 +1120,7 @@ private[elasticsearch] final case class Range[S, A, LB <: LowerBound, UB <: Uppe upper: UB, boost: Option[Double], format: Option[String] -) extends RangeQuery[S, A, LB, UB] { - self => +) extends RangeQuery[S, A, LB, UB] { self => def boost(value: Double): RangeQuery[S, A, LB, UB] = self.copy(boost = Some(value)) @@ -1179,8 +1180,7 @@ private[elasticsearch] final case class Regexp[S]( field: String, value: String, caseInsensitive: Option[Boolean] -) extends RegexpQuery[S] { - self => +) extends RegexpQuery[S] { self => def caseInsensitive(value: Boolean): RegexpQuery[S] = self.copy(caseInsensitive = Some(value)) @@ -1212,8 +1212,7 @@ private[elasticsearch] final case class Term[S, A: ElasticPrimitive]( value: A, boost: Option[Double], caseInsensitive: Option[Boolean] -) extends TermQuery[S] { - self => +) extends TermQuery[S] { self => def boost(value: Double): TermQuery[S] = self.copy(boost = Some(value)) @@ -1236,8 +1235,7 @@ private[elasticsearch] final case class Terms[S, A: ElasticPrimitive]( field: String, values: Chunk[A], boost: Option[Double] -) extends TermsQuery[S] { - self => +) extends TermsQuery[S] { self => def boost(value: Double): TermsQuery[S] = self.copy(boost = Some(value)) @@ -1258,8 +1256,7 @@ private[elasticsearch] final case class TermsSet[S, A: ElasticPrimitive]( boost: Option[Double], minimumShouldMatchField: Option[String], minimumShouldMatchScript: Option[zio.elasticsearch.script.Script] -) extends TermsSetQuery[S] { - self => +) extends TermsSetQuery[S] { self => def boost(value: Double): TermsSetQuery[S] = self.copy(boost = Some(value)) @@ -1284,8 +1281,7 @@ private[elasticsearch] final case class Wildcard[S]( value: String, boost: Option[Double], caseInsensitive: Option[Boolean] -) extends WildcardQuery[S] { - self => +) extends WildcardQuery[S] { self => def boost(value: Double): WildcardQuery[S] = self.copy(boost = Some(value)) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala new file mode 100644 index 000000000..475074b17 --- /dev/null +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -0,0 +1,310 @@ +package zio.elasticsearch + +import zio.elasticsearch.ElasticQuery.intervals +import zio.elasticsearch.domain.TestDocument +import zio.elasticsearch.query.ElasticIntervalQuery.{ + intervalContains, + intervalEndsWith, + intervalMatch, + intervalRange, + intervalStartsWith, + intervalWildcard +} +import zio.elasticsearch.query._ +import zio.test._ +import zio.elasticsearch.utils._ +import zio.test.Assertion.equalTo + +object ElasticIntervalQuerySpec extends ZIOSpecDefault { + + def spec = suite("ElasticIntervalQuerySpec")( + test("intervalsMatchQuery") { + val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") + + val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") + .withOrdered(true) + .withMaxGaps(2) + .withAnalyzer("standard") + + val filter = IntervalFilter[String]( + before = Some(intervalMatch("before_term")), + after = Some(intervalMatch("after_term")) + ) + + val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") + .withOrdered(true) + .withMaxGaps(2) + .withAnalyzer("standard") + .withFilter(filter) + + val queryWithStringField = intervals("stringField", intervalWithOptions) + val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) + val queryWithFilter = intervals("stringField", intervalWithFilter) + + val expectedNoOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works", + | "analyzer": "standard", + | "max_gaps": 2, + | "ordered": true + | } + | } + | } + |} + |""".stripMargin + + val expectedWithFilter = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works", + | "analyzer": "standard", + | "max_gaps": 2, + | "ordered": true, + | "filter": { + | "before": { + | "match": { + | "query": "before_term" + | } + | }, + | "after": { + | "match": { + | "query": "after_term" + | } + | } + | } + | } + | } + | } + |} + |""".stripMargin + + assert(intervalNoOptions)( + equalTo( + IntervalMatch[String]( + query = "lambda works", + analyzer = None, + useField = None, + maxGaps = None, + ordered = None, + filter = None + ) + ) + ) && + assert(intervals("stringField", intervalNoOptions).toJson(None))( + equalTo(expectedNoOptions.toJson) + ) && + assert(queryWithStringField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithTypedField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithFilter.toJson(None))( + equalTo(expectedWithFilter.toJson) + ) + }, + test("intervalRange") { + val intervalNoBounds = intervalRange( + lower = None, + upper = None, + analyzer = None, + useField = None + ) + + val intervalWithBounds = intervalRange( + lower = Some(Left("10")), + upper = Some(Right("20")), + analyzer = Some("standard"), + useField = Some("otherField") + ) + + val intervalWithOnlyGt = intervalRange( + lower = Some(Left("10")), + upper = None, + analyzer = Some("standard"), + useField = Some("otherField") + ) + + val queryWithNoBounds = intervals("stringField", intervalNoBounds) + val queryWithOnlyGt = intervals("stringField", intervalWithOnlyGt) + val queryWithBoundsString = intervals("stringField", intervalWithBounds) + val queryWithBoundsTyped = intervals(TestDocument.stringField, intervalWithBounds) + + val expectedNoBounds = + """ + |{ + | "intervals": { + | "stringField": { + | "range": {} + | } + | } + |} + |""".stripMargin + + val expectedWithBounds = + """ + |{ + | "intervals": { + | "stringField": { + | "range": { + | "gt": "10", + | "lte": "20", + | "analyzer": "standard", + | "use_field": "otherField" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithOnlyGt = + """ + |{ + | "intervals": { + | "stringField": { + | "range": { + | "gt": "10", + | "analyzer": "standard", + | "use_field": "otherField" + | } + | } + | } + |} + |""".stripMargin + + assert(intervalNoBounds)( + equalTo( + IntervalRange( + lower = None, + upper = None, + analyzer = None, + useField = None + ) + ) + ) && + assert(queryWithNoBounds.toJson(None))( + equalTo(expectedNoBounds.toJson) + ) && + assert(queryWithOnlyGt.toJson(None))( + equalTo(expectedWithOnlyGt.toJson) + ) && + assert(queryWithBoundsString.toJson(None))( + equalTo(expectedWithBounds.toJson) + ) && + assert(queryWithBoundsTyped.toJson(None))( + equalTo(expectedWithBounds.toJson) + ) + }, + test("intervalWildcard") { + val wildcardExact: IntervalWildcard[String] = + intervalWildcard("la*mb?da") + + val wildcardContains: IntervalWildcard[String] = + intervalContains("lambda") + + val wildcardStartsWith: IntervalWildcard[String] = + intervalStartsWith("lambda") + + val wildcardEndsWith: IntervalWildcard[String] = + intervalEndsWith("lambda") + + val queryExact: Intervals[String] = + Intervals("stringField", wildcardExact) + + val queryContains: Intervals[String] = + Intervals("stringField", wildcardContains) + + val queryStartsWith: Intervals[String] = + Intervals("stringField", wildcardStartsWith) + + val queryEndsWith: Intervals[String] = + Intervals("stringField", wildcardEndsWith) + + val expectedExact = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "la*mb?da" + | } + | } + | } + |} + |""".stripMargin + + val expectedContains = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda*" + | } + | } + | } + |} + |""".stripMargin + + val expectedStartsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "lambda*" + | } + | } + | } + |} + |""".stripMargin + + val expectedEndsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda" + | } + | } + | } + |} + |""".stripMargin + + assert(wildcardExact)( + equalTo( + IntervalWildcard[String]( + pattern = "la*mb?da", + analyzer = None, + useField = None + ) + ) + ) && + assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && + assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && + assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && + assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) + } + ) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 7ee2e766b..69488da2f 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1,12 +1,15 @@ /* * 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. @@ -1082,290 +1085,6 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) ) }, - test("intervalsMatchQuery") { - val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") - - val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") - .withOrdered(true) - .withMaxGaps(2) - .withAnalyzer("standard") - - val filter = IntervalFilter[String]( - before = Some(intervalMatch("before_term")), - after = Some(intervalMatch("after_term")) - ) - - val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") - .withOrdered(true) - .withMaxGaps(2) - .withAnalyzer("standard") - .withFilter(filter) - - val queryWithStringField = intervals("stringField", intervalWithOptions) - val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) - val queryWithFilter = intervals("stringField", intervalWithFilter) - - val expectedNoOptions = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works" - | } - | } - | } - |} - |""".stripMargin - - val expectedWithOptions = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works", - | "analyzer": "standard", - | "max_gaps": 2, - | "ordered": true - | } - | } - | } - |} - |""".stripMargin - - val expectedWithFilter = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works", - | "analyzer": "standard", - | "max_gaps": 2, - | "ordered": true, - | "filter": { - | "before": { - | "match": { - | "query": "before_term" - | } - | }, - | "after": { - | "match": { - | "query": "after_term" - | } - | } - | } - | } - | } - | } - |} - |""".stripMargin - - assert(intervalNoOptions)( - equalTo( - IntervalMatch[String]( - query = "lambda works", - analyzer = None, - useField = None, - maxGaps = None, - ordered = None, - filter = None - ) - ) - ) && - assert(intervals("stringField", intervalNoOptions).toJson(None))( - equalTo(expectedNoOptions.toJson) - ) && - assert(queryWithStringField.toJson(None))( - equalTo(expectedWithOptions.toJson) - ) && - assert(queryWithTypedField.toJson(None))( - equalTo(expectedWithOptions.toJson) - ) && - assert(queryWithFilter.toJson(None))( - equalTo(expectedWithFilter.toJson) - ) - }, - test("intervalRange") { - val intervalNoBounds = intervalRange( - lower = None, - upper = None, - analyzer = None, - useField = None - ) - - val intervalWithBounds = intervalRange( - lower = Some(Left("10")), - upper = Some(Right("20")), - analyzer = Some("standard"), - useField = Some("otherField") - ) - - val intervalWithOnlyGt = intervalRange( - lower = Some(Left("10")), - upper = None, - analyzer = Some("standard"), - useField = Some("otherField") - ) - - val queryWithStringField = intervals("stringField", intervalWithBounds) - val queryWithTypedField = intervals(TestDocument.stringField, intervalWithBounds) - val queryWithOnlyGt = intervals("stringField", intervalWithOnlyGt) - - val expectedNoBounds = - """ - |{ - | "intervals": { - | "stringField": { - | "range": {} - | } - | } - |} - |""".stripMargin - - val expectedWithBounds = - """ - |{ - | "intervals": { - | "stringField": { - | "range": { - | "gt": "10", - | "lte": "20", - | "analyzer": "standard", - | "use_field": "otherField" - | } - | } - | } - |} - |""".stripMargin - - val expectedWithOnlyGt = - """ - |{ - | "intervals": { - | "stringField": { - | "range": { - | "gt": "10", - | "analyzer": "standard", - | "use_field": "otherField" - | } - | } - | } - |} - |""".stripMargin - - assert(intervalNoBounds)( - equalTo( - IntervalRange( - lower = None, - upper = None, - analyzer = None, - useField = None - ) - ) - ) && - assert(queryWithStringField.toJson(None))( - equalTo(expectedWithBounds.toJson) - ) && - assert(queryWithTypedField.toJson(None))( - equalTo(expectedWithBounds.toJson) - ) && - assert(queryWithOnlyGt.toJson(None))( - equalTo(expectedWithOnlyGt.toJson) - ) - }, - test("intervalWildcard") { - val wildcardExact: IntervalWildcard[String] = - intervalWildcard("la*mb?da") - - val wildcardContains: IntervalWildcard[String] = - intervalContains("lambda") - - val wildcardStartsWith: IntervalWildcard[String] = - intervalStartsWith("lambda") - - val wildcardEndsWith: IntervalWildcard[String] = - intervalEndsWith("lambda") - - val queryExact: Intervals[String] = - Intervals("stringField", wildcardExact) - - val queryContains: Intervals[String] = - Intervals("stringField", wildcardContains) - - val queryStartsWith: Intervals[String] = - Intervals("stringField", wildcardStartsWith) - - val queryEndsWith: Intervals[String] = - Intervals("stringField", wildcardEndsWith) - - val expectedExact = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "la*mb?da" - | } - | } - | } - |} - |""".stripMargin - - val expectedContains = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "*lambda*" - | } - | } - | } - |} - |""".stripMargin - - val expectedStartsWith = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "lambda*" - | } - | } - | } - |} - |""".stripMargin - - val expectedEndsWith = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "*lambda" - | } - | } - | } - |} - |""".stripMargin - - assert(wildcardExact)( - equalTo( - IntervalWildcard[String]( - pattern = "la*mb?da", - analyzer = None, - useField = None - ) - ) - ) && - assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && - assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && - assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && - assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) - }, test("kNN") { val queryString = kNN("stringField", 5, 10, Chunk(1.1, 2.2, 3.3)) val queryBool = kNN("boolField", 5, 10, Chunk(1.1, 2.2, 3.3)) From 805f6bd2f2a37f825a9857ffbb1bcbf44d462c2e Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 11:45:53 +0200 Subject: [PATCH 08/41] Fix IntervalRange, Change order of methods in ElasticQuery --- .../zio/elasticsearch/ElasticQuery.scala | 2629 +++++++++-------- .../ElasticIntervalQuerySpec.scala | 39 +- 2 files changed, 1334 insertions(+), 1334 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index fc1c42d40..484cfaef4 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,1313 +1,1316 @@ -/* - * 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 - -import zio.Chunk -import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.query._ -import zio.elasticsearch.script.Script -import zio.schema.Schema - -object ElasticQuery { - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting[S: Schema]( - negativeBoost: Float, - negativeQuery: ElasticQuery[S], - positiveQuery: ElasticQuery[S] - ): BoostingQuery[S] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting( - negativeBoost: Float, - negativeQuery: ElasticQuery[Any], - positiveQuery: ElasticQuery[Any] - ): BoostingQuery[Any] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @tparam S - * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = - ConstantScore[S](query = query, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = - ConstantScore[Any](query = query, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = - DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = - DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, - * using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists[S](field: Field[S, _]): ExistsQuery[S] = - Exists(field = field.toString, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the - * specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists(field: String): ExistsQuery[Any] = - Exists(field = field, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore[S: Schema]( - functions: FunctionScoreFunction[S]* - ): FunctionScoreQuery[S] = - FunctionScore[S]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore( - functions: FunctionScoreFunction[Any]* - ): FunctionScoreQuery[Any] = - FunctionScore[Any]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = - Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy(field: String, value: String): FuzzyQuery[Any] = - Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe GeoPoint field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = - GeoPolygon( - field = field.toString, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = - GeoPolygon( - field = field, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of - * the child `type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child - * `type` field - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of - * the `parent_type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the - * `parent_type` field - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param value - * value that will be used for the query - * @param values - * array of optional values that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. - */ - final def ids(value: String, values: String*): IdsQuery[Any] = - Ids(values = Chunk.fromIterable(value +: values)) - - /** - * Constructs an intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given field in the intervals query structure. - * - * @param field - * the name of the field to be queried. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals( - field: String, - rule: IntervalRule - ): ElasticQuery[Any] = - Intervals(field, rule) - - /** - * Constructs a type-safe intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given type-safe field in the intervals query - * structure. - * - * @param field - * the type-safe field on which the query is executed. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @tparam S - * the document type for which the query is defined. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals[S]( - field: Field[S, _], - rule: IntervalRule - ): ElasticQuery[S] = - Intervals(field.toString, rule) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the type-safe field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = - KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = - KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. - * - * @return - * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. - */ - final def matchAll: MatchAllQuery = - MatchAll(boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = - MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = - MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = - Match(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = - Match(field = field, value = value) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = - MatchPhrase(field = field.toString, value = value, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = - MatchPhrase(field = field, value = value, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a - * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching - * any words that begin with that term. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the text value to be matched - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = - MatchPhrasePrefix(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in - * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that - * begin with that term. - * - * @param field - * the field for which query is specified for - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = - MatchPhrasePrefix(field = field, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. - * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. - * - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. - */ - final def multiMatch(value: String): MultiMatchQuery[Any] = - MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria - * using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the type-safe path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = - Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = - Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = - Prefix(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix(field: String, value: String): Prefix[Any] = - Prefix(field = field, value = value, caseInsensitive = None) - - /** - * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = - Range.empty(field.toString) - - /** - * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = - Range.empty[Any, Any](field = field) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * regular expression that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = - Regexp(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the field for which query is specified for - * @param value - * regular expression that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp(field: String, value: String): RegexpQuery[Any] = - Regexp(field = field, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. - * @param script - * the script that is used by the query - * @return - * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. - */ - final def script(script: Script): ScriptQuery = - query.Script(script = script, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = - Term(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = - Term(field = field, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the type-safe field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = - Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = - Terms(field = field, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the type-safe field representing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchField: Field[S, _], - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField.toString), - minimumShouldMatchScript = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[A: ElasticPrimitive]( - field: String, - minimumShouldMatchField: String, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField), - minimumShouldMatchScript = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[A: ElasticPrimitive]( - field: String, - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = value, boost = None, caseInsensitive = None) - -} +/* + * 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 + +import zio.Chunk +import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.query._ +import zio.elasticsearch.script.Script +import zio.schema.Schema + +object ElasticQuery { + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting[S: Schema]( + negativeBoost: Float, + negativeQuery: ElasticQuery[S], + positiveQuery: ElasticQuery[S] + ): BoostingQuery[S] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting( + negativeBoost: Float, + negativeQuery: ElasticQuery[Any], + positiveQuery: ElasticQuery[Any] + ): BoostingQuery[Any] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @tparam S + * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = + ConstantScore[S](query = query, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = + ConstantScore[Any](query = query, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = + DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = + DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, + * using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists[S](field: Field[S, _]): ExistsQuery[S] = + Exists(field = field.toString, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the + * specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists(field: String): ExistsQuery[Any] = + Exists(field = field, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore[S: Schema]( + functions: FunctionScoreFunction[S]* + ): FunctionScoreQuery[S] = + FunctionScore[S]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore( + functions: FunctionScoreFunction[Any]* + ): FunctionScoreQuery[Any] = + FunctionScore[Any]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = + Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy(field: String, value: String): FuzzyQuery[Any] = + Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe GeoPoint field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = + GeoPolygon( + field = field.toString, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = + GeoPolygon( + field = field, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of + * the child `type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child + * `type` field + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of + * the `parent_type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the + * `parent_type` field + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param value + * value that will be used for the query + * @param values + * array of optional values that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. + */ + final def ids(value: String, values: String*): IdsQuery[Any] = + Ids(values = Chunk.fromIterable(value +: values)) + + /** + * Constructs a type-safe intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given type-safe field in the intervals query + * structure. + * + * @param field + * the type-safe field on which the query is executed. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @tparam S + * the document type for which the query is defined. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals[S]( + field: Field[S, _], + rule: IntervalRule + ): ElasticQuery[S] = + Intervals(field.toString, rule) + + /** + * Constructs an intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given field in the intervals query structure. + * + * @param field + * the name of the field to be queried. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals( + field: String, + rule: IntervalRule + ): ElasticQuery[Any] = + Intervals(field, rule) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the type-safe field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = + KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = + KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. + * + * @return + * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. + */ + final def matchAll: MatchAllQuery = + MatchAll(boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = + MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = + MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = + Match(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = + Match(field = field, value = value) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = + MatchPhrase(field = field.toString, value = value, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = + MatchPhrase(field = field, value = value, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a + * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching + * any words that begin with that term. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the text value to be matched + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = + MatchPhrasePrefix(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in + * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that + * begin with that term. + * + * @param field + * the field for which query is specified for + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = + MatchPhrasePrefix(field = field, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. + * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. + * + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. + */ + final def multiMatch(value: String): MultiMatchQuery[Any] = + MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria + * using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the type-safe path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = + Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = + Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = + Prefix(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix(field: String, value: String): Prefix[Any] = + Prefix(field = field, value = value, caseInsensitive = None) + + /** + * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = + Range.empty(field.toString) + + /** + * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = + Range.empty[Any, Any](field = field) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * regular expression that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = + Regexp(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the field for which query is specified for + * @param value + * regular expression that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp(field: String, value: String): RegexpQuery[Any] = + Regexp(field = field, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. + * @param script + * the script that is used by the query + * @return + * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. + */ + final def script(script: Script): ScriptQuery = + query.Script(script = script, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = + Term(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = + Term(field = field, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the type-safe field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = + Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = + Terms(field = field, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the type-safe field representing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchField: Field[S, _], + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField.toString), + minimumShouldMatchScript = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[A: ElasticPrimitive]( + field: String, + minimumShouldMatchField: String, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField), + minimumShouldMatchScript = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[A: ElasticPrimitive]( + field: String, + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = value, boost = None, caseInsensitive = None) + +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index 475074b17..f236bcd76 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -124,31 +124,31 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { ) }, test("intervalRange") { - val intervalNoBounds = intervalRange( + + val intervalNoBounds = intervalRange[Any, Inclusive, Exclusive]( lower = None, upper = None, analyzer = None, useField = None ) - val intervalWithBounds = intervalRange( - lower = Some(Left("10")), - upper = Some(Right("20")), + val intervalWithBounds = intervalRange[Any, Inclusive, Exclusive]( + lower = Some(Bound("10", InclusiveBound)), + upper = Some(Bound("20", ExclusiveBound)), analyzer = Some("standard"), useField = Some("otherField") ) - val intervalWithOnlyGt = intervalRange( - lower = Some(Left("10")), + val intervalWithOnlyLower = intervalRange[Any, Inclusive, Inclusive]( + lower = Some(Bound("10", InclusiveBound)), upper = None, analyzer = Some("standard"), useField = Some("otherField") ) - val queryWithNoBounds = intervals("stringField", intervalNoBounds) - val queryWithOnlyGt = intervals("stringField", intervalWithOnlyGt) - val queryWithBoundsString = intervals("stringField", intervalWithBounds) - val queryWithBoundsTyped = intervals(TestDocument.stringField, intervalWithBounds) + val queryWithNoBounds = intervals("stringField", intervalNoBounds) + val queryWithOnlyLower = intervals("stringField", intervalWithOnlyLower) + val queryWithBounds = intervals("stringField", intervalWithBounds) val expectedNoBounds = """ @@ -167,8 +167,8 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { | "intervals": { | "stringField": { | "range": { - | "gt": "10", - | "lte": "20", + | "gte": "10", + | "lt": "20", | "analyzer": "standard", | "use_field": "otherField" | } @@ -177,13 +177,13 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { |} |""".stripMargin - val expectedWithOnlyGt = + val expectedWithOnlyLower = """ |{ | "intervals": { | "stringField": { | "range": { - | "gt": "10", + | "gte": "10", | "analyzer": "standard", | "use_field": "otherField" | } @@ -194,7 +194,7 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { assert(intervalNoBounds)( equalTo( - IntervalRange( + IntervalRange[Any, Inclusive, Exclusive]( lower = None, upper = None, analyzer = None, @@ -205,13 +205,10 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { assert(queryWithNoBounds.toJson(None))( equalTo(expectedNoBounds.toJson) ) && - assert(queryWithOnlyGt.toJson(None))( - equalTo(expectedWithOnlyGt.toJson) - ) && - assert(queryWithBoundsString.toJson(None))( - equalTo(expectedWithBounds.toJson) + assert(queryWithOnlyLower.toJson(None))( + equalTo(expectedWithOnlyLower.toJson) ) && - assert(queryWithBoundsTyped.toJson(None))( + assert(queryWithBounds.toJson(None))( equalTo(expectedWithBounds.toJson) ) }, From f9a4a13e00e522298fd15ee916e3c6483b8c8b54 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 12:26:45 +0200 Subject: [PATCH 09/41] Add ElasticIntervalQuery.scala --- .../query/ElasticIntervalQuery.scala | 99 ++++++++++++++----- .../zio/elasticsearch/query/Queries.scala | 3 +- .../ElasticIntervalQuerySpec.scala | 33 ------- 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala index 7d87cbd0b..5f252651e 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -1,6 +1,6 @@ package zio.elasticsearch.query -import zio.Chunk +import zio.{Chunk, NonEmptyChunk} import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} @@ -8,6 +8,14 @@ import zio.json.ast.Json.{Arr, Obj, Str} sealed trait IntervalRule { private[elasticsearch] def toJson: Json } +sealed trait BoundType +sealed trait Inclusive extends BoundType +sealed trait Exclusive extends BoundType + +case object InclusiveBound extends Inclusive +case object ExclusiveBound extends Exclusive + +final case class Bound[B <: BoundType](value: String, boundType: B) private[elasticsearch] final case class IntervalAllOf[S]( intervals: Chunk[IntervalRule], @@ -147,29 +155,39 @@ private[elasticsearch] final case class IntervalPrefix( ) } -private[elasticsearch] final case class IntervalRange[S]( - lower: Option[Either[String, String]], - upper: Option[Either[String, String]], - analyzer: Option[String], - useField: Option[String] +final case class IntervalRange[S]( + lower: Option[Bound[_ <: BoundType]] = None, + upper: Option[Bound[_ <: BoundType]] = None, + analyzer: Option[String] = None, + useField: Option[String] = None ) extends IntervalRule { private[elasticsearch] def toJson: Json = { - val lowerJson = lower.map { - case Left(gt) => "gt" -> gt.toJson - case Right(gte) => "gte" -> gte.toJson - } - val upperJson = upper.map { - case Left(lt) => "lt" -> lt.toJson - case Right(lte) => "lte" -> lte.toJson + def boundToJson[B <: BoundType](bound: Bound[B], isLower: Boolean): (String, Json) = { + val key = ( + isLower, + bound.boundType match { + case InclusiveBound => true + case ExclusiveBound => false + } + ) match { + case (true, true) => "gte" + case (true, false) => "gt" + case (false, true) => "lte" + case (false, false) => "lt" + } + key -> Json.Str(bound.value) } + val lowerJson = lower.map(bound => boundToJson(bound, isLower = true)) + val upperJson = upper.map(bound => boundToJson(bound, isLower = false)) + Obj( "range" -> Obj( Chunk( lowerJson, upperJson, - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) + analyzer.map("analyzer" -> Str(_)), + useField.map("use_field" -> Str(_)) ).flatten: _* ) ) @@ -216,12 +234,13 @@ private[elasticsearch] final case class IntervalWildcard[S]( ) ) } + object ElasticIntervalQuery { - def intervalAllOf[S](intervals: Chunk[IntervalRule]): IntervalAllOf[S] = + def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) - def intervalAnyOf[S](intervals: Chunk[IntervalRule]): IntervalAnyOf[S] = + def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = IntervalAnyOf(intervals, filter = None) def intervalContains[S](pattern: String): IntervalWildcard[S] = @@ -230,8 +249,44 @@ object ElasticIntervalQuery { def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - def intervalFilter[S](): IntervalFilter[S] = - IntervalFilter() + def intervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None + ): Option[IntervalFilter[S]] = { + + val filter: IntervalFilter[S] = IntervalFilter( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ) + + val isEmpty = Seq( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ).forall(_.isEmpty) + + if (isEmpty) None else Some(filter) + } def intervalFuzzy[S](term: String): IntervalFuzzy[S] = IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) @@ -242,9 +297,9 @@ object ElasticIntervalQuery { def intervalPrefix[S](prefix: String): IntervalPrefix = IntervalPrefix(prefix, analyzer = None, useField = None) - def intervalRange[S]( - lower: Option[Either[String, String]] = None, - upper: Option[Either[String, String]] = None, + def intervalRange[S, L <: BoundType, U <: BoundType]( + lower: Option[Bound[L]] = None, + upper: Option[Bound[U]] = None, analyzer: Option[String] = None, useField: Option[String] = None ): IntervalRange[S] = diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 67e04af94..565897d79 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -1195,8 +1195,7 @@ private[elasticsearch] final case class Regexp[S]( sealed trait ScriptQuery extends ElasticQuery[Any] with HasBoost[ScriptQuery] private[elasticsearch] final case class Script(script: zio.elasticsearch.script.Script, boost: Option[Double]) - extends ScriptQuery { - self => + extends ScriptQuery { self => def boost(value: Double): ScriptQuery = self.copy(boost = Some(value)) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index f236bcd76..f6feb7af6 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -124,14 +124,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { ) }, test("intervalRange") { - - val intervalNoBounds = intervalRange[Any, Inclusive, Exclusive]( - lower = None, - upper = None, - analyzer = None, - useField = None - ) - val intervalWithBounds = intervalRange[Any, Inclusive, Exclusive]( lower = Some(Bound("10", InclusiveBound)), upper = Some(Bound("20", ExclusiveBound)), @@ -146,21 +138,9 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { useField = Some("otherField") ) - val queryWithNoBounds = intervals("stringField", intervalNoBounds) val queryWithOnlyLower = intervals("stringField", intervalWithOnlyLower) val queryWithBounds = intervals("stringField", intervalWithBounds) - val expectedNoBounds = - """ - |{ - | "intervals": { - | "stringField": { - | "range": {} - | } - | } - |} - |""".stripMargin - val expectedWithBounds = """ |{ @@ -192,19 +172,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { |} |""".stripMargin - assert(intervalNoBounds)( - equalTo( - IntervalRange[Any, Inclusive, Exclusive]( - lower = None, - upper = None, - analyzer = None, - useField = None - ) - ) - ) && - assert(queryWithNoBounds.toJson(None))( - equalTo(expectedNoBounds.toJson) - ) && assert(queryWithOnlyLower.toJson(None))( equalTo(expectedWithOnlyLower.toJson) ) && From 84c908b0a0258cf014bb16190d9ca0ba352e9756 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 14:05:38 +0200 Subject: [PATCH 10/41] Add HasAnalyzer and HasUseField, correct some mistakes --- .../zio/elasticsearch/ElasticQuery.scala | 12 +-- .../query/ElasticIntervalQuery.scala | 77 +++++++++++++------ .../zio/elasticsearch/query/Queries.scala | 3 +- .../query/options/HasAnalyzer.scala | 14 ++++ .../query/options/HasUseField.scala | 14 ++++ .../ElasticIntervalQuerySpec.scala | 18 ++--- .../zio/elasticsearch/ElasticQuerySpec.scala | 8 -- 7 files changed, 94 insertions(+), 52 deletions(-) create mode 100644 modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala create mode 100644 modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 484cfaef4..e73bbcb0a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -567,11 +567,7 @@ object ElasticQuery { * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ - final def intervals[S]( - field: Field[S, _], - rule: IntervalRule - ): ElasticQuery[S] = - Intervals(field.toString, rule) + final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) /** * Constructs an intervals query by combining a field and an interval query. @@ -586,11 +582,7 @@ object ElasticQuery { * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ - final def intervals( - field: String, - rule: IntervalRule - ): ElasticQuery[Any] = - Intervals(field, rule) + final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) /** * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala index 5f252651e..efefd9c13 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -2,6 +2,7 @@ package zio.elasticsearch.query import zio.{Chunk, NonEmptyChunk} import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps +import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} @@ -23,7 +24,12 @@ private[elasticsearch] final case class IntervalAllOf[S]( ordered: Option[Boolean], filter: Option[IntervalFilter[S]] ) extends IntervalRule { - private[elasticsearch] def toJson: Json = + + def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) + def orderedOn() = copy(ordered = Some(true)) + def orderedOff() = copy(ordered = Some(false)) + private[elasticsearch] def toJson: Json = Obj( "all_of" -> Obj( Chunk( @@ -41,7 +47,7 @@ private[elasticsearch] final case class IntervalAnyOf[S]( filter: Option[IntervalFilter[S]] ) extends IntervalRule { self => - def withFilter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) + def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) override private[elasticsearch] def toJson: Json = Obj( @@ -88,7 +94,15 @@ private[elasticsearch] final case class IntervalFuzzy[S]( fuzziness: Option[String], analyzer: Option[String], useField: Option[String] -) extends IntervalRule { +) extends IntervalRule + with HasAnalyzer[IntervalFuzzy[S]] + with HasUseField[IntervalFuzzy[S]] { + + override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalFuzzy[S] = copy(useField = Some(value)) + def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + def transpositions(enabled: Boolean): IntervalFuzzy[S] = copy(transpositions = Some(enabled)) + private[elasticsearch] def toJson: Json = Obj( "fuzzy" -> Obj( @@ -103,7 +117,6 @@ private[elasticsearch] final case class IntervalFuzzy[S]( ) ) } - private[elasticsearch] final case class IntervalMatch[S]( query: String, analyzer: Option[String], @@ -111,13 +124,16 @@ private[elasticsearch] final case class IntervalMatch[S]( maxGaps: Option[Int], ordered: Option[Boolean], filter: Option[IntervalFilter[S]] -) extends IntervalRule { self => +) extends IntervalRule + with HasAnalyzer[IntervalMatch[S]] + with HasUseField[IntervalMatch[S]] { self => - def withAnalyzer(a: String) = copy(analyzer = Some(a)) - def withUseField(f: String) = copy(useField = Some(f)) - def withMaxGaps(g: Int) = copy(maxGaps = Some(g)) - def withOrdered(o: Boolean) = copy(ordered = Some(o)) - def withFilter(f: IntervalFilter[S]) = copy(filter = Some(f)) + override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) + def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) + def orderedOn(): IntervalMatch[S] = copy(ordered = Some(true)) + def orderedOff(): IntervalMatch[S] = copy(ordered = Some(false)) + override def useField(value: String): IntervalMatch[S] = copy(useField = Some(value)) override private[elasticsearch] def toJson: Json = Obj( @@ -134,14 +150,16 @@ private[elasticsearch] final case class IntervalMatch[S]( ) } -private[elasticsearch] final case class IntervalPrefix( +private[elasticsearch] final case class IntervalPrefix[S]( prefix: String, analyzer: Option[String], useField: Option[String] -) extends IntervalRule { +) extends IntervalRule + with HasAnalyzer[IntervalPrefix[S]] + with HasUseField[IntervalPrefix[S]] { - def withAnalyzer(a: String) = copy(analyzer = Some(a)) - def withUseField(f: String) = copy(useField = Some(f)) + override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalPrefix[S] = copy(useField = Some(value)) override private[elasticsearch] def toJson: Json = Obj( @@ -160,7 +178,15 @@ final case class IntervalRange[S]( upper: Option[Bound[_ <: BoundType]] = None, analyzer: Option[String] = None, useField: Option[String] = None -) extends IntervalRule { +) extends IntervalRule + with HasAnalyzer[IntervalRange[S]] + with HasUseField[IntervalRange[S]] { + + override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) + def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(b)) + def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(b)) + override def useField(value: String): IntervalRange[S] = copy(useField = Some(value)) + private[elasticsearch] def toJson: Json = { def boundToJson[B <: BoundType](bound: Bound[B], isLower: Boolean): (String, Json) = { val key = ( @@ -198,7 +224,13 @@ private[elasticsearch] final case class IntervalRegexp[S]( pattern: Regexp[S], analyzer: Option[String], useField: Option[String] -) extends IntervalRule { +) extends IntervalRule + with HasAnalyzer[IntervalRegexp[S]] + with HasUseField[IntervalRegexp[S]] { + + override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalRegexp[S] = copy(useField = Some(value)) + private[elasticsearch] def toJson: Json = Obj( "regexp" -> Obj( @@ -215,13 +247,12 @@ private[elasticsearch] final case class IntervalWildcard[S]( pattern: String, analyzer: Option[String], useField: Option[String] -) extends IntervalRule { - - def withAnalyzer(a: String): IntervalWildcard[S] = - copy(analyzer = Some(a)) +) extends IntervalRule + with HasAnalyzer[IntervalWildcard[S]] + with HasUseField[IntervalWildcard[S]] { - def withUseField(f: String): IntervalWildcard[S] = - copy(useField = Some(f)) + override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalWildcard[S] = copy(useField = Some(value)) private[elasticsearch] def toJson: Json = Obj( @@ -294,7 +325,7 @@ object ElasticIntervalQuery { def intervalMatch[S](query: String): IntervalMatch[S] = IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) - def intervalPrefix[S](prefix: String): IntervalPrefix = + def intervalPrefix[S](prefix: String): IntervalPrefix[S] = IntervalPrefix(prefix, analyzer = None, useField = None) def intervalRange[S, L <: BoundType, U <: BoundType]( diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 565897d79..9717c2837 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -966,8 +966,7 @@ private[elasticsearch] final case class Nested[S]( ignoreUnmapped: Option[Boolean], innerHitsField: Option[InnerHits], scoreMode: Option[ScoreMode] -) extends NestedQuery[S] { - self => +) extends NestedQuery[S] { self => def ignoreUnmapped(value: Boolean): NestedQuery[S] = self.copy(ignoreUnmapped = Some(value)) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala new file mode 100644 index 000000000..bbb622ca3 --- /dev/null +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala @@ -0,0 +1,14 @@ +package zio.elasticsearch.query.options + +private[elasticsearch] trait HasAnalyzer[Q <: HasAnalyzer[Q]] { + + /** + * Sets the `analyzer` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the analyzer to use + * @return + * a new instance of the query with the `analyzer` value set + */ + def analyzer(value: String): Q +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala new file mode 100644 index 000000000..cc52cfebf --- /dev/null +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -0,0 +1,14 @@ +package zio.elasticsearch.query.options + +private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { + + /** + * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the field to use + * @return + * a new instance of the query with the `use_field` value set + */ + def useField(value: String): Q +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index f6feb7af6..d248bdef3 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -18,13 +18,13 @@ import zio.test.Assertion.equalTo object ElasticIntervalQuerySpec extends ZIOSpecDefault { def spec = suite("ElasticIntervalQuerySpec")( - test("intervalsMatchQuery") { + test("intervalMatchQuery") { val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") - .withOrdered(true) - .withMaxGaps(2) - .withAnalyzer("standard") + .orderedOn() + .maxGaps(2) + .analyzer("standard") val filter = IntervalFilter[String]( before = Some(intervalMatch("before_term")), @@ -32,10 +32,10 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { ) val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") - .withOrdered(true) - .withMaxGaps(2) - .withAnalyzer("standard") - .withFilter(filter) + .orderedOff() + .maxGaps(2) + .analyzer("standard") + .filter(filter) val queryWithStringField = intervals("stringField", intervalWithOptions) val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) @@ -79,7 +79,7 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { | "query": "lambda works", | "analyzer": "standard", | "max_gaps": 2, - | "ordered": true, + | "ordered": false, | "filter": { | "before": { | "match": { diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 69488da2f..38ed21e38 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -26,14 +26,6 @@ import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain._ import zio.elasticsearch.query.DistanceType.Plane import zio.elasticsearch.query.DistanceUnit.Kilometers -import zio.elasticsearch.query.ElasticIntervalQuery.{ - intervalContains, - intervalEndsWith, - intervalMatch, - intervalRange, - intervalStartsWith, - intervalWildcard -} import zio.elasticsearch.query.FunctionScoreFunction._ import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.MultiValueMode.Max From d5b8bc818bf84c332dfdf0019518e5859ea94f22 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 15:01:34 +0200 Subject: [PATCH 11/41] Error: Scalafmt --- .../zio/elasticsearch/ElasticQuery.scala | 2603 ++++++++--------- .../query/ElasticIntervalQuery.scala | 702 ++--- .../query/options/HasAnalyzer.scala | 44 +- .../query/options/HasUseField.scala | 44 +- .../ElasticIntervalQuerySpec.scala | 456 +-- 5 files changed, 1947 insertions(+), 1902 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index e73bbcb0a..4a15d5ad9 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,1308 +1,1305 @@ -/* - * 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 - +/* + * 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 + import zio.Chunk import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.query._ import zio.elasticsearch.script.Script -import zio.schema.Schema - -object ElasticQuery { - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting[S: Schema]( - negativeBoost: Float, - negativeQuery: ElasticQuery[S], - positiveQuery: ElasticQuery[S] - ): BoostingQuery[S] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting( - negativeBoost: Float, - negativeQuery: ElasticQuery[Any], - positiveQuery: ElasticQuery[Any] - ): BoostingQuery[Any] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @tparam S - * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = - ConstantScore[S](query = query, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = - ConstantScore[Any](query = query, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = - DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = - DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, - * using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists[S](field: Field[S, _]): ExistsQuery[S] = - Exists(field = field.toString, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the - * specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists(field: String): ExistsQuery[Any] = - Exists(field = field, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore[S: Schema]( - functions: FunctionScoreFunction[S]* - ): FunctionScoreQuery[S] = - FunctionScore[S]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore( - functions: FunctionScoreFunction[Any]* - ): FunctionScoreQuery[Any] = - FunctionScore[Any]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = - Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy(field: String, value: String): FuzzyQuery[Any] = - Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe GeoPoint field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = - GeoPolygon( - field = field.toString, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = - GeoPolygon( - field = field, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of - * the child `type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child - * `type` field - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of - * the `parent_type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the - * `parent_type` field - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param value - * value that will be used for the query - * @param values - * array of optional values that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. - */ - final def ids(value: String, values: String*): IdsQuery[Any] = - Ids(values = Chunk.fromIterable(value +: values)) - - /** - * Constructs a type-safe intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given type-safe field in the intervals query - * structure. - * - * @param field - * the type-safe field on which the query is executed. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @tparam S - * the document type for which the query is defined. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) - - /** - * Constructs an intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given field in the intervals query structure. - * - * @param field - * the name of the field to be queried. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the type-safe field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = - KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = - KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. - * - * @return - * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. - */ - final def matchAll: MatchAllQuery = - MatchAll(boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = - MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = - MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = - Match(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = - Match(field = field, value = value) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = - MatchPhrase(field = field.toString, value = value, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = - MatchPhrase(field = field, value = value, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a - * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching - * any words that begin with that term. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the text value to be matched - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = - MatchPhrasePrefix(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in - * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that - * begin with that term. - * - * @param field - * the field for which query is specified for - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = - MatchPhrasePrefix(field = field, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. - * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. - * - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. - */ - final def multiMatch(value: String): MultiMatchQuery[Any] = - MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria - * using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the type-safe path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = - Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = - Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = - Prefix(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix(field: String, value: String): Prefix[Any] = - Prefix(field = field, value = value, caseInsensitive = None) - - /** - * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = - Range.empty(field.toString) - - /** - * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = - Range.empty[Any, Any](field = field) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * regular expression that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = - Regexp(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the field for which query is specified for - * @param value - * regular expression that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp(field: String, value: String): RegexpQuery[Any] = - Regexp(field = field, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. - * @param script - * the script that is used by the query - * @return - * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. - */ - final def script(script: Script): ScriptQuery = - query.Script(script = script, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = - Term(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = - Term(field = field, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the type-safe field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = - Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = - Terms(field = field, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the type-safe field representing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchField: Field[S, _], - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField.toString), - minimumShouldMatchScript = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[A: ElasticPrimitive]( - field: String, - minimumShouldMatchField: String, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField), - minimumShouldMatchScript = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[A: ElasticPrimitive]( - field: String, - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = value, boost = None, caseInsensitive = None) - -} +import zio.schema.Schema + +object ElasticQuery { + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting[S: Schema]( + negativeBoost: Float, + negativeQuery: ElasticQuery[S], + positiveQuery: ElasticQuery[S] + ): BoostingQuery[S] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting( + negativeBoost: Float, + negativeQuery: ElasticQuery[Any], + positiveQuery: ElasticQuery[Any] + ): BoostingQuery[Any] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @tparam S + * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = + ConstantScore[S](query = query, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = + ConstantScore[Any](query = query, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = + DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = + DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, + * using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists[S](field: Field[S, _]): ExistsQuery[S] = + Exists(field = field.toString, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the + * specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists(field: String): ExistsQuery[Any] = + Exists(field = field, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore[S: Schema]( + functions: FunctionScoreFunction[S]* + ): FunctionScoreQuery[S] = + FunctionScore[S]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore( + functions: FunctionScoreFunction[Any]* + ): FunctionScoreQuery[Any] = + FunctionScore[Any]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = + Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy(field: String, value: String): FuzzyQuery[Any] = + Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe GeoPoint field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = + GeoPolygon( + field = field.toString, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = + GeoPolygon( + field = field, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of + * the child `type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child + * `type` field + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of + * the `parent_type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the + * `parent_type` field + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param value + * value that will be used for the query + * @param values + * array of optional values that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. + */ + final def ids(value: String, values: String*): IdsQuery[Any] = + Ids(values = Chunk.fromIterable(value +: values)) + + /** + * Constructs a type-safe intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given type-safe field in the intervals query + * structure. + * + * @param field + * the type-safe field on which the query is executed. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @tparam S + * the document type for which the query is defined. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) + + /** + * Constructs an intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given field in the intervals query structure. + * + * @param field + * the name of the field to be queried. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the type-safe field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = + KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = + KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. + * + * @return + * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. + */ + final def matchAll: MatchAllQuery = + MatchAll(boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = + MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = + MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = + Match(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = + Match(field = field, value = value) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = + MatchPhrase(field = field.toString, value = value, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = + MatchPhrase(field = field, value = value, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a + * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching + * any words that begin with that term. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the text value to be matched + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = + MatchPhrasePrefix(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in + * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that + * begin with that term. + * + * @param field + * the field for which query is specified for + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = + MatchPhrasePrefix(field = field, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. + * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. + * + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. + */ + final def multiMatch(value: String): MultiMatchQuery[Any] = + MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria + * using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the type-safe path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = + Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = + Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = + Prefix(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix(field: String, value: String): Prefix[Any] = + Prefix(field = field, value = value, caseInsensitive = None) + + /** + * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = + Range.empty(field.toString) + + /** + * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = + Range.empty[Any, Any](field = field) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * regular expression that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = + Regexp(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the field for which query is specified for + * @param value + * regular expression that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp(field: String, value: String): RegexpQuery[Any] = + Regexp(field = field, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. + * @param script + * the script that is used by the query + * @return + * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. + */ + final def script(script: Script): ScriptQuery = + query.Script(script = script, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = + Term(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = + Term(field = field, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the type-safe field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = + Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = + Terms(field = field, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the type-safe field representing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchField: Field[S, _], + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField.toString), + minimumShouldMatchScript = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[A: ElasticPrimitive]( + field: String, + minimumShouldMatchField: String, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField), + minimumShouldMatchScript = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[A: ElasticPrimitive]( + field: String, + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = value, boost = None, caseInsensitive = None) + +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala index efefd9c13..b0cc61663 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -1,347 +1,363 @@ -package zio.elasticsearch.query - -import zio.{Chunk, NonEmptyChunk} +/* + * 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.query + import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} - -sealed trait IntervalRule { - private[elasticsearch] def toJson: Json -} -sealed trait BoundType -sealed trait Inclusive extends BoundType -sealed trait Exclusive extends BoundType - -case object InclusiveBound extends Inclusive -case object ExclusiveBound extends Exclusive - -final case class Bound[B <: BoundType](value: String, boundType: B) - -private[elasticsearch] final case class IntervalAllOf[S]( - intervals: Chunk[IntervalRule], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalRule { - - def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) - def orderedOn() = copy(ordered = Some(true)) - def orderedOff() = copy(ordered = Some(false)) - private[elasticsearch] def toJson: Json = - Obj( - "all_of" -> Obj( - Chunk( - Some("intervals" -> Arr(intervals.map(_.toJson): _*)), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalAnyOf[S]( - intervals: Chunk[IntervalRule], - filter: Option[IntervalFilter[S]] -) extends IntervalRule { self => - - def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) - - override private[elasticsearch] def toJson: Json = - Obj( - "any_of" -> Obj( - Chunk( - Some("intervals" -> Arr(intervals.map(_.toJson): _*)), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None -) { - private[elasticsearch] def toJson: Json = - Obj( - Chunk( - after.map("after" -> _.toJson), - before.map("before" -> _.toJson), - containedBy.map("contained_by" -> _.toJson), - containing.map("containing" -> _.toJson), - notContainedBy.map("not_contained_by" -> _.toJson), - notContaining.map("not_containing" -> _.toJson), - notOverlapping.map("not_overlapping" -> _.toJson), - overlapping.map("overlapping" -> _.toJson), - script.map("script" -> _) - ).flatten: _* - ) -} - -private[elasticsearch] final case class IntervalFuzzy[S]( - term: String, - prefixLength: Option[Int], - transpositions: Option[Boolean], - fuzziness: Option[String], - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalFuzzy[S]] - with HasUseField[IntervalFuzzy[S]] { - - override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalFuzzy[S] = copy(useField = Some(value)) - def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) - def transpositions(enabled: Boolean): IntervalFuzzy[S] = copy(transpositions = Some(enabled)) - - private[elasticsearch] def toJson: Json = - Obj( - "fuzzy" -> Obj( - Chunk( - Some("term" -> term.toJson), - prefixLength.map("prefix_length" -> _.toJson), - transpositions.map("transpositions" -> _.toJson), - fuzziness.map("fuzziness" -> _.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} -private[elasticsearch] final case class IntervalMatch[S]( - query: String, - analyzer: Option[String], - useField: Option[String], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalRule - with HasAnalyzer[IntervalMatch[S]] - with HasUseField[IntervalMatch[S]] { self => - - override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) - def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) - def orderedOn(): IntervalMatch[S] = copy(ordered = Some(true)) - def orderedOff(): IntervalMatch[S] = copy(ordered = Some(false)) - override def useField(value: String): IntervalMatch[S] = copy(useField = Some(value)) - - override private[elasticsearch] def toJson: Json = - Obj( - "match" -> Obj( - Chunk( - Some("query" -> Str(query)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalPrefix[S]( - prefix: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalPrefix[S]] - with HasUseField[IntervalPrefix[S]] { - - override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalPrefix[S] = copy(useField = Some(value)) - - override private[elasticsearch] def toJson: Json = - Obj( - "prefix" -> Obj( - Chunk( - Some("prefix" -> Str(prefix)), - analyzer.map(a => "analyzer" -> Str(a)), - useField.map(u => "use_field" -> Str(u)) - ).flatten: _* - ) - ) -} - -final case class IntervalRange[S]( - lower: Option[Bound[_ <: BoundType]] = None, - upper: Option[Bound[_ <: BoundType]] = None, - analyzer: Option[String] = None, - useField: Option[String] = None -) extends IntervalRule - with HasAnalyzer[IntervalRange[S]] - with HasUseField[IntervalRange[S]] { - - override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) - def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(b)) - def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(b)) - override def useField(value: String): IntervalRange[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = { - def boundToJson[B <: BoundType](bound: Bound[B], isLower: Boolean): (String, Json) = { - val key = ( - isLower, - bound.boundType match { - case InclusiveBound => true - case ExclusiveBound => false - } - ) match { - case (true, true) => "gte" - case (true, false) => "gt" - case (false, true) => "lte" - case (false, false) => "lt" - } - key -> Json.Str(bound.value) - } - - val lowerJson = lower.map(bound => boundToJson(bound, isLower = true)) - val upperJson = upper.map(bound => boundToJson(bound, isLower = false)) - - Obj( - "range" -> Obj( - Chunk( - lowerJson, - upperJson, - analyzer.map("analyzer" -> Str(_)), - useField.map("use_field" -> Str(_)) - ).flatten: _* - ) - ) - } -} - -private[elasticsearch] final case class IntervalRegexp[S]( - pattern: Regexp[S], - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalRegexp[S]] - with HasUseField[IntervalRegexp[S]] { - - override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalRegexp[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = - Obj( - "regexp" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson(None)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalWildcard[S]( - pattern: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalWildcard[S]] - with HasUseField[IntervalWildcard[S]] { - - override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalWildcard[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = - Obj( - "wildcard" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -object ElasticIntervalQuery { - - def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = - IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) - - def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = - IntervalAnyOf(intervals, filter = None) - - def intervalContains[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) - - def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - - def intervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None - ): Option[IntervalFilter[S]] = { - - val filter: IntervalFilter[S] = IntervalFilter( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ) - - val isEmpty = Seq( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ).forall(_.isEmpty) - - if (isEmpty) None else Some(filter) - } - - def intervalFuzzy[S](term: String): IntervalFuzzy[S] = - IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) - - def intervalMatch[S](query: String): IntervalMatch[S] = - IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) - - def intervalPrefix[S](prefix: String): IntervalPrefix[S] = - IntervalPrefix(prefix, analyzer = None, useField = None) - - def intervalRange[S, L <: BoundType, U <: BoundType]( - lower: Option[Bound[L]] = None, - upper: Option[Bound[U]] = None, - analyzer: Option[String] = None, - useField: Option[String] = None - ): IntervalRange[S] = - IntervalRange(lower, upper, analyzer, useField) - - def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = - IntervalRegexp(pattern, analyzer = None, useField = None) - - def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"$pattern*", analyzer = None, useField = None) - - def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern, analyzer = None, useField = None) -} +import zio.{Chunk, NonEmptyChunk} + +sealed trait IntervalRule { + private[elasticsearch] def toJson: Json +} +sealed trait BoundType +sealed trait Inclusive extends BoundType +sealed trait Exclusive extends BoundType + +case object InclusiveBound extends Inclusive +case object ExclusiveBound extends Exclusive + +final case class Bound[B <: BoundType](value: String, boundType: B) + +private[elasticsearch] final case class IntervalAllOf[S]( + intervals: Chunk[IntervalRule], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { + + def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) + def orderedOn(): IntervalAllOf[S] = copy(ordered = Some(true)) + def orderedOff(): IntervalAllOf[S] = copy(ordered = Some(false)) + private[elasticsearch] def toJson: Json = + Obj( + "all_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalAnyOf[S]( + intervals: Chunk[IntervalRule], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { self => + + def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) + + override private[elasticsearch] def toJson: Json = + Obj( + "any_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None +) { + private[elasticsearch] def toJson: Json = + Obj( + Chunk( + after.map("after" -> _.toJson), + before.map("before" -> _.toJson), + containedBy.map("contained_by" -> _.toJson), + containing.map("containing" -> _.toJson), + notContainedBy.map("not_contained_by" -> _.toJson), + notContaining.map("not_containing" -> _.toJson), + notOverlapping.map("not_overlapping" -> _.toJson), + overlapping.map("overlapping" -> _.toJson), + script.map("script" -> _) + ).flatten: _* + ) +} + +private[elasticsearch] final case class IntervalFuzzy[S]( + term: String, + prefixLength: Option[Int], + transpositions: Option[Boolean], + fuzziness: Option[String], + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule + with HasAnalyzer[IntervalFuzzy[S]] + with HasUseField[IntervalFuzzy[S]] { + + override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalFuzzy[S] = copy(useField = Some(value)) + def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + def transpositions(enabled: Boolean): IntervalFuzzy[S] = copy(transpositions = Some(enabled)) + + private[elasticsearch] def toJson: Json = + Obj( + "fuzzy" -> Obj( + Chunk( + Some("term" -> term.toJson), + prefixLength.map("prefix_length" -> _.toJson), + transpositions.map("transpositions" -> _.toJson), + fuzziness.map("fuzziness" -> _.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} +private[elasticsearch] final case class IntervalMatch[S]( + query: String, + analyzer: Option[String], + useField: Option[String], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule + with HasAnalyzer[IntervalMatch[S]] + with HasUseField[IntervalMatch[S]] { self => + + override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) + def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) + def orderedOn(): IntervalMatch[S] = copy(ordered = Some(true)) + def orderedOff(): IntervalMatch[S] = copy(ordered = Some(false)) + override def useField(value: String): IntervalMatch[S] = copy(useField = Some(value)) + + override private[elasticsearch] def toJson: Json = + Obj( + "match" -> Obj( + Chunk( + Some("query" -> Str(query)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalPrefix[S]( + prefix: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule + with HasAnalyzer[IntervalPrefix[S]] + with HasUseField[IntervalPrefix[S]] { + + override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalPrefix[S] = copy(useField = Some(value)) + + override private[elasticsearch] def toJson: Json = + Obj( + "prefix" -> Obj( + Chunk( + Some("prefix" -> Str(prefix)), + analyzer.map(a => "analyzer" -> Str(a)), + useField.map(u => "use_field" -> Str(u)) + ).flatten: _* + ) + ) +} + +final case class IntervalRange[S]( + lower: Option[Bound[_ <: BoundType]] = None, + upper: Option[Bound[_ <: BoundType]] = None, + analyzer: Option[String] = None, + useField: Option[String] = None +) extends IntervalRule + with HasAnalyzer[IntervalRange[S]] + with HasUseField[IntervalRange[S]] { + + override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) + def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(b)) + def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(b)) + override def useField(value: String): IntervalRange[S] = copy(useField = Some(value)) + + private[elasticsearch] def toJson: Json = { + def boundToJson[B <: BoundType](bound: Bound[B], isLower: Boolean): (String, Json) = { + val key = ( + isLower, + bound.boundType match { + case InclusiveBound => true + case ExclusiveBound => false + } + ) match { + case (true, true) => "gte" + case (true, false) => "gt" + case (false, true) => "lte" + case (false, false) => "lt" + } + key -> Json.Str(bound.value) + } + + val lowerJson = lower.map(bound => boundToJson(bound, isLower = true)) + val upperJson = upper.map(bound => boundToJson(bound, isLower = false)) + + Obj( + "range" -> Obj( + Chunk( + lowerJson, + upperJson, + analyzer.map("analyzer" -> Str(_)), + useField.map("use_field" -> Str(_)) + ).flatten: _* + ) + ) + } +} + +private[elasticsearch] final case class IntervalRegexp[S]( + pattern: Regexp[S], + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule + with HasAnalyzer[IntervalRegexp[S]] + with HasUseField[IntervalRegexp[S]] { + + override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalRegexp[S] = copy(useField = Some(value)) + + private[elasticsearch] def toJson: Json = + Obj( + "regexp" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson(None)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalWildcard[S]( + pattern: String, + analyzer: Option[String], + useField: Option[String] +) extends IntervalRule + with HasAnalyzer[IntervalWildcard[S]] + with HasUseField[IntervalWildcard[S]] { + + override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) + override def useField(value: String): IntervalWildcard[S] = copy(useField = Some(value)) + + private[elasticsearch] def toJson: Json = + Obj( + "wildcard" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toJson) + ).flatten: _* + ) + ) +} + +object ElasticIntervalQuery { + + def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = + IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + + def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = + IntervalAnyOf(intervals, filter = None) + + def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + def intervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None + ): Option[IntervalFilter[S]] = { + + val filter: IntervalFilter[S] = IntervalFilter( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ) + + val isEmpty = Seq( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ).forall(_.isEmpty) + + if (isEmpty) None else Some(filter) + } + + def intervalFuzzy[S](term: String): IntervalFuzzy[S] = + IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) + + def intervalMatch[S](query: String): IntervalMatch[S] = + IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) + + def intervalPrefix[S](prefix: String): IntervalPrefix[S] = + IntervalPrefix(prefix, analyzer = None, useField = None) + + def intervalRange[S, L <: BoundType, U <: BoundType]( + lower: Option[Bound[L]] = None, + upper: Option[Bound[U]] = None, + analyzer: Option[String] = None, + useField: Option[String] = None + ): IntervalRange[S] = + IntervalRange(lower, upper, analyzer, useField) + + def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = + IntervalRegexp(pattern, analyzer = None, useField = None) + + def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + def intervalWildcard[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(pattern, analyzer = None, useField = None) +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala index bbb622ca3..4afe494c6 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala @@ -1,14 +1,30 @@ -package zio.elasticsearch.query.options - -private[elasticsearch] trait HasAnalyzer[Q <: HasAnalyzer[Q]] { - - /** - * Sets the `analyzer` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. - * - * @param value - * the name of the analyzer to use - * @return - * a new instance of the query with the `analyzer` value set - */ - def analyzer(value: String): Q -} +/* + * 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.query.options + +private[elasticsearch] trait HasAnalyzer[Q <: HasAnalyzer[Q]] { + + /** + * Sets the `analyzer` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the analyzer to use + * @return + * a new instance of the query with the `analyzer` value set + */ + def analyzer(value: String): Q +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala index cc52cfebf..58987004b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -1,14 +1,30 @@ -package zio.elasticsearch.query.options - -private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { - - /** - * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. - * - * @param value - * the name of the field to use - * @return - * a new instance of the query with the `use_field` value set - */ - def useField(value: String): Q -} +/* + * 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.query.options + +private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { + + /** + * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the field to use + * @return + * a new instance of the query with the `use_field` value set + */ + def useField(value: String): Q +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index d248bdef3..349086fe5 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -11,264 +11,264 @@ import zio.elasticsearch.query.ElasticIntervalQuery.{ intervalWildcard } import zio.elasticsearch.query._ -import zio.test._ import zio.elasticsearch.utils._ import zio.test.Assertion.equalTo +import zio.test._ object ElasticIntervalQuerySpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = + suite("ElasticIntervalQuerySpec")( + test("intervalMatchQuery") { + val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") - def spec = suite("ElasticIntervalQuerySpec")( - test("intervalMatchQuery") { - val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") + val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") + .orderedOn() + .maxGaps(2) + .analyzer("standard") - val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") - .orderedOn() - .maxGaps(2) - .analyzer("standard") - - val filter = IntervalFilter[String]( - before = Some(intervalMatch("before_term")), - after = Some(intervalMatch("after_term")) - ) + val filter = IntervalFilter[String]( + before = Some(intervalMatch("before_term")), + after = Some(intervalMatch("after_term")) + ) - val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") - .orderedOff() - .maxGaps(2) - .analyzer("standard") - .filter(filter) + val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") + .orderedOff() + .maxGaps(2) + .analyzer("standard") + .filter(filter) - val queryWithStringField = intervals("stringField", intervalWithOptions) - val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) - val queryWithFilter = intervals("stringField", intervalWithFilter) + val queryWithStringField = intervals("stringField", intervalWithOptions) + val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) + val queryWithFilter = intervals("stringField", intervalWithFilter) - val expectedNoOptions = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works" - | } - | } - | } - |} - |""".stripMargin + val expectedNoOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works" + | } + | } + | } + |} + |""".stripMargin - val expectedWithOptions = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works", - | "analyzer": "standard", - | "max_gaps": 2, - | "ordered": true - | } - | } - | } - |} - |""".stripMargin + val expectedWithOptions = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works", + | "analyzer": "standard", + | "max_gaps": 2, + | "ordered": true + | } + | } + | } + |} + |""".stripMargin - val expectedWithFilter = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works", - | "analyzer": "standard", - | "max_gaps": 2, - | "ordered": false, - | "filter": { - | "before": { - | "match": { - | "query": "before_term" - | } - | }, - | "after": { - | "match": { - | "query": "after_term" - | } - | } - | } - | } - | } - | } - |} - |""".stripMargin + val expectedWithFilter = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "lambda works", + | "analyzer": "standard", + | "max_gaps": 2, + | "ordered": false, + | "filter": { + | "before": { + | "match": { + | "query": "before_term" + | } + | }, + | "after": { + | "match": { + | "query": "after_term" + | } + | } + | } + | } + | } + | } + |} + |""".stripMargin - assert(intervalNoOptions)( - equalTo( - IntervalMatch[String]( - query = "lambda works", - analyzer = None, - useField = None, - maxGaps = None, - ordered = None, - filter = None + assert(intervalNoOptions)( + equalTo( + IntervalMatch[String]( + query = "lambda works", + analyzer = None, + useField = None, + maxGaps = None, + ordered = None, + filter = None + ) ) + ) && + assert(intervals("stringField", intervalNoOptions).toJson(None))( + equalTo(expectedNoOptions.toJson) + ) && + assert(queryWithStringField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithTypedField.toJson(None))( + equalTo(expectedWithOptions.toJson) + ) && + assert(queryWithFilter.toJson(None))( + equalTo(expectedWithFilter.toJson) + ) + }, + test("intervalRange") { + val intervalWithBounds = intervalRange[Any, Inclusive, Exclusive]( + lower = Some(Bound("10", InclusiveBound)), + upper = Some(Bound("20", ExclusiveBound)), + analyzer = Some("standard"), + useField = Some("otherField") ) - ) && - assert(intervals("stringField", intervalNoOptions).toJson(None))( - equalTo(expectedNoOptions.toJson) - ) && - assert(queryWithStringField.toJson(None))( - equalTo(expectedWithOptions.toJson) - ) && - assert(queryWithTypedField.toJson(None))( - equalTo(expectedWithOptions.toJson) - ) && - assert(queryWithFilter.toJson(None))( - equalTo(expectedWithFilter.toJson) - ) - }, - test("intervalRange") { - val intervalWithBounds = intervalRange[Any, Inclusive, Exclusive]( - lower = Some(Bound("10", InclusiveBound)), - upper = Some(Bound("20", ExclusiveBound)), - analyzer = Some("standard"), - useField = Some("otherField") - ) - val intervalWithOnlyLower = intervalRange[Any, Inclusive, Inclusive]( - lower = Some(Bound("10", InclusiveBound)), - upper = None, - analyzer = Some("standard"), - useField = Some("otherField") - ) + val intervalWithOnlyLower = intervalRange[Any, Inclusive, Inclusive]( + lower = Some(Bound("10", InclusiveBound)), + upper = None, + analyzer = Some("standard"), + useField = Some("otherField") + ) - val queryWithOnlyLower = intervals("stringField", intervalWithOnlyLower) - val queryWithBounds = intervals("stringField", intervalWithBounds) + val queryWithOnlyLower = intervals("stringField", intervalWithOnlyLower) + val queryWithBounds = intervals("stringField", intervalWithBounds) - val expectedWithBounds = - """ - |{ - | "intervals": { - | "stringField": { - | "range": { - | "gte": "10", - | "lt": "20", - | "analyzer": "standard", - | "use_field": "otherField" - | } - | } - | } - |} - |""".stripMargin + val expectedWithBounds = + """ + |{ + | "intervals": { + | "stringField": { + | "range": { + | "gte": "10", + | "lt": "20", + | "analyzer": "standard", + | "use_field": "otherField" + | } + | } + | } + |} + |""".stripMargin - val expectedWithOnlyLower = - """ - |{ - | "intervals": { - | "stringField": { - | "range": { - | "gte": "10", - | "analyzer": "standard", - | "use_field": "otherField" - | } - | } - | } - |} - |""".stripMargin + val expectedWithOnlyLower = + """ + |{ + | "intervals": { + | "stringField": { + | "range": { + | "gte": "10", + | "analyzer": "standard", + | "use_field": "otherField" + | } + | } + | } + |} + |""".stripMargin - assert(queryWithOnlyLower.toJson(None))( - equalTo(expectedWithOnlyLower.toJson) - ) && - assert(queryWithBounds.toJson(None))( - equalTo(expectedWithBounds.toJson) - ) - }, - test("intervalWildcard") { - val wildcardExact: IntervalWildcard[String] = - intervalWildcard("la*mb?da") + assert(queryWithOnlyLower.toJson(None))( + equalTo(expectedWithOnlyLower.toJson) + ) && + assert(queryWithBounds.toJson(None))( + equalTo(expectedWithBounds.toJson) + ) + }, + test("intervalWildcard") { + val wildcardExact: IntervalWildcard[String] = + intervalWildcard("la*mb?da") - val wildcardContains: IntervalWildcard[String] = - intervalContains("lambda") + val wildcardContains: IntervalWildcard[String] = + intervalContains("lambda") - val wildcardStartsWith: IntervalWildcard[String] = - intervalStartsWith("lambda") + val wildcardStartsWith: IntervalWildcard[String] = + intervalStartsWith("lambda") - val wildcardEndsWith: IntervalWildcard[String] = - intervalEndsWith("lambda") + val wildcardEndsWith: IntervalWildcard[String] = + intervalEndsWith("lambda") - val queryExact: Intervals[String] = - Intervals("stringField", wildcardExact) + val queryExact: Intervals[String] = + Intervals("stringField", wildcardExact) - val queryContains: Intervals[String] = - Intervals("stringField", wildcardContains) + val queryContains: Intervals[String] = + Intervals("stringField", wildcardContains) - val queryStartsWith: Intervals[String] = - Intervals("stringField", wildcardStartsWith) + val queryStartsWith: Intervals[String] = + Intervals("stringField", wildcardStartsWith) - val queryEndsWith: Intervals[String] = - Intervals("stringField", wildcardEndsWith) + val queryEndsWith: Intervals[String] = + Intervals("stringField", wildcardEndsWith) - val expectedExact = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "la*mb?da" - | } - | } - | } - |} - |""".stripMargin + val expectedExact = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "la*mb?da" + | } + | } + | } + |} + |""".stripMargin - val expectedContains = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "*lambda*" - | } - | } - | } - |} - |""".stripMargin + val expectedContains = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda*" + | } + | } + | } + |} + |""".stripMargin - val expectedStartsWith = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "lambda*" - | } - | } - | } - |} - |""".stripMargin + val expectedStartsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "lambda*" + | } + | } + | } + |} + |""".stripMargin - val expectedEndsWith = - """ - |{ - | "intervals": { - | "stringField": { - | "wildcard": { - | "pattern": "*lambda" - | } - | } - | } - |} - |""".stripMargin + val expectedEndsWith = + """ + |{ + | "intervals": { + | "stringField": { + | "wildcard": { + | "pattern": "*lambda" + | } + | } + | } + |} + |""".stripMargin - assert(wildcardExact)( - equalTo( - IntervalWildcard[String]( - pattern = "la*mb?da", - analyzer = None, - useField = None + assert(wildcardExact)( + equalTo( + IntervalWildcard[String]( + pattern = "la*mb?da", + analyzer = None, + useField = None + ) ) - ) - ) && - assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && - assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && - assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && - assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) - } - ) + ) && + assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && + assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && + assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && + assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) + } + ) } From 7af2c13d11cdecf5f0238240a0307239f8aff40a Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Mon, 16 Jun 2025 16:57:19 +0200 Subject: [PATCH 12/41] Work on It tests --- .../zio/elasticsearch/HttpExecutorSpec.scala | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 24efb9e44..d251cbcaa 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -26,12 +26,21 @@ import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain.{PartialTestDocument, TestDocument, TestSubDocument} import zio.elasticsearch.executor.Executor import zio.elasticsearch.query.DistanceUnit.Kilometers +import zio.elasticsearch.query.ElasticIntervalQuery.intervalRange import zio.elasticsearch.query.FunctionScoreFunction.randomScoreFunction import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max import zio.elasticsearch.query.sort.SortOrder._ import zio.elasticsearch.query.sort.SourceType.NumberType -import zio.elasticsearch.query.{Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} +import zio.elasticsearch.query.{ + Bound, + Distance, + ExclusiveBound, + FunctionScoreBoostMode, + FunctionScoreFunction, + InclusiveBound, + InnerHits +} import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} import zio.elasticsearch.result.{FilterAggregationResult, Item, MaxAggregationResult, UpdateByQueryResult} import zio.elasticsearch.script.{Painless, Script} @@ -50,6 +59,37 @@ object HttpExecutorSpec extends IntegrationSpec { def spec: Spec[TestEnvironment, Any] = { suite("Executor")( suite("HTTP Executor")( + suite("IntervalQuery integration tests")( + test("search for a document using an interval range query on stringField") { + checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { + (lowId, lowDoc, highId, highDoc) => + val lowValue = "banana" + val highValue = "zebra" + val indexedLow = lowDoc.copy(stringField = lowValue) + val indexedHigh = highDoc.copy(stringField = highValue) + + val query = + intervalRange[ + TestDocument, + InclusiveBound.type, + ExclusiveBound.type + ]( + lower = Some(Bound("a", InclusiveBound)), + upper = Some(Bound("c", ExclusiveBound)), + useField = Some(TestDocument.stringField) + ) + + for { + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, lowId, indexedLow)) + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, highId, indexedHigh).refreshTrue) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)(contains(indexedLow) && not(contains(indexedHigh))) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ) + ), suite("aggregation")( test("aggregate using avg aggregation") { checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { From ba54dc126f678c26f1fabb033bd4273018c7be22 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 01:11:39 +0200 Subject: [PATCH 13/41] Add integration tests for IntervalMatch --- .../zio/elasticsearch/HttpExecutorSpec.scala | 126 +++++++++++++----- 1 file changed, 92 insertions(+), 34 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index d251cbcaa..01f5b239b 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -20,13 +20,15 @@ import zio.Chunk import zio.elasticsearch.ElasticAggregation._ import zio.elasticsearch.ElasticHighlight.highlight import zio.elasticsearch.ElasticQuery.{script => _, _} +import zio.elasticsearch.ElasticQuery.{contains => _, _} import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.aggregation.AggregationOrder import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain.{PartialTestDocument, TestDocument, TestSubDocument} import zio.elasticsearch.executor.Executor import zio.elasticsearch.query.DistanceUnit.Kilometers -import zio.elasticsearch.query.ElasticIntervalQuery.intervalRange +import zio.elasticsearch.query.ElasticIntervalQuery.{intervalMatch, intervalRange} +import zio.elasticsearch.query._ import zio.elasticsearch.query.FunctionScoreFunction.randomScoreFunction import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max @@ -35,12 +37,15 @@ import zio.elasticsearch.query.sort.SourceType.NumberType import zio.elasticsearch.query.{ Bound, Distance, + ElasticIntervalQuery, ExclusiveBound, FunctionScoreBoostMode, FunctionScoreFunction, InclusiveBound, - InnerHits + InnerHits, + IntervalMatch } +import zio.elasticsearch.ElasticQuery._ import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} import zio.elasticsearch.result.{FilterAggregationResult, Item, MaxAggregationResult, UpdateByQueryResult} import zio.elasticsearch.script.{Painless, Script} @@ -59,37 +64,6 @@ object HttpExecutorSpec extends IntegrationSpec { def spec: Spec[TestEnvironment, Any] = { suite("Executor")( suite("HTTP Executor")( - suite("IntervalQuery integration tests")( - test("search for a document using an interval range query on stringField") { - checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { - (lowId, lowDoc, highId, highDoc) => - val lowValue = "banana" - val highValue = "zebra" - val indexedLow = lowDoc.copy(stringField = lowValue) - val indexedHigh = highDoc.copy(stringField = highValue) - - val query = - intervalRange[ - TestDocument, - InclusiveBound.type, - ExclusiveBound.type - ]( - lower = Some(Bound("a", InclusiveBound)), - upper = Some(Bound("c", ExclusiveBound)), - useField = Some(TestDocument.stringField) - ) - - for { - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, lowId, indexedLow)) - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, highId, indexedHigh).refreshTrue) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] - } yield assert(res)(contains(indexedLow) && not(contains(indexedHigh))) - } - } @@ around( - Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), - Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie - ) - ), suite("aggregation")( test("aggregate using avg aggregation") { checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) { @@ -186,6 +160,89 @@ object HttpExecutorSpec extends IntegrationSpec { Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie ), + test("intervalMatch returns only matching document") { + checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString, genDocumentId, genTestDocument) { + (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => + val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") + val docShouldNotMatch = docNoMatch.copy(stringField = "completely unrelated text") + + val field = TestDocument.stringField.toString + val query = intervals(field, intervalMatch(targetWord)) + + for { + _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch)) + _ <- Executor.execute( + ElasticRequest.upsert(firstSearchIndex, idNoMatch, docShouldNotMatch).refreshTrue + ) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)( + Assertion.contains(docShouldMatch) && + Assertion.not(Assertion.contains(docShouldNotMatch)) + ) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), + test("intervalMatch query finds document with exact matching term") { + checkOnce(genDocumentId, genTestDocument) { (docId, doc) => + val term = "apple" + val docWithTerm = doc.copy(stringField = s"$term banana orange") + + val query = intervals( + "stringField", + intervalMatch(term) + ) + + for { + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docWithTerm)) + _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)(Assertion.contains(docWithTerm)) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), + test("intervalMatch query does not find document if term is absent") { + checkOnce(genDocumentId, genTestDocument) { (docId, doc) => + val query = intervals( + "stringField", + intervalMatch("nonexistentterm") + ) + + for { + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, doc)) + _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)(Assertion.isEmpty) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), +// test("intervalRange query should not find document with intField outside range") { +// checkOnce(genDocumentId, genTestDocument) { (docId, doc) => +// val docOutOfRange = doc.copy(intField = 100) +// +// val rangeQuery = intervals( +// "intField", +// IntervalRange() +// .lower(Bound("50", InclusiveBound)) +// .upper(Bound("60", InclusiveBound)) +// ) +// +// for { +// _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docOutOfRange)) +// _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) +// res <- Executor.execute(ElasticRequest.search(firstSearchIndex, rangeQuery)).documentAs[TestDocument] +// } yield assert(res)(isEmpty) +// } +// } @@ around( +// Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), +// Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie +// ), test("aggregate using filter aggregation with max aggregation as a sub aggregation") { val expectedResult = ( "aggregation", @@ -229,7 +286,8 @@ object HttpExecutorSpec extends IntegrationSpec { ) .refreshTrue ) - query = term(field = TestDocument.stringField, value = secondDocumentUpdated.stringField.toLowerCase) + query = + term(field = TestDocument.stringField, value = secondDocumentUpdated.stringField.toLowerCase) aggregation = filterAggregation(name = "aggregation", query = query).withSubAgg( maxAggregation("subAggregation", TestDocument.intField) From 593f57534ca06acad046babac865fc41c8e6e959 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 10:15:47 +0200 Subject: [PATCH 14/41] Refactor code in HttpExecutorSpec and create suite for IntervalMatch --- .../zio/elasticsearch/HttpExecutorSpec.scala | 164 +++++++----------- 1 file changed, 66 insertions(+), 98 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 01f5b239b..cf2acaab3 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -27,25 +27,13 @@ import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain.{PartialTestDocument, TestDocument, TestSubDocument} import zio.elasticsearch.executor.Executor import zio.elasticsearch.query.DistanceUnit.Kilometers -import zio.elasticsearch.query.ElasticIntervalQuery.{intervalMatch, intervalRange} -import zio.elasticsearch.query._ +import zio.elasticsearch.query.ElasticIntervalQuery.intervalMatch import zio.elasticsearch.query.FunctionScoreFunction.randomScoreFunction import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max import zio.elasticsearch.query.sort.SortOrder._ import zio.elasticsearch.query.sort.SourceType.NumberType -import zio.elasticsearch.query.{ - Bound, - Distance, - ElasticIntervalQuery, - ExclusiveBound, - FunctionScoreBoostMode, - FunctionScoreFunction, - InclusiveBound, - InnerHits, - IntervalMatch -} -import zio.elasticsearch.ElasticQuery._ +import zio.elasticsearch.query.{Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} import zio.elasticsearch.result.{FilterAggregationResult, Item, MaxAggregationResult, UpdateByQueryResult} import zio.elasticsearch.script.{Painless, Script} @@ -55,7 +43,6 @@ import zio.stream.{Sink, ZSink} import zio.test.Assertion._ import zio.test.TestAspect._ import zio.test._ - import java.time.LocalDate import scala.util.Random @@ -160,89 +147,6 @@ object HttpExecutorSpec extends IntegrationSpec { Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie ), - test("intervalMatch returns only matching document") { - checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString, genDocumentId, genTestDocument) { - (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => - val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") - val docShouldNotMatch = docNoMatch.copy(stringField = "completely unrelated text") - - val field = TestDocument.stringField.toString - val query = intervals(field, intervalMatch(targetWord)) - - for { - _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch)) - _ <- Executor.execute( - ElasticRequest.upsert(firstSearchIndex, idNoMatch, docShouldNotMatch).refreshTrue - ) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] - } yield assert(res)( - Assertion.contains(docShouldMatch) && - Assertion.not(Assertion.contains(docShouldNotMatch)) - ) - } - } @@ around( - Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), - Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie - ), - test("intervalMatch query finds document with exact matching term") { - checkOnce(genDocumentId, genTestDocument) { (docId, doc) => - val term = "apple" - val docWithTerm = doc.copy(stringField = s"$term banana orange") - - val query = intervals( - "stringField", - intervalMatch(term) - ) - - for { - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docWithTerm)) - _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] - } yield assert(res)(Assertion.contains(docWithTerm)) - } - } @@ around( - Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), - Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie - ), - test("intervalMatch query does not find document if term is absent") { - checkOnce(genDocumentId, genTestDocument) { (docId, doc) => - val query = intervals( - "stringField", - intervalMatch("nonexistentterm") - ) - - for { - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, doc)) - _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] - } yield assert(res)(Assertion.isEmpty) - } - } @@ around( - Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), - Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie - ), -// test("intervalRange query should not find document with intField outside range") { -// checkOnce(genDocumentId, genTestDocument) { (docId, doc) => -// val docOutOfRange = doc.copy(intField = 100) -// -// val rangeQuery = intervals( -// "intField", -// IntervalRange() -// .lower(Bound("50", InclusiveBound)) -// .upper(Bound("60", InclusiveBound)) -// ) -// -// for { -// _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docOutOfRange)) -// _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) -// res <- Executor.execute(ElasticRequest.search(firstSearchIndex, rangeQuery)).documentAs[TestDocument] -// } yield assert(res)(isEmpty) -// } -// } @@ around( -// Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), -// Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie -// ), test("aggregate using filter aggregation with max aggregation as a sub aggregation") { val expectedResult = ( "aggregation", @@ -2869,6 +2773,70 @@ object HttpExecutorSpec extends IntegrationSpec { } } @@ after(Executor.execute(ElasticRequest.deleteIndex(geoPolygonIndex)).orDie) ), + suite("interval-match query")( + test("intervalMatch returns only matching document") { + checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString, genDocumentId, genTestDocument) { + (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => + val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") + val docShouldNotMatch = docNoMatch.copy(stringField = "completely unrelated text") + + val field = TestDocument.stringField.toString + val query = intervals(field, intervalMatch(targetWord)) + + for { + _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch)) + _ <- Executor.execute( + ElasticRequest.upsert(firstSearchIndex, idNoMatch, docShouldNotMatch).refreshTrue + ) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)( + Assertion.contains(docShouldMatch) && + Assertion.not(Assertion.contains(docShouldNotMatch)) + ) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), + test("intervalMatch query finds document with exact matching term") { + checkOnce(genDocumentId, genTestDocument) { (docId, doc) => + val term = "apple" + val docWithTerm = doc.copy(stringField = s"$term banana orange") + + val query = intervals( + "stringField", + intervalMatch(term) + ) + + for { + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docWithTerm)) + _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)(Assertion.contains(docWithTerm)) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ), + test("intervalMatch query does not find document if term is absent") { + checkOnce(genDocumentId, genTestDocument) { (docId, doc) => + val query = intervals( + "stringField", + intervalMatch("nonexistentterm") + ) + + for { + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, doc)) + _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) + res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + } yield assert(res)(Assertion.isEmpty) + } + } @@ around( + Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), + Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie + ) + ), suite("search for documents using FunctionScore query")( test("using randomScore function") { checkOnce(genTestDocument, genTestDocument) { (firstDocument, secondDocument) => From 5f42ed15b6801984a42e44d58d22d8d900b8dd42 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 10:45:42 +0200 Subject: [PATCH 15/41] Add elastic_interval_query.md file --- docs/overview/elastic_interval_query.md | 77 +++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 docs/overview/elastic_interval_query.md diff --git a/docs/overview/elastic_interval_query.md b/docs/overview/elastic_interval_query.md new file mode 100644 index 000000000..f1009a78f --- /dev/null +++ b/docs/overview/elastic_interval_query.md @@ -0,0 +1,77 @@ +--- +id: elastic_interval_query +title: "Overview" +--- + +The `IntervalQuery` allows for advanced search queries based on intervals between words in specific fields. +This query provides flexibility for conditions. + +To use the `IntervalQuery`, import the following: + +```scala +import zio.elasticsearch.query.IntervalQuery +import zio.elasticsearch.ElasticQuery._ +``` + +You can create a basic `IntervalQuery` using the `intervals` method: + +```scala +val query: IntervalQuery[Any] = intervals(field = "content", rule = intervalMatch("targetWord")) +``` + +If you want to specify which fields should be searched, you can use the `useField` method: + +```scala +val queryWithField: IntervalQuery[Document] = + intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) +``` + +To define `fields` in a type-safe manner, use the overloaded `useField` method with field definitions from your document: + +```scala +val queryWithSafeField: IntervalQuery[Document] = + intervals(field = Document.stringField, rule = intervalMatch("targetWord")) +``` + +Alternatively, you can pass a `Field` object directly: + +```scala +val queryWithFieldObject: IntervalQuery[Document] = + intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) +``` + +If you want to define the `maxGaps` parameter, use the `maxGaps` method: + +```scala +val queryWithMaxGaps: IntervalQuery[Document] = + intervals(field = "content", rule = intervalMatch("targetWord").maxGaps(2)) +``` + +If you want to specify the word order requirement, use the `orderedOn` method: + +```scala +val queryWithOrder: IntervalQuery[Document] = + intervals(field = "content", rule = intervalMatch("targetWord").orderedOn()) +``` + +You can also apply additional filters to the query: + +```scala +val queryWithFilter: IntervalQuery[Document] = + intervals(field = "content", rule = intervalMatch("targetWord").filter(IntervalFilter.someFilter)) +``` + +Alternatively, you can construct the query manually with all parameters: + +```scala +val queryManually: IntervalQuery[Document] = + IntervalQuery( + field = "content", + rule = intervalMatch("targetWord") + .maxGaps(2) + .orderedOn() + .filter(IntervalFilter.someFilter) + .analyzer("standard") + ) +``` + From ff1916d2b4e60cbde47f8f6ae60b6db32abdc1e4 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 13:37:29 +0200 Subject: [PATCH 16/41] Complete changes on Boosting, refactor on type-safe useField --- .../zio/elasticsearch/HttpExecutorSpec.scala | 21 +- .../zio/elasticsearch/ElasticQuery.scala | 2585 ++++++++--------- .../zio/elasticsearch/query/Queries.scala | 33 +- .../query/options/HasUseField.scala | 46 +- .../zio/elasticsearch/ElasticQuerySpec.scala | 59 +- 5 files changed, 1340 insertions(+), 1404 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index cf2acaab3..40adb5e83 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -1,19 +1,3 @@ -/* - * 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 import zio.Chunk @@ -33,7 +17,7 @@ import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max import zio.elasticsearch.query.sort.SortOrder._ import zio.elasticsearch.query.sort.SourceType.NumberType -import zio.elasticsearch.query.{Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} +import zio.elasticsearch.query.{BoostRange, Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} import zio.elasticsearch.result.{FilterAggregationResult, Item, MaxAggregationResult, UpdateByQueryResult} import zio.elasticsearch.script.{Painless, Script} @@ -43,6 +27,7 @@ import zio.stream.{Sink, ZSink} import zio.test.Assertion._ import zio.test.TestAspect._ import zio.test._ + import java.time.LocalDate import scala.util.Random @@ -1129,7 +1114,7 @@ object HttpExecutorSpec extends IntegrationSpec { .refreshTrue ) query = boosting( - negativeBoost = 0.1f, + negativeBoost = BoostRange(0.1f), negativeQuery = term(field = TestDocument.stringField, value = firstDocument.stringField.toLowerCase), positiveQuery = matchPhrase( diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 4a15d5ad9..20a576c1f 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,1305 +1,1290 @@ -/* - * 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 - +package zio.elasticsearch + import zio.Chunk import zio.elasticsearch.ElasticPrimitive.ElasticPrimitive import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.query._ import zio.elasticsearch.script.Script -import zio.schema.Schema - -object ElasticQuery { - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting[S: Schema]( - negativeBoost: Float, - negativeQuery: ElasticQuery[S], - positiveQuery: ElasticQuery[S] - ): BoostingQuery[S] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria - * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query - * marked as positive while reducing the relevance score of documents that also match a query which is marked as - * negative query. - * - * @param negativeBoost - * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query - * @param negativeQuery - * the query that decreases the relevance score of matching documents - * @param positiveQuery - * the query that must be satisfied - * @return - * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. - */ - final def boosting( - negativeBoost: Float, - negativeQuery: ElasticQuery[Any], - positiveQuery: ElasticQuery[Any] - ): BoostingQuery[Any] = - Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @tparam S - * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = - ConstantScore[S](query = query, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. - * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a - * relevance score equal to the boost parameter value. - * - * @param query - * query to be wrapped inside of constant score query - * @return - * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query - * that must satisfy the criteria to be performed. - */ - final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = - ConstantScore[Any](query = query, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `contains` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def contains(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = - DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. - * - * @param queries - * the rest of the queries to be wrapped inside of disjunction max query - * @return - * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be - * performed. - */ - final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = - DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, - * using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists[S](field: Field[S, _]): ExistsQuery[S] = - Exists(field = field.toString, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the - * specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. - */ - final def exists(field: String): ExistsQuery[Any] = - Exists(field = field, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `filter` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.fromIterable(queries), - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore[S: Schema]( - functions: FunctionScoreFunction[S]* - ): FunctionScoreQuery[S] = - FunctionScore[S]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple - * [[zio.elasticsearch.query.FunctionScoreFunction]]. - * - * @param functions - * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of - * [[zio.elasticsearch.query.FunctionScore]] query - * @return - * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions - * that are used to calculate score for result. - */ - final def functionScore( - functions: FunctionScoreFunction[Any]* - ): FunctionScoreQuery[Any] = - FunctionScore[Any]( - functionScoreFunctions = Chunk.fromIterable(functions), - boost = None, - boostMode = None, - maxBoost = None, - minScore = None, - query = None, - scoreMode = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = - Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. - * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured - * by a Levenshtein edit distance. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. - */ - final def fuzzy(field: String, value: String): FuzzyQuery[Any] = - Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe GeoPoint field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = s"${point.lat},${point.lon}", - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @tparam S - * the type of document on which the query is defined - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = - GeoDistance( - field = field.toString, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. - * - * @param field - * the field for which the query is specified - * @param point - * the geo-point from which the distance should be measured, defined as geo-hash - * @param distance - * the distance within which values should be matched - * @return - * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be - * performed. - */ - final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = - GeoDistance( - field = field, - point = GeoHash.unwrap(point), - distance = distance, - distanceType = None, - queryName = None, - validationMethod = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = - GeoPolygon( - field = field.toString, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @param coordinates - * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash - * (e.g. ["drm3btev3e86", "drm3btev3e87"]) - * @return - * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. - */ - final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = - GeoPolygon( - field = field, - points = coordinates, - queryName = None, - validationMethod = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of - * the child `type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. - * - * @param childType - * a name of the child relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child - * `type` field - * @return - * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. - */ - final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = - HasChild( - childType = childType, - query = query, - ignoreUnmapped = None, - innerHitsField = None, - maxChildren = None, - minChildren = None, - scoreMode = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of - * the `parent_type` field - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. - * - * @param parentType - * a name of the parent relationship mapped for the join field - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the - * `parent_type` field - * @return - * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. - */ - final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = - HasParent( - parentType = parentType, - query = query, - boost = None, - ignoreUnmapped = None, - innerHitsField = None, - score = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param value - * value that will be used for the query - * @param values - * array of optional values that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. - */ - final def ids(value: String, values: String*): IdsQuery[Any] = - Ids(values = Chunk.fromIterable(value +: values)) - - /** - * Constructs a type-safe intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given type-safe field in the intervals query - * structure. - * - * @param field - * the type-safe field on which the query is executed. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @tparam S - * the document type for which the query is defined. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) - - /** - * Constructs an intervals query by combining a field and an interval query. - * - * The resulting query wraps the specified interval query under the given field in the intervals query structure. - * - * @param field - * the name of the field to be queried. - * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. - * @return - * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. - */ - - final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the type-safe field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = - KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. - * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching - * documents. - * - * @param field - * the field for which query is specified for - * @param k - * number of nearest neighbors to return as top hits (must be less than `numCandidates`) - * @param numCandidates - * number of nearest neighbor candidates to consider per shard - * @param queryVector - * query vector - * @return - * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. - */ - final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = - KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. - * - * @return - * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. - */ - final def matchAll: MatchAllQuery = - MatchAll(boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = - MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a - * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a - * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query - * to be performed. - */ - final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = - MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = - Match(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. - */ - final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = - Match(field = field, value = value) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = - MatchPhrase(field = field.toString, value = value, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the value to be matched, represented by an instance of type `A` - * @return - * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be - * performed. - */ - final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = - MatchPhrase(field = field, value = value, boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified - * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a - * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching - * any words that begin with that term. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * the text value to be matched - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = - MatchPhrasePrefix(field = field.toString, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in - * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that - * begin with that term. - * - * @param field - * the field for which query is specified for - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query - * to be performed. - */ - final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = - MatchPhrasePrefix(field = field, value = value) - - /** - * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. - * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. - * - * @param value - * the text value to be matched - * @return - * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. - */ - final def multiMatch(value: String): MultiMatchQuery[Any] = - MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `must` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must - * satisfy the criteria. - */ - final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.fromIterable(queries), - mustNot = Chunk.empty, - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the - * criteria using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria - * using the specified parameters. - * - * @param queries - * a list of queries to add to `mustNot` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not - * satisfy the criteria. - */ - final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.fromIterable(queries), - should = Chunk.empty, - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the type-safe path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = - Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. - * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. - * - * @param path - * the path to the field for which query is specified for - * @param query - * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. - * @return - * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. - */ - final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = - Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = - Prefix(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. - * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. - */ - final def prefix(field: String, value: String): Prefix[Any] = - Prefix(field = field, value = value, caseInsensitive = None) - - /** - * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the type-safe field for which query is specified for - * @tparam S - * document for which field query is executed - * @tparam A - * the type of the value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = - Range.empty(field.toString) - - /** - * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. - * - * @param field - * the field for which query is specified for - * @return - * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. - */ - final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = - Range.empty[Any, Any](field = field) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * regular expression that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = - Regexp(field = field.toString, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. - * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. - * - * @param field - * the field for which query is specified for - * @param value - * regular expression that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. - */ - final def regexp(field: String, value: String): RegexpQuery[Any] = - Regexp(field = field, value = value, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. - * @param script - * the script that is used by the query - * @return - * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. - */ - final def script(script: Script): ScriptQuery = - query.Script(script = script, boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @tparam S - * document for which field query is executed. An implicit `Schema` instance must be in scope - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = - Bool[S]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using - * the specified parameters. - * - * @param queries - * a list of queries to add to `should` inside of the `Bool` query - * @return - * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should - * satisfy the criteria. - */ - final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = - Bool[Any]( - filter = Chunk.empty, - must = Chunk.empty, - mustNot = Chunk.empty, - should = Chunk.fromIterable(queries), - boost = None, - minimumShouldMatch = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the - * specified value in the specified field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query in the pattern that represents `startsWith` - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def startsWith(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = - Term(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided - * field. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. - */ - final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = - Term(field = field, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the type-safe field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = - Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided - * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple - * values. - * - * @param field - * the field for which query is specified for - * @param values - * a list of terms that should be find in the provided field - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. - */ - final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = - Terms(field = field, values = Chunk.fromIterable(values), boost = None) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the type-safe field representing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchField: Field[S, _], - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField.toString), - minimumShouldMatchScript = None - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchField - * the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSet[A: ElasticPrimitive]( - field: String, - minimumShouldMatchField: String, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = Some(minimumShouldMatchField), - minimumShouldMatchScript = None - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the type-safe field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[S, A: ElasticPrimitive]( - field: Field[S, A], - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[S] = - TermsSet( - field = field.toString, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. - * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact - * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you - * can define the number of matching terms required to return a document. - * - * @param field - * the field for which query is specified for - * @param terms - * a list of terms that should be find in the provided field - * @param minimumShouldMatchScript - * custom script containing the number of matching terms required to return a document - * @tparam A - * the type of value to be matched. A JSON decoder must be provided in the scope for this type - * @return - * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. - */ - final def termsSetScript[A: ElasticPrimitive]( - field: String, - minimumShouldMatchScript: Script, - terms: A* - ): TermsSetQuery[Any] = - TermsSet( - field = field, - terms = Chunk.fromIterable(terms), - boost = None, - minimumShouldMatchField = None, - minimumShouldMatchScript = Some(minimumShouldMatchScript) - ) - - /** - * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the type-safe field for which query is specified for - * @param value - * text value that will be used for the query - * @tparam S - * document for which field query is executed - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = - Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) - - /** - * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. - * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided - * pattern value. - * - * @param field - * the field for which query is specified for - * @param value - * text value that will be used for the query - * @return - * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. - */ - final def wildcard(field: String, value: String): WildcardQuery[Any] = - Wildcard(field = field, value = value, boost = None, caseInsensitive = None) - -} +import zio.schema.Schema + +object ElasticQuery { + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + + final def boosting[S: Schema]( + negativeBoost: BoostRange, + negativeQuery: ElasticQuery[S], + positiveQuery: ElasticQuery[S] + ): BoostingQuery[S] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoostingQuery]] with queries that must satisfy the criteria + * using the specified parameters. [[zio.elasticsearch.query.BoostingQuery]] returns documents that match the query + * marked as positive while reducing the relevance score of documents that also match a query which is marked as + * negative query. + * + * @param negativeBoost + * the number between 0 and 1.0 used to decrease the relevance score of documents matching the negative query + * @param negativeQuery + * the query that decreases the relevance score of matching documents + * @param positiveQuery + * the query that must be satisfied + * @return + * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. + */ + final def boosting( + negativeBoost: BoostRange, + negativeQuery: ElasticQuery[Any], + positiveQuery: ElasticQuery[Any] + ): BoostingQuery[Any] = + Boosting(negativeBoost = negativeBoost, negativeQuery = negativeQuery, positiveQuery = positiveQuery) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @tparam S + * document for which field query is specified for. An implicit `Schema` instance must be provided in the scope + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] = + ConstantScore[S](query = query, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query. + * [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a + * relevance score equal to the boost parameter value. + * + * @param query + * query to be wrapped inside of constant score query + * @return + * an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query + * that must satisfy the criteria to be performed. + */ + final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] = + ConstantScore[Any](query = query, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `contains` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def contains(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"*$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax[S: Schema](query: ElasticQuery[S], queries: ElasticQuery[S]*): DisjunctionMaxQuery[S] = + DisjunctionMax[S](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.DisjunctionMax]] using the specified parameters. + * + * @param queries + * the rest of the queries to be wrapped inside of disjunction max query + * @return + * an instance of [[zio.elasticsearch.query.DisjunctionMax]] that represents the `disjunction max` query to be + * performed. + */ + final def disjunctionMax(query: ElasticQuery[Any], queries: ElasticQuery[Any]*): DisjunctionMaxQuery[Any] = + DisjunctionMax[Any](queries = query +: Chunk.fromIterable(queries), tieBreaker = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, + * using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists[S](field: Field[S, _]): ExistsQuery[S] = + Exists(field = field.toString, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ExistsQuery]], that checks existence of the field, using the + * specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.ExistsQuery]] that represents the exists query to be performed. + */ + final def exists(field: String): ExistsQuery[Any] = + Exists(field = field, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `filter` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def filter(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.fromIterable(queries), + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore[S: Schema]( + functions: FunctionScoreFunction[S]* + ): FunctionScoreQuery[S] = + FunctionScore[S]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FunctionScore]] query with one or multiple + * [[zio.elasticsearch.query.FunctionScoreFunction]]. + * + * @param functions + * [[zio.elasticsearch.query.FunctionScoreFunction]] functions that will be part of + * [[zio.elasticsearch.query.FunctionScore]] query + * @return + * an instance of [[zio.elasticsearch.query.FunctionScore]] that represents the Function Score Query with functions + * that are used to calculate score for result. + */ + final def functionScore( + functions: FunctionScoreFunction[Any]* + ): FunctionScoreQuery[Any] = + FunctionScore[Any]( + functionScoreFunctions = Chunk.fromIterable(functions), + boost = None, + boostMode = None, + maxBoost = None, + minScore = None, + query = None, + scoreMode = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy[S](field: Field[S, String], value: String): FuzzyQuery[S] = + Fuzzy(field = field.toString, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.FuzzyQuery]] using the specified parameters. + * [[zio.elasticsearch.query.FuzzyQuery]] returns documents that contain terms similar to the search term, as measured + * by a Levenshtein edit distance. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.FuzzyQuery]] that represents the `fuzzy` query to be performed. + */ + final def fuzzy(field: String, value: String): FuzzyQuery[Any] = + Fuzzy(field = field, value = value, fuzziness = None, maxExpansions = None, prefixLength = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe GeoPoint field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoPoint, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoPoint, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = s"${point.lat},${point.lon}", + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @tparam S + * the type of document on which the query is defined + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance[S](field: Field[S, GeoPoint], point: GeoHash, distance: Distance): GeoDistanceQuery[S] = + GeoDistance( + field = field.toString, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] using the specified parameters. + * + * @param field + * the field for which the query is specified + * @param point + * the geo-point from which the distance should be measured, defined as geo-hash + * @param distance + * the distance within which values should be matched + * @return + * an instance of [[zio.elasticsearch.query.GeoDistanceQuery]] that represents the `geo_distance` query to be + * performed. + */ + final def geoDistance(field: String, point: GeoHash, distance: Distance): GeoDistanceQuery[Any] = + GeoDistance( + field = field, + point = GeoHash.unwrap(point), + distance = distance, + distanceType = None, + queryName = None, + validationMethod = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon[S](field: Field[S, _], coordinates: Chunk[String]): GeoPolygonQuery[S] = + GeoPolygon( + field = field.toString, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @param coordinates + * list of longitudes and latitudes of the desired points written as string (e.g. ["40, 31", "25, 31"]) or geo hash + * (e.g. ["drm3btev3e86", "drm3btev3e87"]) + * @return + * an instance of [[zio.elasticsearch.query.GeoPolygonQuery]] that represents `geo_polygon` query to be performed. + */ + final def geoPolygon(field: String, coordinates: Chunk[String]): GeoPolygonQuery[Any] = + GeoPolygon( + field = field, + points = coordinates, + queryName = None, + validationMethod = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of + * the child `type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild[S: Schema](childType: String, query: ElasticQuery[S]): HasChildQuery[S] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasChildQuery]] using the specified parameters. + * + * @param childType + * a name of the child relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on child documents of the child + * `type` field + * @return + * an instance of [[zio.elasticsearch.query.HasChildQuery]] that represents the `has child query` to be performed. + */ + final def hasChild(childType: String, query: ElasticQuery[Any]): HasChildQuery[Any] = + HasChild( + childType = childType, + query = query, + ignoreUnmapped = None, + innerHitsField = None, + maxChildren = None, + minChildren = None, + scoreMode = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the type-safe [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of + * the `parent_type` field + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent[S: Schema](parentType: String, query: ElasticQuery[S]): HasParentQuery[S] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.HasParentQuery]] using the specified parameters. + * + * @param parentType + * a name of the parent relationship mapped for the join field + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing query you wish to run on parent documents of the + * `parent_type` field + * @return + * an instance of [[zio.elasticsearch.query.HasParentQuery]] that represents the has parent query to be performed. + */ + final def hasParent(parentType: String, query: ElasticQuery[Any]): HasParentQuery[Any] = + HasParent( + parentType = parentType, + query = query, + boost = None, + ignoreUnmapped = None, + innerHitsField = None, + score = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.IdsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.IdsQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param value + * value that will be used for the query + * @param values + * array of optional values that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.IdsQuery]] that represents the ids query to be performed. + */ + final def ids(value: String, values: String*): IdsQuery[Any] = + Ids(values = Chunk.fromIterable(value +: values)) + + /** + * Constructs a type-safe intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given type-safe field in the intervals query + * structure. + * + * @param field + * the type-safe field on which the query is executed. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @tparam S + * the document type for which the query is defined. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) + + /** + * Constructs an intervals query by combining a field and an interval query. + * + * The resulting query wraps the specified interval query under the given field in the intervals query structure. + * + * @param field + * the name of the field to be queried. + * @param rule + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * @return + * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. + */ + + final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the type-safe field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN[S](field: Field[S, _], k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[S] = + KNN(field = field.toString, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. + * [[zio.elasticsearch.query.KNNQuery]] is used to perform a k-nearest neighbor (kNN) search and returns the matching + * documents. + * + * @param field + * the field for which query is specified for + * @param k + * number of nearest neighbors to return as top hits (must be less than `numCandidates`) + * @param numCandidates + * number of nearest neighbor candidates to consider per shard + * @param queryVector + * query vector + * @return + * an instance of [[zio.elasticsearch.query.KNNQuery]] that represents the kNN query to be performed. + */ + final def kNN(field: String, k: Int, numCandidates: Int, queryVector: Chunk[Double]): KNNQuery[Any] = + KNN(field = field, k = k, numCandidates = numCandidates, queryVector = queryVector, similarity = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchAllQuery]] used for matching all documents. + * + * @return + * an instance of [[zio.elasticsearch.query.MatchAllQuery]] that represents the match all query to be performed. + */ + final def matchAll: MatchAllQuery = + MatchAll(boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]] query. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchBooleanPrefixQuery[S] = + MatchBooleanPrefix(field = field.toString, value, minimumShouldMatch = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] analyzes its input and constructs a + * [[zio.elasticsearch.query.BoolQuery]] from the terms. Each term except the last is used in a + * [[zio.elasticsearch.query.TermQuery]]. The last term is used in a [[zio.elasticsearch.query.PrefixQuery]]. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchBooleanPrefixQuery]] that represents the match boolean prefix query + * to be performed. + */ + final def matchBooleanPrefix[A: ElasticPrimitive](field: String, value: A): MatchBooleanPrefixQuery[Any] = + MatchBooleanPrefix(field = field, value = value, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[S, A: ElasticPrimitive](field: Field[S, A], value: A): MatchQuery[S] = + Match(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchQuery]] is used for matching a provided text, number, date or boolean value. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.MatchQuery]] that represents the match query to be performed. + */ + final def matches[A: ElasticPrimitive](field: String, value: A): MatchQuery[Any] = + Match(field = field, value = value) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase[S](field: Field[S, String], value: String): MatchPhraseQuery[S] = + MatchPhrase(field = field.toString, value = value, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhraseQuery]] analyzes the text and creates a phrase query out of the analyzed text. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the value to be matched, represented by an instance of type `A` + * @return + * an instance of [[zio.elasticsearch.query.MatchPhraseQuery]] that represents the match phrase query to be + * performed. + */ + final def matchPhrase(field: String, value: String): MatchPhraseQuery[Any] = + MatchPhrase(field = field, value = value, boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified + * parameters. [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a + * provided text, in the same order as provided. The last term of the provided text is treated as a prefix, matching + * any words that begin with that term. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * the text value to be matched + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix[S](field: Field[S, String], value: String): MatchPhrasePrefixQuery[S] = + MatchPhrasePrefix(field = field.toString, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] returns documents that contain the words of a provided text, in + * the same order as provided. The last term of the provided text is treated as a prefix, matching any words that + * begin with that term. + * + * @param field + * the field for which query is specified for + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MatchPhrasePrefixQuery]] that represents the match phrase prefix query + * to be performed. + */ + final def matchPhrasePrefix(field: String, value: String): MatchPhrasePrefixQuery[Any] = + MatchPhrasePrefix(field = field, value = value) + + /** + * Constructs an instance of [[zio.elasticsearch.query.MultiMatchQuery]] using the specified parameter. + * [[zio.elasticsearch.query.MultiMatchQuery]] query builds on the `match` query to allow multi-field queries. + * + * @param value + * the text value to be matched + * @return + * an instance of [[zio.elasticsearch.query.MultiMatchQuery]] that represents the multi match query to be performed. + */ + final def multiMatch(value: String): MultiMatchQuery[Any] = + MultiMatch(fields = Chunk.empty, value = value, boost = None, matchingType = None, minimumShouldMatch = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `must` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must + * satisfy the criteria. + */ + final def must(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.fromIterable(queries), + mustNot = Chunk.empty, + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the + * criteria using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that must not satisfy the criteria + * using the specified parameters. + * + * @param queries + * a list of queries to add to `mustNot` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that must not + * satisfy the criteria. + */ + final def mustNot(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.fromIterable(queries), + should = Chunk.empty, + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the type-safe path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested[S, A](path: Field[S, Seq[A]], query: ElasticQuery[A]): NestedQuery[S] = + Nested(path = path.toString, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.NestedQuery]] using the specified parameters. + * [[zio.elasticsearch.query.NestedQuery]] wraps another query to search nested fields. + * + * @param path + * the path to the field for which query is specified for + * @param query + * the [[zio.elasticsearch.ElasticQuery]] object representing the query to execute on nested objects. + * @return + * an instance of [[zio.elasticsearch.query.NestedQuery]] that represents the nested query to be performed. + */ + final def nested(path: String, query: ElasticQuery[_]): NestedQuery[Any] = + Nested(path = path, query = query, scoreMode = None, ignoreUnmapped = None, innerHitsField = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix[S](field: Field[S, String], value: String): PrefixQuery[S] = + Prefix(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.PrefixQuery]] using the specified parameters. + * [[zio.elasticsearch.query.PrefixQuery]] is used for matching documents that contain a specific prefix in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.PrefixQuery]] that represents the prefix query to be performed. + */ + final def prefix(field: String, value: String): Prefix[Any] = + Prefix(field = field, value = value, caseInsensitive = None) + + /** + * Constructs a type-safe unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the type-safe field for which query is specified for + * @tparam S + * document for which field query is executed + * @tparam A + * the type of the value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range[S, A](field: Field[S, A]): RangeQuery[S, A, Unbounded.type, Unbounded.type] = + Range.empty(field.toString) + + /** + * Constructs an unbounded instance of [[zio.elasticsearch.query.RangeQuery]] using the specified parameters. + * + * @param field + * the field for which query is specified for + * @return + * an instance of [[zio.elasticsearch.query.RangeQuery]] that represents the range query to be performed. + */ + final def range(field: String): RangeQuery[Any, Any, Unbounded.type, Unbounded.type] = + Range.empty[Any, Any](field = field) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * regular expression that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp[S](field: Field[S, String], value: String): RegexpQuery[S] = + Regexp(field = field.toString, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.RegexpQuery]] using the specified parameters. + * [[zio.elasticsearch.query.RegexpQuery]] returns documents that contain terms matching a regular expression. + * + * @param field + * the field for which query is specified for + * @param value + * regular expression that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.RegexpQuery]] that represents the regexp query to be performed. + */ + final def regexp(field: String, value: String): RegexpQuery[Any] = + Regexp(field = field, value = value, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.ScriptQuery]] with the provided script. + * @param script + * the script that is used by the query + * @return + * an instance of [[zio.elasticsearch.query.ScriptQuery]] that represents the script query to be performed. + */ + final def script(script: Script): ScriptQuery = + query.Script(script = script, boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @tparam S + * document for which field query is executed. An implicit `Schema` instance must be in scope + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should[S: Schema](queries: ElasticQuery[S]*): BoolQuery[S] = + Bool[S]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.BoolQuery]] with queries that should satisfy the criteria using + * the specified parameters. + * + * @param queries + * a list of queries to add to `should` inside of the `Bool` query + * @return + * an instance of [[zio.elasticsearch.query.BoolQuery]] that represents the bool query with queries that should + * satisfy the criteria. + */ + final def should(queries: ElasticQuery[Any]*): BoolQuery[Any] = + Bool[Any]( + filter = Chunk.empty, + must = Chunk.empty, + mustNot = Chunk.empty, + should = Chunk.fromIterable(queries), + boost = None, + minimumShouldMatch = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that starts with the + * specified value in the specified field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query in the pattern that represents `startsWith` + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def startsWith(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = s"$value*", boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[S, A: ElasticPrimitive](field: Field[S, A], value: A): TermQuery[S] = + Term(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermQuery]] is used for matching documents that contain an exact term in a provided + * field. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermQuery]] that represents the term query to be performed. + */ + final def term[A: ElasticPrimitive](field: String, value: A): TermQuery[Any] = + Term(field = field, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the type-safe field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[S, A: ElasticPrimitive](field: Field[S, A], values: A*): TermsQuery[S] = + Terms(field = field.toString, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsQuery]] is used for matching documents that contain one or more term in a provided + * field. The terms query is the same as [[zio.elasticsearch.query.TermQuery]], except you can search for multiple + * values. + * + * @param field + * the field for which query is specified for + * @param values + * a list of terms that should be find in the provided field + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsQuery]] that represents the terms query to be performed. + */ + final def terms[A: ElasticPrimitive](field: String, values: A*): TermsQuery[Any] = + Terms(field = field, values = Chunk.fromIterable(values), boost = None) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the type-safe field representing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchField: Field[S, _], + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField.toString), + minimumShouldMatchScript = None + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchField + * the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSet[A: ElasticPrimitive]( + field: String, + minimumShouldMatchField: String, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = Some(minimumShouldMatchField), + minimumShouldMatchScript = None + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the type-safe field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[S, A: ElasticPrimitive]( + field: Field[S, A], + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[S] = + TermsSet( + field = field.toString, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs an instance of [[zio.elasticsearch.query.TermsSetQuery]] using the specified parameters. + * [[zio.elasticsearch.query.TermsSetQuery]] is used for matching documents that contain the minimum amount of exact + * terms in a provided field. The terms set query is the same as [[zio.elasticsearch.query.TermsQuery]], except you + * can define the number of matching terms required to return a document. + * + * @param field + * the field for which query is specified for + * @param terms + * a list of terms that should be find in the provided field + * @param minimumShouldMatchScript + * custom script containing the number of matching terms required to return a document + * @tparam A + * the type of value to be matched. A JSON decoder must be provided in the scope for this type + * @return + * an instance of [[zio.elasticsearch.query.TermsSetQuery]] that represents the terms set query to be performed. + */ + final def termsSetScript[A: ElasticPrimitive]( + field: String, + minimumShouldMatchScript: Script, + terms: A* + ): TermsSetQuery[Any] = + TermsSet( + field = field, + terms = Chunk.fromIterable(terms), + boost = None, + minimumShouldMatchField = None, + minimumShouldMatchScript = Some(minimumShouldMatchScript) + ) + + /** + * Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the type-safe field for which query is specified for + * @param value + * text value that will be used for the query + * @tparam S + * document for which field query is executed + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard[S](field: Field[S, String], value: String): WildcardQuery[S] = + Wildcard(field = field.toString, value = value, boost = None, caseInsensitive = None) + + /** + * Constructs an instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters. + * [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that matches a provided + * pattern value. + * + * @param field + * the field for which query is specified for + * @param value + * text value that will be used for the query + * @return + * an instance of [[zio.elasticsearch.query.WildcardQuery]] that represents the wildcard query to be performed. + */ + final def wildcard(field: String, value: String): WildcardQuery[Any] = + Wildcard(field = field, value = value, boost = None, caseInsensitive = None) + +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 9717c2837..41889d9e4 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -1,22 +1,3 @@ -/* - * 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.query import zio.Chunk @@ -25,7 +6,7 @@ import zio.elasticsearch.Field import zio.elasticsearch.query.options._ import zio.elasticsearch.query.sort.options.HasFormat import zio.json.ast.Json -import zio.json.ast.Json.{Arr, Obj} +import zio.json.ast.Json.{Arr, Obj, Str} import zio.schema.Schema sealed trait ElasticQuery[-S] { self => @@ -131,6 +112,14 @@ sealed trait BoolQuery[S] extends ElasticQuery[S] with HasBoost[BoolQuery[S]] wi def should(queries: ElasticQuery[Any]*): BoolQuery[S] } +private[elasticsearch] final case class BoostRange(value: Float) { + def validate: Option[BoostRange] = + if (value >= 0 && value <= 1) Some(this) + else None + + def toJson: Json = Json.Str(value.toString) +} + private[elasticsearch] final case class Bool[S]( filter: Chunk[ElasticQuery[S]], must: Chunk[ElasticQuery[S]], @@ -188,13 +177,13 @@ private[elasticsearch] final case class Bool[S]( sealed trait BoostingQuery[S] extends ElasticQuery[S] private[elasticsearch] final case class Boosting[S]( - negativeBoost: Float, + negativeBoost: BoostRange, negativeQuery: ElasticQuery[S], positiveQuery: ElasticQuery[S] ) extends BoostingQuery[S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json = { - val negativeBoostJson = Obj("negative_boost" -> negativeBoost.toJson) + val negativeBoostJson = Obj("negative_boost" -> Str(negativeBoost.value.toString)) val negativeQueryJson = Obj("negative" -> negativeQuery.toJson(fieldPath)) val positiveQueryJson = Obj("positive" -> positiveQuery.toJson(fieldPath)) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala index 58987004b..e902c73f2 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -1,30 +1,16 @@ -/* - * 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.query.options - -private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { - - /** - * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. - * - * @param value - * the name of the field to use - * @return - * a new instance of the query with the `use_field` value set - */ - def useField(value: String): Q -} +package zio.elasticsearch.query.options + +import zio.elasticsearch.Field + +private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { + + /** + * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the field to use + * @return + * a new instance of the query with the `use_field` value set + */ + def useField(field: Field[_, _]): Q +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 38ed21e38..9c1177c12 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1,22 +1,3 @@ -/* - * 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 import zio.Chunk @@ -338,13 +319,15 @@ object ElasticQuerySpec extends ZIOSpecDefault { } ), test("boosting") { - val query = boosting(0.5f, exists("testField"), terms("booleanField", true, false)) - val queryTs = boosting(0.5f, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) + val validBoost = BoostRange(0.5f) + val query = boosting(validBoost, exists("testField"), terms("booleanField", true, false)) + val queryTs = + boosting(validBoost, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) assert(query)( equalTo( Boosting[Any]( - negativeBoost = 0.5f, + negativeBoost = validBoost, negativeQuery = exists("testField"), positiveQuery = terms("booleanField", true, false) ) @@ -352,7 +335,7 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) && assert(queryTs)( equalTo( Boosting[TestDocument]( - negativeBoost = 0.5f, + negativeBoost = validBoost, negativeQuery = exists(TestDocument.stringField), positiveQuery = terms(TestDocument.booleanField, true, false) ) @@ -2621,30 +2604,38 @@ object ElasticQuerySpec extends ZIOSpecDefault { } ), test("boosting") { - val query = boosting(0.5f, exists("stringField"), terms("booleanField", true, false)) - val queryTs = boosting(0.5f, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) + val boostRange = BoostRange(0.5f) + + val query = + boosting(boostRange, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) + + val queryTs = boosting(boostRange, exists("stringField"), terms("booleanField", true, false)) val expected = """ |{ | "boosting": { - | "positive": { - | "terms": { - | "booleanField": [ true, false ] - | } - | }, + | "negative_boost": "0.5", | "negative": { | "exists": { - | "field": "stringField" + | "field": "stringField" | } | }, - | "negative_boost": 0.5 + | "positive": { + | "terms": { + | "booleanField": [true, false] + | } + | } | } |} |""".stripMargin - assert(query.toJson(fieldPath = None))(equalTo(expected.toJson)) && - assert(queryTs.toJson(fieldPath = None))(equalTo(expected.toJson)) + assert(query.toJson(fieldPath = None))( + equalTo(expected.toJson) + ) && + assert(queryTs.toJson(fieldPath = None))( + equalTo(expected.toJson) + ) }, test("constantScore") { val query = constantScore(matchPhrase("stringField", "test")) From ca243e9240f76828a33c6696678a7883c96c83a0 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 13:51:38 +0200 Subject: [PATCH 17/41] Use fieldPath --- .../src/main/scala/zio/elasticsearch/query/Queries.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 41889d9e4..c852f994a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -783,7 +783,7 @@ private[elasticsearch] final case class Intervals[S]( private[elasticsearch] def toJson(fieldPath: Option[String]): Json = Obj( "intervals" -> Obj( - field -> query.toJson + fieldPath.fold(field)(_ + "." + field) -> query.toJson ) ) } From 640500dd30651d19b258e232e72f8cbebca6387f Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Tue, 17 Jun 2025 15:17:18 +0200 Subject: [PATCH 18/41] Implemented methods for gt,gte,lt,lte --- .../query/ElasticIntervalQuery.scala | 711 +++++++++--------- .../ElasticIntervalQuerySpec.scala | 65 +- 2 files changed, 397 insertions(+), 379 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala index b0cc61663..e7331e60b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala @@ -1,363 +1,356 @@ -/* - * 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.query - +package zio.elasticsearch.query + import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} -import zio.{Chunk, NonEmptyChunk} - -sealed trait IntervalRule { - private[elasticsearch] def toJson: Json -} -sealed trait BoundType -sealed trait Inclusive extends BoundType -sealed trait Exclusive extends BoundType - -case object InclusiveBound extends Inclusive -case object ExclusiveBound extends Exclusive - -final case class Bound[B <: BoundType](value: String, boundType: B) - -private[elasticsearch] final case class IntervalAllOf[S]( - intervals: Chunk[IntervalRule], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalRule { - - def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) - def orderedOn(): IntervalAllOf[S] = copy(ordered = Some(true)) - def orderedOff(): IntervalAllOf[S] = copy(ordered = Some(false)) - private[elasticsearch] def toJson: Json = - Obj( - "all_of" -> Obj( - Chunk( - Some("intervals" -> Arr(intervals.map(_.toJson): _*)), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalAnyOf[S]( - intervals: Chunk[IntervalRule], - filter: Option[IntervalFilter[S]] -) extends IntervalRule { self => - - def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) - - override private[elasticsearch] def toJson: Json = - Obj( - "any_of" -> Obj( - Chunk( - Some("intervals" -> Arr(intervals.map(_.toJson): _*)), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None -) { - private[elasticsearch] def toJson: Json = - Obj( - Chunk( - after.map("after" -> _.toJson), - before.map("before" -> _.toJson), - containedBy.map("contained_by" -> _.toJson), - containing.map("containing" -> _.toJson), - notContainedBy.map("not_contained_by" -> _.toJson), - notContaining.map("not_containing" -> _.toJson), - notOverlapping.map("not_overlapping" -> _.toJson), - overlapping.map("overlapping" -> _.toJson), - script.map("script" -> _) - ).flatten: _* - ) -} - -private[elasticsearch] final case class IntervalFuzzy[S]( - term: String, - prefixLength: Option[Int], - transpositions: Option[Boolean], - fuzziness: Option[String], - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalFuzzy[S]] - with HasUseField[IntervalFuzzy[S]] { - - override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalFuzzy[S] = copy(useField = Some(value)) - def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) - def transpositions(enabled: Boolean): IntervalFuzzy[S] = copy(transpositions = Some(enabled)) - - private[elasticsearch] def toJson: Json = - Obj( - "fuzzy" -> Obj( - Chunk( - Some("term" -> term.toJson), - prefixLength.map("prefix_length" -> _.toJson), - transpositions.map("transpositions" -> _.toJson), - fuzziness.map("fuzziness" -> _.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} -private[elasticsearch] final case class IntervalMatch[S]( - query: String, - analyzer: Option[String], - useField: Option[String], - maxGaps: Option[Int], - ordered: Option[Boolean], - filter: Option[IntervalFilter[S]] -) extends IntervalRule - with HasAnalyzer[IntervalMatch[S]] - with HasUseField[IntervalMatch[S]] { self => - - override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) - def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) - def orderedOn(): IntervalMatch[S] = copy(ordered = Some(true)) - def orderedOff(): IntervalMatch[S] = copy(ordered = Some(false)) - override def useField(value: String): IntervalMatch[S] = copy(useField = Some(value)) - - override private[elasticsearch] def toJson: Json = - Obj( - "match" -> Obj( - Chunk( - Some("query" -> Str(query)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson), - maxGaps.map("max_gaps" -> _.toJson), - ordered.map("ordered" -> _.toJson), - filter.map("filter" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalPrefix[S]( - prefix: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalPrefix[S]] - with HasUseField[IntervalPrefix[S]] { - - override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalPrefix[S] = copy(useField = Some(value)) - - override private[elasticsearch] def toJson: Json = - Obj( - "prefix" -> Obj( - Chunk( - Some("prefix" -> Str(prefix)), - analyzer.map(a => "analyzer" -> Str(a)), - useField.map(u => "use_field" -> Str(u)) - ).flatten: _* - ) - ) -} - -final case class IntervalRange[S]( - lower: Option[Bound[_ <: BoundType]] = None, - upper: Option[Bound[_ <: BoundType]] = None, - analyzer: Option[String] = None, - useField: Option[String] = None -) extends IntervalRule - with HasAnalyzer[IntervalRange[S]] - with HasUseField[IntervalRange[S]] { - - override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) - def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(b)) - def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(b)) - override def useField(value: String): IntervalRange[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = { - def boundToJson[B <: BoundType](bound: Bound[B], isLower: Boolean): (String, Json) = { - val key = ( - isLower, - bound.boundType match { - case InclusiveBound => true - case ExclusiveBound => false - } - ) match { - case (true, true) => "gte" - case (true, false) => "gt" - case (false, true) => "lte" - case (false, false) => "lt" - } - key -> Json.Str(bound.value) - } - - val lowerJson = lower.map(bound => boundToJson(bound, isLower = true)) - val upperJson = upper.map(bound => boundToJson(bound, isLower = false)) - - Obj( - "range" -> Obj( - Chunk( - lowerJson, - upperJson, - analyzer.map("analyzer" -> Str(_)), - useField.map("use_field" -> Str(_)) - ).flatten: _* - ) - ) - } -} - -private[elasticsearch] final case class IntervalRegexp[S]( - pattern: Regexp[S], - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalRegexp[S]] - with HasUseField[IntervalRegexp[S]] { - - override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalRegexp[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = - Obj( - "regexp" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson(None)), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -private[elasticsearch] final case class IntervalWildcard[S]( - pattern: String, - analyzer: Option[String], - useField: Option[String] -) extends IntervalRule - with HasAnalyzer[IntervalWildcard[S]] - with HasUseField[IntervalWildcard[S]] { - - override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) - override def useField(value: String): IntervalWildcard[S] = copy(useField = Some(value)) - - private[elasticsearch] def toJson: Json = - Obj( - "wildcard" -> Obj( - Chunk( - Some("pattern" -> pattern.toJson), - analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toJson) - ).flatten: _* - ) - ) -} - -object ElasticIntervalQuery { - - def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = - IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) - - def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = - IntervalAnyOf(intervals, filter = None) - - def intervalContains[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) - - def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - - def intervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None - ): Option[IntervalFilter[S]] = { - - val filter: IntervalFilter[S] = IntervalFilter( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ) - - val isEmpty = Seq( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ).forall(_.isEmpty) - - if (isEmpty) None else Some(filter) - } - - def intervalFuzzy[S](term: String): IntervalFuzzy[S] = - IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) - - def intervalMatch[S](query: String): IntervalMatch[S] = - IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) - - def intervalPrefix[S](prefix: String): IntervalPrefix[S] = - IntervalPrefix(prefix, analyzer = None, useField = None) - - def intervalRange[S, L <: BoundType, U <: BoundType]( - lower: Option[Bound[L]] = None, - upper: Option[Bound[U]] = None, - analyzer: Option[String] = None, - useField: Option[String] = None - ): IntervalRange[S] = - IntervalRange(lower, upper, analyzer, useField) - - def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = - IntervalRegexp(pattern, analyzer = None, useField = None) - - def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"$pattern*", analyzer = None, useField = None) - - def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern, analyzer = None, useField = None) -} +import zio.{Chunk, NonEmptyChunk} +import zio.elasticsearch.Field + +sealed trait BoundType +sealed trait Inclusive extends BoundType +sealed trait Exclusive extends BoundType + +case object InclusiveBound extends Inclusive +case object ExclusiveBound extends Exclusive + +final case class Bound[B <: BoundType](value: String, boundType: B) + +sealed trait IntervalRule { + private[elasticsearch] def toJson: Json +} + +final case class GreaterThanInterval(value: String) extends IntervalRule { + private[elasticsearch] def toJson: Json = Str(value) +} + +final case class GreaterThanOrEqualToInterval(value: String) extends IntervalRule { + private[elasticsearch] def toJson: Json = Str(value) +} + +final case class LessThanInterval(value: String) extends IntervalRule { + private[elasticsearch] def toJson: Json = Str(value) +} + +final case class LessThanOrEqualToInterval(value: String) extends IntervalRule { + private[elasticsearch] def toJson: Json = Str(value) +} + +private[elasticsearch] final case class IntervalAllOf[S]( + intervals: Chunk[IntervalRule], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { + + def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) + def orderedOn: IntervalAllOf[S] = copy(ordered = Some(true)) + def orderedOff: IntervalAllOf[S] = copy(ordered = Some(false)) + private[elasticsearch] def toJson: Json = + Obj( + "all_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalAnyOf[S]( + intervals: Chunk[IntervalRule], + filter: Option[IntervalFilter[S]] +) extends IntervalRule { self => + + def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) + + override private[elasticsearch] def toJson: Json = + Obj( + "any_of" -> Obj( + Chunk( + Some("intervals" -> Arr(intervals.map(_.toJson): _*)), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None +) { + private[elasticsearch] def toJson: Json = + Obj( + Chunk( + after.map("after" -> _.toJson), + before.map("before" -> _.toJson), + containedBy.map("contained_by" -> _.toJson), + containing.map("containing" -> _.toJson), + notContainedBy.map("not_contained_by" -> _.toJson), + notContaining.map("not_containing" -> _.toJson), + notOverlapping.map("not_overlapping" -> _.toJson), + overlapping.map("overlapping" -> _.toJson), + script.map("script" -> _) + ).flatten: _* + ) +} +private[elasticsearch] final case class IntervalFuzzy[S]( + term: String, + prefixLength: Option[Int], + transpositions: Option[Boolean], + fuzziness: Option[String], + analyzer: Option[String], + useField: Option[Field[_, _]] +) extends IntervalRule + with HasAnalyzer[IntervalFuzzy[S]] + with HasUseField[IntervalFuzzy[S]] { + + override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) + override def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field)) + def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + + def transpositionsEnabled: IntervalFuzzy[S] = copy(transpositions = Some(true)) + def transpositionsDisabled: IntervalFuzzy[S] = copy(transpositions = Some(false)) + + private[elasticsearch] def toJson: Json = + Obj( + "fuzzy" -> Obj( + Chunk( + Some("term" -> term.toJson), + prefixLength.map("prefix_length" -> _.toJson), + transpositions.map("transpositions" -> _.toJson), + fuzziness.map("fuzziness" -> _.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toString.toJson) + ).flatten: _* + ) + ) +} +private[elasticsearch] final case class IntervalMatch[S]( + query: String, + analyzer: Option[String], + useField: Option[Field[_, _]], + maxGaps: Option[Int], + ordered: Option[Boolean], + filter: Option[IntervalFilter[S]] +) extends IntervalRule + with HasAnalyzer[IntervalMatch[S]] + with HasUseField[IntervalMatch[S]] { self => + + override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) + def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) + def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) + def orderedOn: IntervalMatch[S] = copy(ordered = Some(true)) + def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) + override def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field)) + + override private[elasticsearch] def toJson: Json = + Obj( + "match" -> Obj( + Chunk( + Some("query" -> Str(query)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toString.toJson), + maxGaps.map("max_gaps" -> _.toJson), + ordered.map("ordered" -> _.toJson), + filter.map("filter" -> _.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalPrefix[S]( + prefix: String, + analyzer: Option[String], + useField: Option[Field[_, _]] +) extends IntervalRule + with HasAnalyzer[IntervalPrefix[S]] + with HasUseField[IntervalPrefix[S]] { + + override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) + override def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field)) + + override private[elasticsearch] def toJson: Json = + Obj( + "prefix" -> Obj( + Chunk( + Some("prefix" -> Str(prefix)), + analyzer.map(a => "analyzer" -> Str(a)), + useField.map("use_field" -> _.toString.toJson) + ).flatten: _* + ) + ) +} +private[elasticsearch] final case class IntervalRange[S]( + lower: Option[IntervalRule] = None, + upper: Option[IntervalRule] = None, + analyzer: Option[String] = None, + useField: Option[Field[_, _]] = None +) extends IntervalRule + with HasAnalyzer[IntervalRange[S]] + with HasUseField[IntervalRange[S]] { + + override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) + def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(b.value))) + def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) + override def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field)) + + def gte[B <: BoundType](value: String): IntervalRange[S] = + copy(lower = Some(GreaterThanOrEqualToInterval(value))) + + def gt[B <: BoundType](value: String): IntervalRange[S] = + copy(lower = Some(GreaterThanInterval(value))) + + def lte[B <: BoundType](value: String): IntervalRange[S] = + copy(upper = Some(LessThanOrEqualToInterval(value))) + + def lt[B <: BoundType](value: String): IntervalRange[S] = + copy(upper = Some(LessThanInterval(value))) + + private[elasticsearch] def toJson: Json = + Obj( + "range" -> Obj( + Chunk( + lower.map("gte" -> _.toJson), + upper.map("lte" -> _.toJson), + analyzer.map("analyzer" -> Str(_)), + useField.map("use_field" -> _.toString.toJson) + ).flatten: _* + ) + ) +} +private[elasticsearch] final case class IntervalRegexp[S]( + pattern: Regexp[S], + analyzer: Option[String], + useField: Option[Field[_, _]] +) extends IntervalRule + with HasAnalyzer[IntervalRegexp[S]] + with HasUseField[IntervalRegexp[S]] { + + override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) + override def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field)) + + private[elasticsearch] def toJson: Json = + Obj( + "regexp" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson(None)), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toString.toJson) + ).flatten: _* + ) + ) +} + +private[elasticsearch] final case class IntervalWildcard[S]( + pattern: String, + analyzer: Option[String], + useField: Option[Field[_, _]] +) extends IntervalRule + with HasAnalyzer[IntervalWildcard[S]] + with HasUseField[IntervalWildcard[S]] { + + override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) + override def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field)) + + private[elasticsearch] def toJson: Json = + Obj( + "wildcard" -> Obj( + Chunk( + Some("pattern" -> pattern.toJson), + analyzer.map("analyzer" -> _.toJson), + useField.map("use_field" -> _.toString.toJson) + ).flatten: _* + ) + ) +} + +object ElasticIntervalQuery { + + def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = + IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + + def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = + IntervalAnyOf(intervals, filter = None) + + def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + def intervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None + ): Option[IntervalFilter[S]] = { + + val filter: IntervalFilter[S] = IntervalFilter( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ) + + val isEmpty = Seq( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ).forall(_.isEmpty) + + if (isEmpty) None else Some(filter) + } + + def intervalFuzzy[S](term: String): IntervalFuzzy[S] = + IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) + + def intervalMatch[S](query: String): IntervalMatch[S] = + IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) + + def intervalPrefix[S](prefix: String): IntervalPrefix[S] = + IntervalPrefix(prefix, analyzer = None, useField = None) + + def intervalRange[S]( + lower: Option[IntervalRule] = None, + upper: Option[IntervalRule] = None, + analyzer: Option[String] = None, + useField: Option[Field[_, _]] = None + ): IntervalRange[S] = + IntervalRange(lower, upper, analyzer, useField) + + def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = + IntervalRegexp(pattern, analyzer = None, useField = None) + + def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + def intervalWildcard[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(pattern, analyzer = None, useField = None) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index 349086fe5..cf03d8dd3 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -11,6 +11,7 @@ import zio.elasticsearch.query.ElasticIntervalQuery.{ intervalWildcard } import zio.elasticsearch.query._ +import zio.elasticsearch.request.Document import zio.elasticsearch.utils._ import zio.test.Assertion.equalTo import zio.test._ @@ -21,8 +22,7 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { test("intervalMatchQuery") { val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") - val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works") - .orderedOn() + val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works").orderedOn .maxGaps(2) .analyzer("standard") @@ -31,8 +31,7 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { after = Some(intervalMatch("after_term")) ) - val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") - .orderedOff() + val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works").orderedOff .maxGaps(2) .analyzer("standard") .filter(filter) @@ -124,22 +123,30 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { ) }, test("intervalRange") { - val intervalWithBounds = intervalRange[Any, Inclusive, Exclusive]( - lower = Some(Bound("10", InclusiveBound)), - upper = Some(Bound("20", ExclusiveBound)), + val intervalWithBounds = intervalRange[Any]( + lower = Some(GreaterThanInterval("10")), + upper = Some(LessThanInterval("20")), analyzer = Some("standard"), - useField = Some("otherField") + useField = Some(TestDocument.stringField) ) - val intervalWithOnlyLower = intervalRange[Any, Inclusive, Inclusive]( - lower = Some(Bound("10", InclusiveBound)), + val intervalWithOnlyLower = intervalRange[Any]( + lower = Some(GreaterThanInterval("10")), upper = None, analyzer = Some("standard"), - useField = Some("otherField") + useField = Some(TestDocument.stringField) ) - val queryWithOnlyLower = intervals("stringField", intervalWithOnlyLower) - val queryWithBounds = intervals("stringField", intervalWithBounds) + val intervalWithOnlyUpper = intervalRange[Any]( + lower = None, + upper = Some(LessThanInterval("20")), + analyzer = Some("standard"), + useField = Some(TestDocument.stringField) + ) + + val queryWithBounds = intervals(TestDocument.stringField, intervalWithBounds) + val queryWithLower = intervals(TestDocument.stringField, intervalWithOnlyLower) + val queryWithUpper = intervals(TestDocument.stringField, intervalWithOnlyUpper) val expectedWithBounds = """ @@ -148,16 +155,16 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { | "stringField": { | "range": { | "gte": "10", - | "lt": "20", + | "lte": "20", | "analyzer": "standard", - | "use_field": "otherField" + | "use_field": "stringField" | } | } | } |} |""".stripMargin - val expectedWithOnlyLower = + val expectedWithLower = """ |{ | "intervals": { @@ -165,18 +172,36 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { | "range": { | "gte": "10", | "analyzer": "standard", - | "use_field": "otherField" + | "use_field": "stringField" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithUpper = + """ + |{ + | "intervals": { + | "stringField": { + | "range": { + | "lte": "20", + | "analyzer": "standard", + | "use_field": "stringField" | } | } | } |} |""".stripMargin - assert(queryWithOnlyLower.toJson(None))( - equalTo(expectedWithOnlyLower.toJson) - ) && assert(queryWithBounds.toJson(None))( equalTo(expectedWithBounds.toJson) + ) && + assert(queryWithLower.toJson(None))( + equalTo(expectedWithLower.toJson) + ) && + assert(queryWithUpper.toJson(None))( + equalTo(expectedWithUpper.toJson) ) }, test("intervalWildcard") { From 6308187be90d95ad3067a234d6906e4436c3d8ff Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 11:44:33 +0200 Subject: [PATCH 19/41] Fix PR comments --- docs/overview/elastic_interval_query.md | 18 +-- .../zio/elasticsearch/HttpExecutorSpec.scala | 5 +- .../zio/elasticsearch/ElasticQuery.scala | 16 +- ...lQuery.scala => ElasticIntervalRule.scala} | 149 +++++++++++------- .../zio/elasticsearch/query/Queries.scala | 4 +- .../query/options/HasAnalyzer.scala | 63 ++++---- .../query/options/HasUseField.scala | 2 +- 7 files changed, 139 insertions(+), 118 deletions(-) rename modules/library/src/main/scala/zio/elasticsearch/query/{ElasticIntervalQuery.scala => ElasticIntervalRule.scala} (70%) diff --git a/docs/overview/elastic_interval_query.md b/docs/overview/elastic_interval_query.md index f1009a78f..b7b15029a 100644 --- a/docs/overview/elastic_interval_query.md +++ b/docs/overview/elastic_interval_query.md @@ -2,67 +2,57 @@ id: elastic_interval_query title: "Overview" --- - -The `IntervalQuery` allows for advanced search queries based on intervals between words in specific fields. +The `Intervals` query allows for advanced search queries based on intervals between words in specific fields. This query provides flexibility for conditions. -To use the `IntervalQuery`, import the following: - +To use the `Intervals` query, import the following: ```scala import zio.elasticsearch.query.IntervalQuery import zio.elasticsearch.ElasticQuery._ ``` -You can create a basic `IntervalQuery` using the `intervals` method: - +You can create a basic `Intervals` query` using the `intervals` method: ```scala val query: IntervalQuery[Any] = intervals(field = "content", rule = intervalMatch("targetWord")) ``` If you want to specify which fields should be searched, you can use the `useField` method: - ```scala val queryWithField: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) ``` -To define `fields` in a type-safe manner, use the overloaded `useField` method with field definitions from your document: - +To define `field` in a type-safe manner, use the overloaded `useField` method with field definitions from your document: ```scala val queryWithSafeField: IntervalQuery[Document] = intervals(field = Document.stringField, rule = intervalMatch("targetWord")) ``` Alternatively, you can pass a `Field` object directly: - ```scala val queryWithFieldObject: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) ``` If you want to define the `maxGaps` parameter, use the `maxGaps` method: - ```scala val queryWithMaxGaps: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").maxGaps(2)) ``` If you want to specify the word order requirement, use the `orderedOn` method: - ```scala val queryWithOrder: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").orderedOn()) ``` You can also apply additional filters to the query: - ```scala val queryWithFilter: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").filter(IntervalFilter.someFilter)) ``` Alternatively, you can construct the query manually with all parameters: - ```scala val queryManually: IntervalQuery[Document] = IntervalQuery( diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 40adb5e83..8bbc43f43 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -2764,9 +2764,8 @@ object HttpExecutorSpec extends IntegrationSpec { (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") val docShouldNotMatch = docNoMatch.copy(stringField = "completely unrelated text") - - val field = TestDocument.stringField.toString - val query = intervals(field, intervalMatch(targetWord)) + val field = TestDocument.stringField.toString + val query = intervals(field, intervalMatch(targetWord)) for { _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 20a576c1f..2d6cc73db 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -534,21 +534,20 @@ object ElasticQuery { Ids(values = Chunk.fromIterable(value +: values)) /** - * Constructs a type-safe intervals query by combining a field and an interval query. + * Constructs a type-safe intervals query by combining a field and an interval rule. * * The resulting query wraps the specified interval query under the given type-safe field in the intervals query * structure. * * @param field - * the type-safe field on which the query is executed. + * the type-safe field on which the query is executed * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule * @tparam S - * the document type for which the query is defined. + * the document type for which the query is defined * @return * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ - final def intervals[S](field: Field[S, _], rule: IntervalRule): ElasticQuery[S] = Intervals(field.toString, rule) /** @@ -557,14 +556,13 @@ object ElasticQuery { * The resulting query wraps the specified interval query under the given field in the intervals query structure. * * @param field - * the name of the field to be queried. + * the name of the field to be queried * @param rule - * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule. + * an instance of [[zio.elasticsearch.query.IntervalRule]] representing the interval query rule * @return * an [[zio.elasticsearch.ElasticQuery]] instance representing the intervals query. */ - - final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field, rule) + final def intervals(field: String, rule: IntervalRule): ElasticQuery[Any] = Intervals(field = field, rule = rule) /** * Constructs a type-safe instance of [[zio.elasticsearch.query.KNNQuery]] using the specified parameters. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala similarity index 70% rename from modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala rename to modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index e7331e60b..ac9ae19ac 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -14,25 +14,25 @@ sealed trait Exclusive extends BoundType case object InclusiveBound extends Inclusive case object ExclusiveBound extends Exclusive -final case class Bound[B <: BoundType](value: String, boundType: B) +private[elasticsearch] final case class Bound[B <: BoundType](value: String, boundType: B) sealed trait IntervalRule { private[elasticsearch] def toJson: Json } -final case class GreaterThanInterval(value: String) extends IntervalRule { +private[elasticsearch] final case class GreaterThanInterval(value: String) extends IntervalRule { private[elasticsearch] def toJson: Json = Str(value) } -final case class GreaterThanOrEqualToInterval(value: String) extends IntervalRule { +private[elasticsearch] final case class GreaterThanOrEqualToInterval(value: String) extends IntervalRule { private[elasticsearch] def toJson: Json = Str(value) } -final case class LessThanInterval(value: String) extends IntervalRule { +private[elasticsearch] final case class LessThanInterval(value: String) extends IntervalRule { private[elasticsearch] def toJson: Json = Str(value) } -final case class LessThanOrEqualToInterval(value: String) extends IntervalRule { +private[elasticsearch] final case class LessThanOrEqualToInterval(value: String) extends IntervalRule { private[elasticsearch] def toJson: Json = Str(value) } @@ -44,10 +44,14 @@ private[elasticsearch] final case class IntervalAllOf[S]( ) extends IntervalRule { def filter(f: IntervalFilter[S]): IntervalAllOf[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) - def orderedOn: IntervalAllOf[S] = copy(ordered = Some(true)) - def orderedOff: IntervalAllOf[S] = copy(ordered = Some(false)) - private[elasticsearch] def toJson: Json = + + def maxGaps(g: Int): IntervalAllOf[S] = copy(maxGaps = Some(g)) + + def orderedOn: IntervalAllOf[S] = copy(ordered = Some(true)) + + def orderedOff: IntervalAllOf[S] = copy(ordered = Some(false)) + + private[elasticsearch] def toJson: Json = Obj( "all_of" -> Obj( Chunk( @@ -104,6 +108,7 @@ private[elasticsearch] final case class IntervalFilter[S]( ).flatten: _* ) } + private[elasticsearch] final case class IntervalFuzzy[S]( term: String, prefixLength: Option[Int], @@ -115,11 +120,14 @@ private[elasticsearch] final case class IntervalFuzzy[S]( with HasAnalyzer[IntervalFuzzy[S]] with HasUseField[IntervalFuzzy[S]] { - override def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - override def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field)) - def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) + + def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field)) + + def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + + def transpositionsEnabled: IntervalFuzzy[S] = copy(transpositions = Some(true)) - def transpositionsEnabled: IntervalFuzzy[S] = copy(transpositions = Some(true)) def transpositionsDisabled: IntervalFuzzy[S] = copy(transpositions = Some(false)) private[elasticsearch] def toJson: Json = @@ -136,6 +144,7 @@ private[elasticsearch] final case class IntervalFuzzy[S]( ) ) } + private[elasticsearch] final case class IntervalMatch[S]( query: String, analyzer: Option[String], @@ -147,12 +156,17 @@ private[elasticsearch] final case class IntervalMatch[S]( with HasAnalyzer[IntervalMatch[S]] with HasUseField[IntervalMatch[S]] { self => - override def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) - def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) - def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) - def orderedOn: IntervalMatch[S] = copy(ordered = Some(true)) - def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) - override def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field)) + def analyzer(value: String): IntervalMatch[S] = copy(analyzer = Some(value)) + + def filter(f: IntervalFilter[S]): IntervalMatch[S] = copy(filter = Some(f)) + + def maxGaps(g: Int): IntervalMatch[S] = copy(maxGaps = Some(g)) + + def orderedOn: IntervalMatch[S] = copy(ordered = Some(true)) + + def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) + + def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field)) override private[elasticsearch] def toJson: Json = Obj( @@ -177,8 +191,9 @@ private[elasticsearch] final case class IntervalPrefix[S]( with HasAnalyzer[IntervalPrefix[S]] with HasUseField[IntervalPrefix[S]] { - override def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) - override def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field)) + def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) + + def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field)) override private[elasticsearch] def toJson: Json = Obj( @@ -191,6 +206,7 @@ private[elasticsearch] final case class IntervalPrefix[S]( ) ) } + private[elasticsearch] final case class IntervalRange[S]( lower: Option[IntervalRule] = None, upper: Option[IntervalRule] = None, @@ -200,10 +216,13 @@ private[elasticsearch] final case class IntervalRange[S]( with HasAnalyzer[IntervalRange[S]] with HasUseField[IntervalRange[S]] { - override def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) - def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(b.value))) - def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) - override def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field)) + def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) + + def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(b.value))) + + def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) + + def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field)) def gte[B <: BoundType](value: String): IntervalRange[S] = copy(lower = Some(GreaterThanOrEqualToInterval(value))) @@ -229,6 +248,7 @@ private[elasticsearch] final case class IntervalRange[S]( ) ) } + private[elasticsearch] final case class IntervalRegexp[S]( pattern: Regexp[S], analyzer: Option[String], @@ -237,8 +257,9 @@ private[elasticsearch] final case class IntervalRegexp[S]( with HasAnalyzer[IntervalRegexp[S]] with HasUseField[IntervalRegexp[S]] { - override def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) - override def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field)) + def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) + + def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -260,8 +281,9 @@ private[elasticsearch] final case class IntervalWildcard[S]( with HasAnalyzer[IntervalWildcard[S]] with HasUseField[IntervalWildcard[S]] { - override def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) - override def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field)) + def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) + + def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -278,10 +300,10 @@ private[elasticsearch] final case class IntervalWildcard[S]( object ElasticIntervalQuery { def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = - IntervalAllOf(intervals, maxGaps = None, ordered = None, filter = None) + IntervalAllOf(intervals = intervals, maxGaps = None, ordered = None, filter = None) def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = - IntervalAnyOf(intervals, filter = None) + IntervalAnyOf(intervals = intervals, filter = None) def intervalContains[S](pattern: String): IntervalWildcard[S] = IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) @@ -302,40 +324,49 @@ object ElasticIntervalQuery { ): Option[IntervalFilter[S]] = { val filter: IntervalFilter[S] = IntervalFilter( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script + after = after, + before = before, + containedBy = containedBy, + containing = containing, + notContainedBy = notContainedBy, + notContaining = notContaining, + notOverlapping = notOverlapping, + overlapping = overlapping, + script = script ) - val isEmpty = Seq( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ).forall(_.isEmpty) - - if (isEmpty) None else Some(filter) + if ( + List( + after, + before, + containedBy, + containing, + notContainedBy, + notContaining, + notOverlapping, + overlapping, + script + ).forall(_.isEmpty) + ) None + else Some(filter) + } def intervalFuzzy[S](term: String): IntervalFuzzy[S] = - IntervalFuzzy(term, prefixLength = None, transpositions = None, fuzziness = None, analyzer = None, useField = None) + IntervalFuzzy( + term = term, + prefixLength = None, + transpositions = None, + fuzziness = None, + analyzer = None, + useField = None + ) def intervalMatch[S](query: String): IntervalMatch[S] = - IntervalMatch(query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) + IntervalMatch(query = query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) def intervalPrefix[S](prefix: String): IntervalPrefix[S] = - IntervalPrefix(prefix, analyzer = None, useField = None) + IntervalPrefix(prefix = prefix, analyzer = None, useField = None) def intervalRange[S]( lower: Option[IntervalRule] = None, @@ -343,14 +374,14 @@ object ElasticIntervalQuery { analyzer: Option[String] = None, useField: Option[Field[_, _]] = None ): IntervalRange[S] = - IntervalRange(lower, upper, analyzer, useField) + IntervalRange(lower = lower, upper = upper, analyzer = analyzer, useField = useField) def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = - IntervalRegexp(pattern, analyzer = None, useField = None) + IntervalRegexp(pattern = pattern, analyzer = None, useField = None) def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = IntervalWildcard(s"$pattern*", analyzer = None, useField = None) def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern, analyzer = None, useField = None) + IntervalWildcard(pattern = pattern, analyzer = None, useField = None) } diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index c852f994a..2c3cbf83f 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -777,13 +777,13 @@ sealed trait IntervalsQuery[S] extends ElasticQuery[S] private[elasticsearch] final case class Intervals[S]( field: String, - query: IntervalRule + rule: IntervalRule ) extends IntervalsQuery[S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json = Obj( "intervals" -> Obj( - fieldPath.fold(field)(_ + "." + field) -> query.toJson + fieldPath.fold(field)(_ + "." + field) -> rule.toJson ) ) } diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala index 4afe494c6..1657e021a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala @@ -1,30 +1,33 @@ -/* - * 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.query.options - -private[elasticsearch] trait HasAnalyzer[Q <: HasAnalyzer[Q]] { - - /** - * Sets the `analyzer` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. - * - * @param value - * the name of the analyzer to use - * @return - * a new instance of the query with the `analyzer` value set - */ - def analyzer(value: String): Q -} +/* + * 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.query.options + +private[elasticsearch] trait HasAnalyzer[Q <: HasAnalyzer[Q]] { + + /** + * Sets the `analyzer` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. + * + * @param value + * the name of the analyzer to use + * @return + * a new instance of the query with the `analyzer` value set. + */ + def analyzer(value: String): Q +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala index e902c73f2..4e045c9ac 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -10,7 +10,7 @@ private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { * @param value * the name of the field to use * @return - * a new instance of the query with the `use_field` value set + * a new instance of the query with the `use_field` value set. */ def useField(field: Field[_, _]): Q } From 41df1981e900b954f67c70df607786fbe9e6dc06 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 12:52:08 +0200 Subject: [PATCH 20/41] Revert boost, add another type parameter into HasUseField --- .../zio/elasticsearch/HttpExecutorSpec.scala | 5 +-- .../zio/elasticsearch/ElasticQuery.scala | 4 +- .../query/ElasticIntervalRule.scala | 40 ++++++++++++------- .../zio/elasticsearch/query/Queries.scala | 14 ++----- .../query/options/HasUseField.scala | 14 ++++++- .../ElasticIntervalQuerySpec.scala | 7 ++-- .../zio/elasticsearch/ElasticQuerySpec.scala | 38 +++++++----------- 7 files changed, 62 insertions(+), 60 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 8bbc43f43..cd8ef8c50 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -3,7 +3,6 @@ package zio.elasticsearch import zio.Chunk import zio.elasticsearch.ElasticAggregation._ import zio.elasticsearch.ElasticHighlight.highlight -import zio.elasticsearch.ElasticQuery.{script => _, _} import zio.elasticsearch.ElasticQuery.{contains => _, _} import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.aggregation.AggregationOrder @@ -17,7 +16,7 @@ import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max import zio.elasticsearch.query.sort.SortOrder._ import zio.elasticsearch.query.sort.SourceType.NumberType -import zio.elasticsearch.query.{BoostRange, Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} +import zio.elasticsearch.query.{Distance, FunctionScoreBoostMode, FunctionScoreFunction, InnerHits} import zio.elasticsearch.request.{CreationOutcome, DeletionOutcome} import zio.elasticsearch.result.{FilterAggregationResult, Item, MaxAggregationResult, UpdateByQueryResult} import zio.elasticsearch.script.{Painless, Script} @@ -1114,7 +1113,7 @@ object HttpExecutorSpec extends IntegrationSpec { .refreshTrue ) query = boosting( - negativeBoost = BoostRange(0.1f), + negativeBoost = 0.1f, negativeQuery = term(field = TestDocument.stringField, value = firstDocument.stringField.toLowerCase), positiveQuery = matchPhrase( diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 2d6cc73db..d503cdbb6 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -28,7 +28,7 @@ object ElasticQuery { */ final def boosting[S: Schema]( - negativeBoost: BoostRange, + negativeBoost: Float, negativeQuery: ElasticQuery[S], positiveQuery: ElasticQuery[S] ): BoostingQuery[S] = @@ -50,7 +50,7 @@ object ElasticQuery { * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. */ final def boosting( - negativeBoost: BoostRange, + negativeBoost: Float, negativeQuery: ElasticQuery[Any], positiveQuery: ElasticQuery[Any] ): BoostingQuery[Any] = diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index ac9ae19ac..a4bf78234 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -1,11 +1,11 @@ package zio.elasticsearch.query import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps +import zio.elasticsearch.Field import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} import zio.{Chunk, NonEmptyChunk} -import zio.elasticsearch.Field sealed trait BoundType sealed trait Inclusive extends BoundType @@ -115,14 +115,16 @@ private[elasticsearch] final case class IntervalFuzzy[S]( transpositions: Option[Boolean], fuzziness: Option[String], analyzer: Option[String], - useField: Option[Field[_, _]] + useField: Option[String] ) extends IntervalRule with HasAnalyzer[IntervalFuzzy[S]] with HasUseField[IntervalFuzzy[S]] { def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalFuzzy[S] = copy(useField = Some(Field(None, field).toString)) def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) @@ -148,7 +150,7 @@ private[elasticsearch] final case class IntervalFuzzy[S]( private[elasticsearch] final case class IntervalMatch[S]( query: String, analyzer: Option[String], - useField: Option[Field[_, _]], + useField: Option[String], maxGaps: Option[Int], ordered: Option[Boolean], filter: Option[IntervalFilter[S]] @@ -166,7 +168,9 @@ private[elasticsearch] final case class IntervalMatch[S]( def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) - def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalMatch[S] = copy(useField = Some(Field(None, field).toString)) override private[elasticsearch] def toJson: Json = Obj( @@ -186,14 +190,16 @@ private[elasticsearch] final case class IntervalMatch[S]( private[elasticsearch] final case class IntervalPrefix[S]( prefix: String, analyzer: Option[String], - useField: Option[Field[_, _]] + useField: Option[String] ) extends IntervalRule with HasAnalyzer[IntervalPrefix[S]] with HasUseField[IntervalPrefix[S]] { def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalPrefix[S] = copy(useField = Some(Field(None, field).toString)) override private[elasticsearch] def toJson: Json = Obj( @@ -211,7 +217,7 @@ private[elasticsearch] final case class IntervalRange[S]( lower: Option[IntervalRule] = None, upper: Option[IntervalRule] = None, analyzer: Option[String] = None, - useField: Option[Field[_, _]] = None + useField: Option[String] = None ) extends IntervalRule with HasAnalyzer[IntervalRange[S]] with HasUseField[IntervalRange[S]] { @@ -222,7 +228,9 @@ private[elasticsearch] final case class IntervalRange[S]( def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) - def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalRange[S] = copy(useField = Some(Field(None, field).toString)) def gte[B <: BoundType](value: String): IntervalRange[S] = copy(lower = Some(GreaterThanOrEqualToInterval(value))) @@ -252,14 +260,16 @@ private[elasticsearch] final case class IntervalRange[S]( private[elasticsearch] final case class IntervalRegexp[S]( pattern: Regexp[S], analyzer: Option[String], - useField: Option[Field[_, _]] + useField: Option[String] ) extends IntervalRule with HasAnalyzer[IntervalRegexp[S]] with HasUseField[IntervalRegexp[S]] { def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalRegexp[S] = copy(useField = Some(Field(None, field).toString)) private[elasticsearch] def toJson: Json = Obj( @@ -276,14 +286,16 @@ private[elasticsearch] final case class IntervalRegexp[S]( private[elasticsearch] final case class IntervalWildcard[S]( pattern: String, analyzer: Option[String], - useField: Option[Field[_, _]] + useField: Option[String] ) extends IntervalRule with HasAnalyzer[IntervalWildcard[S]] with HasUseField[IntervalWildcard[S]] { def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field)) + def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field.toString)) + + def useField(field: String): IntervalWildcard[S] = copy(useField = Some(Field(None, field).toString)) private[elasticsearch] def toJson: Json = Obj( @@ -372,7 +384,7 @@ object ElasticIntervalQuery { lower: Option[IntervalRule] = None, upper: Option[IntervalRule] = None, analyzer: Option[String] = None, - useField: Option[Field[_, _]] = None + useField: Option[String] = None ): IntervalRange[S] = IntervalRange(lower = lower, upper = upper, analyzer = analyzer, useField = useField) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 2c3cbf83f..bea600a6d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -6,7 +6,7 @@ import zio.elasticsearch.Field import zio.elasticsearch.query.options._ import zio.elasticsearch.query.sort.options.HasFormat import zio.json.ast.Json -import zio.json.ast.Json.{Arr, Obj, Str} +import zio.json.ast.Json.{Arr, Obj} import zio.schema.Schema sealed trait ElasticQuery[-S] { self => @@ -112,14 +112,6 @@ sealed trait BoolQuery[S] extends ElasticQuery[S] with HasBoost[BoolQuery[S]] wi def should(queries: ElasticQuery[Any]*): BoolQuery[S] } -private[elasticsearch] final case class BoostRange(value: Float) { - def validate: Option[BoostRange] = - if (value >= 0 && value <= 1) Some(this) - else None - - def toJson: Json = Json.Str(value.toString) -} - private[elasticsearch] final case class Bool[S]( filter: Chunk[ElasticQuery[S]], must: Chunk[ElasticQuery[S]], @@ -177,13 +169,13 @@ private[elasticsearch] final case class Bool[S]( sealed trait BoostingQuery[S] extends ElasticQuery[S] private[elasticsearch] final case class Boosting[S]( - negativeBoost: BoostRange, + negativeBoost: Float, negativeQuery: ElasticQuery[S], positiveQuery: ElasticQuery[S] ) extends BoostingQuery[S] { self => private[elasticsearch] def toJson(fieldPath: Option[String]): Json = { - val negativeBoostJson = Obj("negative_boost" -> Str(negativeBoost.value.toString)) + val negativeBoostJson = Obj("negative_boost" -> negativeBoost.toJson) val negativeQueryJson = Obj("negative" -> negativeQuery.toJson(fieldPath)) val positiveQueryJson = Obj("positive" -> positiveQuery.toJson(fieldPath)) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala index 4e045c9ac..70cfd184a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -7,10 +7,20 @@ private[elasticsearch] trait HasUseField[Q <: HasUseField[Q]] { /** * Sets the `use_field` parameter for this [[zio.elasticsearch.query.ElasticIntervalQuery]] query. * - * @param value - * the name of the field to use + * @param field + * the type-safe field to use from the document definition * @return * a new instance of the query with the `use_field` value set. */ def useField(field: Field[_, _]): Q + + /** + * Sets the `use_field` parameter using a plain string. + * + * @param field + * the name of the field as a string + * @return + * a new instance of the query with the `use_field` value set. + */ + def useField(field: String): Q } diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index cf03d8dd3..a0e6fc2ed 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -11,7 +11,6 @@ import zio.elasticsearch.query.ElasticIntervalQuery.{ intervalWildcard } import zio.elasticsearch.query._ -import zio.elasticsearch.request.Document import zio.elasticsearch.utils._ import zio.test.Assertion.equalTo import zio.test._ @@ -127,21 +126,21 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { lower = Some(GreaterThanInterval("10")), upper = Some(LessThanInterval("20")), analyzer = Some("standard"), - useField = Some(TestDocument.stringField) + useField = Some("stringField") ) val intervalWithOnlyLower = intervalRange[Any]( lower = Some(GreaterThanInterval("10")), upper = None, analyzer = Some("standard"), - useField = Some(TestDocument.stringField) + useField = Some("stringField") ) val intervalWithOnlyUpper = intervalRange[Any]( lower = None, upper = Some(LessThanInterval("20")), analyzer = Some("standard"), - useField = Some(TestDocument.stringField) + useField = Some("stringField") ) val queryWithBounds = intervals(TestDocument.stringField, intervalWithBounds) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 9c1177c12..a007b525a 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -319,15 +319,13 @@ object ElasticQuerySpec extends ZIOSpecDefault { } ), test("boosting") { - val validBoost = BoostRange(0.5f) - val query = boosting(validBoost, exists("testField"), terms("booleanField", true, false)) - val queryTs = - boosting(validBoost, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) + val query = boosting(0.5f, exists("testField"), terms("booleanField", true, false)) + val queryTs = boosting(0.5f, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) assert(query)( equalTo( Boosting[Any]( - negativeBoost = validBoost, + negativeBoost = 0.5f, negativeQuery = exists("testField"), positiveQuery = terms("booleanField", true, false) ) @@ -335,7 +333,7 @@ object ElasticQuerySpec extends ZIOSpecDefault { ) && assert(queryTs)( equalTo( Boosting[TestDocument]( - negativeBoost = validBoost, + negativeBoost = 0.5f, negativeQuery = exists(TestDocument.stringField), positiveQuery = terms(TestDocument.booleanField, true, false) ) @@ -2604,38 +2602,30 @@ object ElasticQuerySpec extends ZIOSpecDefault { } ), test("boosting") { - val boostRange = BoostRange(0.5f) - - val query = - boosting(boostRange, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) - - val queryTs = boosting(boostRange, exists("stringField"), terms("booleanField", true, false)) + val query = boosting(0.5f, exists("stringField"), terms("booleanField", true, false)) + val queryTs = boosting(0.5f, exists(TestDocument.stringField), terms(TestDocument.booleanField, true, false)) val expected = """ |{ | "boosting": { - | "negative_boost": "0.5", + | "positive": { + | "terms": { + | "booleanField": [true, false] + | } + | }, | "negative": { | "exists": { | "field": "stringField" | } | }, - | "positive": { - | "terms": { - | "booleanField": [true, false] - | } - | } + | "negative_boost": 0.5 | } |} |""".stripMargin - assert(query.toJson(fieldPath = None))( - equalTo(expected.toJson) - ) && - assert(queryTs.toJson(fieldPath = None))( - equalTo(expected.toJson) - ) + assert(query.toJson(fieldPath = None))(equalTo(expected.toJson)) && + assert(queryTs.toJson(fieldPath = None))(equalTo(expected.toJson)) }, test("constantScore") { val query = constantScore(matchPhrase("stringField", "test")) From f7cb287cd1d188b3084b4a3a0f273e6713d37a62 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 12:58:04 +0200 Subject: [PATCH 21/41] Fix some warnings about casting. --- .../elasticsearch/query/ElasticIntervalRule.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index a4bf78234..5b19a720d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -141,7 +141,7 @@ private[elasticsearch] final case class IntervalFuzzy[S]( transpositions.map("transpositions" -> _.toJson), fuzziness.map("fuzziness" -> _.toJson), analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toString.toJson) + useField.map("use_field" -> _.toJson) ).flatten: _* ) ) @@ -178,7 +178,7 @@ private[elasticsearch] final case class IntervalMatch[S]( Chunk( Some("query" -> Str(query)), analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toString.toJson), + useField.map("use_field" -> _.toJson), maxGaps.map("max_gaps" -> _.toJson), ordered.map("ordered" -> _.toJson), filter.map("filter" -> _.toJson) @@ -207,7 +207,7 @@ private[elasticsearch] final case class IntervalPrefix[S]( Chunk( Some("prefix" -> Str(prefix)), analyzer.map(a => "analyzer" -> Str(a)), - useField.map("use_field" -> _.toString.toJson) + useField.map("use_field" -> _.toJson) ).flatten: _* ) ) @@ -251,7 +251,7 @@ private[elasticsearch] final case class IntervalRange[S]( lower.map("gte" -> _.toJson), upper.map("lte" -> _.toJson), analyzer.map("analyzer" -> Str(_)), - useField.map("use_field" -> _.toString.toJson) + useField.map("use_field" -> _.toJson) ).flatten: _* ) ) @@ -277,7 +277,7 @@ private[elasticsearch] final case class IntervalRegexp[S]( Chunk( Some("pattern" -> pattern.toJson(None)), analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toString.toJson) + useField.map("use_field" -> _.toJson) ).flatten: _* ) ) @@ -303,7 +303,7 @@ private[elasticsearch] final case class IntervalWildcard[S]( Chunk( Some("pattern" -> pattern.toJson), analyzer.map("analyzer" -> _.toJson), - useField.map("use_field" -> _.toString.toJson) + useField.map("use_field" -> _.toJson) ).flatten: _* ) ) From a136f4f3065e944b5261f39179380ac9c1d26437 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 13:01:34 +0200 Subject: [PATCH 22/41] Try to remove strange chars. --- .../scala/zio/elasticsearch/query/options/HasAnalyzer.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala index 1657e021a..1c393c043 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasAnalyzer.scala @@ -1,15 +1,12 @@ /* * 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. From 7391cece659c931267784349b7a9397eefdf331c Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 16:16:43 +0200 Subject: [PATCH 23/41] Done sbt prepared --- .../zio/elasticsearch/IntegrationSpec.scala | 226 +++---- .../zio/elasticsearch/ElasticQuery.scala | 16 + .../query/ElasticIntervalRule.scala | 16 + .../zio/elasticsearch/query/Queries.scala | 16 + .../query/options/HasUseField.scala | 16 + .../zio/elasticsearch/FieldDSLSpec.scala | 174 ++--- .../HttpElasticExecutorSpec.scala | 596 +++++++++--------- .../zio/elasticsearch/IndexNameSpec.scala | 192 +++--- 8 files changed, 658 insertions(+), 594 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala index 2fa580a6f..62fa4dd6c 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,113 +1,113 @@ -/* - * 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 - -import sttp.client4.httpclient.zio.HttpClientZioBackend -import zio._ -import zio.elasticsearch.ElasticQuery.matchAll -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.domain._ -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.utils.unsafeWrap -import zio.test.Assertion.{containsString, hasMessage} -import zio.test.CheckVariants.CheckN -import zio.test.TestAspect.beforeAll -import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} - -import java.time.LocalDate - -trait IntegrationSpec extends ZIOSpecDefault { - - val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - val index: IndexName = IndexName("users") - - val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") - - val firstSearchIndex: IndexName = IndexName("search-index-1") - - val secondSearchIndex: IndexName = IndexName("search-index-2") - - val createIndexTestName: IndexName = IndexName("create-index-test-name") - - val firstCountIndex: IndexName = IndexName("count-index-1") - - val secondCountIndex: IndexName = IndexName("count-index-2") - - val updateByQueryIndex: IndexName = IndexName("update-by-query-index") - - val geoDistanceIndex: IndexName = IndexName("geo-distance-index") - - val refreshFailIndex: IndexName = IndexName("refresh-fail") - - val IndexPatternAll: IndexPattern = IndexPattern("_all") - - val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") - - val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { - _ <- Executor.execute(ElasticRequest.createIndex(index)) - _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) - } yield ()).provide(elasticsearchLayer)) - - def genIndexName: Gen[Any, IndexName] = - Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) - - def genDocumentId: Gen[Any, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - - def genGeoPoint: Gen[Any, GeoPoint] = - for { - latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - } yield GeoPoint(latitude, longitude) - - def genTestDocument: Gen[Any, TestDocument] = for { - stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) - dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) - subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) - intField <- Gen.int(1, 2000) - doubleField <- Gen.double(100, 2000) - booleanField <- Gen.boolean - geoPointField <- genGeoPoint - vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) - } yield TestDocument( - stringField = stringField, - dateField = dateField, - subDocumentList = subDocumentList, - intField = intField, - doubleField = doubleField, - booleanField = booleanField, - geoPointField = geoPointField, - vectorField = vectorField - ) - - def genTestSubDocument: Gen[Any, TestSubDocument] = for { - stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - longField <- Gen.long(1, 75) - intField <- Gen.int(1, 200) - } yield TestSubDocument( - stringField = stringField1, - nestedField = TestNestedField(stringField2, longField), - intField = intField, - intFieldList = Nil - ) - - def checkOnce: CheckN = checkN(1) - - def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) -} +/* + * 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 + +import sttp.client4.httpclient.zio.HttpClientZioBackend +import zio._ +import zio.elasticsearch.ElasticQuery.matchAll +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.domain._ +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.utils.unsafeWrap +import zio.test.Assertion.{containsString, hasMessage} +import zio.test.CheckVariants.CheckN +import zio.test.TestAspect.beforeAll +import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} + +import java.time.LocalDate + +trait IntegrationSpec extends ZIOSpecDefault { + + val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + val index: IndexName = IndexName("users") + + val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") + + val firstSearchIndex: IndexName = IndexName("search-index-1") + + val secondSearchIndex: IndexName = IndexName("search-index-2") + + val createIndexTestName: IndexName = IndexName("create-index-test-name") + + val firstCountIndex: IndexName = IndexName("count-index-1") + + val secondCountIndex: IndexName = IndexName("count-index-2") + + val updateByQueryIndex: IndexName = IndexName("update-by-query-index") + + val geoDistanceIndex: IndexName = IndexName("geo-distance-index") + + val refreshFailIndex: IndexName = IndexName("refresh-fail") + + val IndexPatternAll: IndexPattern = IndexPattern("_all") + + val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") + + val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { + _ <- Executor.execute(ElasticRequest.createIndex(index)) + _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) + } yield ()).provide(elasticsearchLayer)) + + def genIndexName: Gen[Any, IndexName] = + Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) + + def genDocumentId: Gen[Any, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) + + def genGeoPoint: Gen[Any, GeoPoint] = + for { + latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + } yield GeoPoint(latitude, longitude) + + def genTestDocument: Gen[Any, TestDocument] = for { + stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) + dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) + subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) + intField <- Gen.int(1, 2000) + doubleField <- Gen.double(100, 2000) + booleanField <- Gen.boolean + geoPointField <- genGeoPoint + vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) + } yield TestDocument( + stringField = stringField, + dateField = dateField, + subDocumentList = subDocumentList, + intField = intField, + doubleField = doubleField, + booleanField = booleanField, + geoPointField = geoPointField, + vectorField = vectorField + ) + + def genTestSubDocument: Gen[Any, TestSubDocument] = for { + stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + longField <- Gen.long(1, 75) + intField <- Gen.int(1, 200) + } yield TestSubDocument( + stringField = stringField1, + nestedField = TestNestedField(stringField2, longField), + intField = intField, + intFieldList = Nil + ) + + def checkOnce: CheckN = checkN(1) + + def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index d503cdbb6..f331cd86c 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,3 +1,19 @@ +/* + * 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 import zio.Chunk diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index 5b19a720d..81abf3c8a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -1,3 +1,19 @@ +/* + * 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.query import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index bea600a6d..43d493420 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -1,3 +1,19 @@ +/* + * 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.query import zio.Chunk diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala index 70cfd184a..ff10f5081 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/options/HasUseField.scala @@ -1,3 +1,19 @@ +/* + * 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.query.options import zio.elasticsearch.Field diff --git a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala index a863ea7b9..04d3607c5 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala @@ -1,87 +1,87 @@ -/* - * 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 - -import zio.elasticsearch.domain.{TestNestedField, TestSubDocument} -import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue} - -object FieldDSLSpec extends ZIOSpecDefault { - def spec: Spec[TestEnvironment, Any] = - suite("Field DSL")( - suite("constructing")( - test("field") { - val encodeName = "name" - - val encodeNestedNumber = "number" - val encodeNestedAddress = "address" - val encodeNestedExpectedVal = "address.number" - - val encodeSuffixName = "name" - val encodeSuffixKeyword = "keyword" - val encodeSuffixExpectedVal = "name.keyword" - - val encodeSingleFieldSuffixName = "name" - val encodeSingleFieldSuffixMultiField = "multi_field" - val encodeSingleFieldSuffixKeyword = "keyword" - val encodeSingleFieldSuffixExpectedVal = "name.multi_field.keyword" - - val encodeSingleFieldKeywordSuffixName = "name" - val encodeSingleFieldKeywordSuffixExpectedVal = "name.keyword" - - val encodeSingleFieldRawSuffixKeyword = "name" - val encodeSingleFieldRawSuffixExpectedVal = "name.raw" - - assertTrue(Field(None, encodeName).toString == encodeName) && assertTrue( - Field(Some(Field(None, encodeNestedAddress)), encodeNestedNumber).toString == encodeNestedExpectedVal - ) && assertTrue( - Field[Any, String](None, encodeSuffixName).suffix(encodeSuffixKeyword).toString == encodeSuffixExpectedVal - ) && assertTrue( - Field[Any, String](None, encodeSingleFieldSuffixName) - .suffix(encodeSingleFieldSuffixMultiField) - .suffix(encodeSingleFieldSuffixKeyword) - .toString == encodeSingleFieldSuffixExpectedVal - ) && assertTrue( - Field[Any, String]( - None, - encodeSingleFieldKeywordSuffixName - ).keyword.toString == encodeSingleFieldKeywordSuffixExpectedVal - ) && assertTrue( - Field[Any, String]( - None, - encodeSingleFieldRawSuffixKeyword - ).raw.toString == encodeSingleFieldRawSuffixExpectedVal - ) - }, - test("path") { - val singleFieldExpectedVal = "stringField" - - val nestedFieldAccessorsExpectedVal = "nestedField.longField" - - val singleFieldSuffixAccessorKeyword = "keyword" - val singleFieldSuffixAccessorExpectedVal = "stringField.keyword" - - assertTrue(TestSubDocument.stringField.toString == singleFieldExpectedVal) && assertTrue( - (TestSubDocument.nestedField / TestNestedField.longField).toString == nestedFieldAccessorsExpectedVal - ) && assertTrue( - TestSubDocument.stringField - .suffix(singleFieldSuffixAccessorKeyword) - .toString == singleFieldSuffixAccessorExpectedVal - ) - } - ) - ) -} +/* + * 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 + +import zio.elasticsearch.domain.{TestNestedField, TestSubDocument} +import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue} + +object FieldDSLSpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = + suite("Field DSL")( + suite("constructing")( + test("field") { + val encodeName = "name" + + val encodeNestedNumber = "number" + val encodeNestedAddress = "address" + val encodeNestedExpectedVal = "address.number" + + val encodeSuffixName = "name" + val encodeSuffixKeyword = "keyword" + val encodeSuffixExpectedVal = "name.keyword" + + val encodeSingleFieldSuffixName = "name" + val encodeSingleFieldSuffixMultiField = "multi_field" + val encodeSingleFieldSuffixKeyword = "keyword" + val encodeSingleFieldSuffixExpectedVal = "name.multi_field.keyword" + + val encodeSingleFieldKeywordSuffixName = "name" + val encodeSingleFieldKeywordSuffixExpectedVal = "name.keyword" + + val encodeSingleFieldRawSuffixKeyword = "name" + val encodeSingleFieldRawSuffixExpectedVal = "name.raw" + + assertTrue(Field(None, encodeName).toString == encodeName) && assertTrue( + Field(Some(Field(None, encodeNestedAddress)), encodeNestedNumber).toString == encodeNestedExpectedVal + ) && assertTrue( + Field[Any, String](None, encodeSuffixName).suffix(encodeSuffixKeyword).toString == encodeSuffixExpectedVal + ) && assertTrue( + Field[Any, String](None, encodeSingleFieldSuffixName) + .suffix(encodeSingleFieldSuffixMultiField) + .suffix(encodeSingleFieldSuffixKeyword) + .toString == encodeSingleFieldSuffixExpectedVal + ) && assertTrue( + Field[Any, String]( + None, + encodeSingleFieldKeywordSuffixName + ).keyword.toString == encodeSingleFieldKeywordSuffixExpectedVal + ) && assertTrue( + Field[Any, String]( + None, + encodeSingleFieldRawSuffixKeyword + ).raw.toString == encodeSingleFieldRawSuffixExpectedVal + ) + }, + test("path") { + val singleFieldExpectedVal = "stringField" + + val nestedFieldAccessorsExpectedVal = "nestedField.longField" + + val singleFieldSuffixAccessorKeyword = "keyword" + val singleFieldSuffixAccessorExpectedVal = "stringField.keyword" + + assertTrue(TestSubDocument.stringField.toString == singleFieldExpectedVal) && assertTrue( + (TestSubDocument.nestedField / TestNestedField.longField).toString == nestedFieldAccessorsExpectedVal + ) && assertTrue( + TestSubDocument.stringField + .suffix(singleFieldSuffixAccessorKeyword) + .toString == singleFieldSuffixAccessorExpectedVal + ) + } + ) + ) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala index fdd847540..5545b7868 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala @@ -1,298 +1,298 @@ -/* - * 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 - -import zio.Chunk -import zio.elasticsearch.ElasticAggregation.termsAggregation -import zio.elasticsearch.ElasticQuery.{kNN, matchAll, term} -import zio.elasticsearch.domain.TestDocument -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.executor.response.{BulkResponse, CreateBulkResponse, Shards} -import zio.elasticsearch.request.CreationOutcome.Created -import zio.elasticsearch.request.DeletionOutcome.Deleted -import zio.elasticsearch.request.UpdateConflicts.Proceed -import zio.elasticsearch.request.UpdateOutcome -import zio.elasticsearch.result.{TermsAggregationBucketResult, TermsAggregationResult, UpdateByQueryResult} -import zio.elasticsearch.script.Script -import zio.test.Assertion._ -import zio.test.{Spec, TestEnvironment, TestResultZIOOps, assertZIO} - -object HttpElasticExecutorSpec extends SttpBackendStubSpec { - def spec: Spec[TestEnvironment, Any] = - suite("HttpElasticExecutor")( - test("aggregation") { - val executorAggregate = - Executor - .execute(ElasticRequest.aggregate(index, termsAggregation(name = "aggregation1", field = "name"))) - .aggregations - - val expectedTermsAggregationResult = - Map( - "aggregation1" -> TermsAggregationResult( - docErrorCount = 0, - sumOtherDocCount = 0, - buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) - ) - ) - - assertZIO(executorAggregate)(equalTo(expectedTermsAggregationResult)) - }, - test("bulk") { - val executorBulk = Executor.execute(ElasticRequest.bulk(ElasticRequest.create(index, doc)).refreshTrue) - - val expectedBulkResponse = - BulkResponse( - took = 3, - errors = false, - items = Chunk( - CreateBulkResponse( - index = "repositories", - id = "123", - version = Some(1), - result = Some("created"), - shards = Some(Shards(total = 1, successful = 1, failed = 0)), - status = Some(201), - error = None - ) - ) - ) - - assertZIO(executorBulk)(equalTo(expectedBulkResponse)) - }, - test("count") { - val executorCount = Executor.execute(ElasticRequest.count(index, matchAll).routing(Routing("routing"))) - - assertZIO(executorCount)(equalTo(2)) - }, - test("create") { - val executorCreate = - Executor - .execute( - ElasticRequest - .create[TestDocument](index = index, doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorCreate)(equalTo(DocumentId("V4x8q4UB3agN0z75fv5r"))) - }, - test("create with ID") { - val executorCreateDocumentId = - Executor.execute( - ElasticRequest - .create[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorCreateDocumentId)(equalTo(Created)) - }, - test("createIndex") { - val executorCreateIndex = Executor.execute(ElasticRequest.createIndex(index = index)) - - val mapping = - """ - |{ - | "settings": { - | "index": { - | "number_of_shards": 1 - | } - | }, - | "mappings": { - | "_routing": { - | "required": true - | }, - | "properties": { - | "id": { - | "type": "keyword" - | } - | } - | } - |} - |""".stripMargin - val executorCreateIndexMapping = - Executor.execute(ElasticRequest.createIndex(index = index, definition = mapping)) - - assertZIO(executorCreateIndex)(equalTo(Created)) && - assertZIO(executorCreateIndexMapping)(equalTo(Created)) - }, - test("deleteById") { - val executorDeleteById = - Executor.execute( - ElasticRequest - .deleteById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorDeleteById)(equalTo(Deleted)) - }, - test("deleteByQuery") { - val executorDeleteByQuery = - Executor.execute( - ElasticRequest.deleteByQuery(index = index, query = matchAll).refreshTrue.routing(Routing("routing")) - ) - - assertZIO(executorDeleteByQuery)(equalTo(Deleted)) - }, - test("deleteIndex") { - val executorDeleteIndex = Executor.execute(ElasticRequest.deleteIndex(index = index)) - - assertZIO(executorDeleteIndex)(equalTo(Deleted)) - }, - test("exists") { - val executorExists = - Executor.execute( - ElasticRequest - .exists(index = index, id = DocumentId("example-id")) - .routing(Routing("routing")) - ) - - assertZIO(executorExists)(isTrue) - }, - test("getById") { - val executorGetById = - Executor - .execute( - ElasticRequest - .getById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) - .routing(Routing("routing")) - ) - .documentAs[TestDocument] - - assertZIO(executorGetById)(isSome(equalTo(doc))) - }, - test("knnSearch") { - val executorSearch = - Executor - .execute( - ElasticRequest - .knnSearch(selectors = index, query = kNN(TestDocument.vectorField, 2, 5, Chunk(-5.0, 9.0, -12.0))) - ) - .documentAs[TestDocument] - assertZIO(executorSearch)(equalTo(Chunk(doc))) - }, - test("refresh") { - val executorRefresh = Executor.execute(ElasticRequest.refresh(selectors = index)) - assertZIO(executorRefresh)(equalTo(true)) - }, - test("search") { - val executorSearch = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll)) - .documentAs[TestDocument] - val terms = termsAggregation(name = "aggregation1", field = "name") - val executorSearchWithTerms = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) - .documentAs[TestDocument] - - assertZIO(executorSearch)(equalTo(Chunk(doc))) && assertZIO(executorSearchWithTerms)(equalTo(Chunk(doc))) - }, - test("search + aggregate") { - val terms = termsAggregation(name = "aggregation1", field = "name") - val executorSearchAggregations = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) - .aggregations - - val expectedTermsAggregationResult = - Map( - "aggregation1" -> TermsAggregationResult( - docErrorCount = 0, - sumOtherDocCount = 0, - buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) - ) - ) - - assertZIO(executorSearchAggregations)(equalTo(expectedTermsAggregationResult)) - }, - test("update") { - val executorUpdate = - Executor.execute( - ElasticRequest - .update[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .orCreate(doc = secondDoc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpdate)(equalTo(UpdateOutcome.Updated)) - }, - test("updateAllByQuery") { - val executorUpdateAllByQuery = - Executor.execute( - ElasticRequest - .updateAllByQuery(index = index, script = Script("ctx._source['intField']++")) - .conflicts(Proceed) - .routing(Routing("routing")) - .refreshTrue - ) - - val expectedUpdateByQueryResult = - UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) - - assertZIO(executorUpdateAllByQuery)(equalTo(expectedUpdateByQueryResult)) - }, - test("updateByQuery") { - val executorUpdateByQuery = - Executor.execute( - ElasticRequest - .updateByQuery( - index = index, - query = term(field = TestDocument.stringField.keyword, value = "StringField"), - script = Script("ctx._source['intField']++") - ) - .conflicts(Proceed) - .routing(Routing("routing")) - .refreshTrue - ) - - val expectedUpdateByQueryResult = - UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) - - assertZIO(executorUpdateByQuery)(equalTo(expectedUpdateByQueryResult)) - }, - test("updateByScript") { - val executorUpdateByScript = - Executor.execute( - ElasticRequest - .updateByScript( - index = index, - id = DocumentId("V4x8q4UB3agN0z75fv5r"), - script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) - ) - .orCreate(doc = secondDoc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpdateByScript)(equalTo(UpdateOutcome.Updated)) - }, - test("upsert") { - val executorUpsert = - Executor.execute( - ElasticRequest - .upsert[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpsert)(isUnit) - } - ).provideShared(elasticsearchSttpLayer) -} +/* + * 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 + +import zio.Chunk +import zio.elasticsearch.ElasticAggregation.termsAggregation +import zio.elasticsearch.ElasticQuery.{kNN, matchAll, term} +import zio.elasticsearch.domain.TestDocument +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.executor.response.{BulkResponse, CreateBulkResponse, Shards} +import zio.elasticsearch.request.CreationOutcome.Created +import zio.elasticsearch.request.DeletionOutcome.Deleted +import zio.elasticsearch.request.UpdateConflicts.Proceed +import zio.elasticsearch.request.UpdateOutcome +import zio.elasticsearch.result.{TermsAggregationBucketResult, TermsAggregationResult, UpdateByQueryResult} +import zio.elasticsearch.script.Script +import zio.test.Assertion._ +import zio.test.{Spec, TestEnvironment, TestResultZIOOps, assertZIO} + +object HttpElasticExecutorSpec extends SttpBackendStubSpec { + def spec: Spec[TestEnvironment, Any] = + suite("HttpElasticExecutor")( + test("aggregation") { + val executorAggregate = + Executor + .execute(ElasticRequest.aggregate(index, termsAggregation(name = "aggregation1", field = "name"))) + .aggregations + + val expectedTermsAggregationResult = + Map( + "aggregation1" -> TermsAggregationResult( + docErrorCount = 0, + sumOtherDocCount = 0, + buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) + ) + ) + + assertZIO(executorAggregate)(equalTo(expectedTermsAggregationResult)) + }, + test("bulk") { + val executorBulk = Executor.execute(ElasticRequest.bulk(ElasticRequest.create(index, doc)).refreshTrue) + + val expectedBulkResponse = + BulkResponse( + took = 3, + errors = false, + items = Chunk( + CreateBulkResponse( + index = "repositories", + id = "123", + version = Some(1), + result = Some("created"), + shards = Some(Shards(total = 1, successful = 1, failed = 0)), + status = Some(201), + error = None + ) + ) + ) + + assertZIO(executorBulk)(equalTo(expectedBulkResponse)) + }, + test("count") { + val executorCount = Executor.execute(ElasticRequest.count(index, matchAll).routing(Routing("routing"))) + + assertZIO(executorCount)(equalTo(2)) + }, + test("create") { + val executorCreate = + Executor + .execute( + ElasticRequest + .create[TestDocument](index = index, doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorCreate)(equalTo(DocumentId("V4x8q4UB3agN0z75fv5r"))) + }, + test("create with ID") { + val executorCreateDocumentId = + Executor.execute( + ElasticRequest + .create[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorCreateDocumentId)(equalTo(Created)) + }, + test("createIndex") { + val executorCreateIndex = Executor.execute(ElasticRequest.createIndex(index = index)) + + val mapping = + """ + |{ + | "settings": { + | "index": { + | "number_of_shards": 1 + | } + | }, + | "mappings": { + | "_routing": { + | "required": true + | }, + | "properties": { + | "id": { + | "type": "keyword" + | } + | } + | } + |} + |""".stripMargin + val executorCreateIndexMapping = + Executor.execute(ElasticRequest.createIndex(index = index, definition = mapping)) + + assertZIO(executorCreateIndex)(equalTo(Created)) && + assertZIO(executorCreateIndexMapping)(equalTo(Created)) + }, + test("deleteById") { + val executorDeleteById = + Executor.execute( + ElasticRequest + .deleteById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorDeleteById)(equalTo(Deleted)) + }, + test("deleteByQuery") { + val executorDeleteByQuery = + Executor.execute( + ElasticRequest.deleteByQuery(index = index, query = matchAll).refreshTrue.routing(Routing("routing")) + ) + + assertZIO(executorDeleteByQuery)(equalTo(Deleted)) + }, + test("deleteIndex") { + val executorDeleteIndex = Executor.execute(ElasticRequest.deleteIndex(index = index)) + + assertZIO(executorDeleteIndex)(equalTo(Deleted)) + }, + test("exists") { + val executorExists = + Executor.execute( + ElasticRequest + .exists(index = index, id = DocumentId("example-id")) + .routing(Routing("routing")) + ) + + assertZIO(executorExists)(isTrue) + }, + test("getById") { + val executorGetById = + Executor + .execute( + ElasticRequest + .getById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) + .routing(Routing("routing")) + ) + .documentAs[TestDocument] + + assertZIO(executorGetById)(isSome(equalTo(doc))) + }, + test("knnSearch") { + val executorSearch = + Executor + .execute( + ElasticRequest + .knnSearch(selectors = index, query = kNN(TestDocument.vectorField, 2, 5, Chunk(-5.0, 9.0, -12.0))) + ) + .documentAs[TestDocument] + assertZIO(executorSearch)(equalTo(Chunk(doc))) + }, + test("refresh") { + val executorRefresh = Executor.execute(ElasticRequest.refresh(selectors = index)) + assertZIO(executorRefresh)(equalTo(true)) + }, + test("search") { + val executorSearch = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll)) + .documentAs[TestDocument] + val terms = termsAggregation(name = "aggregation1", field = "name") + val executorSearchWithTerms = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) + .documentAs[TestDocument] + + assertZIO(executorSearch)(equalTo(Chunk(doc))) && assertZIO(executorSearchWithTerms)(equalTo(Chunk(doc))) + }, + test("search + aggregate") { + val terms = termsAggregation(name = "aggregation1", field = "name") + val executorSearchAggregations = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) + .aggregations + + val expectedTermsAggregationResult = + Map( + "aggregation1" -> TermsAggregationResult( + docErrorCount = 0, + sumOtherDocCount = 0, + buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) + ) + ) + + assertZIO(executorSearchAggregations)(equalTo(expectedTermsAggregationResult)) + }, + test("update") { + val executorUpdate = + Executor.execute( + ElasticRequest + .update[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .orCreate(doc = secondDoc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpdate)(equalTo(UpdateOutcome.Updated)) + }, + test("updateAllByQuery") { + val executorUpdateAllByQuery = + Executor.execute( + ElasticRequest + .updateAllByQuery(index = index, script = Script("ctx._source['intField']++")) + .conflicts(Proceed) + .routing(Routing("routing")) + .refreshTrue + ) + + val expectedUpdateByQueryResult = + UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) + + assertZIO(executorUpdateAllByQuery)(equalTo(expectedUpdateByQueryResult)) + }, + test("updateByQuery") { + val executorUpdateByQuery = + Executor.execute( + ElasticRequest + .updateByQuery( + index = index, + query = term(field = TestDocument.stringField.keyword, value = "StringField"), + script = Script("ctx._source['intField']++") + ) + .conflicts(Proceed) + .routing(Routing("routing")) + .refreshTrue + ) + + val expectedUpdateByQueryResult = + UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) + + assertZIO(executorUpdateByQuery)(equalTo(expectedUpdateByQueryResult)) + }, + test("updateByScript") { + val executorUpdateByScript = + Executor.execute( + ElasticRequest + .updateByScript( + index = index, + id = DocumentId("V4x8q4UB3agN0z75fv5r"), + script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) + ) + .orCreate(doc = secondDoc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpdateByScript)(equalTo(UpdateOutcome.Updated)) + }, + test("upsert") { + val executorUpsert = + Executor.execute( + ElasticRequest + .upsert[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpsert)(isUnit) + } + ).provideShared(elasticsearchSttpLayer) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala index 895364f25..c2de29d72 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala @@ -1,96 +1,96 @@ -/* - * 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 - -import zio.elasticsearch.utils.unsafeWrap -import zio.prelude.Validation -import zio.test.Assertion.equalTo -import zio.test._ - -object IndexNameSpec extends ZIOSpecDefault { - def spec: Spec[TestEnvironment, Any] = - suite("IndexName")( - suite("constructing")( - test("fail for empty string") { - val name = "" - - assert(IndexName.make(name))(equalTo(Validation.fail(indexNameFailureMessage(name)))) - }, - test("fail for string '.'") { - val invalidName = "." - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - }, - test("fail for string containing character '*'") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"$part1*$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string containing character ':'") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"$part1:$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string containing upper letter") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"${part1}A$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string longer than 255 bytes") { - check(genString(256, 300)) { invalidName => - assert(IndexName.make(invalidName))( - equalTo(Validation.fail(indexNameFailureMessage(invalidName))) - ) - } - }, - test("fail for string starting with character '-'") { - check(genString(1, 255)) { name => - val invalidName = s"-$name" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("succeed for valid string") { - check(genString(1, 255)) { name => - assert(IndexName.make(name))(equalTo(Validation.succeed(unsafeWrap(name)(IndexName)))) - } - } - ) - ) - - private def indexNameFailureMessage(name: String): String = - s"$name did not satisfy " + - s""" - | - Must be lower case only - | - Cannot include \\, /, *, ?, ", <, >, |, ` `(space character), `,`(comma), #. - | - Cannot include ":"(since 7.0). - | - Cannot be empty - | - Cannot start with -, _, +. - | - Cannot be `.` or `..`. - | - Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit faster). - | - Names starting with . are deprecated, except for hidden indices and internal indices managed by plugins. - |""".stripMargin - - private def genString(min: Int, max: Int): Gen[Any, String] = - Gen.stringBounded(min, max)(Gen.alphaChar).map(_.toLowerCase) -} +/* + * 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 + +import zio.elasticsearch.utils.unsafeWrap +import zio.prelude.Validation +import zio.test.Assertion.equalTo +import zio.test._ + +object IndexNameSpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = + suite("IndexName")( + suite("constructing")( + test("fail for empty string") { + val name = "" + + assert(IndexName.make(name))(equalTo(Validation.fail(indexNameFailureMessage(name)))) + }, + test("fail for string '.'") { + val invalidName = "." + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + }, + test("fail for string containing character '*'") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"$part1*$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string containing character ':'") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"$part1:$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string containing upper letter") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"${part1}A$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string longer than 255 bytes") { + check(genString(256, 300)) { invalidName => + assert(IndexName.make(invalidName))( + equalTo(Validation.fail(indexNameFailureMessage(invalidName))) + ) + } + }, + test("fail for string starting with character '-'") { + check(genString(1, 255)) { name => + val invalidName = s"-$name" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("succeed for valid string") { + check(genString(1, 255)) { name => + assert(IndexName.make(name))(equalTo(Validation.succeed(unsafeWrap(name)(IndexName)))) + } + } + ) + ) + + private def indexNameFailureMessage(name: String): String = + s"$name did not satisfy " + + s""" + | - Must be lower case only + | - Cannot include \\, /, *, ?, ", <, >, |, ` `(space character), `,`(comma), #. + | - Cannot include ":"(since 7.0). + | - Cannot be empty + | - Cannot start with -, _, +. + | - Cannot be `.` or `..`. + | - Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit faster). + | - Names starting with . are deprecated, except for hidden indices and internal indices managed by plugins. + |""".stripMargin + + private def genString(min: Int, max: Int): Gen[Any, String] = + Gen.stringBounded(min, max)(Gen.alphaChar).map(_.toLowerCase) +} From 45bc91e92b692743e83334714704521b6f19946a Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Wed, 18 Jun 2025 16:24:28 +0200 Subject: [PATCH 24/41] Remove manually strange chars --- .../zio/elasticsearch/IntegrationSpec.scala | 226 +++++++++--------- .../zio/elasticsearch/FieldDSLSpec.scala | 174 +++++++------- .../zio/elasticsearch/IndexNameSpec.scala | 192 +++++++-------- 3 files changed, 296 insertions(+), 296 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala index 62fa4dd6c..2fa580a6f 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,113 +1,113 @@ -/* - * 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 - -import sttp.client4.httpclient.zio.HttpClientZioBackend -import zio._ -import zio.elasticsearch.ElasticQuery.matchAll -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.domain._ -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.utils.unsafeWrap -import zio.test.Assertion.{containsString, hasMessage} -import zio.test.CheckVariants.CheckN -import zio.test.TestAspect.beforeAll -import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} - -import java.time.LocalDate - -trait IntegrationSpec extends ZIOSpecDefault { - - val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - val index: IndexName = IndexName("users") - - val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") - - val firstSearchIndex: IndexName = IndexName("search-index-1") - - val secondSearchIndex: IndexName = IndexName("search-index-2") - - val createIndexTestName: IndexName = IndexName("create-index-test-name") - - val firstCountIndex: IndexName = IndexName("count-index-1") - - val secondCountIndex: IndexName = IndexName("count-index-2") - - val updateByQueryIndex: IndexName = IndexName("update-by-query-index") - - val geoDistanceIndex: IndexName = IndexName("geo-distance-index") - - val refreshFailIndex: IndexName = IndexName("refresh-fail") - - val IndexPatternAll: IndexPattern = IndexPattern("_all") - - val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") - - val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { - _ <- Executor.execute(ElasticRequest.createIndex(index)) - _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) - } yield ()).provide(elasticsearchLayer)) - - def genIndexName: Gen[Any, IndexName] = - Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) - - def genDocumentId: Gen[Any, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - - def genGeoPoint: Gen[Any, GeoPoint] = - for { - latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - } yield GeoPoint(latitude, longitude) - - def genTestDocument: Gen[Any, TestDocument] = for { - stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) - dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) - subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) - intField <- Gen.int(1, 2000) - doubleField <- Gen.double(100, 2000) - booleanField <- Gen.boolean - geoPointField <- genGeoPoint - vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) - } yield TestDocument( - stringField = stringField, - dateField = dateField, - subDocumentList = subDocumentList, - intField = intField, - doubleField = doubleField, - booleanField = booleanField, - geoPointField = geoPointField, - vectorField = vectorField - ) - - def genTestSubDocument: Gen[Any, TestSubDocument] = for { - stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - longField <- Gen.long(1, 75) - intField <- Gen.int(1, 200) - } yield TestSubDocument( - stringField = stringField1, - nestedField = TestNestedField(stringField2, longField), - intField = intField, - intFieldList = Nil - ) - - def checkOnce: CheckN = checkN(1) - - def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) -} +/* + * 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 + +import sttp.client4.httpclient.zio.HttpClientZioBackend +import zio._ +import zio.elasticsearch.ElasticQuery.matchAll +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.domain._ +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.utils.unsafeWrap +import zio.test.Assertion.{containsString, hasMessage} +import zio.test.CheckVariants.CheckN +import zio.test.TestAspect.beforeAll +import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} + +import java.time.LocalDate + +trait IntegrationSpec extends ZIOSpecDefault { + + val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + val index: IndexName = IndexName("users") + + val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") + + val firstSearchIndex: IndexName = IndexName("search-index-1") + + val secondSearchIndex: IndexName = IndexName("search-index-2") + + val createIndexTestName: IndexName = IndexName("create-index-test-name") + + val firstCountIndex: IndexName = IndexName("count-index-1") + + val secondCountIndex: IndexName = IndexName("count-index-2") + + val updateByQueryIndex: IndexName = IndexName("update-by-query-index") + + val geoDistanceIndex: IndexName = IndexName("geo-distance-index") + + val refreshFailIndex: IndexName = IndexName("refresh-fail") + + val IndexPatternAll: IndexPattern = IndexPattern("_all") + + val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") + + val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { + _ <- Executor.execute(ElasticRequest.createIndex(index)) + _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) + } yield ()).provide(elasticsearchLayer)) + + def genIndexName: Gen[Any, IndexName] = + Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) + + def genDocumentId: Gen[Any, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) + + def genGeoPoint: Gen[Any, GeoPoint] = + for { + latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + } yield GeoPoint(latitude, longitude) + + def genTestDocument: Gen[Any, TestDocument] = for { + stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) + dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) + subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) + intField <- Gen.int(1, 2000) + doubleField <- Gen.double(100, 2000) + booleanField <- Gen.boolean + geoPointField <- genGeoPoint + vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) + } yield TestDocument( + stringField = stringField, + dateField = dateField, + subDocumentList = subDocumentList, + intField = intField, + doubleField = doubleField, + booleanField = booleanField, + geoPointField = geoPointField, + vectorField = vectorField + ) + + def genTestSubDocument: Gen[Any, TestSubDocument] = for { + stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + longField <- Gen.long(1, 75) + intField <- Gen.int(1, 200) + } yield TestSubDocument( + stringField = stringField1, + nestedField = TestNestedField(stringField2, longField), + intField = intField, + intFieldList = Nil + ) + + def checkOnce: CheckN = checkN(1) + + def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala index 04d3607c5..6b873c7c0 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala @@ -1,87 +1,87 @@ -/* - * 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 - -import zio.elasticsearch.domain.{TestNestedField, TestSubDocument} -import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue} - -object FieldDSLSpec extends ZIOSpecDefault { - def spec: Spec[TestEnvironment, Any] = - suite("Field DSL")( - suite("constructing")( - test("field") { - val encodeName = "name" - - val encodeNestedNumber = "number" - val encodeNestedAddress = "address" - val encodeNestedExpectedVal = "address.number" - - val encodeSuffixName = "name" - val encodeSuffixKeyword = "keyword" - val encodeSuffixExpectedVal = "name.keyword" - - val encodeSingleFieldSuffixName = "name" - val encodeSingleFieldSuffixMultiField = "multi_field" - val encodeSingleFieldSuffixKeyword = "keyword" - val encodeSingleFieldSuffixExpectedVal = "name.multi_field.keyword" - - val encodeSingleFieldKeywordSuffixName = "name" - val encodeSingleFieldKeywordSuffixExpectedVal = "name.keyword" - - val encodeSingleFieldRawSuffixKeyword = "name" - val encodeSingleFieldRawSuffixExpectedVal = "name.raw" - - assertTrue(Field(None, encodeName).toString == encodeName) && assertTrue( - Field(Some(Field(None, encodeNestedAddress)), encodeNestedNumber).toString == encodeNestedExpectedVal - ) && assertTrue( - Field[Any, String](None, encodeSuffixName).suffix(encodeSuffixKeyword).toString == encodeSuffixExpectedVal - ) && assertTrue( - Field[Any, String](None, encodeSingleFieldSuffixName) - .suffix(encodeSingleFieldSuffixMultiField) - .suffix(encodeSingleFieldSuffixKeyword) - .toString == encodeSingleFieldSuffixExpectedVal - ) && assertTrue( - Field[Any, String]( - None, - encodeSingleFieldKeywordSuffixName - ).keyword.toString == encodeSingleFieldKeywordSuffixExpectedVal - ) && assertTrue( - Field[Any, String]( - None, - encodeSingleFieldRawSuffixKeyword - ).raw.toString == encodeSingleFieldRawSuffixExpectedVal - ) - }, - test("path") { - val singleFieldExpectedVal = "stringField" - - val nestedFieldAccessorsExpectedVal = "nestedField.longField" - - val singleFieldSuffixAccessorKeyword = "keyword" - val singleFieldSuffixAccessorExpectedVal = "stringField.keyword" - - assertTrue(TestSubDocument.stringField.toString == singleFieldExpectedVal) && assertTrue( - (TestSubDocument.nestedField / TestNestedField.longField).toString == nestedFieldAccessorsExpectedVal - ) && assertTrue( - TestSubDocument.stringField - .suffix(singleFieldSuffixAccessorKeyword) - .toString == singleFieldSuffixAccessorExpectedVal - ) - } - ) - ) -} +/* + * 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 + +import zio.elasticsearch.domain.{TestNestedField, TestSubDocument} +import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assertTrue} + +object FieldDSLSpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = + suite("Field DSL")( + suite("constructing")( + test("field") { + val encodeName = "name" + + val encodeNestedNumber = "number" + val encodeNestedAddress = "address" + val encodeNestedExpectedVal = "address.number" + + val encodeSuffixName = "name" + val encodeSuffixKeyword = "keyword" + val encodeSuffixExpectedVal = "name.keyword" + + val encodeSingleFieldSuffixName = "name" + val encodeSingleFieldSuffixMultiField = "multi_field" + val encodeSingleFieldSuffixKeyword = "keyword" + val encodeSingleFieldSuffixExpectedVal = "name.multi_field.keyword" + + val encodeSingleFieldKeywordSuffixName = "name" + val encodeSingleFieldKeywordSuffixExpectedVal = "name.keyword" + + val encodeSingleFieldRawSuffixKeyword = "name" + val encodeSingleFieldRawSuffixExpectedVal = "name.raw" + + assertTrue(Field(None, encodeName).toString == encodeName) && assertTrue( + Field(Some(Field(None, encodeNestedAddress)), encodeNestedNumber).toString == encodeNestedExpectedVal + ) && assertTrue( + Field[Any, String](None, encodeSuffixName).suffix(encodeSuffixKeyword).toString == encodeSuffixExpectedVal + ) && assertTrue( + Field[Any, String](None, encodeSingleFieldSuffixName) + .suffix(encodeSingleFieldSuffixMultiField) + .suffix(encodeSingleFieldSuffixKeyword) + .toString == encodeSingleFieldSuffixExpectedVal + ) && assertTrue( + Field[Any, String]( + None, + encodeSingleFieldKeywordSuffixName + ).keyword.toString == encodeSingleFieldKeywordSuffixExpectedVal + ) && assertTrue( + Field[Any, String]( + None, + encodeSingleFieldRawSuffixKeyword + ).raw.toString == encodeSingleFieldRawSuffixExpectedVal + ) + }, + test("path") { + val singleFieldExpectedVal = "stringField" + + val nestedFieldAccessorsExpectedVal = "nestedField.longField" + + val singleFieldSuffixAccessorKeyword = "keyword" + val singleFieldSuffixAccessorExpectedVal = "stringField.keyword" + + assertTrue(TestSubDocument.stringField.toString == singleFieldExpectedVal) && assertTrue( + (TestSubDocument.nestedField / TestNestedField.longField).toString == nestedFieldAccessorsExpectedVal + ) && assertTrue( + TestSubDocument.stringField + .suffix(singleFieldSuffixAccessorKeyword) + .toString == singleFieldSuffixAccessorExpectedVal + ) + } + ) + ) +} diff --git a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala index c2de29d72..1bbd16876 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala @@ -1,96 +1,96 @@ -/* - * 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 - -import zio.elasticsearch.utils.unsafeWrap -import zio.prelude.Validation -import zio.test.Assertion.equalTo -import zio.test._ - -object IndexNameSpec extends ZIOSpecDefault { - def spec: Spec[TestEnvironment, Any] = - suite("IndexName")( - suite("constructing")( - test("fail for empty string") { - val name = "" - - assert(IndexName.make(name))(equalTo(Validation.fail(indexNameFailureMessage(name)))) - }, - test("fail for string '.'") { - val invalidName = "." - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - }, - test("fail for string containing character '*'") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"$part1*$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string containing character ':'") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"$part1:$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string containing upper letter") { - check(genString(0, 127), genString(0, 128)) { (part1, part2) => - val invalidName = s"${part1}A$part2" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("fail for string longer than 255 bytes") { - check(genString(256, 300)) { invalidName => - assert(IndexName.make(invalidName))( - equalTo(Validation.fail(indexNameFailureMessage(invalidName))) - ) - } - }, - test("fail for string starting with character '-'") { - check(genString(1, 255)) { name => - val invalidName = s"-$name" - - assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) - } - }, - test("succeed for valid string") { - check(genString(1, 255)) { name => - assert(IndexName.make(name))(equalTo(Validation.succeed(unsafeWrap(name)(IndexName)))) - } - } - ) - ) - - private def indexNameFailureMessage(name: String): String = - s"$name did not satisfy " + - s""" - | - Must be lower case only - | - Cannot include \\, /, *, ?, ", <, >, |, ` `(space character), `,`(comma), #. - | - Cannot include ":"(since 7.0). - | - Cannot be empty - | - Cannot start with -, _, +. - | - Cannot be `.` or `..`. - | - Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit faster). - | - Names starting with . are deprecated, except for hidden indices and internal indices managed by plugins. - |""".stripMargin - - private def genString(min: Int, max: Int): Gen[Any, String] = - Gen.stringBounded(min, max)(Gen.alphaChar).map(_.toLowerCase) -} +/* + * 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 + +import zio.elasticsearch.utils.unsafeWrap +import zio.prelude.Validation +import zio.test.Assertion.equalTo +import zio.test._ + +object IndexNameSpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = + suite("IndexName")( + suite("constructing")( + test("fail for empty string") { + val name = "" + + assert(IndexName.make(name))(equalTo(Validation.fail(indexNameFailureMessage(name)))) + }, + test("fail for string '.'") { + val invalidName = "." + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + }, + test("fail for string containing character '*'") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"$part1*$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string containing character ':'") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"$part1:$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string containing upper letter") { + check(genString(0, 127), genString(0, 128)) { (part1, part2) => + val invalidName = s"${part1}A$part2" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("fail for string longer than 255 bytes") { + check(genString(256, 300)) { invalidName => + assert(IndexName.make(invalidName))( + equalTo(Validation.fail(indexNameFailureMessage(invalidName))) + ) + } + }, + test("fail for string starting with character '-'") { + check(genString(1, 255)) { name => + val invalidName = s"-$name" + + assert(IndexName.make(invalidName))(equalTo(Validation.fail(indexNameFailureMessage(invalidName)))) + } + }, + test("succeed for valid string") { + check(genString(1, 255)) { name => + assert(IndexName.make(name))(equalTo(Validation.succeed(unsafeWrap(name)(IndexName)))) + } + } + ) + ) + + private def indexNameFailureMessage(name: String): String = + s"$name did not satisfy " + + s""" + | - Must be lower case only + | - Cannot include \\, /, *, ?, ", <, >, |, ` `(space character), `,`(comma), #. + | - Cannot include ":"(since 7.0). + | - Cannot be empty + | - Cannot start with -, _, +. + | - Cannot be `.` or `..`. + | - Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit faster). + | - Names starting with . are deprecated, except for hidden indices and internal indices managed by plugins. + |""".stripMargin + + private def genString(min: Int, max: Int): Gen[Any, String] = + Gen.stringBounded(min, max)(Gen.alphaChar).map(_.toLowerCase) +} From cf316174d617b3ce4c7361550cf7150fcc7128c2 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:17:57 +0200 Subject: [PATCH 25/41] Resolve some comments. --- .../zio/elasticsearch/HttpExecutorSpec.scala | 5 +- .../zio/elasticsearch/IntegrationSpec.scala | 227 +++++++++--------- .../zio/elasticsearch/ElasticQuery.scala | 4 +- .../query/ElasticIntervalRule.scala | 32 +-- .../zio/elasticsearch/ElasticQuerySpec.scala | 22 +- 5 files changed, 150 insertions(+), 140 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index cd8ef8c50..12ab6c820 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -174,8 +174,7 @@ object HttpExecutorSpec extends IntegrationSpec { ) .refreshTrue ) - query = - term(field = TestDocument.stringField, value = secondDocumentUpdated.stringField.toLowerCase) + query = term(field = TestDocument.stringField, value = secondDocumentUpdated.stringField.toLowerCase) aggregation = filterAggregation(name = "aggregation", query = query).withSubAgg( maxAggregation("subAggregation", TestDocument.intField) @@ -2757,7 +2756,7 @@ object HttpExecutorSpec extends IntegrationSpec { } } @@ after(Executor.execute(ElasticRequest.deleteIndex(geoPolygonIndex)).orDie) ), - suite("interval-match query")( + suite("intervals query")( test("intervalMatch returns only matching document") { checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString, genDocumentId, genTestDocument) { (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => diff --git a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala index 2fa580a6f..ec0953e44 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,113 +1,114 @@ -/* - * 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 - -import sttp.client4.httpclient.zio.HttpClientZioBackend -import zio._ -import zio.elasticsearch.ElasticQuery.matchAll -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.domain._ -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.utils.unsafeWrap -import zio.test.Assertion.{containsString, hasMessage} -import zio.test.CheckVariants.CheckN -import zio.test.TestAspect.beforeAll -import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} - -import java.time.LocalDate - -trait IntegrationSpec extends ZIOSpecDefault { - - val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - val index: IndexName = IndexName("users") - - val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") - - val firstSearchIndex: IndexName = IndexName("search-index-1") - - val secondSearchIndex: IndexName = IndexName("search-index-2") - - val createIndexTestName: IndexName = IndexName("create-index-test-name") - - val firstCountIndex: IndexName = IndexName("count-index-1") - - val secondCountIndex: IndexName = IndexName("count-index-2") - - val updateByQueryIndex: IndexName = IndexName("update-by-query-index") - - val geoDistanceIndex: IndexName = IndexName("geo-distance-index") - - val refreshFailIndex: IndexName = IndexName("refresh-fail") - - val IndexPatternAll: IndexPattern = IndexPattern("_all") - - val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") - - val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { - _ <- Executor.execute(ElasticRequest.createIndex(index)) - _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) - } yield ()).provide(elasticsearchLayer)) - - def genIndexName: Gen[Any, IndexName] = - Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) - - def genDocumentId: Gen[Any, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - - def genGeoPoint: Gen[Any, GeoPoint] = - for { - latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - } yield GeoPoint(latitude, longitude) - - def genTestDocument: Gen[Any, TestDocument] = for { - stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) - dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) - subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) - intField <- Gen.int(1, 2000) - doubleField <- Gen.double(100, 2000) - booleanField <- Gen.boolean - geoPointField <- genGeoPoint - vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) - } yield TestDocument( - stringField = stringField, - dateField = dateField, - subDocumentList = subDocumentList, - intField = intField, - doubleField = doubleField, - booleanField = booleanField, - geoPointField = geoPointField, - vectorField = vectorField - ) - - def genTestSubDocument: Gen[Any, TestSubDocument] = for { - stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - longField <- Gen.long(1, 75) - intField <- Gen.int(1, 200) - } yield TestSubDocument( - stringField = stringField1, - nestedField = TestNestedField(stringField2, longField), - intField = intField, - intFieldList = Nil - ) - - def checkOnce: CheckN = checkN(1) - - def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) -} +/* + * 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 + +import sttp.client4.httpclient.zio.HttpClientZioBackend +import zio._ +import zio.elasticsearch.ElasticQuery.matchAll +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.domain._ +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.utils.unsafeWrap +import zio.test.Assertion.{containsString, hasMessage} +import zio.test.CheckVariants.CheckN +import zio.test.TestAspect.beforeAll +import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} + +import java.time.LocalDate + +trait IntegrationSpec extends ZIOSpecDefault { + + val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + val index: IndexName = IndexName("users") + + val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") + + val firstSearchIndex: IndexName = IndexName("search-index-1") + + val secondSearchIndex: IndexName = IndexName("search-index-2") + + val createIndexTestName: IndexName = IndexName("create-index-test-name") + + val firstCountIndex: IndexName = IndexName("count-index-1") + + val secondCountIndex: IndexName = IndexName("count-index-2") + + val updateByQueryIndex: IndexName = IndexName("update-by-query-index") + + val geoDistanceIndex: IndexName = IndexName("geo-distance-index") + + val refreshFailIndex: IndexName = IndexName("refresh-fail") + + val IndexPatternAll: IndexPattern = IndexPattern("_all") + + val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") + + val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { + _ <- Executor.execute(ElasticRequest.createIndex(index)) + _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) + } yield ()).provide(elasticsearchLayer)) + + def genIndexName: Gen[Any, IndexName] = + Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) + + def genDocumentId: Gen[Any, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) + + def genGeoPoint: Gen[Any, GeoPoint] = + for { + latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + } yield GeoPoint(latitude, longitude) + + def genTestDocument: Gen[Any, TestDocument] = for { + stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) + dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) + subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) + intField <- Gen.int(1, 2000) + doubleField <- Gen.double(100, 2000) + booleanField <- Gen.boolean + geoPointField <- genGeoPoint + vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) + } yield TestDocument( + stringField = stringField, + dateField = dateField, + subDocumentList = subDocumentList, + intField = intField, + doubleField = doubleField, + booleanField = booleanField, + geoPointField = geoPointField, + vectorField = vectorField + ) + + def genTestSubDocument: Gen[Any, TestSubDocument] = for { + stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + longField <- Gen.long(1, 75) + intField <- Gen.int(1, 200) + } yield TestSubDocument( + stringField = stringField1, + nestedField = TestNestedField(stringField2, longField), + intField = intField, + intFieldList = Nil + ) + + def checkOnce: CheckN = checkN(1) + + def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index f331cd86c..59ffcc96d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,12 +1,15 @@ /* * 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. @@ -42,7 +45,6 @@ object ElasticQuery { * @return * an instance of [[zio.elasticsearch.query.BoostingQuery]] that represents the boost query to be performed. */ - final def boosting[S: Schema]( negativeBoost: Float, negativeQuery: ElasticQuery[S], diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index 81abf3c8a..f037e9f2c 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -1,12 +1,15 @@ /* * 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. @@ -23,12 +26,12 @@ import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} import zio.{Chunk, NonEmptyChunk} -sealed trait BoundType -sealed trait Inclusive extends BoundType -sealed trait Exclusive extends BoundType +private[elasticsearch] sealed trait BoundType +private[elasticsearch] sealed trait Inclusive extends BoundType +private[elasticsearch] sealed trait Exclusive extends BoundType -case object InclusiveBound extends Inclusive -case object ExclusiveBound extends Exclusive +private[elasticsearch] case object InclusiveBound extends Inclusive +private[elasticsearch] case object ExclusiveBound extends Exclusive private[elasticsearch] final case class Bound[B <: BoundType](value: String, boundType: B) @@ -363,21 +366,10 @@ object ElasticIntervalQuery { script = script ) - if ( - List( - after, - before, - containedBy, - containing, - notContainedBy, - notContaining, - notOverlapping, - overlapping, - script - ).forall(_.isEmpty) - ) None - else Some(filter) - + Some(filter).filterNot(_ => + List(after, before, containedBy, containing, notContainedBy, notContaining, notOverlapping, overlapping, script) + .forall(_.isEmpty) + ) } def intervalFuzzy[S](term: String): IntervalFuzzy[S] = diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index a007b525a..1b88db8f7 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1,3 +1,19 @@ +/* + * 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 import zio.Chunk @@ -2611,12 +2627,12 @@ object ElasticQuerySpec extends ZIOSpecDefault { | "boosting": { | "positive": { | "terms": { - | "booleanField": [true, false] - | } + | "booleanField": [ true, false ] + | } | }, | "negative": { | "exists": { - | "field": "stringField" + | "field": "stringField" | } | }, | "negative_boost": 0.5 From 3f44d446c174e8a3d0f3a93181909d6f02294705 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:32:00 +0200 Subject: [PATCH 26/41] Change elastic_interval_query.md file. --- docs/overview/elastic_interval_query.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/docs/overview/elastic_interval_query.md b/docs/overview/elastic_interval_query.md index b7b15029a..641a17435 100644 --- a/docs/overview/elastic_interval_query.md +++ b/docs/overview/elastic_interval_query.md @@ -16,21 +16,15 @@ You can create a basic `Intervals` query` using the `intervals` method: val query: IntervalQuery[Any] = intervals(field = "content", rule = intervalMatch("targetWord")) ``` -If you want to specify which fields should be searched, you can use the `useField` method: -```scala -val queryWithField: IntervalQuery[Document] = - intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) -``` - To define `field` in a type-safe manner, use the overloaded `useField` method with field definitions from your document: ```scala val queryWithSafeField: IntervalQuery[Document] = intervals(field = Document.stringField, rule = intervalMatch("targetWord")) ``` -Alternatively, you can pass a `Field` object directly: +If you want to specify which fields should be searched, you can use the `useField` method: ```scala -val queryWithFieldObject: IntervalQuery[Document] = +val queryWithField: IntervalQuery[Document] = intervals(field = "content", rule = intervalMatch("targetWord").useField(Document.stringField)) ``` @@ -64,4 +58,3 @@ val queryManually: IntervalQuery[Document] = .analyzer("standard") ) ``` - From dfece62275bce8b3e67eb7c3329de059660551ac Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:41:12 +0200 Subject: [PATCH 27/41] Fix line endings and cleanup .gitattributes --- .gitattributes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 476390ebf..cafb792c1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -sbt linguist-vendored +* text=auto eol=lf +sbt linguist-vendored \ No newline at end of file From 500610f4718a2f48df49e74f67c8dc7d4f2fc49c Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:49:28 +0200 Subject: [PATCH 28/41] Remove strange chars. --- .../zio/elasticsearch/IntegrationSpec.scala | 227 +++++++++--------- 1 file changed, 113 insertions(+), 114 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala index ec0953e44..4bf0f457d 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,114 +1,113 @@ -/* - * 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 - -import sttp.client4.httpclient.zio.HttpClientZioBackend -import zio._ -import zio.elasticsearch.ElasticQuery.matchAll -import zio.elasticsearch.data.GeoPoint -import zio.elasticsearch.domain._ -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.utils.unsafeWrap -import zio.test.Assertion.{containsString, hasMessage} -import zio.test.CheckVariants.CheckN -import zio.test.TestAspect.beforeAll -import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} - -import java.time.LocalDate - -trait IntegrationSpec extends ZIOSpecDefault { - - val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local - - val index: IndexName = IndexName("users") - - val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") - - val firstSearchIndex: IndexName = IndexName("search-index-1") - - val secondSearchIndex: IndexName = IndexName("search-index-2") - - val createIndexTestName: IndexName = IndexName("create-index-test-name") - - val firstCountIndex: IndexName = IndexName("count-index-1") - - val secondCountIndex: IndexName = IndexName("count-index-2") - - val updateByQueryIndex: IndexName = IndexName("update-by-query-index") - - val geoDistanceIndex: IndexName = IndexName("geo-distance-index") - - val refreshFailIndex: IndexName = IndexName("refresh-fail") - - val IndexPatternAll: IndexPattern = IndexPattern("_all") - - val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") - - val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { - _ <- Executor.execute(ElasticRequest.createIndex(index)) - _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) - } yield ()).provide(elasticsearchLayer)) - - def genIndexName: Gen[Any, IndexName] = - Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) - - def genDocumentId: Gen[Any, DocumentId] = - Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) - - def genGeoPoint: Gen[Any, GeoPoint] = - for { - latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) - } yield GeoPoint(latitude, longitude) - - def genTestDocument: Gen[Any, TestDocument] = for { - stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) - dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) - subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) - intField <- Gen.int(1, 2000) - doubleField <- Gen.double(100, 2000) - booleanField <- Gen.boolean - geoPointField <- genGeoPoint - vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) - } yield TestDocument( - stringField = stringField, - dateField = dateField, - subDocumentList = subDocumentList, - intField = intField, - doubleField = doubleField, - booleanField = booleanField, - geoPointField = geoPointField, - vectorField = vectorField - ) - - def genTestSubDocument: Gen[Any, TestSubDocument] = for { - stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) - longField <- Gen.long(1, 75) - intField <- Gen.int(1, 200) - } yield TestSubDocument( - stringField = stringField1, - nestedField = TestNestedField(stringField2, longField), - intField = intField, - intFieldList = Nil - ) - - def checkOnce: CheckN = checkN(1) - - def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) -} +/* + * 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 + +import sttp.client4.httpclient.zio.HttpClientZioBackend +import zio._ +import zio.elasticsearch.ElasticQuery.matchAll +import zio.elasticsearch.data.GeoPoint +import zio.elasticsearch.domain._ +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.utils.unsafeWrap +import zio.test.Assertion.{containsString, hasMessage} +import zio.test.CheckVariants.CheckN +import zio.test.TestAspect.beforeAll +import zio.test.{Assertion, Gen, TestAspect, ZIOSpecDefault, checkN} + +import java.time.LocalDate + +trait IntegrationSpec extends ZIOSpecDefault { + + val elasticsearchLayer: TaskLayer[Executor] = HttpClientZioBackend.layer() >>> ElasticExecutor.local + + val index: IndexName = IndexName("users") + + val deleteByQueryIndex: IndexName = IndexName("delete-by-query-index") + + val firstSearchIndex: IndexName = IndexName("search-index-1") + + val secondSearchIndex: IndexName = IndexName("search-index-2") + + val createIndexTestName: IndexName = IndexName("create-index-test-name") + + val firstCountIndex: IndexName = IndexName("count-index-1") + + val secondCountIndex: IndexName = IndexName("count-index-2") + + val updateByQueryIndex: IndexName = IndexName("update-by-query-index") + + val geoDistanceIndex: IndexName = IndexName("geo-distance-index") + + val refreshFailIndex: IndexName = IndexName("refresh-fail") + + val IndexPatternAll: IndexPattern = IndexPattern("_all") + + val geoPolygonIndex: IndexName = IndexName("geo-polygon-index") + + val prepareElasticsearchIndexForTests: TestAspect[Nothing, Any, Throwable, Any] = beforeAll((for { + _ <- Executor.execute(ElasticRequest.createIndex(index)) + _ <- Executor.execute(ElasticRequest.deleteByQuery(index, matchAll).refreshTrue) + } yield ()).provide(elasticsearchLayer)) + + def genIndexName: Gen[Any, IndexName] = + Gen.stringBounded(10, 40)(Gen.alphaChar).map(name => unsafeWrap(name.toLowerCase)(IndexName)) + + def genDocumentId: Gen[Any, DocumentId] = + Gen.stringBounded(10, 40)(Gen.alphaNumericChar).map(DocumentId(_)) + + def genGeoPoint: Gen[Any, GeoPoint] = + for { + latitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + longitude <- Gen.bigDecimal(10, 90).map(_.setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble) + } yield GeoPoint(latitude, longitude) + + def genTestDocument: Gen[Any, TestDocument] = for { + stringField <- Gen.stringBounded(5, 10)(Gen.alphaChar) + dateField <- Gen.localDate(LocalDate.parse("2010-12-02"), LocalDate.parse("2022-12-05")) + subDocumentList <- Gen.listOfBounded(1, 3)(genTestSubDocument) + intField <- Gen.int(1, 2000) + doubleField <- Gen.double(100, 2000) + booleanField <- Gen.boolean + geoPointField <- genGeoPoint + vectorField <- Gen.listOfN(5)(Gen.int(-10, 10)) + } yield TestDocument( + stringField = stringField, + dateField = dateField, + subDocumentList = subDocumentList, + intField = intField, + doubleField = doubleField, + booleanField = booleanField, + geoPointField = geoPointField, + vectorField = vectorField + ) + + def genTestSubDocument: Gen[Any, TestSubDocument] = for { + stringField1 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + stringField2 <- Gen.stringBounded(5, 10)(Gen.alphaChar) + longField <- Gen.long(1, 75) + intField <- Gen.int(1, 200) + } yield TestSubDocument( + stringField = stringField1, + nestedField = TestNestedField(stringField2, longField), + intField = intField, + intFieldList = Nil + ) + + def checkOnce: CheckN = checkN(1) + + def assertException(substring: String): Assertion[Throwable] = hasMessage(containsString(substring)) +} From 72715dfb2600557282ad2a018507ae9fb5c93047 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:54:04 +0200 Subject: [PATCH 29/41] Remove space from ElasticQuerySpec. --- .../src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 1b88db8f7..da509a1e2 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -2627,7 +2627,7 @@ object ElasticQuerySpec extends ZIOSpecDefault { | "boosting": { | "positive": { | "terms": { - | "booleanField": [ true, false ] + | "booleanField": [ true, false ] | } | }, | "negative": { From 7941fe33b2de64c48e15747b878feffe972c9081 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 10:58:29 +0200 Subject: [PATCH 30/41] Return copyright to HttpExecutorSpec. --- .../zio/elasticsearch/HttpExecutorSpec.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 12ab6c820..7f6a44861 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -1,3 +1,19 @@ +/* + * 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 import zio.Chunk From 26150f138c7a81b45dc8e4d7075cc79e6dac4125 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 11:16:21 +0200 Subject: [PATCH 31/41] Add copyright in intervalSpec and some changes. --- .gitattributes | 2 +- .../scala/zio/elasticsearch/query/Queries.scala | 1 - .../elasticsearch/ElasticIntervalQuerySpec.scala | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index cafb792c1..a45fa8234 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ * text=auto eol=lf -sbt linguist-vendored \ No newline at end of file +sbt linguist-vendored diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala index 43d493420..b74c4a5f7 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/Queries.scala @@ -623,7 +623,6 @@ private[elasticsearch] final case class GeoPolygon[S]( ).flatten: _* ) ) - } sealed trait HasChildQuery[S] diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index a0e6fc2ed..d1fb36bd8 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -1,3 +1,19 @@ +/* + * 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 import zio.elasticsearch.ElasticQuery.intervals From 4d60d5fafbeef040f639b16ff7ad7a2ad85a1b67 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 13:50:37 +0200 Subject: [PATCH 32/41] Try to fix. --- .../zio/elasticsearch/ElasticQuery.scala | 3 - .../query/ElasticIntervalRule.scala | 3 - .../zio/elasticsearch/FieldDSLSpec.scala | 2 +- .../HttpElasticExecutorSpec.scala | 596 +++++++++--------- 4 files changed, 299 insertions(+), 305 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala index 59ffcc96d..897dba8b8 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticQuery.scala @@ -1,15 +1,12 @@ /* * 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. diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index f037e9f2c..0ce74c1c8 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -1,15 +1,12 @@ /* * 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. diff --git a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala index 6b873c7c0..a863ea7b9 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/FieldDSLSpec.scala @@ -1,6 +1,6 @@ /* * 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 diff --git a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala index 5545b7868..7357d7af4 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala @@ -1,298 +1,298 @@ -/* - * 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 - -import zio.Chunk -import zio.elasticsearch.ElasticAggregation.termsAggregation -import zio.elasticsearch.ElasticQuery.{kNN, matchAll, term} -import zio.elasticsearch.domain.TestDocument -import zio.elasticsearch.executor.Executor -import zio.elasticsearch.executor.response.{BulkResponse, CreateBulkResponse, Shards} -import zio.elasticsearch.request.CreationOutcome.Created -import zio.elasticsearch.request.DeletionOutcome.Deleted -import zio.elasticsearch.request.UpdateConflicts.Proceed -import zio.elasticsearch.request.UpdateOutcome -import zio.elasticsearch.result.{TermsAggregationBucketResult, TermsAggregationResult, UpdateByQueryResult} -import zio.elasticsearch.script.Script -import zio.test.Assertion._ -import zio.test.{Spec, TestEnvironment, TestResultZIOOps, assertZIO} - -object HttpElasticExecutorSpec extends SttpBackendStubSpec { - def spec: Spec[TestEnvironment, Any] = - suite("HttpElasticExecutor")( - test("aggregation") { - val executorAggregate = - Executor - .execute(ElasticRequest.aggregate(index, termsAggregation(name = "aggregation1", field = "name"))) - .aggregations - - val expectedTermsAggregationResult = - Map( - "aggregation1" -> TermsAggregationResult( - docErrorCount = 0, - sumOtherDocCount = 0, - buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) - ) - ) - - assertZIO(executorAggregate)(equalTo(expectedTermsAggregationResult)) - }, - test("bulk") { - val executorBulk = Executor.execute(ElasticRequest.bulk(ElasticRequest.create(index, doc)).refreshTrue) - - val expectedBulkResponse = - BulkResponse( - took = 3, - errors = false, - items = Chunk( - CreateBulkResponse( - index = "repositories", - id = "123", - version = Some(1), - result = Some("created"), - shards = Some(Shards(total = 1, successful = 1, failed = 0)), - status = Some(201), - error = None - ) - ) - ) - - assertZIO(executorBulk)(equalTo(expectedBulkResponse)) - }, - test("count") { - val executorCount = Executor.execute(ElasticRequest.count(index, matchAll).routing(Routing("routing"))) - - assertZIO(executorCount)(equalTo(2)) - }, - test("create") { - val executorCreate = - Executor - .execute( - ElasticRequest - .create[TestDocument](index = index, doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorCreate)(equalTo(DocumentId("V4x8q4UB3agN0z75fv5r"))) - }, - test("create with ID") { - val executorCreateDocumentId = - Executor.execute( - ElasticRequest - .create[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorCreateDocumentId)(equalTo(Created)) - }, - test("createIndex") { - val executorCreateIndex = Executor.execute(ElasticRequest.createIndex(index = index)) - - val mapping = - """ - |{ - | "settings": { - | "index": { - | "number_of_shards": 1 - | } - | }, - | "mappings": { - | "_routing": { - | "required": true - | }, - | "properties": { - | "id": { - | "type": "keyword" - | } - | } - | } - |} - |""".stripMargin - val executorCreateIndexMapping = - Executor.execute(ElasticRequest.createIndex(index = index, definition = mapping)) - - assertZIO(executorCreateIndex)(equalTo(Created)) && - assertZIO(executorCreateIndexMapping)(equalTo(Created)) - }, - test("deleteById") { - val executorDeleteById = - Executor.execute( - ElasticRequest - .deleteById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorDeleteById)(equalTo(Deleted)) - }, - test("deleteByQuery") { - val executorDeleteByQuery = - Executor.execute( - ElasticRequest.deleteByQuery(index = index, query = matchAll).refreshTrue.routing(Routing("routing")) - ) - - assertZIO(executorDeleteByQuery)(equalTo(Deleted)) - }, - test("deleteIndex") { - val executorDeleteIndex = Executor.execute(ElasticRequest.deleteIndex(index = index)) - - assertZIO(executorDeleteIndex)(equalTo(Deleted)) - }, - test("exists") { - val executorExists = - Executor.execute( - ElasticRequest - .exists(index = index, id = DocumentId("example-id")) - .routing(Routing("routing")) - ) - - assertZIO(executorExists)(isTrue) - }, - test("getById") { - val executorGetById = - Executor - .execute( - ElasticRequest - .getById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) - .routing(Routing("routing")) - ) - .documentAs[TestDocument] - - assertZIO(executorGetById)(isSome(equalTo(doc))) - }, - test("knnSearch") { - val executorSearch = - Executor - .execute( - ElasticRequest - .knnSearch(selectors = index, query = kNN(TestDocument.vectorField, 2, 5, Chunk(-5.0, 9.0, -12.0))) - ) - .documentAs[TestDocument] - assertZIO(executorSearch)(equalTo(Chunk(doc))) - }, - test("refresh") { - val executorRefresh = Executor.execute(ElasticRequest.refresh(selectors = index)) - assertZIO(executorRefresh)(equalTo(true)) - }, - test("search") { - val executorSearch = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll)) - .documentAs[TestDocument] - val terms = termsAggregation(name = "aggregation1", field = "name") - val executorSearchWithTerms = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) - .documentAs[TestDocument] - - assertZIO(executorSearch)(equalTo(Chunk(doc))) && assertZIO(executorSearchWithTerms)(equalTo(Chunk(doc))) - }, - test("search + aggregate") { - val terms = termsAggregation(name = "aggregation1", field = "name") - val executorSearchAggregations = - Executor - .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) - .aggregations - - val expectedTermsAggregationResult = - Map( - "aggregation1" -> TermsAggregationResult( - docErrorCount = 0, - sumOtherDocCount = 0, - buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) - ) - ) - - assertZIO(executorSearchAggregations)(equalTo(expectedTermsAggregationResult)) - }, - test("update") { - val executorUpdate = - Executor.execute( - ElasticRequest - .update[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .orCreate(doc = secondDoc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpdate)(equalTo(UpdateOutcome.Updated)) - }, - test("updateAllByQuery") { - val executorUpdateAllByQuery = - Executor.execute( - ElasticRequest - .updateAllByQuery(index = index, script = Script("ctx._source['intField']++")) - .conflicts(Proceed) - .routing(Routing("routing")) - .refreshTrue - ) - - val expectedUpdateByQueryResult = - UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) - - assertZIO(executorUpdateAllByQuery)(equalTo(expectedUpdateByQueryResult)) - }, - test("updateByQuery") { - val executorUpdateByQuery = - Executor.execute( - ElasticRequest - .updateByQuery( - index = index, - query = term(field = TestDocument.stringField.keyword, value = "StringField"), - script = Script("ctx._source['intField']++") - ) - .conflicts(Proceed) - .routing(Routing("routing")) - .refreshTrue - ) - - val expectedUpdateByQueryResult = - UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) - - assertZIO(executorUpdateByQuery)(equalTo(expectedUpdateByQueryResult)) - }, - test("updateByScript") { - val executorUpdateByScript = - Executor.execute( - ElasticRequest - .updateByScript( - index = index, - id = DocumentId("V4x8q4UB3agN0z75fv5r"), - script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) - ) - .orCreate(doc = secondDoc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpdateByScript)(equalTo(UpdateOutcome.Updated)) - }, - test("upsert") { - val executorUpsert = - Executor.execute( - ElasticRequest - .upsert[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) - .routing(Routing("routing")) - .refreshTrue - ) - - assertZIO(executorUpsert)(isUnit) - } - ).provideShared(elasticsearchSttpLayer) -} +/* + * 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 + +import zio.Chunk +import zio.elasticsearch.ElasticAggregation.termsAggregation +import zio.elasticsearch.ElasticQuery.{kNN, matchAll, term} +import zio.elasticsearch.domain.TestDocument +import zio.elasticsearch.executor.Executor +import zio.elasticsearch.executor.response.{BulkResponse, CreateBulkResponse, Shards} +import zio.elasticsearch.request.CreationOutcome.Created +import zio.elasticsearch.request.DeletionOutcome.Deleted +import zio.elasticsearch.request.UpdateConflicts.Proceed +import zio.elasticsearch.request.UpdateOutcome +import zio.elasticsearch.result.{TermsAggregationBucketResult, TermsAggregationResult, UpdateByQueryResult} +import zio.elasticsearch.script.Script +import zio.test.Assertion._ +import zio.test.{Spec, TestEnvironment, TestResultZIOOps, assertZIO} + +object HttpElasticExecutorSpec extends SttpBackendStubSpec { + def spec: Spec[TestEnvironment, Any] = + suite("HttpElasticExecutor")( + test("aggregation") { + val executorAggregate = + Executor + .execute(ElasticRequest.aggregate(index, termsAggregation(name = "aggregation1", field = "name"))) + .aggregations + + val expectedTermsAggregationResult = + Map( + "aggregation1" -> TermsAggregationResult( + docErrorCount = 0, + sumOtherDocCount = 0, + buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) + ) + ) + + assertZIO(executorAggregate)(equalTo(expectedTermsAggregationResult)) + }, + test("bulk") { + val executorBulk = Executor.execute(ElasticRequest.bulk(ElasticRequest.create(index, doc)).refreshTrue) + + val expectedBulkResponse = + BulkResponse( + took = 3, + errors = false, + items = Chunk( + CreateBulkResponse( + index = "repositories", + id = "123", + version = Some(1), + result = Some("created"), + shards = Some(Shards(total = 1, successful = 1, failed = 0)), + status = Some(201), + error = None + ) + ) + ) + + assertZIO(executorBulk)(equalTo(expectedBulkResponse)) + }, + test("count") { + val executorCount = Executor.execute(ElasticRequest.count(index, matchAll).routing(Routing("routing"))) + + assertZIO(executorCount)(equalTo(2)) + }, + test("create") { + val executorCreate = + Executor + .execute( + ElasticRequest + .create[TestDocument](index = index, doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorCreate)(equalTo(DocumentId("V4x8q4UB3agN0z75fv5r"))) + }, + test("create with ID") { + val executorCreateDocumentId = + Executor.execute( + ElasticRequest + .create[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorCreateDocumentId)(equalTo(Created)) + }, + test("createIndex") { + val executorCreateIndex = Executor.execute(ElasticRequest.createIndex(index = index)) + + val mapping = + """ + |{ + | "settings": { + | "index": { + | "number_of_shards": 1 + | } + | }, + | "mappings": { + | "_routing": { + | "required": true + | }, + | "properties": { + | "id": { + | "type": "keyword" + | } + | } + | } + |} + |""".stripMargin + val executorCreateIndexMapping = + Executor.execute(ElasticRequest.createIndex(index = index, definition = mapping)) + + assertZIO(executorCreateIndex)(equalTo(Created)) && + assertZIO(executorCreateIndexMapping)(equalTo(Created)) + }, + test("deleteById") { + val executorDeleteById = + Executor.execute( + ElasticRequest + .deleteById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorDeleteById)(equalTo(Deleted)) + }, + test("deleteByQuery") { + val executorDeleteByQuery = + Executor.execute( + ElasticRequest.deleteByQuery(index = index, query = matchAll).refreshTrue.routing(Routing("routing")) + ) + + assertZIO(executorDeleteByQuery)(equalTo(Deleted)) + }, + test("deleteIndex") { + val executorDeleteIndex = Executor.execute(ElasticRequest.deleteIndex(index = index)) + + assertZIO(executorDeleteIndex)(equalTo(Deleted)) + }, + test("exists") { + val executorExists = + Executor.execute( + ElasticRequest + .exists(index = index, id = DocumentId("example-id")) + .routing(Routing("routing")) + ) + + assertZIO(executorExists)(isTrue) + }, + test("getById") { + val executorGetById = + Executor + .execute( + ElasticRequest + .getById(index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r")) + .routing(Routing("routing")) + ) + .documentAs[TestDocument] + + assertZIO(executorGetById)(isSome(equalTo(doc))) + }, + test("knnSearch") { + val executorSearch = + Executor + .execute( + ElasticRequest + .knnSearch(selectors = index, query = kNN(TestDocument.vectorField, 2, 5, Chunk(-5.0, 9.0, -12.0))) + ) + .documentAs[TestDocument] + assertZIO(executorSearch)(equalTo(Chunk(doc))) + }, + test("refresh") { + val executorRefresh = Executor.execute(ElasticRequest.refresh(selectors = index)) + assertZIO(executorRefresh)(equalTo(true)) + }, + test("search") { + val executorSearch = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll)) + .documentAs[TestDocument] + val terms = termsAggregation(name = "aggregation1", field = "name") + val executorSearchWithTerms = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) + .documentAs[TestDocument] + + assertZIO(executorSearch)(equalTo(Chunk(doc))) && assertZIO(executorSearchWithTerms)(equalTo(Chunk(doc))) + }, + test("search + aggregate") { + val terms = termsAggregation(name = "aggregation1", field = "name") + val executorSearchAggregations = + Executor + .execute(ElasticRequest.search(selectors = index, query = matchAll, aggregation = terms)) + .aggregations + + val expectedTermsAggregationResult = + Map( + "aggregation1" -> TermsAggregationResult( + docErrorCount = 0, + sumOtherDocCount = 0, + buckets = Chunk(TermsAggregationBucketResult(docCount = 5, key = "name", subAggregations = Map.empty)) + ) + ) + + assertZIO(executorSearchAggregations)(equalTo(expectedTermsAggregationResult)) + }, + test("update") { + val executorUpdate = + Executor.execute( + ElasticRequest + .update[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .orCreate(doc = secondDoc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpdate)(equalTo(UpdateOutcome.Updated)) + }, + test("updateAllByQuery") { + val executorUpdateAllByQuery = + Executor.execute( + ElasticRequest + .updateAllByQuery(index = index, script = Script("ctx._source['intField']++")) + .conflicts(Proceed) + .routing(Routing("routing")) + .refreshTrue + ) + + val expectedUpdateByQueryResult = + UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) + + assertZIO(executorUpdateAllByQuery)(equalTo(expectedUpdateByQueryResult)) + }, + test("updateByQuery") { + val executorUpdateByQuery = + Executor.execute( + ElasticRequest + .updateByQuery( + index = index, + query = term(field = TestDocument.stringField.keyword, value = "StringField"), + script = Script("ctx._source['intField']++") + ) + .conflicts(Proceed) + .routing(Routing("routing")) + .refreshTrue + ) + + val expectedUpdateByQueryResult = + UpdateByQueryResult(took = 1, total = 10, updated = 8, deleted = 0, versionConflicts = 2) + + assertZIO(executorUpdateByQuery)(equalTo(expectedUpdateByQueryResult)) + }, + test("updateByScript") { + val executorUpdateByScript = + Executor.execute( + ElasticRequest + .updateByScript( + index = index, + id = DocumentId("V4x8q4UB3agN0z75fv5r"), + script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) + ) + .orCreate(doc = secondDoc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpdateByScript)(equalTo(UpdateOutcome.Updated)) + }, + test("upsert") { + val executorUpsert = + Executor.execute( + ElasticRequest + .upsert[TestDocument](index = index, id = DocumentId("V4x8q4UB3agN0z75fv5r"), doc = doc) + .routing(Routing("routing")) + .refreshTrue + ) + + assertZIO(executorUpsert)(isUnit) + } + ).provideShared(elasticsearchSttpLayer) +} From c7eab4e29d430b8449f65a26a1aa5e08b35c5eb1 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 13:52:20 +0200 Subject: [PATCH 33/41] Fix space in copyright --- .../src/test/scala/zio/elasticsearch/IntegrationSpec.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala index 4bf0f457d..2fa580a6f 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/IntegrationSpec.scala @@ -1,10 +1,10 @@ /* * 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 From 377bf8c18ef001a69346b3a994080c31e21eeb54 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 13:54:37 +0200 Subject: [PATCH 34/41] Fix space in copyright --- .../test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala index 7357d7af4..fdd847540 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/HttpElasticExecutorSpec.scala @@ -6,7 +6,7 @@ * 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. From b21a202b68f2d55ac824c1de8f08be7610a99268 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 13:54:55 +0200 Subject: [PATCH 35/41] Fix space in copyright --- .../src/test/scala/zio/elasticsearch/IndexNameSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala index 1bbd16876..895364f25 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/IndexNameSpec.scala @@ -4,7 +4,7 @@ * 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 From b14e4d9072524bb18aae9b6c883f4ead5ccf9b81 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Thu, 19 Jun 2025 16:45:22 +0200 Subject: [PATCH 36/41] Add to sidebars.js --- .../elastic_query_interval.md} | 0 website/sidebars.js | 1 + 2 files changed, 1 insertion(+) rename docs/overview/{elastic_interval_query.md => queries/elastic_query_interval.md} (100%) diff --git a/docs/overview/elastic_interval_query.md b/docs/overview/queries/elastic_query_interval.md similarity index 100% rename from docs/overview/elastic_interval_query.md rename to docs/overview/queries/elastic_query_interval.md diff --git a/website/sidebars.js b/website/sidebars.js index 8c11fe381..e90bdb609 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -25,6 +25,7 @@ module.exports = { 'overview/queries/elastic_query_geo_polygon', 'overview/queries/elastic_query_has_child', 'overview/queries/elastic_query_has_parent', + 'overview/queries/elastic_query_interval.md', 'overview/queries/elastic_query_match', 'overview/queries/elastic_query_match_all', 'overview/queries/elastic_query_match_boolean_prefix', From 72e782b61fcf1bb1ad02c52adb83e18519aef4d3 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 20 Jun 2025 10:08:40 +0200 Subject: [PATCH 37/41] Move ElasticInterval object in separated file, fix some problems. --- .../queries/elastic_query_interval.md | 4 +- .../zio/elasticsearch/HttpExecutorSpec.scala | 24 ++-- .../elasticsearch/ElasticIntervalQuery.scala | 95 ++++++++++++++ .../query/ElasticIntervalRule.scala | 120 +++--------------- .../ElasticIntervalQuerySpec.scala | 27 +--- 5 files changed, 127 insertions(+), 143 deletions(-) create mode 100644 modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala diff --git a/docs/overview/queries/elastic_query_interval.md b/docs/overview/queries/elastic_query_interval.md index 641a17435..6cb26ee01 100644 --- a/docs/overview/queries/elastic_query_interval.md +++ b/docs/overview/queries/elastic_query_interval.md @@ -37,7 +37,7 @@ val queryWithMaxGaps: IntervalQuery[Document] = If you want to specify the word order requirement, use the `orderedOn` method: ```scala val queryWithOrder: IntervalQuery[Document] = - intervals(field = "content", rule = intervalMatch("targetWord").orderedOn()) + intervals(field = "content", rule = intervalMatch("targetWord").orderedOn) ``` You can also apply additional filters to the query: @@ -53,7 +53,7 @@ val queryManually: IntervalQuery[Document] = field = "content", rule = intervalMatch("targetWord") .maxGaps(2) - .orderedOn() + .orderedOn .filter(IntervalFilter.someFilter) .analyzer("standard") ) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 7f6a44861..9cea6208a 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -19,6 +19,7 @@ package zio.elasticsearch import zio.Chunk import zio.elasticsearch.ElasticAggregation._ import zio.elasticsearch.ElasticHighlight.highlight +import zio.elasticsearch.ElasticIntervalQuery.intervalMatch import zio.elasticsearch.ElasticQuery.{contains => _, _} import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.aggregation.AggregationOrder @@ -26,7 +27,6 @@ import zio.elasticsearch.data.GeoPoint import zio.elasticsearch.domain.{PartialTestDocument, TestDocument, TestSubDocument} import zio.elasticsearch.executor.Executor import zio.elasticsearch.query.DistanceUnit.Kilometers -import zio.elasticsearch.query.ElasticIntervalQuery.intervalMatch import zio.elasticsearch.query.FunctionScoreFunction.randomScoreFunction import zio.elasticsearch.query.MultiMatchType._ import zio.elasticsearch.query.sort.SortMode.Max @@ -2774,24 +2774,16 @@ object HttpExecutorSpec extends IntegrationSpec { ), suite("intervals query")( test("intervalMatch returns only matching document") { - checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString, genDocumentId, genTestDocument) { - (idMatch, docMatch, targetWord, idNoMatch, docNoMatch) => - val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") - val docShouldNotMatch = docNoMatch.copy(stringField = "completely unrelated text") - val field = TestDocument.stringField.toString - val query = intervals(field, intervalMatch(targetWord)) + checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString.filter(_.nonEmpty)) { + (idMatch, docMatch, targetWord) => + val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") + val query = intervals(TestDocument.stringField, intervalMatch(targetWord)) for { - _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) - _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch)) - _ <- Executor.execute( - ElasticRequest.upsert(firstSearchIndex, idNoMatch, docShouldNotMatch).refreshTrue - ) + _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) + _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch).refreshTrue) res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] - } yield assert(res)( - Assertion.contains(docShouldMatch) && - Assertion.not(Assertion.contains(docShouldNotMatch)) - ) + } yield assert(res)(Assertion.hasSameElements(Chunk(docShouldMatch))) } } @@ around( Executor.execute(ElasticRequest.createIndex(firstSearchIndex)), diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala new file mode 100644 index 000000000..95aea5282 --- /dev/null +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala @@ -0,0 +1,95 @@ +package zio.elasticsearch + +import zio.NonEmptyChunk +import zio.elasticsearch.query.{ + IntervalAllOf, + IntervalAnyOf, + IntervalFilter, + IntervalFuzzy, + IntervalMatch, + IntervalPrefix, + IntervalRange, + IntervalRegexp, + IntervalRule, + IntervalWildcard, + Regexp +} +import zio.json.ast.Json + +object ElasticIntervalQuery { + + def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = + IntervalAllOf(intervals = intervals, maxGaps = None, ordered = None, filter = None) + + def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = + IntervalAnyOf(intervals = intervals, filter = None) + + def intervalContains[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) + + def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"*$pattern", analyzer = None, useField = None) + + def intervalFilter[S]( + after: Option[IntervalRule] = None, + before: Option[IntervalRule] = None, + containedBy: Option[IntervalRule] = None, + containing: Option[IntervalRule] = None, + notContainedBy: Option[IntervalRule] = None, + notContaining: Option[IntervalRule] = None, + notOverlapping: Option[IntervalRule] = None, + overlapping: Option[IntervalRule] = None, + script: Option[Json] = None + ): Option[IntervalFilter[S]] = { + + val filter: IntervalFilter[S] = IntervalFilter( + after = after, + before = before, + containedBy = containedBy, + containing = containing, + notContainedBy = notContainedBy, + notContaining = notContaining, + notOverlapping = notOverlapping, + overlapping = overlapping, + script = script + ) + + Some(filter).filterNot(_ => + List(after, before, containedBy, containing, notContainedBy, notContaining, notOverlapping, overlapping, script) + .forall(_.isEmpty) + ) + } + + def intervalFuzzy[S](term: String): IntervalFuzzy[S] = + IntervalFuzzy( + term = term, + prefixLength = None, + transpositions = None, + fuzziness = None, + analyzer = None, + useField = None + ) + + def intervalMatch[S](query: String): IntervalMatch[S] = + IntervalMatch(query = query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) + + def intervalPrefix[S](prefix: String): IntervalPrefix[S] = + IntervalPrefix(prefix = prefix, analyzer = None, useField = None) + + def intervalRange[S]( + lower: Option[IntervalRule] = None, + upper: Option[IntervalRule] = None, + analyzer: Option[String] = None, + useField: Option[String] = None + ): IntervalRange[S] = + IntervalRange(lower = lower, upper = upper, analyzer = analyzer, useField = useField) + + def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = + IntervalRegexp(pattern = pattern, analyzer = None, useField = None) + + def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(s"$pattern*", analyzer = None, useField = None) + + def intervalWildcard[S](pattern: String): IntervalWildcard[S] = + IntervalWildcard(pattern = pattern, analyzer = None, useField = None) +} diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index 0ce74c1c8..6bf2d231b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -21,7 +21,7 @@ import zio.elasticsearch.Field import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} -import zio.{Chunk, NonEmptyChunk} +import zio.Chunk private[elasticsearch] sealed trait BoundType private[elasticsearch] sealed trait Inclusive extends BoundType @@ -138,9 +138,9 @@ private[elasticsearch] final case class IntervalFuzzy[S]( def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field.toString)) + def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field.name)) - def useField(field: String): IntervalFuzzy[S] = copy(useField = Some(Field(None, field).toString)) + def useField(field: String): IntervalFuzzy[S] = copy(useField = Some(field)) def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) @@ -184,9 +184,9 @@ private[elasticsearch] final case class IntervalMatch[S]( def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) - def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field.toString)) + def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field.name)) - def useField(field: String): IntervalMatch[S] = copy(useField = Some(Field(None, field).toString)) + def useField(field: String): IntervalMatch[S] = copy(useField = Some(field)) override private[elasticsearch] def toJson: Json = Obj( @@ -213,9 +213,9 @@ private[elasticsearch] final case class IntervalPrefix[S]( def analyzer(value: String): IntervalPrefix[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field.toString)) + def useField(field: Field[_, _]): IntervalPrefix[S] = copy(useField = Some(field.name)) - def useField(field: String): IntervalPrefix[S] = copy(useField = Some(Field(None, field).toString)) + def useField(field: String): IntervalPrefix[S] = copy(useField = Some(field)) override private[elasticsearch] def toJson: Json = Obj( @@ -240,25 +240,21 @@ private[elasticsearch] final case class IntervalRange[S]( def analyzer(value: String): IntervalRange[S] = copy(analyzer = Some(value)) - def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(b.value))) + def gt[B <: BoundType](value: String): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(value))) - def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) + def gte[B <: BoundType](value: String): IntervalRange[S] = copy(lower = Some(GreaterThanOrEqualToInterval(value))) - def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field.toString)) + def lower[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(lower = Some(GreaterThanInterval(b.value))) - def useField(field: String): IntervalRange[S] = copy(useField = Some(Field(None, field).toString)) + def lt[B <: BoundType](value: String): IntervalRange[S] = copy(upper = Some(LessThanInterval(value))) - def gte[B <: BoundType](value: String): IntervalRange[S] = - copy(lower = Some(GreaterThanOrEqualToInterval(value))) + def lte[B <: BoundType](value: String): IntervalRange[S] = copy(upper = Some(LessThanOrEqualToInterval(value))) - def gt[B <: BoundType](value: String): IntervalRange[S] = - copy(lower = Some(GreaterThanInterval(value))) + def upper[B <: BoundType](b: Bound[B]): IntervalRange[S] = copy(upper = Some(LessThanInterval(b.value))) - def lte[B <: BoundType](value: String): IntervalRange[S] = - copy(upper = Some(LessThanOrEqualToInterval(value))) + def useField(field: Field[_, _]): IntervalRange[S] = copy(useField = Some(field.name)) - def lt[B <: BoundType](value: String): IntervalRange[S] = - copy(upper = Some(LessThanInterval(value))) + def useField(field: String): IntervalRange[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -283,9 +279,9 @@ private[elasticsearch] final case class IntervalRegexp[S]( def analyzer(value: String): IntervalRegexp[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field.toString)) + def useField(field: Field[_, _]): IntervalRegexp[S] = copy(useField = Some(field.name)) - def useField(field: String): IntervalRegexp[S] = copy(useField = Some(Field(None, field).toString)) + def useField(field: String): IntervalRegexp[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -309,9 +305,9 @@ private[elasticsearch] final case class IntervalWildcard[S]( def analyzer(value: String): IntervalWildcard[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field.toString)) + def useField(field: Field[_, _]): IntervalWildcard[S] = copy(useField = Some(field.name)) - def useField(field: String): IntervalWildcard[S] = copy(useField = Some(Field(None, field).toString)) + def useField(field: String): IntervalWildcard[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -324,81 +320,3 @@ private[elasticsearch] final case class IntervalWildcard[S]( ) ) } - -object ElasticIntervalQuery { - - def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = - IntervalAllOf(intervals = intervals, maxGaps = None, ordered = None, filter = None) - - def intervalAnyOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAnyOf[S] = - IntervalAnyOf(intervals = intervals, filter = None) - - def intervalContains[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern*", analyzer = None, useField = None) - - def intervalEndsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"*$pattern", analyzer = None, useField = None) - - def intervalFilter[S]( - after: Option[IntervalRule] = None, - before: Option[IntervalRule] = None, - containedBy: Option[IntervalRule] = None, - containing: Option[IntervalRule] = None, - notContainedBy: Option[IntervalRule] = None, - notContaining: Option[IntervalRule] = None, - notOverlapping: Option[IntervalRule] = None, - overlapping: Option[IntervalRule] = None, - script: Option[Json] = None - ): Option[IntervalFilter[S]] = { - - val filter: IntervalFilter[S] = IntervalFilter( - after = after, - before = before, - containedBy = containedBy, - containing = containing, - notContainedBy = notContainedBy, - notContaining = notContaining, - notOverlapping = notOverlapping, - overlapping = overlapping, - script = script - ) - - Some(filter).filterNot(_ => - List(after, before, containedBy, containing, notContainedBy, notContaining, notOverlapping, overlapping, script) - .forall(_.isEmpty) - ) - } - - def intervalFuzzy[S](term: String): IntervalFuzzy[S] = - IntervalFuzzy( - term = term, - prefixLength = None, - transpositions = None, - fuzziness = None, - analyzer = None, - useField = None - ) - - def intervalMatch[S](query: String): IntervalMatch[S] = - IntervalMatch(query = query, analyzer = None, useField = None, maxGaps = None, ordered = None, filter = None) - - def intervalPrefix[S](prefix: String): IntervalPrefix[S] = - IntervalPrefix(prefix = prefix, analyzer = None, useField = None) - - def intervalRange[S]( - lower: Option[IntervalRule] = None, - upper: Option[IntervalRule] = None, - analyzer: Option[String] = None, - useField: Option[String] = None - ): IntervalRange[S] = - IntervalRange(lower = lower, upper = upper, analyzer = analyzer, useField = useField) - - def intervalRegexp[S](pattern: Regexp[S]): IntervalRegexp[S] = - IntervalRegexp(pattern = pattern, analyzer = None, useField = None) - - def intervalStartsWith[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(s"$pattern*", analyzer = None, useField = None) - - def intervalWildcard[S](pattern: String): IntervalWildcard[S] = - IntervalWildcard(pattern = pattern, analyzer = None, useField = None) -} diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index d1fb36bd8..a9240ce70 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -16,9 +16,7 @@ package zio.elasticsearch -import zio.elasticsearch.ElasticQuery.intervals -import zio.elasticsearch.domain.TestDocument -import zio.elasticsearch.query.ElasticIntervalQuery.{ +import zio.elasticsearch.ElasticIntervalQuery.{ intervalContains, intervalEndsWith, intervalMatch, @@ -26,6 +24,8 @@ import zio.elasticsearch.query.ElasticIntervalQuery.{ intervalStartsWith, intervalWildcard } +import zio.elasticsearch.ElasticQuery.intervals +import zio.elasticsearch.domain.TestDocument import zio.elasticsearch.query._ import zio.elasticsearch.utils._ import zio.test.Assertion.equalTo @@ -112,18 +112,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { |} |""".stripMargin - assert(intervalNoOptions)( - equalTo( - IntervalMatch[String]( - query = "lambda works", - analyzer = None, - useField = None, - maxGaps = None, - ordered = None, - filter = None - ) - ) - ) && assert(intervals("stringField", intervalNoOptions).toJson(None))( equalTo(expectedNoOptions.toJson) ) && @@ -296,15 +284,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { |} |""".stripMargin - assert(wildcardExact)( - equalTo( - IntervalWildcard[String]( - pattern = "la*mb?da", - analyzer = None, - useField = None - ) - ) - ) && assert(queryExact.toJson(None))(equalTo(expectedExact.toJson)) && assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && From 626dfda4b7e9378a046ce9bfa9e1e73d61878327 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 20 Jun 2025 10:12:27 +0200 Subject: [PATCH 38/41] Add line in elastic_query_interval.md and do sbt prepare --- docs/overview/queries/elastic_query_interval.md | 1 + .../zio/elasticsearch/ElasticIntervalQuery.scala | 16 ++++++++++++++++ .../query/ElasticIntervalRule.scala | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/overview/queries/elastic_query_interval.md b/docs/overview/queries/elastic_query_interval.md index 6cb26ee01..c5db98dd0 100644 --- a/docs/overview/queries/elastic_query_interval.md +++ b/docs/overview/queries/elastic_query_interval.md @@ -2,6 +2,7 @@ id: elastic_interval_query title: "Overview" --- + The `Intervals` query allows for advanced search queries based on intervals between words in specific fields. This query provides flexibility for conditions. diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala index 95aea5282..d1b628386 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala @@ -1,3 +1,19 @@ +/* + * 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 import zio.NonEmptyChunk diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index 6bf2d231b..b78a3d18d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -16,12 +16,12 @@ package zio.elasticsearch.query +import zio.Chunk import zio.elasticsearch.ElasticPrimitive.ElasticPrimitiveOps import zio.elasticsearch.Field import zio.elasticsearch.query.options.{HasAnalyzer, HasUseField} import zio.json.ast.Json import zio.json.ast.Json.{Arr, Obj, Str} -import zio.Chunk private[elasticsearch] sealed trait BoundType private[elasticsearch] sealed trait Inclusive extends BoundType From 61a4949476efb82a8a3f4c28c386089e5ab6c653 Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 20 Jun 2025 10:39:35 +0200 Subject: [PATCH 39/41] Done. --- .../scala/zio/elasticsearch/HttpExecutorSpec.scala | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 9cea6208a..27d13d640 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -2773,16 +2773,22 @@ object HttpExecutorSpec extends IntegrationSpec { } @@ after(Executor.execute(ElasticRequest.deleteIndex(geoPolygonIndex)).orDie) ), suite("intervals query")( - test("intervalMatch returns only matching document") { + test("intervalMatch query returns only matching document") { checkOnce(genDocumentId, genTestDocument, Gen.alphaNumericString.filter(_.nonEmpty)) { (idMatch, docMatch, targetWord) => val docShouldMatch = docMatch.copy(stringField = s"prefix $targetWord suffix") - val query = intervals(TestDocument.stringField, intervalMatch(targetWord)) for { _ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll)) _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, idMatch, docShouldMatch).refreshTrue) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + res <- Executor + .execute( + ElasticRequest.search( + firstSearchIndex, + intervals(TestDocument.stringField, intervalMatch(targetWord)) + ) + ) + .documentAs[TestDocument] } yield assert(res)(Assertion.hasSameElements(Chunk(docShouldMatch))) } } @@ around( From 1aae089fc8c55d1fa0e55baa4f40d337433a9d8c Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 20 Jun 2025 14:05:04 +0200 Subject: [PATCH 40/41] Some fixes. --- .../zio/elasticsearch/HttpExecutorSpec.scala | 34 ++++++++++++------- .../query/ElasticIntervalRule.scala | 20 +++++------ .../ElasticIntervalQuerySpec.scala | 2 +- website/sidebars.js | 2 +- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 27d13d640..13c863c3f 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -2800,15 +2800,20 @@ object HttpExecutorSpec extends IntegrationSpec { val term = "apple" val docWithTerm = doc.copy(stringField = s"$term banana orange") - val query = intervals( - "stringField", - intervalMatch(term) - ) - for { _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, docWithTerm)) _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + res <- Executor + .execute( + ElasticRequest.search( + firstSearchIndex, + intervals( + TestDocument.stringField, + intervalMatch(term) + ) + ) + ) + .documentAs[TestDocument] } yield assert(res)(Assertion.contains(docWithTerm)) } } @@ around( @@ -2817,15 +2822,20 @@ object HttpExecutorSpec extends IntegrationSpec { ), test("intervalMatch query does not find document if term is absent") { checkOnce(genDocumentId, genTestDocument) { (docId, doc) => - val query = intervals( - "stringField", - intervalMatch("nonexistentterm") - ) - for { _ <- Executor.execute(ElasticRequest.upsert(firstSearchIndex, docId, doc)) _ <- Executor.execute(ElasticRequest.refresh(firstSearchIndex)) - res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument] + res <- Executor + .execute( + ElasticRequest.search( + firstSearchIndex, + intervals( + TestDocument.stringField, + intervalMatch("nonexistentterm") + ) + ) + ) + .documentAs[TestDocument] } yield assert(res)(Assertion.isEmpty) } } @@ around( diff --git a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala index b78a3d18d..a7ae616a4 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/query/ElasticIntervalRule.scala @@ -65,8 +65,6 @@ private[elasticsearch] final case class IntervalAllOf[S]( def orderedOn: IntervalAllOf[S] = copy(ordered = Some(true)) - def orderedOff: IntervalAllOf[S] = copy(ordered = Some(false)) - private[elasticsearch] def toJson: Json = Obj( "all_of" -> Obj( @@ -87,7 +85,7 @@ private[elasticsearch] final case class IntervalAnyOf[S]( def filter(f: IntervalFilter[S]): IntervalAnyOf[S] = copy(filter = Some(f)) - override private[elasticsearch] def toJson: Json = + private[elasticsearch] def toJson: Json = Obj( "any_of" -> Obj( Chunk( @@ -138,15 +136,15 @@ private[elasticsearch] final case class IntervalFuzzy[S]( def analyzer(value: String): IntervalFuzzy[S] = copy(analyzer = Some(value)) - def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field.name)) - - def useField(field: String): IntervalFuzzy[S] = copy(useField = Some(field)) - def prefixLength(length: Int): IntervalFuzzy[S] = copy(prefixLength = Some(length)) + def transpositionsDisabled: IntervalFuzzy[S] = copy(transpositions = Some(false)) + def transpositionsEnabled: IntervalFuzzy[S] = copy(transpositions = Some(true)) - def transpositionsDisabled: IntervalFuzzy[S] = copy(transpositions = Some(false)) + def useField(field: Field[_, _]): IntervalFuzzy[S] = copy(useField = Some(field.name)) + + def useField(field: String): IntervalFuzzy[S] = copy(useField = Some(field)) private[elasticsearch] def toJson: Json = Obj( @@ -182,13 +180,11 @@ private[elasticsearch] final case class IntervalMatch[S]( def orderedOn: IntervalMatch[S] = copy(ordered = Some(true)) - def orderedOff: IntervalMatch[S] = copy(ordered = Some(false)) - def useField(field: Field[_, _]): IntervalMatch[S] = copy(useField = Some(field.name)) def useField(field: String): IntervalMatch[S] = copy(useField = Some(field)) - override private[elasticsearch] def toJson: Json = + private[elasticsearch] def toJson: Json = Obj( "match" -> Obj( Chunk( @@ -217,7 +213,7 @@ private[elasticsearch] final case class IntervalPrefix[S]( def useField(field: String): IntervalPrefix[S] = copy(useField = Some(field)) - override private[elasticsearch] def toJson: Json = + private[elasticsearch] def toJson: Json = Obj( "prefix" -> Obj( Chunk( diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala index a9240ce70..a38f19c90 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala @@ -46,7 +46,7 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { after = Some(intervalMatch("after_term")) ) - val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works").orderedOff + val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") .maxGaps(2) .analyzer("standard") .filter(filter) diff --git a/website/sidebars.js b/website/sidebars.js index e90bdb609..ce8b26f1b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -25,7 +25,7 @@ module.exports = { 'overview/queries/elastic_query_geo_polygon', 'overview/queries/elastic_query_has_child', 'overview/queries/elastic_query_has_parent', - 'overview/queries/elastic_query_interval.md', + 'overview/queries/elastic_query_interval', 'overview/queries/elastic_query_match', 'overview/queries/elastic_query_match_all', 'overview/queries/elastic_query_match_boolean_prefix', From 689ab2e5155d7ee9c57f835bee08f4d515ac5fcf Mon Sep 17 00:00:00 2001 From: Marko Krstic Date: Fri, 20 Jun 2025 16:30:44 +0200 Subject: [PATCH 41/41] Add unit tests for query. --- .../zio/elasticsearch/HttpExecutorSpec.scala | 2 +- ...lQuery.scala => ElasticIntervalRule.scala} | 2 +- ...ec.scala => ElasticIntervalRuleSpec.scala} | 109 +++++++++++------- 3 files changed, 69 insertions(+), 44 deletions(-) rename modules/library/src/main/scala/zio/elasticsearch/{ElasticIntervalQuery.scala => ElasticIntervalRule.scala} (99%) rename modules/library/src/test/scala/zio/elasticsearch/{ElasticIntervalQuerySpec.scala => ElasticIntervalRuleSpec.scala} (82%) diff --git a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala index 13c863c3f..939be62a6 100644 --- a/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala +++ b/modules/integration/src/test/scala/zio/elasticsearch/HttpExecutorSpec.scala @@ -19,7 +19,7 @@ package zio.elasticsearch import zio.Chunk import zio.elasticsearch.ElasticAggregation._ import zio.elasticsearch.ElasticHighlight.highlight -import zio.elasticsearch.ElasticIntervalQuery.intervalMatch +import zio.elasticsearch.ElasticIntervalRule.intervalMatch import zio.elasticsearch.ElasticQuery.{contains => _, _} import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.aggregation.AggregationOrder diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalRule.scala similarity index 99% rename from modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala rename to modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalRule.scala index d1b628386..cac26b2d1 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalQuery.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticIntervalRule.scala @@ -32,7 +32,7 @@ import zio.elasticsearch.query.{ } import zio.json.ast.Json -object ElasticIntervalQuery { +object ElasticIntervalRule { def intervalAllOf[S](intervals: NonEmptyChunk[IntervalRule]): IntervalAllOf[S] = IntervalAllOf(intervals = intervals, maxGaps = None, ordered = None, filter = None) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalRuleSpec.scala similarity index 82% rename from modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala rename to modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalRuleSpec.scala index a38f19c90..2241c2b3d 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticIntervalRuleSpec.scala @@ -16,7 +16,7 @@ package zio.elasticsearch -import zio.elasticsearch.ElasticIntervalQuery.{ +import zio.elasticsearch.ElasticIntervalRule.{ intervalContains, intervalEndsWith, intervalMatch, @@ -31,10 +31,10 @@ import zio.elasticsearch.utils._ import zio.test.Assertion.equalTo import zio.test._ -object ElasticIntervalQuerySpec extends ZIOSpecDefault { - def spec: Spec[TestEnvironment, Any] = - suite("ElasticIntervalQuerySpec")( - test("intervalMatchQuery") { +object ElasticIntervalRuleSpec extends ZIOSpecDefault { + def spec: Spec[TestEnvironment, Any] = { + suite("ElasticIntervalRuleSpec")( + test("intervalMatch") { val intervalNoOptions: IntervalMatch[String] = intervalMatch("lambda works") val intervalWithOptions: IntervalMatch[String] = intervalMatch("lambda works").orderedOn @@ -46,14 +46,8 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { after = Some(intervalMatch("after_term")) ) - val intervalWithFilter: IntervalMatch[String] = intervalMatch("lambda works") - .maxGaps(2) - .analyzer("standard") - .filter(filter) - val queryWithStringField = intervals("stringField", intervalWithOptions) val queryWithTypedField = intervals(TestDocument.stringField, intervalWithOptions) - val queryWithFilter = intervals("stringField", intervalWithFilter) val expectedNoOptions = """ @@ -84,34 +78,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { |} |""".stripMargin - val expectedWithFilter = - """ - |{ - | "intervals": { - | "stringField": { - | "match": { - | "query": "lambda works", - | "analyzer": "standard", - | "max_gaps": 2, - | "ordered": false, - | "filter": { - | "before": { - | "match": { - | "query": "before_term" - | } - | }, - | "after": { - | "match": { - | "query": "after_term" - | } - | } - | } - | } - | } - | } - |} - |""".stripMargin - assert(intervals("stringField", intervalNoOptions).toJson(None))( equalTo(expectedNoOptions.toJson) ) && @@ -120,9 +86,6 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { ) && assert(queryWithTypedField.toJson(None))( equalTo(expectedWithOptions.toJson) - ) && - assert(queryWithFilter.toJson(None))( - equalTo(expectedWithFilter.toJson) ) }, test("intervalRange") { @@ -288,6 +251,68 @@ object ElasticIntervalQuerySpec extends ZIOSpecDefault { assert(queryContains.toJson(None))(equalTo(expectedContains.toJson)) && assert(queryStartsWith.toJson(None))(equalTo(expectedStartsWith.toJson)) && assert(queryEndsWith.toJson(None))(equalTo(expectedEndsWith.toJson)) + }, + test("interval query") { + val query1 = intervals(TestDocument.stringField, intervalMatch("test query")) + + val query2 = intervals( + TestDocument.stringField, + intervalMatch("another test") + .maxGaps(3) + .orderedOn + ) + + val query3 = intervals( + TestDocument.stringField, + intervalMatch("sample text") + .analyzer("standard") + ) + val expectedJson1 = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "test query" + | } + | } + | } + |} + |""".stripMargin + + val expectedJson2 = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "another test", + | "max_gaps": 3, + | "ordered": true + | } + | } + | } + |} + |""".stripMargin + + val expectedJson3 = + """ + |{ + | "intervals": { + | "stringField": { + | "match": { + | "query": "sample text", + | "analyzer": "standard" + | } + | } + | } + |} + |""".stripMargin + + assert(query1.toJson(None))(equalTo(expectedJson1.toJson)) && + assert(query2.toJson(None))(equalTo(expectedJson2.toJson)) && + assert(query3.toJson(None))(equalTo(expectedJson3.toJson)) } ) + } }