Skip to content

Commit

Permalink
Add parsing methods for UpdateResponse (#22586)
Browse files Browse the repository at this point in the history
This commit adds the fromXContent() method to the UpdateResponse class, so that it can be used with the high level rest client.
  • Loading branch information
tlrx authored Jan 19, 2017
1 parent 21dae19 commit 833284c
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ protected static void declareParserFields(ConstructingObjectParser<? extends Doc
objParser.declareString(constructorArg(), new ParseField(_ID));
objParser.declareLong(constructorArg(), new ParseField(_VERSION));
objParser.declareString(constructorArg(), new ParseField(RESULT));
objParser.declareObject(optionalConstructorArg(), (p, c) -> ShardInfo.fromXContent(p), new ParseField(_SHARDS));
objParser.declareLong(optionalConstructorArg(), new ParseField(_SEQ_NO));
objParser.declareBoolean(DocWriteResponse::setForcedRefresh, new ParseField(FORCED_REFRESH));
objParser.declareObject(DocWriteResponse::setShardInfo, (p, c) -> ShardInfo.fromXContent(p), new ParseField(_SHARDS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@ public XContentBuilder innerToXContent(XContentBuilder builder, Params params) t
String type = (String) args[1];
String id = (String) args[2];
long version = (long) args[3];
long seqNo = (args[5] != null) ? (long) args[5] : SequenceNumbersService.UNASSIGNED_SEQ_NO;
boolean created = (boolean) args[6];
return new IndexResponse(shardId, type, id, seqNo, version, created);
ShardInfo shardInfo = (ShardInfo) args[5];
long seqNo = (args[6] != null) ? (long) args[6] : SequenceNumbersService.UNASSIGNED_SEQ_NO;
boolean created = (boolean) args[7];

IndexResponse indexResponse = new IndexResponse(shardId, type, id, seqNo, version, created);
indexResponse.setShardInfo(shardInfo);
return indexResponse;
});
DocWriteResponse.declareParserFields(PARSER);
PARSER.declareBoolean(constructorArg(), new ParseField(CREATED));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@
package org.elasticsearch.action.update;

import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.seqno.SequenceNumbersService;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;
import java.util.function.BiConsumer;

public class UpdateResponse extends DocWriteResponse {

private static final String GET = "get";

private GetResult getResult;

public UpdateResponse() {
Expand Down Expand Up @@ -82,15 +90,11 @@ public void writeTo(StreamOutput out) throws IOException {
}
}

static final class Fields {
static final String GET = "get";
}

@Override
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
super.innerToXContent(builder, params);
if (getGetResult() != null) {
builder.startObject(Fields.GET);
builder.startObject(GET);
getGetResult().toXContentEmbedded(builder, params);
builder.endObject();
}
Expand All @@ -109,4 +113,45 @@ public String toString() {
builder.append(",shards=").append(getShardInfo());
return builder.append("]").toString();
}

private static final ConstructingObjectParser<UpdateResponse, Void> PARSER;
static {
PARSER = new ConstructingObjectParser<>(UpdateResponse.class.getName(),
args -> {
// index uuid and shard id are unknown and can't be parsed back for now.
String index = (String) args[0];
ShardId shardId = new ShardId(new Index(index, IndexMetaData.INDEX_UUID_NA_VALUE), -1);
String type = (String) args[1];
String id = (String) args[2];
long version = (long) args[3];
ShardInfo shardInfo = (ShardInfo) args[5];
Long seqNo = (Long) args[6];

Result result = null;
for (Result r : Result.values()) {
if (r.getLowercase().equals(args[4])) {
result = r;
break;
}
}

UpdateResponse updateResponse = null;
if (shardInfo != null && seqNo != null) {
updateResponse = new UpdateResponse(shardInfo, shardId, type, id, seqNo, version, result);
} else {
updateResponse = new UpdateResponse(shardId, type, id, version, result);
}
return updateResponse;
});

DocWriteResponse.declareParserFields(PARSER);
BiConsumer<UpdateResponse, GetResult> setGetResult = (update, get) ->
update.setGetResult(new GetResult(update.getIndex(), update.getType(), update.getId(), update.getVersion(),
get.isExists(), get.internalSourceRef(), get.getFields()));
PARSER.declareObject(setGetResult, (parser, context) -> GetResult.fromXContentEmbedded(parser), new ParseField(GET));
}

public static UpdateResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
}
14 changes: 11 additions & 3 deletions core/src/main/java/org/elasticsearch/index/get/GetResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,11 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
return builder;
}

public static GetResult fromXContent(XContentParser parser) throws IOException {
public static GetResult fromXContentEmbedded(XContentParser parser) throws IOException {
XContentParser.Token token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
String currentFieldName = null;
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);

String currentFieldName = parser.currentName();
String index = null, type = null, id = null;
long version = -1;
boolean found = false;
Expand Down Expand Up @@ -313,6 +314,13 @@ public static GetResult fromXContent(XContentParser parser) throws IOException {
return new GetResult(index, type, id, version, found, source, fields);
}

public static GetResult fromXContent(XContentParser parser) throws IOException {
XContentParser.Token token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);

return fromXContentEmbedded(parser);
}

public static GetResult readGetResult(StreamInput in) throws IOException {
GetResult result = new GetResult();
result.readFrom(in);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.action.index;

import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
Expand Down Expand Up @@ -81,19 +82,19 @@ public void testToAndFromXContent() throws IOException {
}
}

private static void assertIndexResponse(IndexResponse expected, Map<String, Object> actual) {
public static void assertDocWriteResponse(DocWriteResponse expected, Map<String, Object> actual) {
assertEquals(expected.getIndex(), actual.get("_index"));
assertEquals(expected.getType(), actual.get("_type"));
assertEquals(expected.getId(), actual.get("_id"));
assertEquals(expected.getVersion(), ((Integer) actual.get("_version")).longValue());
assertEquals(expected.getVersion(), ((Number) actual.get("_version")).longValue());
assertEquals(expected.getResult().getLowercase(), actual.get("result"));
if (expected.forcedRefresh()) {
assertTrue((Boolean) actual.get("forced_refresh"));
} else {
assertFalse(actual.containsKey("forced_refresh"));
}
if (expected.getSeqNo() >= 0) {
assertEquals(expected.getSeqNo(), ((Integer) actual.get("_seq_no")).longValue());
assertEquals(expected.getSeqNo(), ((Number) actual.get("_seq_no")).longValue());
} else {
assertFalse(actual.containsKey("_seq_no"));
}
Expand Down Expand Up @@ -151,6 +152,15 @@ private static void assertIndexResponse(IndexResponse expected, Map<String, Obje
}
}

private static void assertIndexResponse(IndexResponse expected, Map<String, Object> actual) {
assertDocWriteResponse(expected, actual);
if (expected.getResult() == DocWriteResponse.Result.CREATED) {
assertTrue((boolean) actual.get("created"));
} else {
assertFalse((boolean) actual.get("created"));
}
}

private static IndexResponse randomIndexResponse() {
ShardId shardId = new ShardId(randomAsciiOfLength(5), randomAsciiOfLength(5), randomIntBetween(0, 5));
String type = randomAsciiOfLength(5);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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 org.elasticsearch.action.update;

import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.index.IndexResponseTests;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.get.GetResultTests;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.RandomObjects;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static org.elasticsearch.action.DocWriteResponse.Result.DELETED;
import static org.elasticsearch.action.DocWriteResponse.Result.NOT_FOUND;
import static org.elasticsearch.action.DocWriteResponse.Result.UPDATED;
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;

public class UpdateResponseTests extends ESTestCase {

public void testToXContent() throws IOException {
{
UpdateResponse updateResponse = new UpdateResponse(new ShardId("index", "index_uuid", 0), "type", "id", 0, NOT_FOUND);
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":0,\"result\":\"not_found\"," +
"\"_shards\":{\"total\":0,\"successful\":0,\"failed\":0}}", output);
}
{
UpdateResponse updateResponse = new UpdateResponse(new ReplicationResponse.ShardInfo(10, 6),
new ShardId("index", "index_uuid", 1), "type", "id", 3, 1, DELETED);
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"result\":\"deleted\"," +
"\"_shards\":{\"total\":10,\"successful\":6,\"failed\":0},\"_seq_no\":3}", output);
}
{
BytesReference source = new BytesArray("{\"title\":\"Book title\",\"isbn\":\"ABC-123\"}");
Map<String, GetField> fields = new HashMap<>();
fields.put("title", new GetField("title", Collections.singletonList("Book title")));
fields.put("isbn", new GetField("isbn", Collections.singletonList("ABC-123")));

UpdateResponse updateResponse = new UpdateResponse(new ReplicationResponse.ShardInfo(3, 2),
new ShardId("books", "books_uuid", 2), "book", "1", 7, 2, UPDATED);
updateResponse.setGetResult(new GetResult("books", "book", "1", 2, true, source, fields));

String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"books\",\"_type\":\"book\",\"_id\":\"1\",\"_version\":2,\"result\":\"updated\"," +
"\"_shards\":{\"total\":3,\"successful\":2,\"failed\":0},\"_seq_no\":7,\"get\":{\"found\":true," +
"\"_source\":{\"title\":\"Book title\",\"isbn\":\"ABC-123\"},\"fields\":{\"isbn\":[\"ABC-123\"],\"title\":[\"Book " +
"title\"]}}}", output);
}
}

public void testToAndFromXContent() throws IOException {
final XContentType xContentType = randomFrom(XContentType.values());
final Tuple<UpdateResponse, UpdateResponse> tuple = randomUpdateResponse(xContentType);

// Parse the XContent bytes to obtain a parsed UpdateResponse
UpdateResponse parsedUpdateResponse;
try (XContentParser parser = createParser(xContentType.xContent(), toXContent(tuple.v1(), xContentType))) {
parsedUpdateResponse = UpdateResponse.fromXContent(parser);
assertNull(parser.nextToken());
}

final UpdateResponse expectedUpdateResponse = tuple.v2();
try (XContentParser parser = createParser(xContentType.xContent(), toXContent(parsedUpdateResponse, xContentType))) {
IndexResponseTests.assertDocWriteResponse(expectedUpdateResponse, parser.map());
}
assertEquals(expectedUpdateResponse.getGetResult(), parsedUpdateResponse.getGetResult());
}

private static Tuple<UpdateResponse, UpdateResponse> randomUpdateResponse(XContentType xContentType) {
Tuple<GetResult, GetResult> getResults = GetResultTests.randomGetResult(xContentType);
GetResult actualGetResult = getResults.v1();
GetResult expectedGetResult = getResults.v2();

ShardId shardId = new ShardId(actualGetResult.getIndex(), randomAsciiOfLength(5), randomIntBetween(0, 5));
String type = actualGetResult.getType();
String id = actualGetResult.getId();
long version = actualGetResult.getVersion();
DocWriteResponse.Result result = actualGetResult.isExists() ? DocWriteResponse.Result.UPDATED : DocWriteResponse.Result.NOT_FOUND;

// We also want small number values (randomNonNegativeLong() tend to generate high numbers)
// in order to catch some conversion error that happen between int/long after parsing.
Long seqNo = randomFrom(randomNonNegativeLong(), (long) randomIntBetween(0, 10_000), null);

UpdateResponse actual, expected;
if (seqNo != null) {
ReplicationResponse.ShardInfo shardInfo = RandomObjects.randomShardInfo(random(), true);
actual = new UpdateResponse(shardInfo, shardId, type, id, seqNo, version, result);
expected = new UpdateResponse(shardInfo, shardId, type, id, seqNo, version, result);

} else {
actual = new UpdateResponse(shardId, type, id, version, result);
expected = new UpdateResponse(shardId, type, id, version, result);
}

if (actualGetResult.isExists()) {
actual.setGetResult(actualGetResult);
}

if (expectedGetResult.isExists()) {
expected.setGetResult(new GetResult(shardId.getIndexName(), type, id, version,
expectedGetResult.isExists(), expectedGetResult.internalSourceRef(), expectedGetResult.getFields()));
}

boolean forcedRefresh = randomBoolean();
actual.setForcedRefresh(forcedRefresh);
expected.setForcedRefresh(forcedRefresh);

return Tuple.tuple(actual, expected);
}
}
Loading

0 comments on commit 833284c

Please sign in to comment.