Enhanced search request de/serialization
- now enables defining `types` (for document types) - enables defining `types` and `indices` as comma-delimited strings (not just string arrays) - aligned the parsing in `WatcherUtils` with the way we're parsing xcontent across the board (e.g. using `ParseField`) - Added additional unit test to test deserialization Original commit: elastic/x-pack-elasticsearch@5491b85f75
This commit is contained in:
parent
a1cda57863
commit
be5fefc6dd
|
@ -5,12 +5,10 @@
|
|||
*/
|
||||
package org.elasticsearch.watcher.support;
|
||||
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.watcher.WatcherException;
|
||||
import org.elasticsearch.watcher.WatcherSettingsException;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
@ -19,18 +17,33 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.watcher.WatcherException;
|
||||
import org.elasticsearch.watcher.WatcherSettingsException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
import static org.elasticsearch.watcher.support.WatcherDateUtils.formatDate;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.watcher.support.WatcherDateUtils.formatDate;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class WatcherUtils {
|
||||
|
||||
static final ParseField INDICES_FIELD = new ParseField("indices");
|
||||
static final ParseField TYPES_FIELD = new ParseField("types");
|
||||
static final ParseField BODY_FIELD = new ParseField("body");
|
||||
static final ParseField SEARCH_TYPE_FIELD = new ParseField("search_type");
|
||||
static final ParseField INDICES_OPTIONS_FIELD = new ParseField("indices_options");
|
||||
static final ParseField EXPAND_WILDCARDS_FIELD = new ParseField("expand_wildcards");
|
||||
static final ParseField IGNORE_UNAVAILABLE_FIELD = new ParseField("ignore_unavailable");
|
||||
static final ParseField ALLOW_NO_INDICES_FIELD = new ParseField("allow_no_indices");
|
||||
static final ParseField TEMPLATE_FIELD = new ParseField("template");
|
||||
static final ParseField TEMPLATE_NAME_FIELD = new ParseField("name");
|
||||
static final ParseField TEMPLATE_TYPE_FIELD = new ParseField("type");
|
||||
static final ParseField TEMPLATE_PARAMS_FIELD = new ParseField("params");
|
||||
|
||||
public final static IndicesOptions DEFAULT_INDICES_OPTIONS = IndicesOptions.lenientExpandOpen();
|
||||
|
||||
private WatcherUtils() {
|
||||
|
@ -57,42 +70,45 @@ public final class WatcherUtils {
|
|||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
switch (currentFieldName) {
|
||||
case "indices":
|
||||
if (INDICES_FIELD.match(currentFieldName)) {
|
||||
List<String> indices = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
indices.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected token [" + token + "]");
|
||||
throw new WatcherSettingsException("could not read search request. expected string values in [" + currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.indices(indices.toArray(new String[indices.size()]));
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
|
||||
} else if (TYPES_FIELD.match(currentFieldName)) {
|
||||
List<String> types = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
types.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. expected string values in [" + currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.types(types.toArray(new String[types.size()]));
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected array field [" + currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
XContentBuilder builder;
|
||||
switch (currentFieldName) {
|
||||
case "body":
|
||||
if (BODY_FIELD.match(currentFieldName)) {
|
||||
builder = XContentBuilder.builder(parser.contentType().xContent());
|
||||
builder.copyCurrentStructure(parser);
|
||||
searchRequest.source(builder);
|
||||
break;
|
||||
case "indices_options":
|
||||
} else if (INDICES_OPTIONS_FIELD.match(currentFieldName)) {
|
||||
boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen();
|
||||
boolean expandClosed = DEFAULT_INDICES_OPTIONS.expandWildcardsClosed();
|
||||
boolean allowNoIndices = DEFAULT_INDICES_OPTIONS.allowNoIndices();
|
||||
boolean ignoreUnavailable = DEFAULT_INDICES_OPTIONS.ignoreUnavailable();
|
||||
|
||||
String indicesFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
indicesFieldName = parser.currentName();
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
switch (indicesFieldName) {
|
||||
case "expand_wildcards":
|
||||
if (EXPAND_WILDCARDS_FIELD.match(currentFieldName)) {
|
||||
switch (parser.text()) {
|
||||
case "all":
|
||||
expandOpen = true;
|
||||
|
@ -111,61 +127,61 @@ public final class WatcherUtils {
|
|||
expandClosed = false;
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected value [" + parser.text() + "]");
|
||||
throw new WatcherSettingsException("could not read search request. unknown value [" + parser.text() + "] for [" + currentFieldName + "] field ");
|
||||
}
|
||||
break;
|
||||
case "ignore_unavailable":
|
||||
} else if (IGNORE_UNAVAILABLE_FIELD.match(currentFieldName)) {
|
||||
ignoreUnavailable = parser.booleanValue();
|
||||
break;
|
||||
case "allow_no_indices":
|
||||
} else if (ALLOW_NO_INDICES_FIELD.match(currentFieldName)) {
|
||||
allowNoIndices = parser.booleanValue();
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + indicesFieldName + "]");
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected index option [" + currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected token [" + token + "]");
|
||||
throw new WatcherSettingsException("could not read search request. unexpected object field [" + currentFieldName + "]");
|
||||
}
|
||||
}
|
||||
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed, DEFAULT_INDICES_OPTIONS);
|
||||
break;
|
||||
case "template":
|
||||
} else if (TEMPLATE_FIELD.match(currentFieldName)) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
switch (currentFieldName) {
|
||||
case "name":
|
||||
if (TEMPLATE_NAME_FIELD.match(currentFieldName)) {
|
||||
searchRequest.templateName(parser.textOrNull());
|
||||
break;
|
||||
case "type":
|
||||
} else if (TEMPLATE_TYPE_FIELD.match(currentFieldName)) {
|
||||
try {
|
||||
searchRequest.templateType(ScriptService.ScriptType.valueOf(parser.text().toUpperCase(Locale.ROOT)));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new WatcherSettingsException("could not parse search request. unknown template type [" + parser.text() + "]");
|
||||
}
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected template field [" + currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("params".equals(currentFieldName)) {
|
||||
searchRequest.templateParams(flattenModel(parser.map()));
|
||||
}
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected template token [" + token + "]");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
switch (currentFieldName) {
|
||||
case "search_type":
|
||||
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT));
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
|
||||
throw new WatcherSettingsException("could not read search request. unexpected object field [" + currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
if (INDICES_FIELD.match(currentFieldName)) {
|
||||
String indicesStr = parser.text();
|
||||
searchRequest.indices(Strings.delimitedListToStringArray(indicesStr, ",", " \t"));
|
||||
} else if (TYPES_FIELD.match(currentFieldName)) {
|
||||
String typesStr = parser.text();
|
||||
searchRequest.types(Strings.delimitedListToStringArray(typesStr, ",", " \t"));
|
||||
} else if (SEARCH_TYPE_FIELD.match(currentFieldName)) {
|
||||
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT));
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected string field [" + currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new WatcherSettingsException("could not read search request. unexpected token [" + token + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,29 +204,32 @@ public final class WatcherUtils {
|
|||
|
||||
builder.startObject();
|
||||
if (searchRequest.searchType() != null) {
|
||||
builder.field("search_type", searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
builder.field(SEARCH_TYPE_FIELD.getPreferredName(), searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (searchRequest.indices() != null) {
|
||||
builder.array("indices", searchRequest.indices());
|
||||
builder.array(INDICES_FIELD.getPreferredName(), searchRequest.indices());
|
||||
}
|
||||
if (searchRequest.types() != null) {
|
||||
builder.array(TYPES_FIELD.getPreferredName(), searchRequest.types());
|
||||
}
|
||||
if (Strings.hasLength(searchRequest.source())) {
|
||||
XContentHelper.writeRawField("body", searchRequest.source(), builder, params);
|
||||
XContentHelper.writeRawField(BODY_FIELD.getPreferredName(), searchRequest.source(), builder, params);
|
||||
}
|
||||
if (searchRequest.templateName() != null) {
|
||||
builder.startObject("template")
|
||||
.field("name", searchRequest.templateName());
|
||||
builder.startObject(TEMPLATE_FIELD.getPreferredName())
|
||||
.field(TEMPLATE_NAME_FIELD.getPreferredName(), searchRequest.templateName());
|
||||
if (searchRequest.templateType() != null) {
|
||||
builder.field("type", searchRequest.templateType().name().toLowerCase(Locale.ROOT));
|
||||
builder.field(TEMPLATE_TYPE_FIELD.getPreferredName(), searchRequest.templateType().name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
if (searchRequest.templateParams() != null && !searchRequest.templateParams().isEmpty()) {
|
||||
builder.field("params", searchRequest.templateParams());
|
||||
builder.field(TEMPLATE_PARAMS_FIELD.getPreferredName(), searchRequest.templateParams());
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||
IndicesOptions options = searchRequest.indicesOptions();
|
||||
builder.startObject("indices_options");
|
||||
builder.startObject(INDICES_OPTIONS_FIELD.getPreferredName());
|
||||
String value;
|
||||
if (options.expandWildcardsClosed() && options.expandWildcardsOpen()) {
|
||||
value = "all";
|
||||
|
@ -221,9 +240,9 @@ public final class WatcherUtils {
|
|||
} else {
|
||||
value = "none";
|
||||
}
|
||||
builder.field("expand_wildcards", value);
|
||||
builder.field("ignore_unavailable", options.ignoreUnavailable());
|
||||
builder.field("allow_no_indices", options.allowNoIndices());
|
||||
builder.field(EXPAND_WILDCARDS_FIELD.getPreferredName(), value);
|
||||
builder.field(IGNORE_UNAVAILABLE_FIELD.getPreferredName(), options.ignoreUnavailable());
|
||||
builder.field(ALLOW_NO_INDICES_FIELD.getPreferredName(), options.allowNoIndices());
|
||||
builder.endObject();
|
||||
}
|
||||
return builder.endObject();
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
*/
|
||||
package org.elasticsearch.watcher.support;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.watcher.input.search.SearchInput;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
|
@ -18,16 +20,16 @@ import org.elasticsearch.index.query.QueryBuilders;
|
|||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.watcher.input.search.SearchInput;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.elasticsearch.watcher.support.WatcherUtils.flattenModel;
|
||||
import static org.elasticsearch.watcher.support.WatcherDateUtils.formatDate;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.watcher.support.WatcherDateUtils.formatDate;
|
||||
import static org.elasticsearch.watcher.support.WatcherUtils.DEFAULT_INDICES_OPTIONS;
|
||||
import static org.elasticsearch.watcher.support.WatcherUtils.flattenModel;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
|
@ -83,10 +85,16 @@ public class WatcherUtilsTests extends ElasticsearchTestCase {
|
|||
assertThat(result, equalTo(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test @Repeat(iterations = 20)
|
||||
public void testSerializeSearchRequest() throws Exception {
|
||||
String[] randomIndices = generateRandomStringArray(5, 5);
|
||||
SearchRequest expectedRequest = new SearchRequest(randomIndices);
|
||||
|
||||
if (randomBoolean()) {
|
||||
String[] randomTypes = generateRandomStringArray(2, 5);
|
||||
expectedRequest.types(randomTypes);
|
||||
}
|
||||
|
||||
expectedRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS));
|
||||
expectedRequest.searchType(randomFrom(SearchType.values()));
|
||||
|
||||
|
@ -116,6 +124,7 @@ public class WatcherUtilsTests extends ElasticsearchTestCase {
|
|||
SearchRequest result = WatcherUtils.readSearchRequest(parser, SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
|
||||
assertThat(result.indices(), arrayContainingInAnyOrder(expectedRequest.indices()));
|
||||
assertThat(result.types(), arrayContainingInAnyOrder(expectedRequest.types()));
|
||||
assertThat(result.indicesOptions(), equalTo(expectedRequest.indicesOptions()));
|
||||
assertThat(result.searchType(), equalTo(expectedRequest.searchType()));
|
||||
assertThat(result.source().toUtf8(), equalTo(expectedSource));
|
||||
|
@ -124,4 +133,95 @@ public class WatcherUtilsTests extends ElasticsearchTestCase {
|
|||
assertThat(result.templateParams(), equalTo(expectedRequest.templateParams()));
|
||||
}
|
||||
|
||||
@Test @Repeat(iterations = 100)
|
||||
public void testDeserializeSearchRequest() throws Exception {
|
||||
|
||||
XContentBuilder builder = jsonBuilder().startObject();
|
||||
|
||||
String[] indices = Strings.EMPTY_ARRAY;
|
||||
if (randomBoolean()) {
|
||||
indices = generateRandomStringArray(5, 5);
|
||||
if (randomBoolean()) {
|
||||
builder.array("indices", indices);
|
||||
} else {
|
||||
builder.field("indices", Strings.arrayToCommaDelimitedString(indices));
|
||||
}
|
||||
}
|
||||
|
||||
String[] types = Strings.EMPTY_ARRAY;
|
||||
if (randomBoolean()) {
|
||||
types = generateRandomStringArray(2, 5);
|
||||
if (randomBoolean()) {
|
||||
builder.array("types", types);
|
||||
} else {
|
||||
builder.field("types", Strings.arrayToCommaDelimitedString(types));
|
||||
}
|
||||
}
|
||||
|
||||
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
if (randomBoolean()) {
|
||||
indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS);
|
||||
builder.startObject("indices_options")
|
||||
.field("allow_no_indices", indicesOptions.allowNoIndices())
|
||||
.field("expand_wildcards", indicesOptions.expandWildcardsClosed() && indicesOptions.expandWildcardsOpen() ? "all" :
|
||||
indicesOptions.expandWildcardsClosed() ? "closed" :
|
||||
indicesOptions.expandWildcardsOpen() ? "open" :
|
||||
"none")
|
||||
.field("ignore_unavailable", indicesOptions.ignoreUnavailable())
|
||||
.endObject();
|
||||
}
|
||||
|
||||
SearchType searchType = SearchType.DEFAULT;
|
||||
if (randomBoolean()) {
|
||||
searchType = randomFrom(SearchType.values());
|
||||
builder.field("search_type", randomBoolean() ? searchType.name() : searchType.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
BytesReference source = null;
|
||||
if (randomBoolean()) {
|
||||
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource().query(QueryBuilders.matchAllQuery()).size(11);
|
||||
XContentBuilder searchSourceJsonBuilder = jsonBuilder();
|
||||
searchSourceBuilder.toXContent(searchSourceJsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
source = searchSourceBuilder.buildAsBytes(XContentType.JSON);
|
||||
builder.rawField("body", source);
|
||||
}
|
||||
|
||||
String templateName = null;
|
||||
ScriptService.ScriptType templateType = null;
|
||||
Map<String, Object> templateParams = Collections.emptyMap();
|
||||
if (randomBoolean()) {
|
||||
builder.startObject("template");
|
||||
if (randomBoolean()) {
|
||||
templateName = randomAsciiOfLengthBetween(1, 5);
|
||||
builder.field("name", templateName);
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
templateType = randomFrom(ScriptService.ScriptType.values());
|
||||
builder.field("type", randomBoolean() ? templateType.name() : templateType.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
templateParams = new HashMap<>();
|
||||
int maxParams = randomIntBetween(1, 10);
|
||||
for (int i = 0; i < maxParams; i++) {
|
||||
templateParams.put(randomAsciiOfLengthBetween(1, 5), randomAsciiOfLengthBetween(1, 5));
|
||||
}
|
||||
builder.field("params", templateParams);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
XContentParser parser = XContentHelper.createParser(builder.bytes());
|
||||
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
|
||||
SearchRequest result = WatcherUtils.readSearchRequest(parser, SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
|
||||
assertThat(result.indices(), arrayContainingInAnyOrder(indices));
|
||||
assertThat(result.types(), arrayContainingInAnyOrder(types));
|
||||
assertThat(result.indicesOptions(), equalTo(indicesOptions));
|
||||
assertThat(result.searchType(), equalTo(searchType));
|
||||
assertThat(result.source(), equalTo(source));
|
||||
assertThat(result.templateName(), equalTo(templateName));
|
||||
assertThat(result.templateType(), equalTo(templateType));
|
||||
assertThat(result.templateParams(), equalTo(templateParams));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue