Skip to content

Commit

Permalink
DeleteOne command #29 (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
maheshrajamani authored Jan 19, 2023
1 parent 10b0fc1 commit fe83148
Show file tree
Hide file tree
Showing 24 changed files with 841 additions and 95 deletions.
26 changes: 24 additions & 2 deletions src/main/java/io/stargate/sgv3/docsapi/StargateDocsV3Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,21 @@
{
"findOne": {
"sort": ["-race.competitors"],
"filter": {"user", "name"}
"filter": {"location": "London"}
}
}
"""),
@ExampleObject(
name = "deleteOne",
summary = "`deleteOne` command",
value =
"""
{
"deleteOne": {
"filter": {"_id": "1"}
}
}
"""),
@ExampleObject(
name = "insertOne",
summary = "`insertOne` command",
Expand All @@ -88,7 +99,7 @@
"""
{
"createCollection": {
"name": "test_collection"
"name": "events"
}
}
"""),
Expand Down Expand Up @@ -133,6 +144,17 @@
}
}
"""),
@ExampleObject(
name = "resultDelete",
summary = "Delete command result",
value =
"""
{
"status": {
"deletedIds": ["1", "2"]
}
}
"""),
@ExampleObject(
name = "resultError",
summary = "Error result",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.stargate.sgv3.docsapi.api.model.command.impl.CreateCollectionCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.DeleteOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.FindOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.InsertOneCommand;

Expand Down Expand Up @@ -31,5 +32,6 @@
@JsonSubTypes.Type(value = CreateCollectionCommand.class),
@JsonSubTypes.Type(value = FindOneCommand.class),
@JsonSubTypes.Type(value = InsertOneCommand.class),
@JsonSubTypes.Type(value = DeleteOneCommand.class),
})
public interface Command {}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.fasterxml.jackson.annotation.JsonProperty;

public enum CommandStatus {
@JsonProperty("deletedIds")
DELETED_IDS,
@JsonProperty("insertedIds")
INSERTED_IDS,
@JsonProperty("ok")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
@JsonDeserialize(using = FilterClauseDeserializer.class)
@Schema(
type = SchemaType.OBJECT,
implementation = String[].class,
implementation = Object.class,
example = """
{"username": "aaron"}
{"name": "Aaron", "country": "US"}
""")
public record FilterClause(List<ComparisonExpression> comparisonExpressions) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.stargate.sgv3.docsapi.api.model.command.impl;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.stargate.sgv3.docsapi.api.model.command.Command;
import io.stargate.sgv3.docsapi.api.model.command.Filterable;
import io.stargate.sgv3.docsapi.api.model.command.ModifyCommand;
import io.stargate.sgv3.docsapi.api.model.command.clause.filter.FilterClause;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

/**
* Representation of the deleteOne API {@link Command}.
*
* @param filterClause {@link FilterClause} used to identify the document.
*/
@Schema(description = "Command that finds a single document and deletes it from a collection")
@JsonTypeName("deleteOne")
public record DeleteOneCommand(
@NotNull
@Schema(
description = "Filter clause based on which document is identified",
implementation = FilterClause.class)
@Valid
@JsonProperty("filter")
FilterClause filterClause)
implements ModifyCommand, Filterable {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.stargate.sgv3.docsapi.api.model.command.Command;
import io.stargate.sgv3.docsapi.api.model.command.CommandContext;
import io.stargate.sgv3.docsapi.api.model.command.CommandResult;
import io.stargate.sgv3.docsapi.api.model.command.impl.DeleteOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.FindOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.InsertOneCommand;
import io.stargate.sgv3.docsapi.config.constants.OpenApiConstants;
Expand Down Expand Up @@ -58,10 +59,17 @@ public CollectionResource(CommandProcessor commandProcessor) {
content =
@Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(anyOf = {FindOneCommand.class, InsertOneCommand.class}),
schema =
@Schema(
anyOf = {
FindOneCommand.class,
InsertOneCommand.class,
DeleteOneCommand.class
}),
examples = {
@ExampleObject(ref = "findOne"),
@ExampleObject(ref = "insertOne"),
@ExampleObject(ref = "deleteOne"),
}))
@APIResponses(
@APIResponse(
Expand All @@ -76,6 +84,7 @@ public CollectionResource(CommandProcessor commandProcessor) {
@ExampleObject(ref = "resultRead"),
@ExampleObject(ref = "resultInsert"),
@ExampleObject(ref = "resultError"),
@ExampleObject(ref = "resultDelete"),
})))
@POST
public Uni<RestResponse<CommandResult>> postCommand(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.stargate.sgv3.docsapi.service.operation.model;

/** Interface for operations that modify data, insert, delete, update. */
public interface ModifyOperation {}
public interface ModifyOperation extends Operation {}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ default Uni<FindResponse> findDocument(
document =
new ReadDocument(
Values.string(row.getValues(0)), // key
Optional.of(Values.uuid(row.getValues(1))), // tx_id
Values.uuid(row.getValues(1)), // tx_id
readDocument
? objectMapper.readTree(Values.string(row.getValues(2)))
: null);
Expand All @@ -76,5 +76,14 @@ private String extractPagingStateFromResultSet(QueryOuterClass.ResultSet rSet) {
return null;
}

/**
* A operation method which can return FindResponse instead of CommandResult. This method will be
* used by other commands which needs a document to be read.
*
* @param queryExecutor
* @return
*/
Uni<FindResponse> getDocuments(QueryExecutor queryExecutor);

public static record FindResponse(List<ReadDocument> docs, String pagingState) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.stargate.sgv3.docsapi.service.operation.model.impl;

import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.stargate.bridge.grpc.Values;
import io.stargate.bridge.proto.QueryOuterClass;
import io.stargate.sgv3.docsapi.api.model.command.CommandContext;
import io.stargate.sgv3.docsapi.api.model.command.CommandResult;
import io.stargate.sgv3.docsapi.service.bridge.executor.QueryExecutor;
import io.stargate.sgv3.docsapi.service.operation.model.ModifyOperation;
import io.stargate.sgv3.docsapi.service.operation.model.ReadOperation;
import io.stargate.sgv3.docsapi.service.operation.model.ReadOperation.FindResponse;
import java.util.List;
import java.util.function.Supplier;

/**
* Executes readOperation to get the documents ids based on filter condition. All the ids are
* deleted as LWT based on the id and tx_id.
*/
public record DeleteOperation(CommandContext commandContext, ReadOperation readOperation)
implements ModifyOperation {
@Override
public Uni<Supplier<CommandResult>> execute(QueryExecutor queryExecutor) {
Uni<FindResponse> docsToDelete = readOperation().getDocuments(queryExecutor);
final QueryOuterClass.Query delete = buildDeleteQuery();
final Uni<List<String>> ids =
docsToDelete
.onItem()
.transformToMulti(
findResponse -> Multi.createFrom().items(findResponse.docs().stream()))
.onItem()
.transformToUniAndConcatenate(
readDocument -> deleteDocument(queryExecutor, delete, readDocument))
.collect()
.asList();
return ids.onItem().transform(DeleteOperationPage::new);
}

private QueryOuterClass.Query buildDeleteQuery() {
String delete = "DELETE FROM \"%s\".\"%s\" WHERE key = ? IF tx_id = ?";
return QueryOuterClass.Query.newBuilder()
.setCql(String.format(delete, commandContext.database(), commandContext.collection()))
.build();
}

/**
* When delete is run with LWT, applied field is always the first field and in case the
* transaction id mismatch the latest transaction id is returned as second field Eg:
* cassandra@cqlsh:docsapi> delete from docsapi.test1 where key = 'doc2' IF tx_id =
* 13659a90-9361-11ed-92df-515ba7f99655 ;
*
* <p>[applied] | tx_id -----------+-------------------------------------- False |
* 13659a90-9361-11ed-92df-515ba7f99654
*
* <p>cassandra@cqlsh:docsapi> delete from docsapi.test1 where key = 'doc2' IF tx_id =
* 13659a90-9361-11ed-92df-515ba7f99654 ;
*
* <p>[applied] ----------- True
*
* @param queryExecutor
* @param query
* @param doc
* @return
*/
private static Uni<String> deleteDocument(
QueryExecutor queryExecutor, QueryOuterClass.Query query, ReadDocument doc) {
query = bindDeleteQuery(query, doc);
return queryExecutor
.executeWrite(query)
.onItem()
.transformToUni(
result -> {
if (result.getRows(0).getValues(0).getBoolean()) {
return Uni.createFrom().item(doc.id());
} else {
return Uni.createFrom().nothing();
}
});
}

private static QueryOuterClass.Query bindDeleteQuery(
QueryOuterClass.Query builtQuery, ReadDocument doc) {
QueryOuterClass.Values.Builder values =
QueryOuterClass.Values.newBuilder()
.addValues(Values.of(doc.id()))
.addValues(Values.of(doc.txnId()));
return QueryOuterClass.Query.newBuilder(builtQuery).setValues(values).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.stargate.sgv3.docsapi.service.operation.model.impl;

import io.stargate.sgv3.docsapi.api.model.command.CommandResult;
import io.stargate.sgv3.docsapi.api.model.command.CommandStatus;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
* This represents the response for a delete operation. .
*
* @param deletedIds - document ids deleted
*/
public record DeleteOperationPage(List<String> deletedIds) implements Supplier<CommandResult> {
@Override
public CommandResult get() {
return new CommandResult(Map.of(CommandStatus.DELETED_IDS, deletedIds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ public record FindOperation(

@Override
public Uni<Supplier<CommandResult>> execute(QueryExecutor queryExecutor) {
QueryOuterClass.Query query = buildSelectQuery();
return findDocument(queryExecutor, query, pagingState, readDocument, objectMapper)
return getDocuments(queryExecutor)
.onItem()
.transform(docs -> new ReadOperationPage(docs.docs(), docs.pagingState()));
}

@Override
public Uni<FindResponse> getDocuments(QueryExecutor queryExecutor) {
QueryOuterClass.Query query = buildSelectQuery();
return findDocument(queryExecutor, query, pagingState, readDocument, objectMapper);
}

private QueryOuterClass.Query buildSelectQuery() {
List<BuiltCondition> conditions = new ArrayList<>(filters.size());
for (DBFilterBase filter : filters) {
Expand All @@ -56,23 +61,6 @@ private QueryOuterClass.Query buildSelectQuery() {
.build();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FindOperation that = (FindOperation) o;
return limit == that.limit
&& readDocument == that.readDocument
&& commandContext.equals(that.commandContext)
&& filters.equals(that.filters)
&& Objects.equals(pagingState, that.pagingState);
}

@Override
public int hashCode() {
return Objects.hash(commandContext, filters, pagingState, limit, readDocument);
}

/** Base for the DB filters / conditions that we want to update the dynamic query */
public abstract static class DBFilterBase implements Supplier<BuiltCondition> {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import io.stargate.sgv3.docsapi.api.model.command.CommandResult;
import io.stargate.sgv3.docsapi.service.bridge.executor.QueryExecutor;
import io.stargate.sgv3.docsapi.service.bridge.serializer.CustomValueSerializers;
import io.stargate.sgv3.docsapi.service.operation.model.Operation;
import io.stargate.sgv3.docsapi.service.operation.model.ModifyOperation;
import io.stargate.sgv3.docsapi.service.shredding.model.WritableShreddedDocument;
import java.util.List;
import java.util.function.Supplier;

/** Operation that inserts one or more documents. */
public record InsertOperation(
CommandContext commandContext, List<WritableShreddedDocument> documents) implements Operation {
CommandContext commandContext, List<WritableShreddedDocument> documents)
implements ModifyOperation {

public InsertOperation(CommandContext commandContext, WritableShreddedDocument document) {
this(commandContext, List.of(document));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.stargate.sgv3.docsapi.service.operation.model.impl;

import com.fasterxml.jackson.databind.JsonNode;
import java.util.Optional;
import java.util.UUID;

/**
Expand All @@ -11,4 +10,4 @@
* @param txnId Unique UUID resenting point in time of a document, used for LWT transactions
* @param document JsonNode representation of the document
*/
public record ReadDocument(String id, Optional<UUID> txnId, JsonNode document) {}
public record ReadDocument(String id, UUID txnId, JsonNode document) {}
Loading

0 comments on commit fe83148

Please sign in to comment.