Skip to content

Commit

Permalink
Add EQ|QL version support with its default value (#791)
Browse files Browse the repository at this point in the history
  • Loading branch information
swallez authored Apr 30, 2024
1 parent fff5381 commit 2333f38
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.esql.ElasticsearchEsqlAsyncClient;
import co.elastic.clients.elasticsearch.esql.ElasticsearchEsqlClient;
import co.elastic.clients.elasticsearch.esql.EsqlVersion;
import co.elastic.clients.elasticsearch.esql.QueryRequest;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.transport.endpoints.BinaryResponse;
Expand All @@ -36,9 +37,9 @@ public class EsqlHelper {
//----- Synchronous

public static <T> T query(
ElasticsearchEsqlClient client, EsqlAdapter<T> adapter, String query, Object... params
ElasticsearchEsqlClient client, EsqlVersion version, EsqlAdapter<T> adapter, String query, Object... params
) throws IOException {
QueryRequest request = buildRequest(adapter, query, params);
QueryRequest request = buildRequest(version, adapter, query, params);
BinaryResponse response = client.query(request);
return adapter.deserialize(client, request, response);
}
Expand All @@ -52,9 +53,9 @@ public static <T> T query(ElasticsearchEsqlClient client, EsqlAdapter<T> adapter
//----- Asynchronous

public static <T> CompletableFuture<T> queryAsync(
ElasticsearchEsqlAsyncClient client, EsqlAdapter<T> adapter, String query, Object... params
ElasticsearchEsqlAsyncClient client, EsqlVersion version, EsqlAdapter<T> adapter, String query, Object... params
) {
return doQueryAsync(client, adapter, buildRequest(adapter, query, params));
return doQueryAsync(client, adapter, buildRequest(version, adapter, query, params));
}

public static <T> CompletableFuture<T> queryAsync(
Expand All @@ -79,9 +80,19 @@ private static <T> CompletableFuture<T> doQueryAsync(

//----- Utilities

private static QueryRequest buildRequest(EsqlAdapter<?> adapter, String query, Object... params) {
private static QueryRequest buildRequest(EsqlVersion version, EsqlAdapter<?> adapter, String query, Object... params) {
if (version == null) {
version = EsqlVersion.getDefault();
}
if (version == null) {
throw new IllegalStateException(
"ES|QL default version not set. Either specify it explicitly or set a default value");
}
EsqlVersion v = version;

return QueryRequest.of(esql -> esql
.format(adapter.format())
.version(v)
.columnar(adapter.columnar())
.query(query)
.params(asFieldValues(params))
Expand All @@ -99,6 +110,7 @@ private static QueryRequest buildRequest(EsqlAdapter<?> adapter, QueryRequest re
.locale(request.locale())
.params(request.params())
.query(request.query())
.version(request.version())
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,24 @@ public final CompletableFuture<BinaryResponse> query(
* values for query parameters, if any
*/
public final <T> CompletableFuture<T> query(EsqlAdapter<T> adapter, String query, Object... parameters) {
return EsqlHelper.queryAsync(this, adapter, query, parameters);
return EsqlHelper.queryAsync(this, null, adapter, query, parameters);
}

/**
* Executes an ES|QL request and adapts its result to a target type.
*
* @param version
* the ES|QL language version
* @param adapter
* the ES|QL response adapter
* @param query
* the ES|QL query
* @param parameters
* values for query parameters, if any
*/
public final <T> CompletableFuture<T> query(EsqlVersion version, EsqlAdapter<T> adapter, String query,
Object... parameters) {
return EsqlHelper.queryAsync(this, version, adapter, query, parameters);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,24 @@ public final BinaryResponse query(Function<QueryRequest.Builder, ObjectBuilder<Q
*/
public final <T> T query(EsqlAdapter<T> adapter, String query, Object... parameters)
throws IOException, ElasticsearchException {
return EsqlHelper.query(this, adapter, query, parameters);
return EsqlHelper.query(this, null, adapter, query, parameters);
}

/**
* Executes an ES|QL request and adapts its result to a target type.
*
* @param version
* the ES|QL language version
* @param adapter
* the ES|QL response adapter
* @param query
* the ES|QL query
* @param parameters
* values for query parameters, if any
*/
public final <T> T query(EsqlVersion version, EsqlAdapter<T> adapter, String query, Object... parameters)
throws IOException, ElasticsearchException {
return EsqlHelper.query(this, version, adapter, query, parameters);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package co.elastic.clients.elasticsearch.esql;

import co.elastic.clients.json.JsonEnum;
import co.elastic.clients.json.JsonpDeserializable;
import co.elastic.clients.json.JsonpDeserializer;

//----------------------------------------------------------------
// THIS CODE IS GENERATED. MANUAL EDITS WILL BE LOST.
//----------------------------------------------------------------
//
// This code is generated from the Elasticsearch API specification
// at https://github.com/elastic/elasticsearch-specification
//
// Manual updates to this file will be lost when the code is
// re-generated.
//
// If you find a property that is missing or wrongly typed, please
// open an issue or a PR on the API specification repository.
//
//----------------------------------------------------------------

/**
*
* @see <a href="../doc-files/api-spec.html#esql._types.EsqlVersion">API
* specification</a>
*/
@JsonpDeserializable
public enum EsqlVersion implements JsonEnum {
/**
* Run against the first version of ES|QL.
*/
V2024_04_01("2024.04.01"),

;

private final String jsonValue;

EsqlVersion(String jsonValue) {
this.jsonValue = jsonValue;
}

public String jsonValue() {
return this.jsonValue;
}

private static EsqlVersion DEFAULT_VERSION = V2024_04_01;

/**
* The default ES|QL language version used when not explicitly specified.
*/
public static EsqlVersion getDefault() {
return DEFAULT_VERSION;
}

/**
* Set the default ES|QL language version to be used. This is a global
* application-wide setting.
*/
public static void setDefault(EsqlVersion version) {
DEFAULT_VERSION = version;
}

public static final JsonEnum.Deserializer<EsqlVersion> _DESERIALIZER = new JsonEnum.Deserializer<>(
EsqlVersion.values());
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ public class QueryRequest extends RequestBase implements JsonpSerializable {

private final String query;

private final EsqlVersion version;

// ---------------------------------------------------------------------------------------------

private QueryRequest(Builder builder) {
Expand All @@ -101,6 +103,7 @@ private QueryRequest(Builder builder) {
this.locale = builder.locale;
this.params = ApiTypeHelper.unmodifiable(builder.params);
this.query = ApiTypeHelper.requireNonNull(builder.query, this, "query");
this.version = ApiTypeHelper.requireNonNull(builder.version, this, "version");

}

Expand Down Expand Up @@ -182,6 +185,16 @@ public final String query() {
return this.query;
}

/**
* Required - The version of the ES|QL language in which the &quot;query&quot;
* field was written.
* <p>
* API name: {@code version}
*/
public final EsqlVersion version() {
return this.version;
}

/**
* Serialize this object to JSON.
*/
Expand Down Expand Up @@ -221,6 +234,9 @@ protected void serializeInternal(JsonGenerator generator, JsonpMapper mapper) {
generator.writeKey("query");
generator.write(this.query);

generator.writeKey("version");
this.version.serialize(generator, mapper);

}

// ---------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -250,6 +266,8 @@ public static class Builder extends RequestBase.AbstractBuilder<Builder> impleme

private String query;

private EsqlVersion version;

/**
* By default, ES|QL returns results as rows. For example, FROM returns each
* individual document as one row. For the JSON, YAML, CBOR and smile formats,
Expand Down Expand Up @@ -365,6 +383,17 @@ public final Builder query(String value) {
return this;
}

/**
* Required - The version of the ES|QL language in which the &quot;query&quot;
* field was written.
* <p>
* API name: {@code version}
*/
public final Builder version(EsqlVersion value) {
this.version = value;
return this;
}

@Override
protected Builder self() {
return this;
Expand All @@ -381,6 +410,10 @@ public QueryRequest build() {

return new QueryRequest(this);
}
{
// Use the default ES|QL language version if not set explicitly
this.version = EsqlVersion.getDefault();
}
}

// ---------------------------------------------------------------------------------------------
Expand All @@ -398,6 +431,7 @@ protected static void setupQueryRequestDeserializer(ObjectDeserializer<QueryRequ
op.add(Builder::locale, JsonpDeserializer.stringDeserializer(), "locale");
op.add(Builder::params, JsonpDeserializer.arrayDeserializer(FieldValue._DESERIALIZER), "params");
op.add(Builder::query, JsonpDeserializer.stringDeserializer(), "query");
op.add(Builder::version, EsqlVersion._DESERIALIZER, "version");

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ public synchronized ElasticsearchTestServer start() {
return this;
}

Version version = Version.VERSION.major() < 8 ? new Version(7,17,5,false) : new Version(8,12,0,false);
Version version = Version.VERSION.major() < 8 ? new Version(7,17,5,false) : new Version(8,14,0,false);

// Note we could use version.major() + "." + version.minor() + "-SNAPSHOT" but plugins won't install on a snapshot version
String esImage = "docker.elastic.co/elasticsearch/elasticsearch:" + version;
String esImage = "docker.elastic.co/elasticsearch/elasticsearch:" + version + "-SNAPSHOT";

DockerImageName image;
if (plugins.length == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public void objectsTest() throws Exception {
{
EmpData emp = it.next();
assertEquals("10042", emp.empNo);
assertEquals(Arrays.asList("Architect", "Business Analyst", "Internship", "Junior Developer"), emp.jobPositions);
assertEquals(Arrays.asList("Architect", "Business Analyst", "Junior Developer", "Internship"), emp.jobPositions);

assertEquals("1993-03-21T00:00:00Z[UTC]",
DateTimeFormatter.ISO_DATE_TIME.format(emp.hireDate.toInstant().atZone(ZoneId.of("UTC")))
Expand Down Expand Up @@ -172,7 +172,7 @@ public void asyncObjects() throws Exception {
{
EmpData emp = it.next();
assertEquals("10042", emp.empNo);
assertEquals(Arrays.asList("Architect", "Business Analyst", "Internship", "Junior Developer"), emp.jobPositions);
assertEquals(Arrays.asList("Architect", "Business Analyst", "Junior Developer", "Internship"), emp.jobPositions);

assertEquals("1993-03-21T00:00:00Z[UTC]",
DateTimeFormatter.ISO_DATE_TIME.format(emp.hireDate.toInstant().atZone(ZoneId.of("UTC")))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package co.elastic.clients.elasticsearch._helpers.esql;

import co.elastic.clients.elasticsearch.esql.EsqlVersion;
import co.elastic.clients.elasticsearch.esql.QueryRequest;
import co.elastic.clients.util.MissingRequiredPropertyException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class EsqlVersionTest extends Assertions {

@Test
public void testDefaultVersion() {

// If version is missing, the default one is used.
QueryRequest r = QueryRequest.of(q -> q
.query("foo")
);

assertEquals(EsqlVersion.getDefault(), r.version());
}

@Test
public void testSetVersionToNull() {

assertThrows(MissingRequiredPropertyException.class, () -> {
// If version is explicitly set to null, the default isn't used
QueryRequest r = QueryRequest.of(q -> q
.version(null)
.query("foo")
);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ public void i0254_suggesterTest() throws Exception {
}

@Test
@Disabled("Plugins cannot be installed on snapshot versions of ES")
public void i0249_variantKind() throws Exception {
try (ElasticsearchTestServer server = new ElasticsearchTestServer("analysis-icu").start()) {

Expand Down

0 comments on commit 2333f38

Please sign in to comment.