diff --git a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/ComparisonExpression.java b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/ComparisonExpression.java index 43ffe676e2..b635afef2c 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/ComparisonExpression.java +++ b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/ComparisonExpression.java @@ -2,6 +2,7 @@ import io.stargate.sgv3.docsapi.exception.DocsException; import io.stargate.sgv3.docsapi.exception.ErrorCode; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.math.BigDecimal; import java.util.EnumSet; import java.util.List; @@ -58,6 +59,9 @@ private static JsonLiteral getLiteral(Object value) { if (value == null) { return new JsonLiteral<>(null, JsonType.NULL); } + if (value instanceof DocumentId) { + return new JsonLiteral<>((DocumentId) value, JsonType.DOCUMENT_ID); + } if (value instanceof BigDecimal) { return new JsonLiteral<>((BigDecimal) value, JsonType.NUMBER); } diff --git a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/JsonType.java b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/JsonType.java index 095da4c44e..b4860e249c 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/JsonType.java +++ b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/clause/filter/JsonType.java @@ -7,5 +7,7 @@ public enum JsonType { STRING, NULL, SUB_DOC, - ARRAY + ARRAY, + // DOCUMENT_ID represent the _id field type which is union of String, Number, Boolean and Null + DOCUMENT_ID } diff --git a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/deserializers/FilterClauseDeserializer.java b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/deserializers/FilterClauseDeserializer.java index 8904fd0509..7703757817 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/api/model/command/deserializers/FilterClauseDeserializer.java +++ b/src/main/java/io/stargate/sgv3/docsapi/api/model/command/deserializers/FilterClauseDeserializer.java @@ -8,8 +8,10 @@ import io.stargate.sgv3.docsapi.api.model.command.clause.filter.ComparisonExpression; import io.stargate.sgv3.docsapi.api.model.command.clause.filter.FilterClause; import io.stargate.sgv3.docsapi.api.model.command.clause.filter.ValueComparisonOperator; +import io.stargate.sgv3.docsapi.config.constants.DocumentConstants; import io.stargate.sgv3.docsapi.exception.DocsException; import io.stargate.sgv3.docsapi.exception.ErrorCode; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; @@ -44,7 +46,8 @@ public FilterClause deserialize( } else { // @TODO: Need to add array value type to this condition expressionList.add( - ComparisonExpression.eq(entry.getKey(), jsonNodeValue(entry.getValue()))); + ComparisonExpression.eq( + entry.getKey(), jsonNodeValue(entry.getKey(), entry.getValue()))); } } return new FilterClause(expressionList); @@ -70,12 +73,15 @@ private ComparisonExpression createComparisonExpression(Map.Entry keyIDMap = + Map.of( + TYPE_ID_STRING, + JsonType.STRING, + TYPE_ID_NUMBER, + JsonType.NUMBER, + TYPE_ID_BOOLEAN, + JsonType.BOOLEAN, + TYPE_ID_NULL, + JsonType.NULL); + + static JsonType getJsonType(int typeId) { + return keyIDMap.get(typeId); + } + } } diff --git a/src/main/java/io/stargate/sgv3/docsapi/exception/DocsException.java b/src/main/java/io/stargate/sgv3/docsapi/exception/DocsException.java index 40157ff37d..27bb6bcc1a 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/exception/DocsException.java +++ b/src/main/java/io/stargate/sgv3/docsapi/exception/DocsException.java @@ -18,7 +18,7 @@ public class DocsException extends RuntimeException implements Supplier getDoubleMapValu return to; } - public static QueryOuterClass.Value getDocumentIdValue(DocumentId documentId) { + public static List getDocumentIdValue(DocumentId documentId) { // Temporary implementation until we convert it to Tuple in DB - return Values.of(documentId.toString()); + List tupleValues = + List.of(Values.of(documentId.typeId()), Values.of(documentId.toString())); + return tupleValues; } } diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/ReadOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/ReadOperation.java index ec9af7a6e0..58dc4b8d6e 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/ReadOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/ReadOperation.java @@ -10,6 +10,7 @@ import io.stargate.sgv3.docsapi.exception.ErrorCode; import io.stargate.sgv3.docsapi.service.bridge.executor.QueryExecutor; import io.stargate.sgv3.docsapi.service.operation.model.impl.ReadDocument; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -56,7 +57,7 @@ default Uni findDocument( try { document = new ReadDocument( - Values.string(row.getValues(0)), // key + getDocumentId(row.getValues(0)), // key Values.uuid(row.getValues(1)), // tx_id readDocument ? objectMapper.readTree(Values.string(row.getValues(2))) @@ -70,6 +71,19 @@ default Uni findDocument( }); } + /** + * Database key type is tuple, first field is json value type and second field is text + * + * @param value + * @return + */ + default DocumentId getDocumentId(QueryOuterClass.Value value) { + QueryOuterClass.Collection coll = value.getCollection(); + int typeId = Values.tinyint(coll.getElements(0)); + String documentIdAsText = Values.string(coll.getElements(1)); + return DocumentId.fromDatabase(typeId, documentIdAsText); + } + private String extractPagingStateFromResultSet(QueryOuterClass.ResultSet rSet) { if (rSet.hasPagingState()) { return BytesValues.toBase64(rSet.getPagingState()); diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperation.java index 412bbf3ca6..d5a860c1bf 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperation.java @@ -35,7 +35,7 @@ public Uni> execute(QueryExecutor queryExecutor) { protected QueryOuterClass.Query getCreateTable(String keyspace, String table) { String createTable = "CREATE TABLE IF NOT EXISTS %s.%s (" - + " key text," + + " key tuple," + " tx_id timeuuid, " + " doc_json text," + " doc_properties map," diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperation.java index 030b881942..f4a1bfe977 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperation.java @@ -7,9 +7,11 @@ 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.bridge.serializer.CustomValueSerializers; 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 io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import java.util.function.Supplier; @@ -23,7 +25,7 @@ public record DeleteOperation(CommandContext commandContext, ReadOperation readO public Uni> execute(QueryExecutor queryExecutor) { Uni docsToDelete = readOperation().getDocuments(queryExecutor); final QueryOuterClass.Query delete = buildDeleteQuery(); - final Uni> ids = + final Uni> ids = docsToDelete .onItem() .transformToMulti( @@ -62,7 +64,7 @@ private QueryOuterClass.Query buildDeleteQuery() { * @param doc * @return */ - private static Uni deleteDocument( + private static Uni deleteDocument( QueryExecutor queryExecutor, QueryOuterClass.Query query, ReadDocument doc) { query = bindDeleteQuery(query, doc); return queryExecutor @@ -82,7 +84,7 @@ 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(CustomValueSerializers.getDocumentIdValue(doc.id()))) .addValues(Values.of(doc.txnId())); return QueryOuterClass.Query.newBuilder(builtQuery).setValues(values).build(); } diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationPage.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationPage.java index 37070666c3..155bed5ac5 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationPage.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationPage.java @@ -2,6 +2,7 @@ import io.stargate.sgv3.docsapi.api.model.command.CommandResult; import io.stargate.sgv3.docsapi.api.model.command.CommandStatus; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import java.util.Map; import java.util.function.Supplier; @@ -11,7 +12,7 @@ * * @param deletedIds - document ids deleted */ -public record DeleteOperationPage(List deletedIds) implements Supplier { +public record DeleteOperationPage(List deletedIds) implements Supplier { @Override public CommandResult get() { return new CommandResult(Map.of(CommandStatus.DELETED_IDS, deletedIds)); diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperation.java index 734e2297c7..58ed03358f 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperation.java @@ -12,7 +12,9 @@ import io.stargate.sgv3.docsapi.exception.DocsException; import io.stargate.sgv3.docsapi.exception.ErrorCode; 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.ReadOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -145,9 +147,9 @@ public enum Operator { } protected final Operator operator; - protected final String value; + protected final DocumentId value; - public IDFilter(Operator operator, String value) { + public IDFilter(Operator operator, DocumentId value) { this.operator = operator; this.value = value; } @@ -169,7 +171,8 @@ public int hashCode() { public BuiltCondition get() { switch (operator) { case EQ: - return BuiltCondition.of(BuiltCondition.LHS.column("key"), Predicate.EQ, getValue(value)); + return BuiltCondition.of( + BuiltCondition.LHS.column("key"), Predicate.EQ, getDocumentIdValue(value)); default: throw new DocsException( ErrorCode.UNSUPPORTED_FILTER_OPERATION, @@ -245,4 +248,8 @@ private static QueryOuterClass.Value getValue(Object value) { } return Values.of((String) null); } + + private static QueryOuterClass.Value getDocumentIdValue(DocumentId value) { + return Values.of(CustomValueSerializers.getDocumentIdValue(value)); + } } diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperation.java index b4e46e9390..1ca7b7fd36 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperation.java @@ -9,6 +9,7 @@ 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.ModifyOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import io.stargate.sgv3.docsapi.service.shredding.model.WritableShreddedDocument; import java.util.List; import java.util.function.Supplier; @@ -26,20 +27,20 @@ public InsertOperation(CommandContext commandContext, WritableShreddedDocument d @Override public Uni> execute(QueryExecutor queryExecutor) { QueryOuterClass.Query query = buildInsertQuery(); - final Uni> ids = + final Uni> ids = Multi.createFrom() .items(documents.stream()) .onItem() .transformToUniAndConcatenate(doc -> insertDocument(queryExecutor, query, doc)) .collect() .asList(); - return ids.onItem().transform(insertedIds -> new ModifyOperationPage(insertedIds, documents)); + return ids.onItem().transform(insertedIds -> new InsertOperationPage(insertedIds, documents)); } - private static Uni insertDocument( + private static Uni insertDocument( QueryExecutor queryExecutor, QueryOuterClass.Query query, WritableShreddedDocument doc) { query = bindInsertValues(query, doc); - return queryExecutor.executeWrite(query).onItem().transform(result -> doc.id().toString()); + return queryExecutor.executeWrite(query).onItem().transform(result -> doc.id()); } private QueryOuterClass.Query buildInsertQuery() { @@ -58,7 +59,7 @@ private static QueryOuterClass.Query bindInsertValues( // respect the order in the DocsApiConstants.ALL_COLUMNS_NAMES QueryOuterClass.Values.Builder values = QueryOuterClass.Values.newBuilder() - .addValues(CustomValueSerializers.getDocumentIdValue(doc.id())) + .addValues(Values.of(CustomValueSerializers.getDocumentIdValue(doc.id()))) .addValues(Values.of(doc.docJson())) .addValues(Values.of(CustomValueSerializers.getIntegerMapValues(doc.docProperties()))) .addValues(Values.of(CustomValueSerializers.getSetValue(doc.existKeys()))) diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ModifyOperationPage.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperationPage.java similarity index 78% rename from src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ModifyOperationPage.java rename to src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperationPage.java index 5eced11fe7..c4a84fa75f 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ModifyOperationPage.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/InsertOperationPage.java @@ -2,6 +2,7 @@ import io.stargate.sgv3.docsapi.api.model.command.CommandResult; import io.stargate.sgv3.docsapi.api.model.command.CommandStatus; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import io.stargate.sgv3.docsapi.service.shredding.model.WritableShreddedDocument; import java.util.List; import java.util.Map; @@ -11,8 +12,8 @@ * The internal to modification operation results, what were the ID's of the docs we changed and * what change. */ -public record ModifyOperationPage( - List insertedIds, List insertedDocs) +public record InsertOperationPage( + List insertedIds, List insertedDocs) implements Supplier { @Override public CommandResult get() { diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadAndUpdateOperation.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadAndUpdateOperation.java index b092bdc1de..343e34698a 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadAndUpdateOperation.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadAndUpdateOperation.java @@ -12,6 +12,7 @@ import io.stargate.sgv3.docsapi.service.operation.model.ModifyOperation; import io.stargate.sgv3.docsapi.service.operation.model.ReadOperation; import io.stargate.sgv3.docsapi.service.shredding.Shredder; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import io.stargate.sgv3.docsapi.service.shredding.model.WritableShreddedDocument; import io.stargate.sgv3.docsapi.service.updater.DocumentUpdater; import java.util.List; @@ -52,7 +53,7 @@ public Uni> execute(QueryExecutor queryExecutor) { .transform(updates -> new UpdateOperationPage(updates, returnDoc())); } - private Uni updatedDocument( + private Uni updatedDocument( QueryExecutor queryExecutor, WritableShreddedDocument writableShreddedDocument) { final QueryOuterClass.Query updateQuery = bindUpdateValues(buildUpdateQuery(), writableShreddedDocument); @@ -62,7 +63,7 @@ private Uni updatedDocument( .transformToUni( result -> { if (result.getRows(0).getValues(0).getBoolean()) { - return Uni.createFrom().item(writableShreddedDocument.id().toString()); + return Uni.createFrom().item(writableShreddedDocument.id()); } else { return Uni.createFrom().nothing(); } @@ -111,10 +112,10 @@ protected static QueryOuterClass.Query bindUpdateValues( .addValues(Values.of(CustomValueSerializers.getStringMapValues(doc.queryTextValues()))) .addValues(Values.of(CustomValueSerializers.getSetValue(doc.queryNullValues()))) .addValues(Values.of(doc.docJson())) - .addValues(CustomValueSerializers.getDocumentIdValue(doc.id())) + .addValues(Values.of(CustomValueSerializers.getDocumentIdValue(doc.id()))) .addValues(Values.of(doc.txID())); return QueryOuterClass.Query.newBuilder(builtQuery).setValues(values).build(); } - record UpdatedDocument(String id, JsonNode document) {} + record UpdatedDocument(DocumentId id, JsonNode document) {} } diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadDocument.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadDocument.java index 1ffd0fbc9f..fc6aae1719 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadDocument.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/ReadDocument.java @@ -1,6 +1,7 @@ package io.stargate.sgv3.docsapi.service.operation.model.impl; import com.fasterxml.jackson.databind.JsonNode; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.UUID; /** @@ -10,4 +11,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, UUID txnId, JsonNode document) {} +public record ReadDocument(DocumentId id, UUID txnId, JsonNode document) {} diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/UpdateOperationPage.java b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/UpdateOperationPage.java index ff943e05dc..5f33a6c6a9 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/UpdateOperationPage.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/operation/model/impl/UpdateOperationPage.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import io.stargate.sgv3.docsapi.api.model.command.CommandResult; import io.stargate.sgv3.docsapi.api.model.command.CommandStatus; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -13,7 +14,7 @@ public record UpdateOperationPage( implements Supplier { @Override public CommandResult get() { - List updatedIds = new ArrayList<>(updatedDocuments().size()); + List updatedIds = new ArrayList<>(updatedDocuments().size()); List updatedDocs = new ArrayList<>(updatedDocuments().size()); updatedDocuments.forEach( update -> { diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/matcher/FilterableResolver.java b/src/main/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/matcher/FilterableResolver.java index 7967749830..d71f48e695 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/matcher/FilterableResolver.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/matcher/FilterableResolver.java @@ -8,6 +8,7 @@ import io.stargate.sgv3.docsapi.api.model.command.clause.filter.ValueComparisonOperator; import io.stargate.sgv3.docsapi.service.operation.model.ReadOperation; import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -54,7 +55,7 @@ public FilterableResolver(ObjectMapper objectMapper, boolean findOne, boolean re .addMatchRule(this::findById, FilterMatcher.MatchStrategy.STRICT) .matcher() .capture(ID_GROUP) - .compareValues("_id", ValueComparisonOperator.EQ, JsonType.STRING); + .compareValues("_id", ValueComparisonOperator.EQ, JsonType.DOCUMENT_ID); // NOTE - can only do eq ops on fields until SAI changes matchRules @@ -83,8 +84,8 @@ public record FilteringOptions(int limit, String pagingState, int pageSize) {} private ReadOperation findById(CommandContext commandContext, CaptureGroups captures) { List filters = new ArrayList<>(); - final CaptureGroup idGroup = - (CaptureGroup) captures.getGroupIfPresent(ID_GROUP); + final CaptureGroup idGroup = + (CaptureGroup) captures.getGroupIfPresent(ID_GROUP); if (idGroup != null) { idGroup.consumeAllCaptures( expression -> @@ -118,8 +119,8 @@ private ReadOperation findNoFilter(CommandContext commandContext, CaptureGroups< private ReadOperation findDynamic(CommandContext commandContext, CaptureGroups captures) { List filters = new ArrayList<>(); - final CaptureGroup idGroup = - (CaptureGroup) captures.getGroupIfPresent(ID_GROUP); + final CaptureGroup idGroup = + (CaptureGroup) captures.getGroupIfPresent(ID_GROUP); if (idGroup != null) { idGroup.consumeAllCaptures( expression -> diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/shredding/Shredder.java b/src/main/java/io/stargate/sgv3/docsapi/service/shredding/Shredder.java index 3d38b73ec3..0b849233be 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/shredding/Shredder.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/shredding/Shredder.java @@ -57,7 +57,7 @@ public WritableShreddedDocument shred(JsonNode doc, UUID txId) { // We will extract id if there is one; stored separately, but also included in JSON document // before storing in persistence. Need to make copy to avoid modifying input doc ObjectNode docWithoutId = ((ObjectNode) doc).objectNode().setAll((ObjectNode) doc); - JsonNode idNode = docWithoutId.remove("_id"); + JsonNode idNode = docWithoutId.remove(DocumentConstants.Fields.DOC_ID); // We will use `_id`, if passed (but must be JSON String or Number); if not passed, // need to generate diff --git a/src/main/java/io/stargate/sgv3/docsapi/service/shredding/model/DocumentId.java b/src/main/java/io/stargate/sgv3/docsapi/service/shredding/model/DocumentId.java index da3fffa03c..b0b6c083d6 100644 --- a/src/main/java/io/stargate/sgv3/docsapi/service/shredding/model/DocumentId.java +++ b/src/main/java/io/stargate/sgv3/docsapi/service/shredding/model/DocumentId.java @@ -1,12 +1,15 @@ package io.stargate.sgv3.docsapi.service.shredding.model; +import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import io.stargate.sgv3.docsapi.api.model.command.clause.filter.JsonType; +import io.quarkus.runtime.annotations.RegisterForReflection; +import io.stargate.sgv3.docsapi.config.constants.DocumentConstants; import io.stargate.sgv3.docsapi.exception.DocsException; import io.stargate.sgv3.docsapi.exception.ErrorCode; import java.math.BigDecimal; +import java.util.Objects; import java.util.UUID; /** @@ -20,8 +23,12 @@ *
  • null * */ +@RegisterForReflection public interface DocumentId { - JsonType type(); + int typeId(); + + @JsonValue + Object value(); default JsonNode asJson(ObjectMapper mapper) { return asJson(mapper.getNodeFactory()); @@ -51,6 +58,28 @@ static DocumentId fromJson(JsonNode node) { ErrorCode.SHRED_BAD_DOCID_TYPE.getMessage(), node.getNodeType())); } + static DocumentId fromDatabase(int typeId, String documentIdAsText) { + switch (DocumentConstants.KeyTypeId.getJsonType(typeId)) { + case BOOLEAN -> { + return fromBoolean(Boolean.valueOf(documentIdAsText)); + } + case NULL -> { + return fromNull(); + } + case NUMBER -> { + return fromNumber(new BigDecimal(documentIdAsText)); + } + case STRING -> { + return fromString(documentIdAsText); + } + } + throw new DocsException( + ErrorCode.SHRED_BAD_DOCID_TYPE, + String.format( + "%s: Document Id must be a JSON String(1), Number(2), Boolean(3) or NULL(4) instead got %s", + ErrorCode.SHRED_BAD_DOCID_TYPE.getMessage(), typeId)); + } + static DocumentId fromBoolean(boolean key) { return BooleanId.valueOf(key); } @@ -60,10 +89,15 @@ static DocumentId fromNull() { } static DocumentId fromNumber(BigDecimal key) { + key = Objects.requireNonNull(key); return new NumberId(key); } static DocumentId fromString(String key) { + key = Objects.requireNonNull(key); + if (key.isEmpty()) { + throw new DocsException(ErrorCode.SHRED_BAD_DOCID_EMPTY_STRING); + } return new StringId(key); } @@ -79,8 +113,13 @@ static DocumentId fromUUID(UUID uuid) { record StringId(String key) implements DocumentId { @Override - public JsonType type() { - return JsonType.STRING; + public int typeId() { + return DocumentConstants.KeyTypeId.TYPE_ID_STRING; + } + + @Override + public Object value() { + return key(); } @Override @@ -96,8 +135,13 @@ public String toString() { record NumberId(BigDecimal key) implements DocumentId { @Override - public JsonType type() { - return JsonType.NUMBER; + public int typeId() { + return DocumentConstants.KeyTypeId.TYPE_ID_NUMBER; + } + + @Override + public Object value() { + return key(); } @Override @@ -120,8 +164,13 @@ public static BooleanId valueOf(boolean b) { } @Override - public JsonType type() { - return JsonType.BOOLEAN; + public int typeId() { + return DocumentConstants.KeyTypeId.TYPE_ID_BOOLEAN; + } + + @Override + public Object value() { + return key(); } @Override @@ -139,8 +188,13 @@ record NullId() implements DocumentId { public static final NullId NULL = new NullId(); @Override - public JsonType type() { - return JsonType.NULL; + public Object value() { + return null; + } + + @Override + public int typeId() { + return DocumentConstants.KeyTypeId.TYPE_ID_NULL; } @Override diff --git a/src/test/java/io/stargate/sgv3/docsapi/api/v3/InsertIntegrationTest.java b/src/test/java/io/stargate/sgv3/docsapi/api/v3/InsertIntegrationTest.java index f3a556421a..0a6c1a01c9 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/api/v3/InsertIntegrationTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/api/v3/InsertIntegrationTest.java @@ -68,6 +68,50 @@ public void insertDocument() { .body("data.docs[0]", jsonEquals(expected)); } + @Test + public void insertDocumentWithNumberId() { + String json = + """ + { + "insertOne": { + "document": { + "_id": 4, + "username": "user4" + } + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.insertedIds[0]", is(4)); + + json = + """ + { + "find": { + "filter" : {"_id" : 4} + } + } + """; + String expected = "{\"_id\": 4, \"username\":\"user4\"}"; + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("data.docs[0]", jsonEquals(expected)); + } + @Test public void emptyDocument() { String json = @@ -163,6 +207,73 @@ public void insertDocument() { .body("data.docs[0]", jsonEquals(expected)); } + @Test + public void insertDocumentWithDifferentTypes() { + String json = + """ + { + "insertMany": { + "documents": [{ + "_id": "5", + "username": "user_id_5" + }, + { + "_id": 5, + "username": "user_id_5_number" + }] + } + } + """; + + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("status.insertedIds", contains("5", 5)); + + json = + """ + { + "find": { + "filter" : {"_id" : "5"} + } + } + """; + String expected = "{\"_id\":\"5\", \"username\":\"user_id_5\"}"; + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("data.docs[0]", jsonEquals(expected)); + + json = + """ + { + "find": { + "filter" : {"_id" : 5} + } + } + """; + expected = "{\"_id\":5, \"username\":\"user_id_5_number\"}"; + given() + .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, keyspaceId.asInternal(), collectionName) + .then() + .statusCode(200) + .body("data.docs[0]", jsonEquals(expected)); + } + @Test public void emptyDocument() { String json = diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperationTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperationTest.java index d035199667..a401139025 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperationTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/CreateCollectionOperationTest.java @@ -53,7 +53,7 @@ private List getAllQueryString(String database, String collection) { List queries = new ArrayList<>(); String create = "CREATE TABLE IF NOT EXISTS %s.%s (" - + " key text," + + " key tuple," + " tx_id timeuuid, " + " doc_json text," + " doc_properties map," diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationTest.java index 6df477f037..0e3ed9d6bb 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/DeleteOperationTest.java @@ -15,6 +15,8 @@ import io.stargate.sgv3.docsapi.service.bridge.AbstractValidatingStargateBridgeTest; import io.stargate.sgv3.docsapi.service.bridge.ValidatingStargateBridge; import io.stargate.sgv3.docsapi.service.bridge.executor.QueryExecutor; +import io.stargate.sgv3.docsapi.service.bridge.serializer.CustomValueSerializers; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import java.util.UUID; import java.util.function.Supplier; @@ -43,30 +45,45 @@ public void deleteWithId() throws Exception { .formatted(KEYSPACE_NAME, COLLECTION_NAME); UUID tx_id = UUID.randomUUID(); ValidatingStargateBridge.QueryAssert readAssert = - withQuery(collectionReadCql, Values.of("doc1")) + withQuery( + collectionReadCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1")))) .withPageSize(1) .withColumnSpec( List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") .setType(TypeSpecs.UUID) .build())) - .returning(List.of(List.of(Values.of("doc1"), Values.of(tx_id)))); + .returning( + List.of( + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(tx_id)))); String collectionDeleteCql = "DELETE FROM \"%s\".\"%s\" WHERE key = ? IF tx_id = ?" .formatted(KEYSPACE_NAME, COLLECTION_NAME); ValidatingStargateBridge.QueryAssert deleteAssert = - withQuery(collectionDeleteCql, Values.of("doc1"), Values.of(tx_id)) + withQuery( + collectionDeleteCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1"))), + Values.of(tx_id)) .returning(List.of(List.of(Values.of(true)))); FindOperation findOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "doc1")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("doc1"))), null, 1, 1, @@ -81,10 +98,10 @@ public void deleteWithId() throws Exception { .satisfies( commandResult -> { assertThat(result.status().get(CommandStatus.DELETED_IDS)).isNotNull(); - assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) + assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) .hasSize(1); - assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) - .contains("doc1"); + assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) + .contains(DocumentId.fromString("doc1")); }); } @@ -95,7 +112,10 @@ public void deleteWithIdNoData() throws Exception { .formatted(KEYSPACE_NAME, COLLECTION_NAME); UUID tx_id = UUID.randomUUID(); ValidatingStargateBridge.QueryAssert readAssert = - withQuery(collectionReadCql, Values.of("doc1")) + withQuery( + collectionReadCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1")))) .withPageSize(1) .withColumnSpec( List.of( @@ -112,7 +132,9 @@ public void deleteWithIdNoData() throws Exception { FindOperation findOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "doc1")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("doc1"))), null, 1, 1, @@ -151,12 +173,22 @@ public void deleteWithDynamic() throws Exception { .setName("tx_id") .setType(TypeSpecs.UUID) .build())) - .returning(List.of(List.of(Values.of("doc1"), Values.of(tx_id)))); + .returning( + List.of( + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(tx_id)))); String collectionDeleteCql = "DELETE FROM \"%s\".\"%s\" WHERE key = ? IF tx_id = ?" .formatted(KEYSPACE_NAME, COLLECTION_NAME); ValidatingStargateBridge.QueryAssert deleteAssert = - withQuery(collectionDeleteCql, Values.of("doc1"), Values.of(tx_id)) + withQuery( + collectionDeleteCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1"))), + Values.of(tx_id)) .returning(List.of(List.of(Values.of(true)))); FindOperation findOperation = @@ -179,10 +211,10 @@ public void deleteWithDynamic() throws Exception { .satisfies( commandResult -> { assertThat(result.status().get(CommandStatus.DELETED_IDS)).isNotNull(); - assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) + assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) .hasSize(1); - assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) - .contains("doc1"); + assertThat((List) result.status().get(CommandStatus.DELETED_IDS)) + .contains(DocumentId.fromString("doc1")); }); } diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperationTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperationTest.java index 2a9c4847e5..43809a324b 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperationTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/operation/model/impl/FindOperationTest.java @@ -14,6 +14,8 @@ import io.stargate.sgv3.docsapi.service.bridge.AbstractValidatingStargateBridgeTest; import io.stargate.sgv3.docsapi.service.bridge.ValidatingStargateBridge; import io.stargate.sgv3.docsapi.service.bridge.executor.QueryExecutor; +import io.stargate.sgv3.docsapi.service.bridge.serializer.CustomValueSerializers; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import java.util.UUID; import java.util.function.Supplier; @@ -62,7 +64,7 @@ public void findAll() throws Exception { List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") @@ -74,8 +76,18 @@ public void findAll() throws Exception { .build())) .returning( List.of( - List.of(Values.of("doc1"), Values.of(UUID.randomUUID()), Values.of(doc1)), - List.of(Values.of("doc2"), Values.of(UUID.randomUUID()), Values.of(doc2)))); + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(UUID.randomUUID()), + Values.of(doc1)), + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc2"))), + Values.of(UUID.randomUUID()), + Values.of(doc2)))); FindOperation findOperation = new FindOperation(commandContext, List.of(), null, 2, 2, true, objectMapper); final Supplier execute = @@ -102,13 +114,16 @@ public void findWithId() throws Exception { } """; ValidatingStargateBridge.QueryAssert candidatesAssert = - withQuery(collectionReadCql, Values.of("doc1")) + withQuery( + collectionReadCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1")))) .withPageSize(1) .withColumnSpec( List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") @@ -120,11 +135,18 @@ public void findWithId() throws Exception { .build())) .returning( List.of( - List.of(Values.of("doc1"), Values.of(UUID.randomUUID()), Values.of(doc1)))); + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(UUID.randomUUID()), + Values.of(doc1)))); FindOperation findOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "doc1")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("doc1"))), null, 1, 1, @@ -147,13 +169,16 @@ public void findWithIdNoData() throws Exception { "SELECT key, tx_id, doc_json FROM \"%s\".\"%s\" WHERE key = ? LIMIT 1" .formatted(KEYSPACE_NAME, COLLECTION_NAME); ValidatingStargateBridge.QueryAssert candidatesAssert = - withQuery(collectionReadCql, Values.of("doc1")) + withQuery( + collectionReadCql, + Values.of( + CustomValueSerializers.getDocumentIdValue(DocumentId.fromString("doc1")))) .withPageSize(1) .withColumnSpec( List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") @@ -167,7 +192,9 @@ public void findWithIdNoData() throws Exception { FindOperation findOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "doc1")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("doc1"))), null, 1, 1, @@ -203,7 +230,7 @@ public void findWithDynamic() throws Exception { List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") @@ -215,7 +242,12 @@ public void findWithDynamic() throws Exception { .build())) .returning( List.of( - List.of(Values.of("doc1"), Values.of(UUID.randomUUID()), Values.of(doc1)))); + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(UUID.randomUUID()), + Values.of(doc1)))); FindOperation findOperation = new FindOperation( commandContext, @@ -258,7 +290,7 @@ public void findWithBooleanFilter() throws Exception { List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") @@ -270,7 +302,12 @@ public void findWithBooleanFilter() throws Exception { .build())) .returning( List.of( - List.of(Values.of("doc1"), Values.of(UUID.randomUUID()), Values.of(doc1)))); + List.of( + Values.of( + CustomValueSerializers.getDocumentIdValue( + DocumentId.fromString("doc1"))), + Values.of(UUID.randomUUID()), + Values.of(doc1)))); FindOperation findOperation = new FindOperation( commandContext, @@ -312,7 +349,7 @@ public void findWithNoResult() throws Exception { List.of( QueryOuterClass.ColumnSpec.newBuilder() .setName("key") - .setType(TypeSpecs.VARCHAR) + .setType(TypeSpecs.tuple(TypeSpecs.TINYINT, TypeSpecs.VARCHAR)) .build(), QueryOuterClass.ColumnSpec.newBuilder() .setName("tx_id") diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/DeleteOneCommandResolverTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/DeleteOneCommandResolverTest.java index 6de743ba9e..a84c1c7ff4 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/DeleteOneCommandResolverTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/DeleteOneCommandResolverTest.java @@ -11,6 +11,7 @@ import io.stargate.sgv3.docsapi.service.operation.model.Operation; import io.stargate.sgv3.docsapi.service.operation.model.impl.DeleteOperation; import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import javax.inject.Inject; import org.junit.jupiter.api.Nested; @@ -43,7 +44,9 @@ public void idFilterCondition() throws Exception { FindOperation findOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "id")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("id"))), null, 1, 1, diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindCommandResolverTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindCommandResolverTest.java index c72b02fcd0..14c65d6560 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindCommandResolverTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindCommandResolverTest.java @@ -11,6 +11,7 @@ import io.stargate.sgv3.docsapi.service.bridge.config.DocumentConfig; import io.stargate.sgv3.docsapi.service.operation.model.Operation; import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import javax.inject.Inject; import org.junit.jupiter.api.Nested; @@ -43,7 +44,9 @@ public void idFilterCondition() throws Exception { FindOperation expected = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "id")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("id"))), null, documentConfig.maxLimit(), documentConfig.defaultPageSize(), diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneAndUpdateResolverTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneAndUpdateResolverTest.java index 124e6467ec..0367acc6c3 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneAndUpdateResolverTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneAndUpdateResolverTest.java @@ -14,6 +14,7 @@ import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; import io.stargate.sgv3.docsapi.service.operation.model.impl.ReadAndUpdateOperation; import io.stargate.sgv3.docsapi.service.shredding.Shredder; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import io.stargate.sgv3.docsapi.service.testutil.DocumentUpdaterUtils; import io.stargate.sgv3.docsapi.service.updater.DocumentUpdater; import java.util.List; @@ -51,7 +52,9 @@ public void idFilterConditionBsonType() throws Exception { ReadOperation readOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "id")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("id"))), null, 1, 1, diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneCommandResolverTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneCommandResolverTest.java index b1453c826e..0d8e168eeb 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneCommandResolverTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/FindOneCommandResolverTest.java @@ -10,6 +10,7 @@ import io.stargate.sgv3.docsapi.api.model.command.impl.FindOneCommand; import io.stargate.sgv3.docsapi.service.operation.model.Operation; import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import java.util.List; import javax.inject.Inject; import org.junit.jupiter.api.Nested; @@ -46,7 +47,9 @@ public void idFilterCondition() throws Exception { FindOperation expected = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "id")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("id"))), null, 1, 1, diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/UpdateOneResolverTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/UpdateOneResolverTest.java index b40c521c01..d7457810ba 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/UpdateOneResolverTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/resolver/model/impl/UpdateOneResolverTest.java @@ -14,6 +14,7 @@ import io.stargate.sgv3.docsapi.service.operation.model.impl.FindOperation; import io.stargate.sgv3.docsapi.service.operation.model.impl.ReadAndUpdateOperation; import io.stargate.sgv3.docsapi.service.shredding.Shredder; +import io.stargate.sgv3.docsapi.service.shredding.model.DocumentId; import io.stargate.sgv3.docsapi.service.testutil.DocumentUpdaterUtils; import io.stargate.sgv3.docsapi.service.updater.DocumentUpdater; import java.util.List; @@ -50,7 +51,9 @@ public void idFilterConditionBsonType() throws Exception { ReadOperation readOperation = new FindOperation( commandContext, - List.of(new FindOperation.IDFilter(FindOperation.IDFilter.Operator.EQ, "id")), + List.of( + new FindOperation.IDFilter( + FindOperation.IDFilter.Operator.EQ, DocumentId.fromString("id"))), null, 1, 1, diff --git a/src/test/java/io/stargate/sgv3/docsapi/service/shredding/ShredderTest.java b/src/test/java/io/stargate/sgv3/docsapi/service/shredding/ShredderTest.java index 83ce7bf767..c6c7f563a7 100644 --- a/src/test/java/io/stargate/sgv3/docsapi/service/shredding/ShredderTest.java +++ b/src/test/java/io/stargate/sgv3/docsapi/service/shredding/ShredderTest.java @@ -187,7 +187,7 @@ public void docBadJSONType() { } @Test - public void docBadDocIdType() { + public void docBadDocIdTypeArray() { Throwable t = catchThrowable(() -> shredder.shred(objectMapper.readTree("{ \"_id\" : [ ] }"))); @@ -197,5 +197,16 @@ public void docBadDocIdType() { "Bad type for '_id' property: Document Id must be a JSON String, Number, Boolean or NULL instead got ARRAY") .hasFieldOrPropertyWithValue("errorCode", ErrorCode.SHRED_BAD_DOCID_TYPE); } + + @Test + public void docBadDocIdEmptyString() { + Throwable t = + catchThrowable(() -> shredder.shred(objectMapper.readTree("{ \"_id\" : \"\" }"))); + + assertThat(t) + .isNotNull() + .hasMessage("Bad value for '_id' property: empty String not allowed") + .hasFieldOrPropertyWithValue("errorCode", ErrorCode.SHRED_BAD_DOCID_EMPTY_STRING); + } } }