From 6753dcf2a8d64df673a682c81f6728322b07f49f Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Mon, 15 May 2023 17:12:21 +0200 Subject: [PATCH 1/7] Add tests for constructing Elastic requests --- .../elasticsearch/ElasticRequestDSLSpec.scala | 1690 +++++++++++++---- 1 file changed, 1286 insertions(+), 404 deletions(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala index b4434cad4..e7fe170cd 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala @@ -1,12 +1,17 @@ package zio.elasticsearch +import zio.Chunk import zio.elasticsearch.ElasticAggregation.termsAggregation import zio.elasticsearch.ElasticHighlight.highlight import zio.elasticsearch.ElasticQuery.term import zio.elasticsearch.ElasticRequest._ import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.domain.{Location, TestDocument} +import zio.elasticsearch.highlights.{HighlightField, Highlights} import zio.elasticsearch.query.sort.Missing.First +import zio.elasticsearch.query.sort.SortByFieldOptions +import zio.elasticsearch.request.Document +import zio.elasticsearch.request.UpdateConflicts.Abort import zio.elasticsearch.script.Script import zio.elasticsearch.utils.RichString import zio.json.ast.Json @@ -18,413 +23,1290 @@ import java.time.LocalDate object ElasticRequestDSLSpec extends ZIOSpecDefault { override def spec: Spec[TestEnvironment, Any] = - suite("Elastic Requests JSON encoding")( - test("successfully encode search request to JSON") { - val jsonRequest: Json = search(Index, Query) match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with search after parameter") { - val jsonRequest: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | }, - | "search_after" : [ - | "12345" - | ] - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with size parameter") { - val jsonRequest: Json = search(Index, Query).size(20) match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | }, - | "size" : 20 - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with excludes") { - val jsonRequest: Json = search(Index, Query).excludes("subDocumentList") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "_source" : { - | "excludes" : [ - | "subDocumentList" - | ] - | }, - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with includes") { - val jsonRequest: Json = search(Index, Query).includes("stringField", "doubleField") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "_source" : { - | "includes" : [ - | "stringField", - | "doubleField" - | ] - | }, - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with includes using a schema") { - val jsonRequest: Json = search(Index, Query).includes[TestDocument] match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "_source" : { - | "includes" : [ - | "stringField", - | "subDocumentList.stringField", - | "subDocumentList.nestedField.stringField", - | "subDocumentList.nestedField.longField", - | "subDocumentList.intField", - | "subDocumentList.intFieldList", - | "dateField", - | "intField", - | "doubleField", - | "booleanField", - | "locationField.lat", - | "locationField.lon" - | ] - | }, - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with multiple parameters") { - val jsonRequest = search(Index, Query) - .size(20) - .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | }, - | "size" : 20, - | "from" : 10, - | "sort": [ - | { - | "intField": { - | "missing": "_first" - | } - | } - | ] - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with all parameters") { - val jsonRequest = search(Index, Query) - .size(20) - .highlights(highlight(TestDocument.intField)) - .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) - .includes("stringField") - .excludes("intField") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "_source" : { - | "includes" : [ - | "stringField" - | ], - | "excludes" : [ - | "intField" - | ] - | }, - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | }, - | "size" : 20, - | "from" : 10, - | "sort": [ - | { - | "intField": { - | "missing": "_first" - | } - | } - | ], - | "highlight" : { - | "fields" : { - | "intField" : {} - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search and aggregate request to JSON with all parameters") { - val jsonRequest = search(Index, Query) - .aggregate(termsAggregation(name = "aggregation", field = "day_of_week")) - .size(20) - .highlights(highlight(TestDocument.intField)) - .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) - .includes("stringField") - .excludes("intField") match { - case r: ElasticRequest.SearchAndAggregate => r.toJson - } - val expected = - """ - |{ - | "_source" : { - | "includes" : [ - | "stringField" - | ], - | "excludes" : [ - | "intField" - | ] - | }, - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | }, - | "size" : 20, - | "from" : 10, - | "sort": [ - | { - | "intField": { - | "missing": "_first" - | } - | } - | ], - | "highlight" : { - | "fields" : { - | "intField" : {} - | } - | }, - | "aggs": { - | "aggregation" : { - | "terms" : { - | "field" : "day_of_week" - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode update by query request to JSON") { - val jsonRequest = updateByQuery( - index = Index, - query = term(TestDocument.stringField.keyword, "StringField"), - script = Script("ctx._source['intField']++") - ) match { case r: UpdateByQuery => r.toJson } - - val expected = - """ - |{ - | "script": { - | "source": "ctx._source['intField']++" - | }, - | "query": { - | "term": { - | "stringField.keyword": { - | "value": "StringField" - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode update request to JSON with all parameters - script") { - val jsonRequest = updateByScript( - index = Index, - id = DocId, - script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) - ).orCreate[TestDocument]( - TestDocument( - stringField = "stringField", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-10-10"), - intField = 1, - doubleField = 1.0, - booleanField = true, - locationField = Location(1.0, 1.0) + suite("ElasticRequest")( + suite("constructing")( + test("aggregate") { + val aggregateRequest = aggregate(index = Index, aggregation = Aggregation) + + assert(aggregateRequest)(equalTo(Aggregate(index = Index, aggregation = Aggregation))) + }, + // todo bulk + test("count") { + val countRequest = count(Index) + val countRequestWithQuery = count(Index, Query) + val countRequestWithRouting = count(Index).routing(RoutingValue) + val countRequestWithAllParams = count(Index, Query).routing(RoutingValue) + + assert(countRequest)(equalTo(Count(index = Index, query = None, routing = None))) && + assert(countRequestWithQuery)(equalTo(Count(index = Index, query = Some(Query), routing = None))) && + assert(countRequestWithRouting)(equalTo(Count(index = Index, query = None, routing = Some(RoutingValue)))) && + assert(countRequestWithAllParams)( + equalTo(Count(index = Index, query = Some(Query), routing = Some(RoutingValue))) + ) + }, + test("create without id") { + val createRequest = create(index = Index, doc = Doc1) + val createRequestWithRefresh = create(index = Index, doc = Doc1).refreshTrue + val createRequestWithRouting = create(index = Index, doc = Doc1).routing(RoutingValue) + val createRequestWithAllParams = create(index = Index, doc = Doc1).refreshTrue.routing(RoutingValue) + + assert(createRequest)( + equalTo(Create(index = Index, document = Document.from(Doc1), refresh = None, routing = None)) + ) && assert(createRequestWithRefresh)( + equalTo(Create(index = Index, document = Document.from(Doc1), refresh = Some(true), routing = None)) + ) && assert(createRequestWithRouting)( + equalTo(Create(index = Index, document = Document.from(Doc1), refresh = None, routing = Some(RoutingValue))) + ) && assert(createRequestWithAllParams)( + equalTo( + Create(index = Index, document = Document.from(Doc1), refresh = Some(true), routing = Some(RoutingValue)) + ) + ) + }, + test("create with id") { + val createRequest = create(index = Index, id = DocId, doc = Doc1) + val createRequestWithRefresh = create(index = Index, id = DocId, doc = Doc1).refreshTrue + val createRequestWithRouting = create(index = Index, id = DocId, doc = Doc1).routing(RoutingValue) + val createRequestWithAllParams = + create(index = Index, id = DocId, doc = Doc1).refreshTrue.routing(RoutingValue) + + assert(createRequest)( + equalTo( + CreateWithId( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = None, + routing = None + ) + ) + ) && assert(createRequestWithRefresh)( + equalTo( + CreateWithId( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = Some(true), + routing = None + ) + ) + ) && assert(createRequestWithRouting)( + equalTo( + CreateWithId( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = None, + routing = Some(RoutingValue) + ) + ) + ) && assert(createRequestWithAllParams)( + equalTo( + CreateWithId( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = Some(true), + routing = Some(RoutingValue) + ) + ) + ) + }, + test("create index") { + val createIndexRequest = createIndex(Index) + val createIndexRequestWithDefinition = createIndex(name = Index, definition = "definition") + + assert(createIndexRequest)(equalTo(CreateIndex(name = Index, definition = None))) && + assert(createIndexRequestWithDefinition)(equalTo(CreateIndex(name = Index, definition = Some("definition")))) + }, + test("delete by id") { + val deleteByIdRequest = deleteById(index = Index, id = DocId) + val deleteByIdRequestWithRefresh = deleteById(index = Index, id = DocId).refreshTrue + val deleteByIdRequestWithRouting = deleteById(index = Index, id = DocId).routing(RoutingValue) + val deleteByIdRequestWithAllParams = deleteById(index = Index, id = DocId).refreshTrue.routing(RoutingValue) + + assert(deleteByIdRequest)( + equalTo(DeleteById(index = Index, id = DocId, refresh = None, routing = None)) + ) && assert(deleteByIdRequestWithRefresh)( + equalTo(DeleteById(index = Index, id = DocId, refresh = Some(true), routing = None)) + ) && assert(deleteByIdRequestWithRouting)( + equalTo(DeleteById(index = Index, id = DocId, refresh = None, routing = Some(RoutingValue))) + ) && assert(deleteByIdRequestWithAllParams)( + equalTo(DeleteById(index = Index, id = DocId, refresh = Some(true), routing = Some(RoutingValue))) + ) + }, + test("delete by query") { + val deleteByQueryRequest = deleteByQuery(index = Index, query = Query) + val deleteByQueryRequestWithRefresh = deleteByQuery(index = Index, query = Query).refreshTrue + val deleteByQueryRequestWithRouting = deleteByQuery(index = Index, query = Query).routing(RoutingValue) + val deleteByQueryRequestWithAllParams = + deleteByQuery(index = Index, query = Query).refreshTrue.routing(RoutingValue) + + assert(deleteByQueryRequest)( + equalTo(DeleteByQuery(index = Index, query = Query, refresh = None, routing = None)) + ) && assert(deleteByQueryRequestWithRefresh)( + equalTo(DeleteByQuery(index = Index, query = Query, refresh = Some(true), routing = None)) + ) && assert(deleteByQueryRequestWithRouting)( + equalTo(DeleteByQuery(index = Index, query = Query, refresh = None, routing = Some(RoutingValue))) + ) && assert(deleteByQueryRequestWithAllParams)( + equalTo(DeleteByQuery(index = Index, query = Query, refresh = Some(true), routing = Some(RoutingValue))) + ) + }, + test("delete index") { + val deleteIndexRequest = deleteIndex(Index) + + assert(deleteIndexRequest)(equalTo(DeleteIndex(Index))) + }, + test("exists") { + val existsRequest = exists(index = Index, id = DocId) + val existsRequestWithRouting = exists(index = Index, id = DocId).routing(RoutingValue) + + assert(existsRequest)(equalTo(Exists(index = Index, id = DocId, routing = None))) && + assert(existsRequestWithRouting)(equalTo(Exists(index = Index, id = DocId, routing = Some(RoutingValue)))) + }, + test("get by id") { + val getByIdRequest = getById(index = Index, id = DocId) + val getByIdRequestWithRefresh = getById(index = Index, id = DocId).refreshTrue + val getByIdRequestWithRouting = getById(index = Index, id = DocId).routing(RoutingValue) + val getByIdRequestWithAllParams = getById(index = Index, id = DocId).refreshTrue.routing(RoutingValue) + + assert(getByIdRequest)(equalTo(GetById(index = Index, id = DocId, refresh = None, routing = None))) && assert( + getByIdRequestWithRefresh + )( + equalTo(GetById(index = Index, id = DocId, refresh = Some(true), routing = None)) + ) && assert(getByIdRequestWithRouting)( + equalTo(GetById(index = Index, id = DocId, refresh = None, routing = Some(RoutingValue))) + ) && assert(getByIdRequestWithAllParams)( + equalTo(GetById(index = Index, id = DocId, refresh = Some(true), routing = Some(RoutingValue))) ) - ) match { case r: Update => r.toJson } - - val expected = - """ - |{ - | "script": { - | "source": "ctx._source.intField += params['factor']", - | "params": { - | "factor": 2 - | } - | }, - | "upsert": { - | "stringField": "stringField", - | "subDocumentList": [], - | "dateField": "2020-10-10", - | "intField": 1, - | "doubleField": 1.0, - | "booleanField": true, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode update request to JSON with all parameters - doc") { - val jsonRequest = update[TestDocument]( - index = Index, - id = DocId, - doc = TestDocument( - stringField = "stringField1", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-10-10"), - intField = 1, - doubleField = 1.0, - booleanField = true, - locationField = Location(1.0, 1.0) + }, + test("search") { + val searchRequest = search(index = Index, query = Query) + val searchRequestWithSort = search(index = Index, query = Query).sort(sortBy(TestDocument.intField)) + val searchRequestWithSourceFiltering = + search(index = Index, query = Query).includes("stringField", "doubleField").excludes("booleanField") + val searchRequestWithFrom = search(index = Index, query = Query).from(5) + val searchRequestWithHighlights = + search(index = Index, query = Query).highlights(highlight(TestDocument.intField)) + val searchRequestWithRouting = search(index = Index, query = Query).routing(RoutingValue) + val searchRequestWithSearchAfter = search(index = Index, query = Query).searchAfter(Arr(Str("12345"))) + val searchRequestWithSize = search(index = Index, query = Query).size(5) + val searchRequestWithAllParams = search(index = Index, query = Query) + .sort(sortBy("intField")) + .includes("stringField", "doubleField") + .excludes("booleanField") + .from(5) + .highlights(highlight("intField")) + .routing(RoutingValue) + .searchAfter(Arr(Str("12345"))) + .size(5) + + assert(searchRequest)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithSort)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk( + SortByFieldOptions( + field = "intField", + format = None, + missing = None, + mode = None, + numericType = None, + order = None, + unmappedType = None + ) + ), + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithSourceFiltering)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = Some(Chunk("booleanField")), + from = None, + highlights = None, + included = Some(Chunk("stringField", "doubleField")), + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithFrom)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = Some(5), + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithHighlights)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = Some( + Highlights(fields = Chunk(HighlightField(field = "intField", config = Map.empty)), config = Map.empty) + ), + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithRouting)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = Some(RoutingValue), + searchAfter = None, + size = None + ) + ) + ) && assert(searchRequestWithSearchAfter)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = Some(Arr(Str("12345"))), + size = None + ) + ) + ) && assert(searchRequestWithSize)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = Some(5) + ) + ) + ) && assert(searchRequestWithAllParams)( + equalTo( + Search( + index = Index, + query = Query, + sortBy = Chunk( + SortByFieldOptions( + field = "intField", + format = None, + missing = None, + mode = None, + numericType = None, + order = None, + unmappedType = None + ) + ), + excluded = Some(Chunk("booleanField")), + from = Some(5), + highlights = Some( + Highlights(fields = Chunk(HighlightField(field = "intField", config = Map.empty)), config = Map.empty) + ), + included = Some(Chunk("stringField", "doubleField")), + routing = Some(RoutingValue), + searchAfter = Some(Arr(Str("12345"))), + size = Some(5) + ) + ) ) - ).orCreate[TestDocument]( - TestDocument( - stringField = "stringField2", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-11-11"), - intField = 2, - doubleField = 2.0, - booleanField = false, - locationField = Location(1.0, 1.0) + }, + test("search and aggregate") { + val searchAndAggRequest = search(index = Index, query = Query, aggregation = Aggregation) + val searchAndAggRequestWithSort = + search(index = Index, query = Query, aggregation = Aggregation).sort(sortBy(TestDocument.intField)) + val searchAndAggRequestWithSourceFiltering = + search(index = Index, query = Query, aggregation = Aggregation) + .includes("stringField", "doubleField") + .excludes("booleanField") + val searchAndAggRequestWithFrom = search(index = Index, query = Query, aggregation = Aggregation).from(5) + val searchAndAggRequestWithHighlights = + search(index = Index, query = Query, aggregation = Aggregation).highlights(highlight(TestDocument.intField)) + val searchAndAggRequestWithRouting = + search(index = Index, query = Query, aggregation = Aggregation).routing(RoutingValue) + val searchAndAggRequestWithSearchAfter = + search(index = Index, query = Query, aggregation = Aggregation).searchAfter(Arr(Str("12345"))) + val searchAndAggRequestWithSize = search(index = Index, query = Query, aggregation = Aggregation).size(5) + val searchAndAggRequestWithAllParams = search(index = Index, query = Query, aggregation = Aggregation) + .sort(sortBy("intField")) + .includes("stringField", "doubleField") + .excludes("booleanField") + .from(5) + .highlights(highlight("intField")) + .routing(RoutingValue) + .searchAfter(Arr(Str("12345"))) + .size(5) + + assert(searchAndAggRequest)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithSort)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk( + SortByFieldOptions( + field = "intField", + format = None, + missing = None, + mode = None, + numericType = None, + order = None, + unmappedType = None + ) + ), + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithSourceFiltering)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = Some(Chunk("booleanField")), + from = None, + highlights = None, + included = Some(Chunk("stringField", "doubleField")), + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithFrom)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = Some(5), + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithHighlights)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = Some( + Highlights(fields = Chunk(HighlightField(field = "intField", config = Map.empty)), config = Map.empty) + ), + included = None, + routing = None, + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithRouting)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = Some(RoutingValue), + searchAfter = None, + size = None + ) + ) + ) && assert(searchAndAggRequestWithSearchAfter)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = Some(Arr(Str("12345"))), + size = None + ) + ) + ) && assert(searchAndAggRequestWithSize)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk.empty, + excluded = None, + from = None, + highlights = None, + included = None, + routing = None, + searchAfter = None, + size = Some(5) + ) + ) + ) && assert(searchAndAggRequestWithAllParams)( + equalTo( + SearchAndAggregate( + index = Index, + query = Query, + aggregation = Aggregation, + sortBy = Chunk( + SortByFieldOptions( + field = "intField", + format = None, + missing = None, + mode = None, + numericType = None, + order = None, + unmappedType = None + ) + ), + excluded = Some(Chunk("booleanField")), + from = Some(5), + highlights = Some( + Highlights(fields = Chunk(HighlightField(field = "intField", config = Map.empty)), config = Map.empty) + ), + included = Some(Chunk("stringField", "doubleField")), + routing = Some(RoutingValue), + searchAfter = Some(Arr(Str("12345"))), + size = Some(5) + ) + ) + ) + }, + test("update") { + val updateRequest = update(Index, DocId, Doc1) + val updateRequestWithRefresh = update(Index, DocId, Doc1).refreshTrue + val updateRequestWithRouting = update(Index, DocId, Doc1).routing(RoutingValue) + val updateRequestWithUpsert = update(Index, DocId, Doc1).orCreate(Doc2) + val updateRequestWithAllParams = update(Index, DocId, Doc1).refreshTrue.routing(RoutingValue).orCreate(Doc2) + + assert(updateRequest)( + equalTo( + Update( + index = Index, + id = DocId, + doc = Some(Document.from(Doc1)), + refresh = None, + routing = None, + script = None, + upsert = None + ) + ) + ) && assert(updateRequestWithRefresh)( + equalTo( + Update( + index = Index, + id = DocId, + doc = Some(Document.from(Doc1)), + refresh = Some(true), + routing = None, + script = None, + upsert = None + ) + ) + ) && assert(updateRequestWithRouting)( + equalTo( + Update( + index = Index, + id = DocId, + doc = Some(Document.from(Doc1)), + refresh = None, + routing = Some(RoutingValue), + script = None, + upsert = None + ) + ) + ) && assert(updateRequestWithUpsert)( + equalTo( + Update( + index = Index, + id = DocId, + doc = Some(Document.from(Doc1)), + refresh = None, + routing = None, + script = None, + upsert = Some(Document.from(Doc2)) + ) + ) + ) && assert(updateRequestWithAllParams)( + equalTo( + Update( + index = Index, + id = DocId, + doc = Some(Document.from(Doc1)), + refresh = Some(true), + routing = Some(RoutingValue), + script = None, + upsert = Some(Document.from(Doc2)) + ) + ) ) - ) match { case r: Update => r.toJson } - - val expected = - """ - |{ - | "doc": { - | "stringField": "stringField1", - | "subDocumentList": [], - | "dateField": "2020-10-10", - | "intField": 1, - | "doubleField": 1.0, - | "booleanField": true, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 - | } - | }, - | "upsert": { - | "stringField": "stringField2", - | "subDocumentList": [], - | "dateField": "2020-11-11", - | "intField": 2, - | "doubleField": 2.0, - | "booleanField": false, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - } + }, + test("update all by query") { + val updateByQueryRequest = updateAllByQuery(index = Index, script = Script1) + val updateByQueryRequestWithConflicts = updateAllByQuery(index = Index, script = Script1).conflicts(Abort) + val updateByQueryRequestWithRefresh = updateAllByQuery(index = Index, script = Script1).refreshTrue + val updateByQueryRequestWithRouting = updateAllByQuery(index = Index, script = Script1).routing(RoutingValue) + val updateByQueryRequestWithAllParams = + updateAllByQuery(index = Index, script = Script1).conflicts(Abort).refreshTrue.routing(RoutingValue) + + assert(updateByQueryRequest)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = None, + refresh = None, + routing = None + ) + ) + ) && assert(updateByQueryRequestWithConflicts)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = Some(Abort), + query = None, + refresh = None, + routing = None + ) + ) + ) && assert(updateByQueryRequestWithRefresh)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = None, + refresh = Some(true), + routing = None + ) + ) + ) && assert(updateByQueryRequestWithRouting)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = None, + refresh = None, + routing = Some(RoutingValue) + ) + ) + ) && assert(updateByQueryRequestWithAllParams)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = Some(Abort), + query = None, + refresh = Some(true), + routing = Some(RoutingValue) + ) + ) + ) + }, + test("update by query") { + val updateByQueryRequest = updateByQuery(index = Index, query = Query, script = Script1) + val updateByQueryRequestWithConflicts = + updateByQuery(index = Index, query = Query, script = Script1).conflicts(Abort) + val updateByQueryRequestWithRefresh = + updateByQuery(index = Index, query = Query, script = Script1).refreshTrue + val updateByQueryRequestWithRouting = + updateByQuery(index = Index, query = Query, script = Script1).routing(RoutingValue) + val updateByQueryRequestWithAllParams = + updateByQuery(index = Index, query = Query, script = Script1) + .conflicts(Abort) + .refreshTrue + .routing(RoutingValue) + + assert(updateByQueryRequest)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = Some(Query), + refresh = None, + routing = None + ) + ) + ) && assert(updateByQueryRequestWithConflicts)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = Some(Abort), + query = Some(Query), + refresh = None, + routing = None + ) + ) + ) && assert(updateByQueryRequestWithRefresh)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = Some(Query), + refresh = Some(true), + routing = None + ) + ) + ) && assert(updateByQueryRequestWithRouting)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = None, + query = Some(Query), + refresh = None, + routing = Some(RoutingValue) + ) + ) + ) && assert(updateByQueryRequestWithAllParams)( + equalTo( + UpdateByQuery( + index = Index, + script = Script1, + conflicts = Some(Abort), + query = Some(Query), + refresh = Some(true), + routing = Some(RoutingValue) + ) + ) + ) + }, + test("update by script") { + val updateRequest = updateByScript(Index, DocId, Script1) + val updateRequestWithRefresh = updateByScript(Index, DocId, Script1).refreshTrue + val updateRequestWithRouting = updateByScript(Index, DocId, Script1).routing(RoutingValue) + val updateRequestWithUpsert = updateByScript(Index, DocId, Script1).orCreate(Doc2) + val updateRequestWithAllParams = + updateByScript(Index, DocId, Script1).refreshTrue.routing(RoutingValue).orCreate(Doc2) + + assert(updateRequest)( + equalTo( + Update( + index = Index, + id = DocId, + doc = None, + refresh = None, + routing = None, + script = Some(Script1), + upsert = None + ) + ) + ) && assert(updateRequestWithRefresh)( + equalTo( + Update( + index = Index, + id = DocId, + doc = None, + refresh = Some(true), + routing = None, + script = Some(Script1), + upsert = None + ) + ) + ) && assert(updateRequestWithRouting)( + equalTo( + Update( + index = Index, + id = DocId, + doc = None, + refresh = None, + routing = Some(RoutingValue), + script = Some(Script1), + upsert = None + ) + ) + ) && assert(updateRequestWithUpsert)( + equalTo( + Update( + index = Index, + id = DocId, + doc = None, + refresh = None, + routing = None, + script = Some(Script1), + upsert = Some(Document.from(Doc2)) + ) + ) + ) && assert(updateRequestWithAllParams)( + equalTo( + Update( + index = Index, + id = DocId, + doc = None, + refresh = Some(true), + routing = Some(RoutingValue), + script = Some(Script1), + upsert = Some(Document.from(Doc2)) + ) + ) + ) + }, + test("upsert") { + val upsertRequest = upsert(index = Index, id = DocId, doc = Doc1) + val upsertRequestWithRefresh = upsert(index = Index, id = DocId, doc = Doc1).refreshTrue + val upsertRequestWithRouting = upsert(index = Index, id = DocId, doc = Doc1).routing(RoutingValue) + val upsertRequestWithAllParams = + upsert(index = Index, id = DocId, doc = Doc1).refreshTrue.routing(RoutingValue) + + assert(upsertRequest)( + equalTo( + CreateOrUpdate(index = Index, id = DocId, document = Document.from(Doc1), refresh = None, routing = None) + ) + ) && assert(upsertRequestWithRefresh)( + equalTo( + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = Some(true), + routing = None + ) + ) + ) && assert(upsertRequestWithRouting)( + equalTo( + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = None, + routing = Some(RoutingValue) + ) + ) + ) && assert(upsertRequestWithAllParams)( + equalTo( + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc1), + refresh = Some(true), + routing = Some(RoutingValue) + ) + ) + ) + } + ), + suite("encoding as JSON")( + test("successfully encode search request to JSON") { + val jsonRequest: Json = search(Index, Query) match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with search after parameter") { + val jsonRequest: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, + | "search_after" : [ + | "12345" + | ] + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with size parameter") { + val jsonRequest: Json = search(Index, Query).size(20) match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, + | "size" : 20 + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with excludes") { + val jsonRequest: Json = search(Index, Query).excludes("subDocumentList") match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "_source" : { + | "excludes" : [ + | "subDocumentList" + | ] + | }, + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with includes") { + val jsonRequest: Json = search(Index, Query).includes("stringField", "doubleField") match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "_source" : { + | "includes" : [ + | "stringField", + | "doubleField" + | ] + | }, + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with includes using a schema") { + val jsonRequest: Json = search(Index, Query).includes[TestDocument] match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "_source" : { + | "includes" : [ + | "stringField", + | "subDocumentList.stringField", + | "subDocumentList.nestedField.stringField", + | "subDocumentList.nestedField.longField", + | "subDocumentList.intField", + | "subDocumentList.intFieldList", + | "dateField", + | "intField", + | "doubleField", + | "booleanField", + | "locationField.lat", + | "locationField.lon" + | ] + | }, + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with multiple parameters") { + val jsonRequest = search(Index, Query) + .size(20) + .sort(sortBy(TestDocument.intField).missing(First)) + .from(10) match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, + | "size" : 20, + | "from" : 10, + | "sort": [ + | { + | "intField": { + | "missing": "_first" + | } + | } + | ] + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search request to JSON with all parameters") { + val jsonRequest = search(Index, Query) + .size(20) + .highlights(highlight(TestDocument.intField)) + .sort(sortBy(TestDocument.intField).missing(First)) + .from(10) + .includes("stringField") + .excludes("intField") match { + case r: ElasticRequest.Search => r.toJson + } + val expected = + """ + |{ + | "_source" : { + | "includes" : [ + | "stringField" + | ], + | "excludes" : [ + | "intField" + | ] + | }, + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, + | "size" : 20, + | "from" : 10, + | "sort": [ + | { + | "intField": { + | "missing": "_first" + | } + | } + | ], + | "highlight" : { + | "fields" : { + | "intField" : {} + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode search and aggregate request to JSON with all parameters") { + val jsonRequest = search(Index, Query) + .aggregate(termsAggregation(name = "aggregation", field = "day_of_week")) + .size(20) + .highlights(highlight(TestDocument.intField)) + .sort(sortBy(TestDocument.intField).missing(First)) + .from(10) + .includes("stringField") + .excludes("intField") match { + case r: ElasticRequest.SearchAndAggregate => r.toJson + } + val expected = + """ + |{ + | "_source" : { + | "includes" : [ + | "stringField" + | ], + | "excludes" : [ + | "intField" + | ] + | }, + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, + | "size" : 20, + | "from" : 10, + | "sort": [ + | { + | "intField": { + | "missing": "_first" + | } + | } + | ], + | "highlight" : { + | "fields" : { + | "intField" : {} + | } + | }, + | "aggs": { + | "aggregation" : { + | "terms" : { + | "field" : "day_of_week" + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode update by query request to JSON") { + val jsonRequest = updateByQuery( + index = Index, + query = term(TestDocument.stringField.keyword, "StringField"), + script = Script("ctx._source['intField']++") + ) match { case r: UpdateByQuery => r.toJson } + + val expected = + """ + |{ + | "script": { + | "source": "ctx._source['intField']++" + | }, + | "query": { + | "term": { + | "stringField.keyword": { + | "value": "StringField" + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode update request to JSON with all parameters - script") { + val jsonRequest = updateByScript( + index = Index, + id = DocId, + script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) + ).orCreate[TestDocument]( + TestDocument( + stringField = "stringField", + subDocumentList = Nil, + dateField = LocalDate.parse("2020-10-10"), + intField = 1, + doubleField = 1.0, + booleanField = true, + locationField = Location(1.0, 1.0) + ) + ) match { case r: Update => r.toJson } + + val expected = + """ + |{ + | "script": { + | "source": "ctx._source.intField += params['factor']", + | "params": { + | "factor": 2 + | } + | }, + | "upsert": { + | "stringField": "stringField", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 1, + | "doubleField": 1.0, + | "booleanField": true, + | "locationField" : { + | "lat" : 1.0, + | "lon" : 1.0 + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("successfully encode update request to JSON with all parameters - doc") { + val jsonRequest = update[TestDocument]( + index = Index, + id = DocId, + doc = TestDocument( + stringField = "stringField1", + subDocumentList = Nil, + dateField = LocalDate.parse("2020-10-10"), + intField = 1, + doubleField = 1.0, + booleanField = true, + locationField = Location(1.0, 1.0) + ) + ).orCreate[TestDocument]( + TestDocument( + stringField = "stringField2", + subDocumentList = Nil, + dateField = LocalDate.parse("2020-11-11"), + intField = 2, + doubleField = 2.0, + booleanField = false, + locationField = Location(1.0, 1.0) + ) + ) match { case r: Update => r.toJson } + + val expected = + """ + |{ + | "doc": { + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 1, + | "doubleField": 1.0, + | "booleanField": true, + | "locationField" : { + | "lat" : 1.0, + | "lon" : 1.0 + | } + | }, + | "upsert": { + | "stringField": "stringField2", + | "subDocumentList": [], + | "dateField": "2020-11-11", + | "intField": 2, + | "doubleField": 2.0, + | "booleanField": false, + | "locationField" : { + | "lat" : 1.0, + | "lon" : 1.0 + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + } + ) ) - private val Query = ElasticQuery.range(TestDocument.intField).gte(10) - private val Index = IndexName("index") - private val DocId = DocumentId("documentid") + private val Aggregation = ElasticAggregation.maxAggregation(name = "aggregation", field = TestDocument.intField) + private val Query = ElasticQuery.range(TestDocument.intField).gte(10) + private val Index = IndexName("index") + private val DocId = DocumentId("documentid") + private val RoutingValue = Routing("routing") + + private val Doc1 = TestDocument( + stringField = "stringField1", + subDocumentList = List(), + dateField = LocalDate.parse("2020-10-10"), + intField = 5, + doubleField = 7.0, + booleanField = true, + locationField = Location(20.0, 21.0) + ) + private val Doc2 = TestDocument( + stringField = "stringField2", + subDocumentList = List(), + dateField = LocalDate.parse("2022-10-10"), + intField = 10, + doubleField = 17.0, + booleanField = false, + locationField = Location(10.0, 11.0) + ) + private val Script1 = Script("doc['intField'].value * params['factor']").params("factor" -> 2) + } From 68b32d589d353abed7c3ba2e21acb9350fbe841e Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 16 May 2023 12:03:48 +0200 Subject: [PATCH 2/7] Add constructing bulk request --- .../elasticsearch/ElasticRequestDSLSpec.scala | 104 ++++++++++++++---- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala index e7fe170cd..afa676d8a 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala @@ -30,7 +30,90 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { assert(aggregateRequest)(equalTo(Aggregate(index = Index, aggregation = Aggregation))) }, - // todo bulk + test("bulk") { + val bulkRequest = bulk(create(index = Index, doc = Doc1), upsert(index = Index, id = DocId, doc = Doc2)) + val bulkRequestWithRefresh = + bulk(create(index = Index, doc = Doc1), upsert(index = Index, id = DocId, doc = Doc2)).refreshTrue + val bulkRequestWithRouting = + bulk(create(index = Index, doc = Doc1), upsert(index = Index, id = DocId, doc = Doc2)).routing(RoutingValue) + val bulkRequestWithAllParams = + bulk(create(index = Index, doc = Doc1), upsert(index = Index, id = DocId, doc = Doc2)).refreshTrue + .routing(RoutingValue) + + assert(bulkRequest)( + equalTo( + Bulk( + requests = Chunk( + Create(index = Index, document = Document.from(Doc1), refresh = None, routing = None), + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc2), + refresh = None, + routing = None + ) + ), + index = None, + refresh = None, + routing = None + ) + ) + ) && assert(bulkRequestWithRefresh)( + equalTo( + Bulk( + requests = Chunk( + Create(index = Index, document = Document.from(Doc1), refresh = None, routing = None), + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc2), + refresh = None, + routing = None + ) + ), + index = None, + refresh = Some(true), + routing = None + ) + ) + ) && assert(bulkRequestWithRouting)( + equalTo( + Bulk( + requests = Chunk( + Create(index = Index, document = Document.from(Doc1), refresh = None, routing = None), + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc2), + refresh = None, + routing = None + ) + ), + index = None, + refresh = None, + routing = Some(RoutingValue) + ) + ) + ) && assert(bulkRequestWithAllParams)( + equalTo( + Bulk( + requests = Chunk( + Create(index = Index, document = Document.from(Doc1), refresh = None, routing = None), + CreateOrUpdate( + index = Index, + id = DocId, + document = Document.from(Doc2), + refresh = None, + routing = None + ) + ), + index = None, + refresh = Some(true), + routing = Some(RoutingValue) + ) + ) + ) + }, test("count") { val countRequest = count(Index) val countRequestWithQuery = count(Index, Query) @@ -877,25 +960,6 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { } ), suite("encoding as JSON")( - test("successfully encode search request to JSON") { - val jsonRequest: Json = search(Index, Query) match { - case r: ElasticRequest.Search => r.toJson - } - val expected = - """ - |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 - | } - | } - | } - |} - |""".stripMargin - - assert(jsonRequest)(equalTo(expected.toJson)) - }, test("successfully encode search request to JSON with search after parameter") { val jsonRequest: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { case r: ElasticRequest.Search => r.toJson From 121cccad55762c7651f2e5c5ea3170c0e5906b4f Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 16 May 2023 14:52:08 +0200 Subject: [PATCH 3/7] Add some of encoding tests --- .../zio/elasticsearch/ElasticRequest.scala | 2 + .../elasticsearch/ElasticRequestDSLSpec.scala | 599 +++++++++++------- 2 files changed, 369 insertions(+), 232 deletions(-) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala index 9b0cd4865..b383b201e 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala @@ -649,6 +649,7 @@ object ElasticRequest { includes merge excludes }) } + Obj("query" -> query.toJson(fieldPath = None)) merge fromJson merge sizeJson merge @@ -734,6 +735,7 @@ object ElasticRequest { includes merge excludes }) } + Obj("query" -> query.toJson(fieldPath = None)) merge Obj("aggs" -> aggregation.toJson) merge fromJson merge diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala index afa676d8a..b5103fdee 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala @@ -3,7 +3,6 @@ package zio.elasticsearch import zio.Chunk import zio.elasticsearch.ElasticAggregation.termsAggregation import zio.elasticsearch.ElasticHighlight.highlight -import zio.elasticsearch.ElasticQuery.term import zio.elasticsearch.ElasticRequest._ import zio.elasticsearch.ElasticSort.sortBy import zio.elasticsearch.domain.{Location, TestDocument} @@ -26,9 +25,9 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { suite("ElasticRequest")( suite("constructing")( test("aggregate") { - val aggregateRequest = aggregate(index = Index, aggregation = Aggregation) + val aggregateRequest = aggregate(index = Index, aggregation = MaxAggregation) - assert(aggregateRequest)(equalTo(Aggregate(index = Index, aggregation = Aggregation))) + assert(aggregateRequest)(equalTo(Aggregate(index = Index, aggregation = MaxAggregation))) }, test("bulk") { val bulkRequest = bulk(create(index = Index, doc = Doc1), upsert(index = Index, id = DocId, doc = Doc2)) @@ -445,22 +444,24 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { ) }, test("search and aggregate") { - val searchAndAggRequest = search(index = Index, query = Query, aggregation = Aggregation) + val searchAndAggRequest = search(index = Index, query = Query, aggregation = MaxAggregation) val searchAndAggRequestWithSort = - search(index = Index, query = Query, aggregation = Aggregation).sort(sortBy(TestDocument.intField)) + search(index = Index, query = Query, aggregation = MaxAggregation).sort(sortBy(TestDocument.intField)) val searchAndAggRequestWithSourceFiltering = - search(index = Index, query = Query, aggregation = Aggregation) + search(index = Index, query = Query, aggregation = MaxAggregation) .includes("stringField", "doubleField") .excludes("booleanField") - val searchAndAggRequestWithFrom = search(index = Index, query = Query, aggregation = Aggregation).from(5) + val searchAndAggRequestWithFrom = search(index = Index, query = Query, aggregation = MaxAggregation).from(5) val searchAndAggRequestWithHighlights = - search(index = Index, query = Query, aggregation = Aggregation).highlights(highlight(TestDocument.intField)) + search(index = Index, query = Query, aggregation = MaxAggregation).highlights( + highlight(TestDocument.intField) + ) val searchAndAggRequestWithRouting = - search(index = Index, query = Query, aggregation = Aggregation).routing(RoutingValue) + search(index = Index, query = Query, aggregation = MaxAggregation).routing(RoutingValue) val searchAndAggRequestWithSearchAfter = - search(index = Index, query = Query, aggregation = Aggregation).searchAfter(Arr(Str("12345"))) - val searchAndAggRequestWithSize = search(index = Index, query = Query, aggregation = Aggregation).size(5) - val searchAndAggRequestWithAllParams = search(index = Index, query = Query, aggregation = Aggregation) + search(index = Index, query = Query, aggregation = MaxAggregation).searchAfter(Arr(Str("12345"))) + val searchAndAggRequestWithSize = search(index = Index, query = Query, aggregation = MaxAggregation).size(5) + val searchAndAggRequestWithAllParams = search(index = Index, query = Query, aggregation = MaxAggregation) .sort(sortBy("intField")) .includes("stringField", "doubleField") .excludes("booleanField") @@ -475,7 +476,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = None, @@ -491,7 +492,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk( SortByFieldOptions( field = "intField", @@ -517,7 +518,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = Some(Chunk("booleanField")), from = None, @@ -533,7 +534,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = Some(5), @@ -549,7 +550,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = None, @@ -567,7 +568,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = None, @@ -583,7 +584,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = None, @@ -599,7 +600,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk.empty, excluded = None, from = None, @@ -615,7 +616,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { SearchAndAggregate( index = Index, query = Query, - aggregation = Aggregation, + aggregation = MaxAggregation, sortBy = Chunk( SortByFieldOptions( field = "intField", @@ -960,32 +961,74 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { } ), suite("encoding as JSON")( - test("successfully encode search request to JSON with search after parameter") { - val jsonRequest: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { - case r: ElasticRequest.Search => r.toJson + test("aggregate") { + val jsonRequest: Json = aggregate(Index, MaxAggregation) match { + case r: ElasticRequest.Aggregate => r.toJson } + val expected = """ |{ - | "query" : { - | "range" : { - | "intField" : { - | "gte" : 10 + | "aggs": { + | "aggregation" : { + | "max" : { + | "field" : "intField" | } | } - | }, - | "search_after" : [ - | "12345" - | ] + | } |} |""".stripMargin assert(jsonRequest)(equalTo(expected.toJson)) }, - test("successfully encode search request to JSON with size parameter") { - val jsonRequest: Json = search(Index, Query).size(20) match { + test("bulk") { + val requestBody = bulk( + create(index = Index, doc = Doc1).routing(RoutingValue), + upsert(index = Index, id = DocId, doc = Doc2) + ) match { + case r: Bulk => r.body + } + + val expected = + """|{ "create" : { "_index" : "index", "routing" : "routing" } } + |{"stringField":"stringField1","subDocumentList":[],"dateField":"2020-10-10","intField":5,"doubleField":7.0,"booleanField":true,"locationField":{"lat":20.0,"lon":21.0}} + |{ "index" : { "_index" : "index", "_id" : "documentid" } } + |{"stringField":"stringField2","subDocumentList":[],"dateField":"2022-10-10","intField":10,"doubleField":17.0,"booleanField":false,"locationField":{"lat":10.0,"lon":11.0}} + |""".stripMargin + + assert(requestBody)(equalTo(expected)) + }, + test("search") { + val jsonRequest: Json = search(Index, Query) match { + case r: ElasticRequest.Search => r.toJson + } + val jsonRequestWithSearchAfter: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { + case r: ElasticRequest.Search => r.toJson + } + val jsonRequestWithSize: Json = search(Index, Query).size(20) match { case r: ElasticRequest.Search => r.toJson } + val jsonRequestWithExcludes: Json = search(Index, Query).excludes("subDocumentList") match { + case r: ElasticRequest.Search => r.toJson + } + val jsonRequestWithIncludes: Json = search(Index, Query).includes("stringField", "doubleField") match { + case r: ElasticRequest.Search => r.toJson + } + val jsonRequestWithInclSchema: Json = search(Index, Query).includes[TestDocument] match { + case r: ElasticRequest.Search => r.toJson + } + val jsonRequestWithAllParams: Json = search(Index, Query) + .size(20) + .sort(sortBy(TestDocument.intField).missing(First)) + .excludes("intField") + .from(10) + .highlights(highlight(TestDocument.intField)) + .includes("stringField") + .searchAfter(Arr(Str("12345"))) + .size(20) match { + case r: ElasticRequest.Search => r.toJson + } + val expected = """ |{ @@ -995,25 +1038,30 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "gte" : 10 | } | } - | }, - | "size" : 20 + | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with excludes") { - val jsonRequest: Json = search(Index, Query).excludes("subDocumentList") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = + val expectedWithSearchAfter = """ |{ - | "_source" : { - | "excludes" : [ - | "subDocumentList" - | ] + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } | }, + | "search_after" : [ + | "12345" + | ] + |} + |""".stripMargin + + val expectedWithSize = + """ + |{ + | "size" : 20, | "query" : { | "range" : { | "intField" : { @@ -1024,40 +1072,53 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with includes") { - val jsonRequest: Json = search(Index, Query).includes("stringField", "doubleField") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = + val expectedWithExcludes = """ |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, | "_source" : { - | "includes" : [ - | "stringField", - | "doubleField" + | "excludes" : [ + | "subDocumentList" | ] - | }, + | } + |} + |""".stripMargin + + val expectedWithIncludes = + """ + |{ | "query" : { | "range" : { | "intField" : { | "gte" : 10 | } | } + | }, + | "_source" : { + | "includes" : [ + | "stringField", + | "doubleField" + | ] | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with includes using a schema") { - val jsonRequest: Json = search(Index, Query).includes[TestDocument] match { - case r: ElasticRequest.Search => r.toJson - } - val expected = + val expectedWithInclSchema = """ |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | }, | "_source" : { | "includes" : [ | "stringField", @@ -1073,128 +1134,164 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "locationField.lat", | "locationField.lon" | ] + | } + |} + |""".stripMargin + + val expectedWithAllParams = + """ + |{ + | "from" : 10, + | "size" : 20, + | "highlight" : { + | "fields" : { + | "intField" : {} + | } | }, + | "sort": [ + | { + | "intField": { + | "missing": "_first" + | } + | } + | ], | "query" : { | "range" : { | "intField" : { | "gte" : 10 | } | } + | }, + | "search_after" : [ + | "12345" + | ], + | "_source" : { + | "includes" : [ + | "stringField" + | ], + | "excludes" : [ + | "intField" + | ] | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithSearchAfter)(equalTo(expectedWithSearchAfter.toJson)) && + assert(jsonRequestWithSize)(equalTo(expectedWithSize.toJson)) && + assert(jsonRequestWithExcludes)(equalTo(expectedWithExcludes.toJson)) && + assert(jsonRequestWithIncludes)(equalTo(expectedWithIncludes.toJson)) && + assert(jsonRequestWithInclSchema)(equalTo(expectedWithInclSchema.toJson)) && + assert(jsonRequestWithAllParams)(equalTo(expectedWithAllParams.toJson)) }, - test("successfully encode search request to JSON with multiple parameters") { - val jsonRequest = search(Index, Query) + test("search and aggregate") { + val jsonRequest = search(index = Index, query = Query, aggregation = TermsAggregation) match { + case r: SearchAndAggregate => r.toJson + } + val jsonRequestWithFrom = + search(index = Index, query = Query, aggregation = TermsAggregation).from(10) match { + case r: SearchAndAggregate => r.toJson + } + val jsonRequestWithSortAndHighlights = search(index = Index, query = Query, aggregation = TermsAggregation) + .sort(sortBy(TestDocument.intField).missing(First)) + .highlights(highlight(TestDocument.intField)) match { + case r: SearchAndAggregate => r.toJson + } + val jsonRequestWithAllParams = search(index = Index, query = Query) + .aggregate(TermsAggregation) + .from(10) .size(20) + .highlights(highlight(TestDocument.intField)) .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) match { - case r: ElasticRequest.Search => r.toJson + .includes("stringField") + .excludes("intField") + .searchAfter(Arr(Str("12345"))) match { + case r: ElasticRequest.SearchAndAggregate => r.toJson } + val expected = """ |{ | "query" : { | "range" : { | "intField" : { - | "gte" : 10 + | "gte" : 10 | } | } | }, - | "size" : 20, - | "from" : 10, - | "sort": [ - | { - | "intField": { - | "missing": "_first" + | "aggs": { + | "aggregation" : { + | "terms" : { + | "field" : "day_of_week" | } | } - | ] + | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search request to JSON with all parameters") { - val jsonRequest = search(Index, Query) - .size(20) - .highlights(highlight(TestDocument.intField)) - .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) - .includes("stringField") - .excludes("intField") match { - case r: ElasticRequest.Search => r.toJson - } - val expected = + val expectedWithFrom = """ - |{ - | "_source" : { - | "includes" : [ - | "stringField" - | ], - | "excludes" : [ - | "intField" - | ] - | }, + { + | "from": 10, | "query" : { | "range" : { | "intField" : { - | "gte" : 10 + | "gte" : 10 | } | } | }, - | "size" : 20, - | "from" : 10, - | "sort": [ - | { - | "intField": { - | "missing": "_first" + | "aggs": { + | "aggregation" : { + | "terms" : { + | "field" : "day_of_week" | } | } - | ], - | "highlight" : { - | "fields" : { - | "intField" : {} - | } | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) - }, - test("successfully encode search and aggregate request to JSON with all parameters") { - val jsonRequest = search(Index, Query) - .aggregate(termsAggregation(name = "aggregation", field = "day_of_week")) - .size(20) - .highlights(highlight(TestDocument.intField)) - .sort(sortBy(TestDocument.intField).missing(First)) - .from(10) - .includes("stringField") - .excludes("intField") match { - case r: ElasticRequest.SearchAndAggregate => r.toJson - } - val expected = + val expectedWithSortAndHighlights = """ |{ - | "_source" : { - | "includes" : [ - | "stringField" - | ], - | "excludes" : [ - | "intField" - | ] + | "highlight" : { + | "fields" : { + | "intField" : {} + | } | }, + | "sort": [ + | { + | "intField": { + | "missing": "_first" + | } + | } + | ], | "query" : { | "range" : { | "intField" : { - | "gte" : 10 + | "gte" : 10 | } | } | }, - | "size" : 20, + | "aggs": { + | "aggregation" : { + | "terms" : { + | "field" : "day_of_week" + | } + | } + | } + |} + |""".stripMargin + + val expectedWithAllParams = + """ + |{ | "from" : 10, + | "size" : 20, + | "highlight" : { + | "fields" : { + | "intField" : {} + | } + | }, | "sort": [ | { | "intField": { @@ -1202,9 +1299,11 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | } | } | ], - | "highlight" : { - | "fields" : { - | "intField" : {} + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } | } | }, | "aggs": { @@ -1213,146 +1312,177 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "field" : "day_of_week" | } | } + | }, + | "search_after" : [ + | "12345" + | ], + | "_source" : { + | "includes" : [ + | "stringField" + | ], + | "excludes" : [ + | "intField" + | ] | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithFrom)(equalTo(expectedWithFrom.toJson)) && + assert(jsonRequestWithSortAndHighlights)(equalTo(expectedWithSortAndHighlights.toJson)) && + assert(jsonRequestWithAllParams)(equalTo(expectedWithAllParams.toJson)) }, - test("successfully encode update by query request to JSON") { - val jsonRequest = updateByQuery( - index = Index, - query = term(TestDocument.stringField.keyword, "StringField"), - script = Script("ctx._source['intField']++") - ) match { case r: UpdateByQuery => r.toJson } + test("update - doc") { + val jsonRequest = update(index = Index, id = DocId, doc = Doc1) match { + case r: Update => r.toJson + } + val jsonRequestWithUpsert = update(index = Index, id = DocId, doc = Doc1).orCreate(Doc2) match { + case r: Update => r.toJson + } val expected = """ |{ - | "script": { - | "source": "ctx._source['intField']++" + | "doc": { + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 5, + | "doubleField": 7.0, + | "booleanField": true, + | "locationField": { + | "lat": 20.0, + | "lon": 21.0 + | } + | } + |} + |""".stripMargin + + val expectedWithUpsert = + """ + |{ + | "doc": { + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 5, + | "doubleField": 7.0, + | "booleanField": true, + | "locationField": { + | "lat": 20.0, + | "lon": 21.0 + | } | }, - | "query": { - | "term": { - | "stringField.keyword": { - | "value": "StringField" - | } + | "upsert": { + | "stringField": "stringField2", + | "subDocumentList": [], + | "dateField": "2022-10-10", + | "intField": 10, + | "doubleField": 17.0, + | "booleanField": false, + | "locationField": { + | "lat": 10.0, + | "lon": 11.0 | } | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithUpsert)(equalTo(expectedWithUpsert.toJson)) }, - test("successfully encode update request to JSON with all parameters - script") { - val jsonRequest = updateByScript( - index = Index, - id = DocId, - script = Script("ctx._source.intField += params['factor']").params("factor" -> 2) - ).orCreate[TestDocument]( - TestDocument( - stringField = "stringField", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-10-10"), - intField = 1, - doubleField = 1.0, - booleanField = true, - locationField = Location(1.0, 1.0) - ) - ) match { case r: Update => r.toJson } + test("update - script") { + val jsonRequest = updateByScript(index = Index, id = DocId, script = Script1) match { + case r: Update => r.toJson + } + val jsonRequestWithUpsert = updateByScript(index = Index, id = DocId, script = Script1).orCreate(Doc2) match { + case r: Update => r.toJson + } val expected = """ |{ | "script": { - | "source": "ctx._source.intField += params['factor']", + | "source": "doc['intField'].value * params['factor']", + | "params": { + | "factor": 2 + | } + | } + |} + |""".stripMargin + + val expectedWithUpsert = + """ + |{ + | "script": { + | "source": "doc['intField'].value * params['factor']", | "params": { | "factor": 2 | } | }, | "upsert": { - | "stringField": "stringField", + | "stringField": "stringField2", | "subDocumentList": [], - | "dateField": "2020-10-10", - | "intField": 1, - | "doubleField": 1.0, - | "booleanField": true, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 + | "dateField": "2022-10-10", + | "intField": 10, + | "doubleField": 17.0, + | "booleanField": false, + | "locationField": { + | "lat": 10.0, + | "lon": 11.0 | } | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithUpsert)(equalTo(expectedWithUpsert.toJson)) }, - test("successfully encode update request to JSON with all parameters - doc") { - val jsonRequest = update[TestDocument]( - index = Index, - id = DocId, - doc = TestDocument( - stringField = "stringField1", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-10-10"), - intField = 1, - doubleField = 1.0, - booleanField = true, - locationField = Location(1.0, 1.0) - ) - ).orCreate[TestDocument]( - TestDocument( - stringField = "stringField2", - subDocumentList = Nil, - dateField = LocalDate.parse("2020-11-11"), - intField = 2, - doubleField = 2.0, - booleanField = false, - locationField = Location(1.0, 1.0) - ) - ) match { case r: Update => r.toJson } + test("update by query") { + val jsonRequest = updateAllByQuery(index = Index, script = Script1) match { + case r: UpdateByQuery => r.toJson + } + val jsonRequestWithQuery = updateByQuery(index = Index, query = Query, script = Script1) match { + case r: UpdateByQuery => r.toJson + } val expected = """ |{ - | "doc": { - | "stringField": "stringField1", - | "subDocumentList": [], - | "dateField": "2020-10-10", - | "intField": 1, - | "doubleField": 1.0, - | "booleanField": true, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 + | "script": { + | "source": "doc['intField'].value * params['factor']", + | "params": { + | "factor": 2 + | } + | } + |} + |""".stripMargin + + val expectedWithQuery = + """ + |{ + | "script": { + | "source": "doc['intField'].value * params['factor']", + | "params": { + | "factor": 2 | } | }, - | "upsert": { - | "stringField": "stringField2", - | "subDocumentList": [], - | "dateField": "2020-11-11", - | "intField": 2, - | "doubleField": 2.0, - | "booleanField": false, - | "locationField" : { - | "lat" : 1.0, - | "lon" : 1.0 + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } | } | } |} |""".stripMargin - assert(jsonRequest)(equalTo(expected.toJson)) + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithQuery)(equalTo(expectedWithQuery.toJson)) } ) ) - private val Aggregation = ElasticAggregation.maxAggregation(name = "aggregation", field = TestDocument.intField) - private val Query = ElasticQuery.range(TestDocument.intField).gte(10) - private val Index = IndexName("index") - private val DocId = DocumentId("documentid") - private val RoutingValue = Routing("routing") - private val Doc1 = TestDocument( stringField = "stringField1", subDocumentList = List(), @@ -1371,6 +1501,11 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { booleanField = false, locationField = Location(10.0, 11.0) ) - private val Script1 = Script("doc['intField'].value * params['factor']").params("factor" -> 2) - + private val DocId = DocumentId("documentid") + private val Index = IndexName("index") + private val MaxAggregation = ElasticAggregation.maxAggregation(name = "aggregation", field = TestDocument.intField) + private val Query = ElasticQuery.range(TestDocument.intField).gte(10) + private val RoutingValue = Routing("routing") + private val Script1 = Script("doc['intField'].value * params['factor']").params("factor" -> 2) + private val TermsAggregation = termsAggregation(name = "aggregation", field = "day_of_week") } From 366602324fe1185eee25d1d54233e260858ada66 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 16 May 2023 15:55:15 +0200 Subject: [PATCH 4/7] Add missing encoding tests --- .../zio/elasticsearch/ElasticRequest.scala | 13 +- .../elasticsearch/executor/HttpExecutor.scala | 12 +- ...DSLSpec.scala => ElasticRequestSpec.scala} | 163 ++++++++++++++++-- 3 files changed, 166 insertions(+), 22 deletions(-) rename modules/library/src/test/scala/zio/elasticsearch/{ElasticRequestDSLSpec.scala => ElasticRequestSpec.scala} (91%) diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala index b383b201e..960b9c566 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala @@ -440,6 +440,9 @@ object ElasticRequest { def routing(value: Routing): CreateRequest = self.copy(routing = Some(value)) + + def toJson: Json = + document.json } sealed trait CreateWithIdRequest @@ -459,6 +462,9 @@ object ElasticRequest { def routing(value: Routing): CreateWithIdRequest = self.copy(routing = Some(value)) + + def toJson: Json = + document.json } sealed trait CreateIndexRequest extends ElasticRequest[CreationOutcome] @@ -466,7 +472,9 @@ object ElasticRequest { private[elasticsearch] final case class CreateIndex( name: IndexName, definition: Option[String] - ) extends CreateIndexRequest + ) extends CreateIndexRequest { + def toJson: String = definition.getOrElse("") + } sealed trait CreateOrUpdateRequest extends BulkableRequest[Unit] @@ -485,6 +493,9 @@ object ElasticRequest { def routing(value: Routing): CreateOrUpdateRequest = self.copy(routing = Some(value)) + + def toJson: Json = + document.json } sealed trait DeleteByIdRequest diff --git a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala index 4323e6e14..0c3f6cd3b 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/executor/HttpExecutor.scala @@ -180,7 +180,7 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig baseRequest .post(uri) .contentType(ApplicationJson) - .body(r.document.json) + .body(r.toJson) .response(asJson[CreateResponse]) ).flatMap { response => response.code match { @@ -206,7 +206,7 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig baseRequest .post(uri) .contentType(ApplicationJson) - .body(r.document.json) + .body(r.toJson) ).flatMap { response => response.code match { case HttpCreated => ZIO.succeed(CreationOutcome.Created) @@ -216,12 +216,12 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig } } - private def executeCreateIndex(createIndex: CreateIndex): Task[CreationOutcome] = + private def executeCreateIndex(r: CreateIndex): Task[CreationOutcome] = sendRequest( baseRequest - .put(uri"${esConfig.uri}/${createIndex.name}") + .put(uri"${esConfig.uri}/${r.name}") .contentType(ApplicationJson) - .body(createIndex.definition.getOrElse("")) + .body(r.toJson) ).flatMap { response => response.code match { case HttpOk => ZIO.succeed(CreationOutcome.Created) @@ -234,7 +234,7 @@ private[elasticsearch] final class HttpExecutor private (esConfig: ElasticConfig val uri = uri"${esConfig.uri}/${r.index}/$Doc/${r.id}" .withParams(getQueryParams(Chunk(("refresh", r.refresh), ("routing", r.routing)))) - sendRequest(baseRequest.put(uri).contentType(ApplicationJson).body(r.document.json)).flatMap { response => + sendRequest(baseRequest.put(uri).contentType(ApplicationJson).body(r.toJson)).flatMap { response => response.code match { case HttpOk | HttpCreated => ZIO.unit case _ => ZIO.fail(handleFailures(response)) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala similarity index 91% rename from modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala rename to modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala index b5103fdee..56ee5c18f 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestDSLSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala @@ -13,14 +13,13 @@ import zio.elasticsearch.request.Document import zio.elasticsearch.request.UpdateConflicts.Abort import zio.elasticsearch.script.Script import zio.elasticsearch.utils.RichString -import zio.json.ast.Json import zio.json.ast.Json.{Arr, Str} import zio.test.Assertion.equalTo import zio.test._ import java.time.LocalDate -object ElasticRequestDSLSpec extends ZIOSpecDefault { +object ElasticRequestSpec extends ZIOSpecDefault { override def spec: Spec[TestEnvironment, Any] = suite("ElasticRequest")( suite("constructing")( @@ -962,7 +961,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { ), suite("encoding as JSON")( test("aggregate") { - val jsonRequest: Json = aggregate(Index, MaxAggregation) match { + val jsonRequest = aggregate(Index, MaxAggregation) match { case r: ElasticRequest.Aggregate => r.toJson } @@ -998,26 +997,160 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { assert(requestBody)(equalTo(expected)) }, + test("count") { + val jsonRequest = count(Index) match { + case r: Count => r.toJson + } + val jsonRequestWithQuery = count(Index, Query) match { + case r: Count => r.toJson + } + + val expected = + "{}" + val expectedWithQuery = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) && + assert(jsonRequestWithQuery)(equalTo(expectedWithQuery.toJson)) + }, + test("create") { + val jsonRequest = create(Index, Doc1) match { + case r: Create => r.toJson + } + + val expected = + """ + |{ + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 5, + | "doubleField": 7.0, + | "booleanField": true, + | "locationField": { + | "lat": 20.0, + | "lon": 21.0 + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("create with id") { + val jsonRequest = create(index = Index, id = DocId, doc = Doc1) match { + case r: CreateWithId => r.toJson + } + + val expected = + """ + |{ + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 5, + | "doubleField": 7.0, + | "booleanField": true, + | "locationField": { + | "lat": 20.0, + | "lon": 21.0 + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("create index") { + val definition = + """ + |{ + | "settings": { + | "number_of_shards": 3 + | } + |} + |""".stripMargin + val jsonRequest = createIndex(Index) match { + case r: CreateIndex => r.toJson + } + val jsonRequestWithDefinition = createIndex(name = Index, definition = definition) match { + case r: CreateIndex => r.toJson + } + + assert(jsonRequest)(equalTo("")) && + assert(jsonRequestWithDefinition)(equalTo(definition)) + }, + test("create or update") { + val jsonRequest = upsert(index = Index, id = DocId, doc = Doc1) match { + case r: CreateOrUpdate => r.toJson + } + + val expected = + """ + |{ + | "stringField": "stringField1", + | "subDocumentList": [], + | "dateField": "2020-10-10", + | "intField": 5, + | "doubleField": 7.0, + | "booleanField": true, + | "locationField": { + | "lat": 20.0, + | "lon": 21.0 + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, + test("delete by query") { + val jsonRequest = deleteByQuery(index = Index, query = Query) match { + case r: DeleteByQuery => r.toJson + } + + val expected = + """ + |{ + | "query" : { + | "range" : { + | "intField" : { + | "gte" : 10 + | } + | } + | } + |} + |""".stripMargin + + assert(jsonRequest)(equalTo(expected.toJson)) + }, test("search") { - val jsonRequest: Json = search(Index, Query) match { + val jsonRequest = search(Index, Query) match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithSearchAfter: Json = search(Index, Query).searchAfter(Arr(Str("12345"))) match { + val jsonRequestWithSearchAfter = search(Index, Query).searchAfter(Arr(Str("12345"))) match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithSize: Json = search(Index, Query).size(20) match { + val jsonRequestWithSize = search(Index, Query).size(20) match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithExcludes: Json = search(Index, Query).excludes("subDocumentList") match { + val jsonRequestWithExcludes = search(Index, Query).excludes("subDocumentList") match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithIncludes: Json = search(Index, Query).includes("stringField", "doubleField") match { + val jsonRequestWithIncludes = search(Index, Query).includes("stringField", "doubleField") match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithInclSchema: Json = search(Index, Query).includes[TestDocument] match { + val jsonRequestWithInclSchema = search(Index, Query).includes[TestDocument] match { case r: ElasticRequest.Search => r.toJson } - val jsonRequestWithAllParams: Json = search(Index, Query) + val jsonRequestWithAllParams = search(Index, Query) .size(20) .sort(sortBy(TestDocument.intField).missing(First)) .excludes("intField") @@ -1222,7 +1355,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "aggs": { | "aggregation" : { | "terms" : { - | "field" : "day_of_week" + | "field" : "intField" | } | } | } @@ -1243,7 +1376,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "aggs": { | "aggregation" : { | "terms" : { - | "field" : "day_of_week" + | "field" : "intField" | } | } | } @@ -1275,7 +1408,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "aggs": { | "aggregation" : { | "terms" : { - | "field" : "day_of_week" + | "field" : "intField" | } | } | } @@ -1309,7 +1442,7 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { | "aggs": { | "aggregation" : { | "terms" : { - | "field" : "day_of_week" + | "field" : "intField" | } | } | }, @@ -1507,5 +1640,5 @@ object ElasticRequestDSLSpec extends ZIOSpecDefault { private val Query = ElasticQuery.range(TestDocument.intField).gte(10) private val RoutingValue = Routing("routing") private val Script1 = Script("doc['intField'].value * params['factor']").params("factor" -> 2) - private val TermsAggregation = termsAggregation(name = "aggregation", field = "day_of_week") + private val TermsAggregation = termsAggregation(name = "aggregation", field = "intField") } From d010b35276fee18a60a147785f5b12f440c53612 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 16 May 2023 15:56:07 +0200 Subject: [PATCH 5/7] Remove bulk test from ElasticQuerySpec --- .../zio/elasticsearch/ElasticQuerySpec.scala | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index 7a9542de0..b96c8b1bb 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -1533,46 +1533,6 @@ object ElasticQuerySpec extends ZIOSpecDefault { assert(queryWithAllParams.toJson(fieldPath = None))(equalTo(expectedWithAllParams.toJson)) } ), - test("bulk") { - val query = IndexName.make("users").map { index => - val nestedField = TestNestedField("NestedField", 1) - val subDoc = TestSubDocument( - stringField = "StringField", - nestedField = nestedField, - intField = 100, - intFieldList = Nil - ) - val req1 = - ElasticRequest - .create[TestSubDocument](index, DocumentId("ETux1srpww2ObCx"), subDoc.copy(intField = 65)) - .routing(unsafeWrap(subDoc.stringField)(Routing)) - val req2 = - ElasticRequest.create[TestSubDocument](index, subDoc).routing(unsafeWrap(subDoc.stringField)(Routing)) - val req3 = ElasticRequest - .upsert[TestSubDocument](index, DocumentId("yMyEG8iFL5qx"), subDoc.copy(stringField = "StringField2")) - .routing(unsafeWrap(subDoc.stringField)(Routing)) - val req4 = - ElasticRequest - .deleteById(index, DocumentId("1VNzFt2XUFZfXZheDc")) - .routing(unsafeWrap(subDoc.stringField)(Routing)) - ElasticRequest.bulk(req1, req2, req3, req4) match { - case r: Bulk => Some(r.body) - case _ => None - } - } - - val expected = - """|{ "create" : { "_index" : "users", "_id" : "ETux1srpww2ObCx", "routing" : "StringField" } } - |{"stringField":"StringField","nestedField":{"stringField":"NestedField","longField":1},"intField":65,"intFieldList":[]} - |{ "create" : { "_index" : "users", "routing" : "StringField" } } - |{"stringField":"StringField","nestedField":{"stringField":"NestedField","longField":1},"intField":100,"intFieldList":[]} - |{ "index" : { "_index" : "users", "_id" : "yMyEG8iFL5qx", "routing" : "StringField" } } - |{"stringField":"StringField2","nestedField":{"stringField":"NestedField","longField":1},"intField":100,"intFieldList":[]} - |{ "delete" : { "_index" : "users", "_id" : "1VNzFt2XUFZfXZheDc", "routing" : "StringField" } } - |""".stripMargin - - assert(query)(equalTo(Validation.succeed(Some(expected)))) - }, test("contains") { val query = contains(TestDocument.stringField, "test") val queryWithBoost = contains(TestDocument.stringField, "test").boost(3.14) From af100fa410fec21552e50160d2ba61ccc6efdf63 Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Tue, 16 May 2023 16:00:41 +0200 Subject: [PATCH 6/7] Fix lint --- .../src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala index b96c8b1bb..a297c8246 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticQuerySpec.scala @@ -18,14 +18,12 @@ package zio.elasticsearch import zio.Chunk import zio.elasticsearch.ElasticQuery._ -import zio.elasticsearch.ElasticRequest.Bulk import zio.elasticsearch.domain._ import zio.elasticsearch.query.DistanceType.Plane import zio.elasticsearch.query.DistanceUnit.Kilometers import zio.elasticsearch.query.ValidationMethod.IgnoreMalformed import zio.elasticsearch.query._ import zio.elasticsearch.utils._ -import zio.prelude.Validation import zio.test.Assertion.equalTo import zio.test.{Spec, TestEnvironment, ZIOSpecDefault, assert} From 2b2619845820f850647329622d60034afb31466b Mon Sep 17 00:00:00 2001 From: Dimitrije Bulaja Date: Thu, 18 May 2023 09:29:54 +0200 Subject: [PATCH 7/7] Fix code remarks --- .../elasticsearch/ElasticRequestSpec.scala | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala index 56ee5c18f..c62e0016f 100644 --- a/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala +++ b/modules/library/src/test/scala/zio/elasticsearch/ElasticRequestSpec.scala @@ -125,7 +125,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { equalTo(Count(index = Index, query = Some(Query), routing = Some(RoutingValue))) ) }, - test("create without id") { + test("create") { val createRequest = create(index = Index, doc = Doc1) val createRequestWithRefresh = create(index = Index, doc = Doc1).refreshTrue val createRequestWithRouting = create(index = Index, doc = Doc1).routing(RoutingValue) @@ -143,7 +143,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { ) ) }, - test("create with id") { + test("create with ID") { val createRequest = create(index = Index, id = DocId, doc = Doc1) val createRequestWithRefresh = create(index = Index, id = DocId, doc = Doc1).refreshTrue val createRequestWithRouting = create(index = Index, id = DocId, doc = Doc1).routing(RoutingValue) @@ -192,14 +192,14 @@ object ElasticRequestSpec extends ZIOSpecDefault { ) ) }, - test("create index") { + test("createIndex") { val createIndexRequest = createIndex(Index) val createIndexRequestWithDefinition = createIndex(name = Index, definition = "definition") assert(createIndexRequest)(equalTo(CreateIndex(name = Index, definition = None))) && assert(createIndexRequestWithDefinition)(equalTo(CreateIndex(name = Index, definition = Some("definition")))) }, - test("delete by id") { + test("deleteById") { val deleteByIdRequest = deleteById(index = Index, id = DocId) val deleteByIdRequestWithRefresh = deleteById(index = Index, id = DocId).refreshTrue val deleteByIdRequestWithRouting = deleteById(index = Index, id = DocId).routing(RoutingValue) @@ -215,7 +215,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { equalTo(DeleteById(index = Index, id = DocId, refresh = Some(true), routing = Some(RoutingValue))) ) }, - test("delete by query") { + test("deleteByQuery") { val deleteByQueryRequest = deleteByQuery(index = Index, query = Query) val deleteByQueryRequestWithRefresh = deleteByQuery(index = Index, query = Query).refreshTrue val deleteByQueryRequestWithRouting = deleteByQuery(index = Index, query = Query).routing(RoutingValue) @@ -232,7 +232,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { equalTo(DeleteByQuery(index = Index, query = Query, refresh = Some(true), routing = Some(RoutingValue))) ) }, - test("delete index") { + test("deleteIndex") { val deleteIndexRequest = deleteIndex(Index) assert(deleteIndexRequest)(equalTo(DeleteIndex(Index))) @@ -244,7 +244,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(existsRequest)(equalTo(Exists(index = Index, id = DocId, routing = None))) && assert(existsRequestWithRouting)(equalTo(Exists(index = Index, id = DocId, routing = Some(RoutingValue)))) }, - test("get by id") { + test("getById") { val getByIdRequest = getById(index = Index, id = DocId) val getByIdRequestWithRefresh = getById(index = Index, id = DocId).refreshTrue val getByIdRequestWithRouting = getById(index = Index, id = DocId).routing(RoutingValue) @@ -709,7 +709,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { ) ) }, - test("update all by query") { + test("updateAllByQuery") { val updateByQueryRequest = updateAllByQuery(index = Index, script = Script1) val updateByQueryRequestWithConflicts = updateAllByQuery(index = Index, script = Script1).conflicts(Abort) val updateByQueryRequestWithRefresh = updateAllByQuery(index = Index, script = Script1).refreshTrue @@ -774,7 +774,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { ) ) }, - test("update by query") { + test("updateByQuery") { val updateByQueryRequest = updateByQuery(index = Index, query = Query, script = Script1) val updateByQueryRequestWithConflicts = updateByQuery(index = Index, query = Query, script = Script1).conflicts(Abort) @@ -845,7 +845,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { ) ) }, - test("update by script") { + test("updateByScript") { val updateRequest = updateByScript(Index, DocId, Script1) val updateRequestWithRefresh = updateByScript(Index, DocId, Script1).refreshTrue val updateRequestWithRouting = updateByScript(Index, DocId, Script1).routing(RoutingValue) @@ -1046,7 +1046,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(jsonRequest)(equalTo(expected.toJson)) }, - test("create with id") { + test("create with ID") { val jsonRequest = create(index = Index, id = DocId, doc = Doc1) match { case r: CreateWithId => r.toJson } @@ -1069,7 +1069,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(jsonRequest)(equalTo(expected.toJson)) }, - test("create index") { + test("createIndex") { val definition = """ |{ @@ -1088,7 +1088,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(jsonRequest)(equalTo("")) && assert(jsonRequestWithDefinition)(equalTo(definition)) }, - test("create or update") { + test("upsert") { val jsonRequest = upsert(index = Index, id = DocId, doc = Doc1) match { case r: CreateOrUpdate => r.toJson } @@ -1111,7 +1111,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(jsonRequest)(equalTo(expected.toJson)) }, - test("delete by query") { + test("deleteByQuery") { val jsonRequest = deleteByQuery(index = Index, query = Query) match { case r: DeleteByQuery => r.toJson } @@ -1571,7 +1571,7 @@ object ElasticRequestSpec extends ZIOSpecDefault { assert(jsonRequest)(equalTo(expected.toJson)) && assert(jsonRequestWithUpsert)(equalTo(expectedWithUpsert.toJson)) }, - test("update by query") { + test("updateByQuery") { val jsonRequest = updateAllByQuery(index = Index, script = Script1) match { case r: UpdateByQuery => r.toJson }