From 4cc468f6ba2e14f4b87d10d63d5918f173053a76 Mon Sep 17 00:00:00 2001 From: philippus Date: Mon, 6 May 2024 00:20:47 +0200 Subject: [PATCH] Keep includes when specifying excludes and vice versa --- .../elastic4s/requests/get/GetRequest.scala | 30 +++++++++++++++---- .../requests/searches/SearchRequest.scala | 20 ++++++++++--- .../elastic4s/requests/get/GetTest.scala | 11 +++++++ .../elastic4s/search/SearchTest.scala | 5 ++++ .../search/queries/MatchQueryTest.scala | 18 +++++++++++ 5 files changed, 74 insertions(+), 10 deletions(-) diff --git a/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/get/GetRequest.scala b/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/get/GetRequest.scala index 16ef7b89c..478aa5406 100644 --- a/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/get/GetRequest.scala +++ b/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/get/GetRequest.scala @@ -25,13 +25,31 @@ case class GetRequest(index: IndexLike, def fetchSourceContext(context: FetchSourceContext): GetRequest = copy(fetchSource = context.some) - def fetchSourceInclude(include: String): GetRequest = fetchSourceContext(List(include), Nil) - def fetchSourceInclude(includes: Iterable[String]): GetRequest = fetchSourceContext(includes, Nil) - def fetchSourceInclude(includes: String*): GetRequest = fetchSourceContext(includes, Nil) + def fetchSourceInclude(include: String): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(List(include), ctx.excludes) + case None => fetchSourceContext(List(include), Nil) + } + def fetchSourceInclude(includes: Iterable[String]): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(includes, ctx.excludes) + case None => fetchSourceContext(includes, Nil) + } + def fetchSourceInclude(includes: String*): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(includes, ctx.excludes) + case None => fetchSourceContext(includes, Nil) + } - def fetchSourceExclude(exclude: String): GetRequest = fetchSourceContext(Nil, List(exclude)) - def fetchSourceExclude(excludes: Iterable[String]): GetRequest = fetchSourceContext(Nil, excludes) - def fetchSourceExclude(excludes: String*): GetRequest = fetchSourceContext(Nil, excludes) + def fetchSourceExclude(exclude: String): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(ctx.includes, List(exclude)) + case None => fetchSourceContext(Nil, List(exclude)) + } + def fetchSourceExclude(excludes: Iterable[String]): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(ctx.includes, excludes) + case None => fetchSourceContext(Nil, excludes) + } + def fetchSourceExclude(excludes: String*): GetRequest = fetchSource match { + case Some(ctx) => fetchSourceContext(ctx.includes, excludes) + case None => fetchSourceContext(Nil, excludes) + } def storedFields(first: String, rest: String*): GetRequest = storedFields(first +: rest) def storedFields(fs: Iterable[String]): GetRequest = copy(storedFields = fs.toSeq) diff --git a/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchRequest.scala b/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchRequest.scala index db4675606..f8ea8f650 100644 --- a/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchRequest.scala +++ b/elastic4s-domain/src/main/scala/com/sksamuel/elastic4s/requests/searches/SearchRequest.scala @@ -273,13 +273,25 @@ case class SearchRequest(indexes: Indexes, def fetchSource(fetch: Boolean): SearchRequest = copy(fetchContext = FetchSourceContext(fetch).some) - def sourceInclude(first: String, rest: String*): SearchRequest = sourceFiltering(first +: rest, Nil) + def sourceInclude(first: String, rest: String*): SearchRequest = fetchContext match { + case Some(ctx) => sourceFiltering(first +: rest, ctx.excludes) + case None => sourceFiltering(first +: rest, Nil) + } - def sourceInclude(includes: Iterable[String]): SearchRequest = sourceFiltering(includes, Nil) + def sourceInclude(includes: Iterable[String]): SearchRequest = fetchContext match { + case Some(ctx) => sourceFiltering(includes, ctx.excludes) + case None => sourceFiltering(includes, Nil) + } - def sourceExclude(first: String, rest: String*): SearchRequest = sourceFiltering(Nil, first +: rest) + def sourceExclude(first: String, rest: String*): SearchRequest = fetchContext match { + case Some(ctx) => sourceFiltering(ctx.includes, first +: rest) + case None => sourceFiltering(Nil, first +: rest) + } - def sourceExclude(excludes: Iterable[String]): SearchRequest = sourceFiltering(Nil, excludes) + def sourceExclude(excludes: Iterable[String]): SearchRequest = fetchContext match { + case Some(ctx) => sourceFiltering(ctx.includes, excludes) + case None => sourceFiltering(Nil, excludes) + } def sourceFiltering(includes: Iterable[String], excludes: Iterable[String]): SearchRequest = copy(fetchContext = FetchSourceContext(true, includes.toArray, excludes.toArray).some) diff --git a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/requests/get/GetTest.scala b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/requests/get/GetTest.scala index 2f11f423a..fb048a022 100644 --- a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/requests/get/GetTest.scala +++ b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/requests/get/GetTest.scala @@ -106,6 +106,17 @@ class GetTest extends AnyFlatSpec with Matchers with DockerTests { resp.sourceAsMap shouldBe Map("name" -> "bud lite") } + it should "support specifying source includes and excludes separately" in { + + val resp = client.execute { + get("8") from "beer" fetchSourceInclude(List("name")) fetchSourceExclude(List("bran")) + }.await.result + + resp.exists should be(true) + resp.id shouldBe "8" + resp.sourceAsMap shouldBe Map("name" -> "bud lite") + } + it should "retrieve a document supporting stored fields" in { val resp = client.execute { diff --git a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/SearchTest.scala b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/SearchTest.scala index 3420deb16..06c0b1561 100644 --- a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/SearchTest.scala +++ b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/SearchTest.scala @@ -113,6 +113,11 @@ class SearchTest extends AnyWordSpec with DockerTests with Matchers { search("chess") query matchAllQuery() sourceExclude "count" }.await.result.hits.hits.map(_.sourceAsString).toSet shouldBe Set("{\"name\":\"pawn\",\"value\":1}", "{\"aka\":\"horse\",\"name\":\"knight\",\"value\":3}", "{\"name\":\"king\",\"value\":0}", "{\"aka\":\"castle\",\"name\":\"rook\",\"value\":5}", "{\"name\":\"queen\",\"value\":10}", "{\"name\":\"bishop\",\"value\":3}") } + "support a mix of source includes and excludes" in { + client.execute { + search("chess") query matchAllQuery() sourceInclude "value" sourceExclude "name" + }.await.result.hits.hits.map(_.sourceAsString).toSet shouldBe Set("{\"value\":0}", "{\"value\":1}", "{\"value\":3}", "{\"value\":5}", "{\"value\":10}") + } "support constantScoreQuery" should { "work with termQuery" in { client.execute { diff --git a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/queries/MatchQueryTest.scala b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/queries/MatchQueryTest.scala index 43ee15573..13a307d60 100644 --- a/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/queries/MatchQueryTest.scala +++ b/elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/search/queries/MatchQueryTest.scala @@ -36,4 +36,22 @@ class MatchQueryTest resp.hits.hits.head.sourceAsMap shouldBe Map("scientist.name" -> "Jules Violle") } + + "a match query" should "support excluding nested properties" in { + + val resp = client.execute { + search("units") query matchQuery("name", "candela") sourceExclude "scientist.name" + }.await.result + + resp.hits.hits.head.sourceAsMap shouldBe Map("name" -> "candela", "scientist.country" -> "France") + } + + "a match query" should "support including and excluding nested properties" in { + + val resp = client.execute { + search("units") query matchQuery("name", "candela") sourceInclude "*name" sourceExclude "scientist.*" + }.await.result + + resp.hits.hits.head.sourceAsMap shouldBe Map("name" -> "candela") + } }