Skip to content

Commit

Permalink
closes #178: findOne and findOneUpdate per spec, improved tests (#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Senic authored Mar 20, 2023
1 parent 3e2c49b commit 5099318
Show file tree
Hide file tree
Showing 17 changed files with 1,520 additions and 968 deletions.
59 changes: 47 additions & 12 deletions src/main/java/io/stargate/sgv2/jsonapi/StargateJsonApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@
}
"""),
@ExampleObject(
name = "resultRead",
summary = "Read command result",
name = "resultFind",
summary = "`find` command result",
value =
"""
{
Expand Down Expand Up @@ -315,6 +315,28 @@
}
}
"""),
@ExampleObject(
name = "resultFindOne",
summary = "`findOne` command result",
value =
"""
{
"data": {
"docs": [
{
"_id": "1",
"location": "London",
"race": {
"competitors": 100,
"start_date": "2022-08-15"
},
"tags": [ "eu" ]
}
],
"count": 1
}
}
"""),
@ExampleObject(
name = "resultFindOneAndUpdate",
summary = "`findOneAndUpdate` command result",
Expand All @@ -330,24 +352,37 @@
"competitors": 100,
"start_date": "2022-08-15"
},
"tags": [
"eu"
],
"count": 3
}
],
"count": 1,
"status": {
"upsertedId": "1",
"matchedCount": 0,
"matchedCount": 1,
"modifiedCount": 1
},
"errors": [
}
}
}
"""),
@ExampleObject(
name = "resultFindOneAndUpdateUpsert",
summary = "`findOneAndUpdate` command with upsert result",
value =
"""
{
"data": {
"docs": [
{
"message": "Failed to update document with _id doc1: Unable to complete transaction due to concurrent transactions",
"errorCode": "CONCURRENCY_FAILURE"
"_id": "1",
"location": "New York",
"count": 3
}
]
],
"count": 1,
"status": {
"upsertedId": "1",
"matchedCount": 0,
"modifiedCount": 1
}
}
}
"""),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.stargate.sgv2.jsonapi.api.model.command.clause.update.UpdateClause;
import javax.annotation.Nullable;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

Expand All @@ -17,15 +18,26 @@
@JsonTypeName("findOneAndUpdate")
public record FindOneAndUpdateCommand(
@Valid @JsonProperty("filter") FilterClause filterClause,
@Valid @JsonProperty("update") UpdateClause updateClause,
@NotNull @Valid @JsonProperty("update") UpdateClause updateClause,
@Valid @Nullable Options options)
implements ReadCommand, Filterable {

@Schema(
name = "FindOneAndUpdateCommand.Options",
description = "Options for `findOneAndUpdate` command.")
public record Options(
@Valid
@Nullable
@Nullable
@Pattern(
regexp = "(after|before)",
message = "returnDocument value can only be 'before' or 'after'")
@Schema(
description =
"Specifies which document to perform the projection on. If `before` the projection is performed on the document before the update is applied, if `after` the document projection is from the document after the update.",
defaultValue = "before")
String returnDocument,
boolean upsert) {}
@Schema(
description =
"When `true`, if no documents match the `filter` clause the command will create a new _empty_ document and apply the `update` clause and all equality filters to the empty document.",
defaultValue = "false")
boolean upsert) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,12 @@
import io.stargate.sgv2.jsonapi.api.model.command.ReadCommand;
import io.stargate.sgv2.jsonapi.api.model.command.clause.filter.FilterClause;
import io.stargate.sgv2.jsonapi.api.model.command.clause.sort.SortClause;
import javax.annotation.Nullable;
import javax.validation.Valid;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

@Schema(description = "Command that finds a single JSON document from a collection.")
@JsonTypeName("findOne")
public record FindOneCommand(
@Valid @JsonProperty("filter") FilterClause filterClause,
@Valid @JsonProperty("sort") SortClause sortClause,
@Nullable Options options)
implements ReadCommand, Filterable {
public record Options() {}
}
@Valid @JsonProperty("sort") SortClause sortClause)
implements ReadCommand, Filterable {}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public record UpdateManyCommand(
public record Options(
@Schema(
description =
"When `true`, if no documents match the `filter` clause the command will create a new _empty_ document and apply the `update` clause to the empty document.",
"When `true`, if no documents match the `filter` clause the command will create a new _empty_ document and apply the `update` clause and all equality filters to the empty document.",
defaultValue = "false")
boolean upsert) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public record UpdateOneCommand(
public record Options(
@Schema(
description =
"When `true`, if no documents match the `filter` clause the command will create a new _empty_ document and apply the `update` clause to the empty document.",
"When `true`, if no documents match the `filter` clause the command will create a new _empty_ document and apply the `update` clause and all equality filters to the empty document.",
defaultValue = "false")
boolean upsert) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public CollectionResource(CommandProcessor commandProcessor) {
@ExampleObject(ref = "countDocuments"),
@ExampleObject(ref = "deleteOne"),
@ExampleObject(ref = "deleteMany"),
@ExampleObject(ref = "findOne"),
@ExampleObject(ref = "find"),
@ExampleObject(ref = "findOne"),
@ExampleObject(ref = "findOneAndUpdate"),
@ExampleObject(ref = "insertOne"),
@ExampleObject(ref = "insertMany"),
Expand All @@ -105,8 +105,10 @@ public CollectionResource(CommandProcessor commandProcessor) {
@ExampleObject(ref = "resultCount"),
@ExampleObject(ref = "resultDeleteOne"),
@ExampleObject(ref = "resultDeleteMany"),
@ExampleObject(ref = "resultRead"),
@ExampleObject(ref = "resultFind"),
@ExampleObject(ref = "resultFindOne"),
@ExampleObject(ref = "resultFindOneAndUpdate"),
@ExampleObject(ref = "resultFindOneAndUpdateUpsert"),
@ExampleObject(ref = "resultInsert"),
@ExampleObject(ref = "resultUpdateOne"),
@ExampleObject(ref = "resultUpdateOneUpsert"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,40 +33,48 @@ public record FindOperation(

@Override
public Uni<Supplier<CommandResult>> execute(QueryExecutor queryExecutor) {
// get FindResponse
return getDocuments(queryExecutor, pagingState(), null)
.onItem()
.transform(docs -> new ReadOperationPage(docs.docs(), docs.pagingState()));

// map the response to result
.map(docs -> new ReadOperationPage(docs.docs(), docs.pagingState()));
}

@Override
public Uni<FindResponse> getDocuments(
QueryExecutor queryExecutor, String pagingState, DBFilterBase.IDFilter additionalIdFilter) {

// ensure we pass failure down if read type is not DOCUMENT or KEY
// COUNT is not supported
switch (readType) {
case DOCUMENT:
case KEY:
{
QueryOuterClass.Query query = buildSelectQuery(additionalIdFilter);
return findDocument(
queryExecutor,
query,
pagingState,
pageSize,
ReadType.DOCUMENT == readType,
objectMapper);
}
default:
throw new JsonApiException(
ErrorCode.UNSUPPORTED_OPERATION, "Unsupported find operation read type " + readType);
case DOCUMENT, KEY -> {
QueryOuterClass.Query query = buildSelectQuery(additionalIdFilter);
return findDocument(
queryExecutor,
query,
pagingState,
pageSize,
ReadType.DOCUMENT == readType,
objectMapper);
}
default -> {
JsonApiException failure =
new JsonApiException(
ErrorCode.UNSUPPORTED_OPERATION,
"Unsupported find operation read type " + readType);
return Uni.createFrom().failure(failure);
}
}
}

/** {@inheritDoc} */
@Override
public ReadDocument getNewDocument() {
ObjectNode rootNode = objectMapper().createObjectNode();
DocumentId documentId = null;
for (DBFilterBase filter : filters) {
if (filter instanceof DBFilterBase.IDFilter) {
documentId = ((DBFilterBase.IDFilter) filter).value;
if (filter instanceof DBFilterBase.IDFilter idFilter) {
documentId = idFilter.value;
rootNode.putIfAbsent(filter.getPath(), filter.asJson(objectMapper().getNodeFactory()));
} else {
if (filter.canAddField()) {
Expand All @@ -78,20 +86,28 @@ public ReadDocument getNewDocument() {
}
}
}
ReadDocument doc = new ReadDocument(documentId, null, rootNode);
return doc;

return new ReadDocument(documentId, null, rootNode);
}

// builds select query
private QueryOuterClass.Query buildSelectQuery(DBFilterBase.IDFilter additionalIdFilter) {
List<BuiltCondition> conditions = new ArrayList<>(filters.size());

// if we have id filter overwrite ignore existing IDFilter
boolean idFilterOverwrite = additionalIdFilter != null;
for (DBFilterBase filter : filters) {
if (additionalIdFilter == null
|| (additionalIdFilter != null && !(filter instanceof DBFilterBase.IDFilter)))
if (!(idFilterOverwrite && filter instanceof DBFilterBase.IDFilter)) {
conditions.add(filter.get());
}
}
if (additionalIdFilter != null) {

// then add id overwrite if there
if (idFilterOverwrite) {
conditions.add(additionalIdFilter.get());
}

// create query
return new QueryBuilder()
.select()
.column(ReadType.DOCUMENT == readType ? documentColumns : documentKeyColumns)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,14 @@ public Class<FindOneAndUpdateCommand> getCommandClass() {
public Operation resolveCommand(CommandContext ctx, FindOneAndUpdateCommand command) {
ReadOperation readOperation = resolve(ctx, command);
DocumentUpdater documentUpdater = DocumentUpdater.construct(command.updateClause());

// resolve options
FindOneAndUpdateCommand.Options options = command.options();
boolean returnUpdatedDocument =
command.options() != null && "after".equals(command.options().returnDocument());
options != null && "after".equals(command.options().returnDocument());
boolean upsert = command.options() != null && command.options().upsert();

// return
return new ReadAndUpdateOperation(
ctx,
readOperation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ public void happyPath() throws Exception {
"user.name",
"-user.age"
],
"filter": {"username": "aaron"},
"options": {}
"filter": {"username": "aaron"}
}
}
""";
Expand Down
Loading

0 comments on commit 5099318

Please sign in to comment.