diff --git a/CHANGELOG.md b/CHANGELOG.md index 6479abf08d..62ddcb5839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased 2.x] ### Added +- Added `searchAfterVals` to `SearchRequest` to allow passing arbitrary `FieldValue`s to `search_after` ([#1105](https://github.com/opensearch-project/opensearch-java/pull/1105)) ### Dependencies diff --git a/java-client/src/main/java/org/opensearch/client/opensearch/core/SearchRequest.java b/java-client/src/main/java/org/opensearch/client/opensearch/core/SearchRequest.java index 188b61cd45..632a051dd7 100644 --- a/java-client/src/main/java/org/opensearch/client/opensearch/core/SearchRequest.java +++ b/java-client/src/main/java/org/opensearch/client/opensearch/core/SearchRequest.java @@ -48,6 +48,7 @@ import org.opensearch.client.json.PlainJsonSerializable; import org.opensearch.client.opensearch._types.ErrorResponse; import org.opensearch.client.opensearch._types.ExpandWildcard; +import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.RequestBase; import org.opensearch.client.opensearch._types.ScriptField; import org.opensearch.client.opensearch._types.SearchType; @@ -191,7 +192,7 @@ public class SearchRequest extends RequestBase implements PlainJsonSerializable @Nullable private final Time scroll; - private final List searchAfter; + private final List searchAfter; @Nullable private final SearchType searchType; @@ -710,8 +711,19 @@ public final Time scroll() { /** * API name: {@code search_after} + * + * @implNote In version 3.0.0 of opensearch-java, this method will instead return a {@code List}. */ public final List searchAfter() { + return this.searchAfter.stream().map(FieldValue::_toJsonString).collect(Collectors.toList()); + } + + /** + * API name: {@code search_after} + * + * @implNote In version 3.0.0 of opensearch-java, this method will be renamed to replace {@link #searchAfter()}. + */ + public final List searchAfterVals() { return this.searchAfter; } @@ -1006,8 +1018,8 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) { if (ApiTypeHelper.isDefined(this.searchAfter)) { generator.writeKey("search_after"); generator.writeStartArray(); - for (String item0 : this.searchAfter) { - generator.write(item0); + for (FieldValue item0 : this.searchAfter) { + item0.serialize(generator, mapper); } generator.writeEnd(); @@ -1143,7 +1155,7 @@ public Builder toBuilder() { .runtimeMappings(runtimeMappings) .scriptFields(scriptFields) .scroll(scroll) - .searchAfter(searchAfter) + .searchAfterVals(searchAfter) .searchType(searchType) .seqNoPrimaryTerm(seqNoPrimaryTerm) .size(size) @@ -1288,7 +1300,7 @@ public static class Builder extends ObjectBuilderBase implements ObjectBuilder searchAfter; + private List searchAfter; @Nullable private SearchType searchType; @@ -1998,9 +2010,11 @@ public final Builder scroll(Function> fn) { * API name: {@code search_after} *

* Adds all elements of list to searchAfter. + * + * @implNote In version 3.0.0 of opensearch-java, this method will instead accept a {@code List}. */ public final Builder searchAfter(List list) { - this.searchAfter = _listAddAll(this.searchAfter, list); + this.searchAfter = _listAddAll(this.searchAfter, FieldValue::of, list); return this; } @@ -2008,8 +2022,34 @@ public final Builder searchAfter(List list) { * API name: {@code search_after} *

* Adds one or more values to searchAfter. + * + * @implNote In version 3.0.0 of opensearch-java, this method will instead accept values of type {@code FieldValue}. */ public final Builder searchAfter(String value, String... values) { + this.searchAfter = _listAdd(this.searchAfter, FieldValue::of, value, values); + return this; + } + + /** + * API name: {@code search_after} + *

+ * Adds all elements of list to searchAfter. + * + * @implNote In version 3.0.0 of opensearch-java, this method will be renamed to replace {@link #searchAfter(List)}. + */ + public final Builder searchAfterVals(List list) { + this.searchAfter = _listAddAll(this.searchAfter, list); + return this; + } + + /** + * API name: {@code search_after} + *

+ * Adds one or more values to searchAfter. + * + * @implNote In version 3.0.0 of opensearch-java, this method will be renamed to replace {@link #searchAfter(String, String...)}. + */ + public final Builder searchAfterVals(FieldValue value, FieldValue... values) { this.searchAfter = _listAdd(this.searchAfter, value, values); return this; } diff --git a/java-client/src/main/java/org/opensearch/client/util/ObjectBuilderBase.java b/java-client/src/main/java/org/opensearch/client/util/ObjectBuilderBase.java index 788078c9dd..fc8b642f1d 100644 --- a/java-client/src/main/java/org/opensearch/client/util/ObjectBuilderBase.java +++ b/java-client/src/main/java/org/opensearch/client/util/ObjectBuilderBase.java @@ -39,6 +39,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; public class ObjectBuilderBase { private boolean _used = false; @@ -73,17 +75,38 @@ private static List _mutableList(List list) { } } + /** Add a value to a (possibly {@code null}) list */ + @SafeVarargs + protected static List _listAdd(List list, Function mapper, TIn value, TIn... values) { + List mappedValues = values.length > 0 + ? Arrays.stream(values).map(mapper).collect(Collectors.toList()) + : null; + return _listAdd(list, mapper.apply(value), mappedValues); + } + /** Add a value to a (possibly {@code null}) list */ @SafeVarargs protected static List _listAdd(List list, T value, T... values) { + return _listAdd(list, value, values.length > 0 ? Arrays.asList(values) : null); + } + + private static List _listAdd(List list, T value, List values) { list = _mutableList(list); list.add(value); - if (values.length > 0) { - list.addAll(Arrays.asList(values)); + if (values != null) { + list.addAll(values); } return list; } + /** Add all elements of a list to a (possibly {@code null}) list */ + protected static List _listAddAll(List list, Function mapper, List values) { + List mappedValues = values != null + ? values.stream().map(mapper).collect(Collectors.toList()) + : null; + return _listAddAll(list, mappedValues); + } + /** Add all elements of a list to a (possibly {@code null}) list */ protected static List _listAddAll(List list, List values) { if (list == null) { diff --git a/java-client/src/test/java/org/opensearch/client/opensearch/core/SearchRequestTest.java b/java-client/src/test/java/org/opensearch/client/opensearch/core/SearchRequestTest.java index 07eda7fce0..c7b97c10b2 100644 --- a/java-client/src/test/java/org/opensearch/client/opensearch/core/SearchRequestTest.java +++ b/java-client/src/test/java/org/opensearch/client/opensearch/core/SearchRequestTest.java @@ -11,10 +11,22 @@ import java.util.Collections; import org.junit.Test; import org.opensearch.client.json.JsonData; +import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch.model.ModelTestCase; public class SearchRequestTest extends ModelTestCase { + @Test + public void afterSearch() { + SearchRequest request = new SearchRequest.Builder().searchAfter("string1", "string2").build(); + + assertEquals("{\"search_after\":[\"string1\",\"string2\"]}", toJson(request)); + + request = new SearchRequest.Builder().searchAfterVals(FieldValue.of(1), FieldValue.of("string")).build(); + + assertEquals("{\"search_after\":[1,\"string\"]}", toJson(request)); + } + @Test public void ext() { SearchRequest request = new SearchRequest.Builder().ext(