diff --git a/core/src/main/java/com/scalar/db/api/Delete.java b/core/src/main/java/com/scalar/db/api/Delete.java index 93d8eed600..83acf7a947 100644 --- a/core/src/main/java/com/scalar/db/api/Delete.java +++ b/core/src/main/java/com/scalar/db/api/Delete.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import com.scalar.db.api.DeleteBuilder.BuildableFromExisting; import com.scalar.db.api.DeleteBuilder.Namespace; import com.scalar.db.io.Key; @@ -25,8 +26,9 @@ public class Delete extends Mutation { Key partitionKey, @Nullable Key clusteringKey, @Nullable Consistency consistency, + ImmutableMap attributes, @Nullable MutationCondition condition) { - super(namespace, tableName, partitionKey, clusteringKey, consistency, condition); + super(namespace, tableName, partitionKey, clusteringKey, consistency, attributes, condition); } /** @@ -172,6 +174,7 @@ public String toString() { .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) .add("consistency", getConsistency()) + .add("attributes", getAttributes()) .add("condition", getCondition()) .toString(); } diff --git a/core/src/main/java/com/scalar/db/api/DeleteBuilder.java b/core/src/main/java/com/scalar/db/api/DeleteBuilder.java index 539b2e64f9..0b2831d53a 100644 --- a/core/src/main/java/com/scalar/db/api/DeleteBuilder.java +++ b/core/src/main/java/com/scalar/db/api/DeleteBuilder.java @@ -2,6 +2,9 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableMap; +import com.scalar.db.api.OperationBuilder.Attribute; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearCondition; import com.scalar.db.api.OperationBuilder.ClearNamespace; @@ -11,6 +14,8 @@ import com.scalar.db.api.OperationBuilder.PartitionKeyBuilder; import com.scalar.db.api.OperationBuilder.TableBuilder; import com.scalar.db.io.Key; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; public class DeleteBuilder { @@ -60,10 +65,14 @@ public Buildable partitionKey(Key partitionKey) { } public static class Buildable extends OperationBuilder.Buildable - implements ClusteringKey, Consistency, Condition { + implements ClusteringKey, + Consistency, + Condition, + Attribute { @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; @Nullable MutationCondition condition; + final Map attributes = new HashMap<>(); private Buildable(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -90,10 +99,31 @@ public Buildable consistency(com.scalar.db.api.Consistency consistency) { return this; } + @Override + public Buildable attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public Buildable attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Delete build() { return new Delete( - namespaceName, tableName, partitionKey, clusteringKey, consistency, condition); + namespaceName, + tableName, + partitionKey, + clusteringKey, + consistency, + ImmutableMap.copyOf(attributes), + condition); } } @@ -103,17 +133,18 @@ public static class BuildableFromExisting extends Buildable OperationBuilder.PartitionKey, ClearCondition, ClearClusteringKey, - ClearNamespace { + ClearNamespace, + ClearAttribute { BuildableFromExisting(Delete delete) { super( delete.forNamespace().orElse(null), delete.forTable().orElse(null), delete.getPartitionKey()); - this.clusteringKey = delete.getClusteringKey().orElse(null); this.consistency = delete.getConsistency(); this.condition = delete.getCondition().orElse(null); + this.attributes.putAll(delete.getAttributes()); } @Override @@ -149,6 +180,18 @@ public BuildableFromExisting consistency(com.scalar.db.api.Consistency consisten return this; } + @Override + public BuildableFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableFromExisting condition(MutationCondition condition) { super.condition(condition); @@ -172,5 +215,17 @@ public BuildableFromExisting clearNamespace() { this.namespaceName = null; return this; } + + @Override + public BuildableFromExisting clearAttributes() { + this.attributes.clear(); + return this; + } + + @Override + public BuildableFromExisting clearAttribute(String name) { + this.attributes.remove(name); + return this; + } } } diff --git a/core/src/main/java/com/scalar/db/api/Get.java b/core/src/main/java/com/scalar/db/api/Get.java index f6202734fa..3e1d898a68 100644 --- a/core/src/main/java/com/scalar/db/api/Get.java +++ b/core/src/main/java/com/scalar/db/api/Get.java @@ -3,6 +3,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.GetBuilder.BuildableGetOrGetWithIndexFromExisting; import com.scalar.db.api.GetBuilder.Namespace; @@ -26,10 +27,18 @@ public class Get extends Selection { Key partitionKey, @Nullable Key clusteringKey, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions) { super( - namespace, tableName, partitionKey, clusteringKey, consistency, projections, conjunctions); + namespace, + tableName, + partitionKey, + clusteringKey, + consistency, + attributes, + projections, + conjunctions); } /** @@ -178,9 +187,10 @@ public String toString() { .add("table", forTable()) .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) + .add("consistency", getConsistency()) + .add("attributes", getAttributes()) .add("projections", getProjections()) .add("conjunctions", getConjunctions()) - .add("consistency", getConsistency()) .toString(); } } diff --git a/core/src/main/java/com/scalar/db/api/GetBuilder.java b/core/src/main/java/com/scalar/db/api/GetBuilder.java index 3b92cfa499..86a1eb418d 100644 --- a/core/src/main/java/com/scalar/db/api/GetBuilder.java +++ b/core/src/main/java/com/scalar/db/api/GetBuilder.java @@ -2,9 +2,12 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.OperationBuilder.And; +import com.scalar.db.api.OperationBuilder.Attribute; import com.scalar.db.api.OperationBuilder.Buildable; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearConditions; import com.scalar.db.api.OperationBuilder.ClearNamespace; @@ -25,8 +28,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -85,10 +90,14 @@ public BuildableGetWithIndex indexKey(Key indexKey) { } public static class BuildableGet extends Buildable - implements ClusteringKey, Consistency, Projection { + implements ClusteringKey, + Consistency, + Projection, + Attribute { final List projections = new ArrayList<>(); @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; + final Map attributes = new HashMap<>(); private BuildableGet(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -134,6 +143,21 @@ public BuildableGet consistency(com.scalar.db.api.Consistency consistency) { return this; } + @Override + public BuildableGet attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public BuildableGet attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Get build() { return build(ImmutableSet.of()); @@ -146,6 +170,7 @@ private Get build(ImmutableSet conjunctions) { partitionKey, clusteringKey, consistency, + ImmutableMap.copyOf(attributes), projections, conjunctions); } @@ -190,6 +215,18 @@ public BuildableGetWithPartitionKey consistency(com.scalar.db.api.Consistency co return this; } + @Override + public BuildableGetWithPartitionKey attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableGetWithPartitionKey attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableGetWithOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -352,6 +389,7 @@ public Get build() { public static class BuildableGetWithIndex implements Consistency, Projection, + Attribute, OperationBuilder.Where, WhereAnd, WhereOr { @@ -360,6 +398,7 @@ public static class BuildableGetWithIndex private final Key indexKey; private final List projections = new ArrayList<>(); @Nullable private com.scalar.db.api.Consistency consistency; + private final Map attributes = new HashMap<>(); private BuildableGetWithIndex(@Nullable String namespace, String table, Key indexKey) { namespaceName = namespace; @@ -393,6 +432,21 @@ public BuildableGetWithIndex consistency(com.scalar.db.api.Consistency consisten return this; } + @Override + public BuildableGetWithIndex attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public BuildableGetWithIndex attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public BuildableGetWithIndexOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -429,7 +483,13 @@ public Get build() { private Get build(ImmutableSet conjunctions) { return new GetWithIndex( - namespaceName, tableName, indexKey, consistency, projections, conjunctions); + namespaceName, + tableName, + indexKey, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions); } } @@ -540,7 +600,9 @@ public BuildableGetWithIndexOngoingWhereOr or(AndConditionSet andConditionSet) { } public static class BuildableGetWithIndexWhere - implements Consistency, Projection { + implements Consistency, + Projection, + Attribute { BuildableGetWithIndex buildableGetWithIndex; final SelectionBuilder.Where where; @@ -583,6 +645,18 @@ public BuildableGetWithIndexWhere consistency(com.scalar.db.api.Consistency cons return this; } + @Override + public BuildableGetWithIndexWhere attribute(String name, String value) { + buildableGetWithIndex = buildableGetWithIndex.attribute(name, value); + return this; + } + + @Override + public BuildableGetWithIndexWhere attributes(Map attributes) { + buildableGetWithIndex = buildableGetWithIndex.attributes(attributes); + return this; + } + public Get build() { return buildableGetWithIndex.build(getConjunctions(where)); } @@ -599,7 +673,8 @@ public static class BuildableGetOrGetWithIndexFromExisting extends BuildableGet ClearConditions, ClearProjections, ClearClusteringKey, - ClearNamespace { + ClearNamespace, + ClearAttribute { private Key indexKey; private final boolean isGetWithIndex; @@ -610,6 +685,7 @@ public static class BuildableGetOrGetWithIndexFromExisting extends BuildableGet clusteringKey = get.getClusteringKey().orElse(null); projections.addAll(get.getProjections()); consistency = get.getConsistency(); + attributes.putAll(get.getAttributes()); isGetWithIndex = get instanceof GetWithIndex; if (isGetWithIndex) { indexKey = get.getPartitionKey(); @@ -682,6 +758,18 @@ public BuildableGetOrGetWithIndexFromExisting projections(String... projections) return this; } + @Override + public BuildableGetOrGetWithIndexFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableGetOrGetWithIndexFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableGetFromExistingWithOngoingWhere where(ConditionalExpression condition) { checkConditionsEmpty(); @@ -744,6 +832,19 @@ public BuildableGetOrGetWithIndexFromExisting clearNamespace() { return this; } + @Override + public BuildableGetOrGetWithIndexFromExisting clearAttributes() { + this.attributes.clear(); + return this; + } + + @Override + public BuildableGetOrGetWithIndexFromExisting clearAttribute(String name) { + checkNotNull(name); + this.attributes.remove(name); + return this; + } + private void checkNotGet() { if (!isGetWithIndex) { throw new UnsupportedOperationException( @@ -779,7 +880,13 @@ public Get build() { private Get build(ImmutableSet conjunctions) { if (isGetWithIndex) { return new GetWithIndex( - namespaceName, tableName, indexKey, consistency, projections, conjunctions); + namespaceName, + tableName, + indexKey, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions); } else { return new Get( namespaceName, @@ -787,6 +894,7 @@ private Get build(ImmutableSet conjunctions) { partitionKey, clusteringKey, consistency, + ImmutableMap.copyOf(attributes), projections, conjunctions); } @@ -801,8 +909,10 @@ public static class BuildableGetFromExistingWithWhere IndexKey, Consistency, Projection, + Attribute, ClearProjections, - ClearNamespace { + ClearNamespace, + ClearAttribute { private final BuildableGetOrGetWithIndexFromExisting BuildableGetFromExisting; final SelectionBuilder.Where where; @@ -877,6 +987,18 @@ public BuildableGetFromExistingWithWhere consistency( return this; } + @Override + public BuildableGetFromExistingWithWhere attribute(String name, String value) { + BuildableGetFromExisting.attribute(name, value); + return this; + } + + @Override + public BuildableGetFromExistingWithWhere attributes(Map attributes) { + BuildableGetFromExisting.attributes(attributes); + return this; + } + @Override public BuildableGetFromExistingWithWhere clearProjections() { BuildableGetFromExisting.clearProjections(); @@ -889,6 +1011,18 @@ public BuildableGetFromExistingWithWhere clearNamespace() { return this; } + @Override + public BuildableGetFromExistingWithWhere clearAttributes() { + BuildableGetFromExisting.clearAttributes(); + return this; + } + + @Override + public BuildableGetFromExistingWithWhere clearAttribute(String name) { + BuildableGetFromExisting.clearAttribute(name); + return this; + } + public Get build() { return BuildableGetFromExisting.build(getConjunctions(where)); } diff --git a/core/src/main/java/com/scalar/db/api/GetWithIndex.java b/core/src/main/java/com/scalar/db/api/GetWithIndex.java index 393837dc58..6e6d530d29 100644 --- a/core/src/main/java/com/scalar/db/api/GetWithIndex.java +++ b/core/src/main/java/com/scalar/db/api/GetWithIndex.java @@ -1,5 +1,7 @@ package com.scalar.db.api; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.io.Key; import java.util.Collection; @@ -17,9 +19,10 @@ public class GetWithIndex extends Get { String tableName, Key indexKey, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions) { - super(namespace, tableName, indexKey, null, consistency, projections, conjunctions); + super(namespace, tableName, indexKey, null, consistency, attributes, projections, conjunctions); } /** @@ -112,4 +115,17 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(super.hashCode()); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("namespace", forNamespace()) + .add("table", forTable()) + .add("indexKey", getPartitionKey()) + .add("consistency", getConsistency()) + .add("attributes", getAttributes()) + .add("projections", getProjections()) + .add("conjunctions", getConjunctions()) + .toString(); + } } diff --git a/core/src/main/java/com/scalar/db/api/Insert.java b/core/src/main/java/com/scalar/db/api/Insert.java index f728a35ba1..ac8715c5d4 100644 --- a/core/src/main/java/com/scalar/db/api/Insert.java +++ b/core/src/main/java/com/scalar/db/api/Insert.java @@ -24,8 +24,9 @@ public class Insert extends Mutation { String tableName, Key partitionKey, @Nullable Key clusteringKey, + ImmutableMap attributes, ImmutableMap> columns) { - super(namespace, tableName, partitionKey, clusteringKey, null, null); + super(namespace, tableName, partitionKey, clusteringKey, null, attributes, null); this.columns = columns; } @@ -105,6 +106,7 @@ public String toString() { .add("table", forTable()) .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) + .add("attributes", getAttributes()) .add("columns", getColumns()) .toString(); } diff --git a/core/src/main/java/com/scalar/db/api/InsertBuilder.java b/core/src/main/java/com/scalar/db/api/InsertBuilder.java index 52d177fef4..137f408c09 100644 --- a/core/src/main/java/com/scalar/db/api/InsertBuilder.java +++ b/core/src/main/java/com/scalar/db/api/InsertBuilder.java @@ -3,6 +3,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableMap; +import com.scalar.db.api.OperationBuilder.Attribute; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearNamespace; import com.scalar.db.api.OperationBuilder.ClearValues; @@ -20,6 +22,7 @@ import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; @@ -71,9 +74,10 @@ public Buildable partitionKey(Key partitionKey) { } public static class Buildable extends OperationBuilder.Buildable - implements ClusteringKey, Values { + implements ClusteringKey, Values, Attribute { final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; + final Map attributes = new HashMap<>(); private Buildable(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -86,6 +90,21 @@ public Buildable clusteringKey(Key clusteringKey) { return this; } + @Override + public Buildable attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public Buildable attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Buildable booleanValue(String columnName, boolean value) { columns.put(columnName, BooleanColumn.of(columnName, value)); @@ -188,7 +207,12 @@ public Buildable value(Column column) { @Override public Insert build() { return new Insert( - namespaceName, tableName, partitionKey, clusteringKey, ImmutableMap.copyOf(columns)); + namespaceName, + tableName, + partitionKey, + clusteringKey, + ImmutableMap.copyOf(attributes), + ImmutableMap.copyOf(columns)); } } @@ -198,7 +222,8 @@ public static class BuildableFromExisting extends Buildable OperationBuilder.PartitionKey, ClearClusteringKey, ClearValues, - ClearNamespace { + ClearNamespace, + ClearAttribute { BuildableFromExisting(Insert insert) { super( @@ -207,6 +232,7 @@ public static class BuildableFromExisting extends Buildable insert.getPartitionKey()); this.clusteringKey = insert.getClusteringKey().orElse(null); this.columns.putAll(insert.getColumns()); + this.attributes.putAll(insert.getAttributes()); } @Override @@ -236,6 +262,18 @@ public BuildableFromExisting clusteringKey(Key clusteringKey) { return this; } + @Override + public BuildableFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableFromExisting booleanValue(String columnName, boolean value) { super.booleanValue(columnName, value); @@ -343,5 +381,17 @@ public BuildableFromExisting clearNamespace() { this.namespaceName = null; return this; } + + @Override + public BuildableFromExisting clearAttributes() { + attributes.clear(); + return this; + } + + @Override + public BuildableFromExisting clearAttribute(String name) { + attributes.remove(name); + return this; + } } } diff --git a/core/src/main/java/com/scalar/db/api/Mutation.java b/core/src/main/java/com/scalar/db/api/Mutation.java index d6554a16b2..2626ad3651 100644 --- a/core/src/main/java/com/scalar/db/api/Mutation.java +++ b/core/src/main/java/com/scalar/db/api/Mutation.java @@ -1,6 +1,7 @@ package com.scalar.db.api; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Key; import java.util.Objects; import java.util.Optional; @@ -26,8 +27,9 @@ public abstract class Mutation extends Operation { Key partitionKey, @Nullable Key clusteringKey, @Nullable Consistency consistency, + ImmutableMap attributes, @Nullable MutationCondition condition) { - super(namespace, tableName, partitionKey, clusteringKey, consistency); + super(namespace, tableName, partitionKey, clusteringKey, consistency, attributes); this.condition = condition; } diff --git a/core/src/main/java/com/scalar/db/api/Operation.java b/core/src/main/java/com/scalar/db/api/Operation.java index 7225bab70c..b81781844d 100644 --- a/core/src/main/java/com/scalar/db/api/Operation.java +++ b/core/src/main/java/com/scalar/db/api/Operation.java @@ -1,8 +1,8 @@ package com.scalar.db.api; -import com.google.common.collect.ComparisonChain; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Key; -import java.util.Comparator; +import java.util.Map; import java.util.Objects; import java.util.Optional; import javax.annotation.Nonnull; @@ -25,18 +25,21 @@ public abstract class Operation { @Nullable private String namespace; private String tableName; private Consistency consistency; + private final ImmutableMap attributes; Operation( @Nullable String namespace, String tableName, Key partitionKey, @Nullable Key clusteringKey, - @Nullable Consistency consistency) { + @Nullable Consistency consistency, + ImmutableMap attributes) { this.partitionKey = Objects.requireNonNull(partitionKey); this.clusteringKey = clusteringKey; this.namespace = namespace; this.tableName = Objects.requireNonNull(tableName); this.consistency = consistency != null ? consistency : Consistency.SEQUENTIAL; + this.attributes = attributes; } /** @@ -53,6 +56,7 @@ public Operation(Key partitionKey, @Nullable Key clusteringKey) { namespace = null; tableName = null; consistency = Consistency.SEQUENTIAL; + attributes = ImmutableMap.of(); } /** @@ -72,6 +76,7 @@ public Operation( this.namespace = namespace; this.tableName = tableName; consistency = Consistency.SEQUENTIAL; + attributes = ImmutableMap.of(); } /** @@ -87,6 +92,7 @@ public Operation(Operation operation) { namespace = operation.namespace; tableName = operation.tableName; consistency = operation.consistency; + attributes = operation.attributes; } /** @@ -191,6 +197,25 @@ public Operation withConsistency(Consistency consistency) { return this; } + /** + * Returns the attributes for this operation. + * + * @return the attributes + */ + public Map getAttributes() { + return attributes; + } + + /** + * Returns the value of the specified attribute. + * + * @param name the name of the attribute + * @return the value of the specified attribute + */ + public Optional getAttribute(String name) { + return Optional.ofNullable(attributes.get(name)); + } + /** * Indicates whether some other object is "equal to" this object. The other object is considered * equal if: @@ -213,22 +238,17 @@ public boolean equals(Object o) { return false; } Operation other = (Operation) o; - return ComparisonChain.start() - .compare(partitionKey, other.partitionKey) - .compare( - clusteringKey, - other.clusteringKey, - Comparator.nullsFirst(Comparator.naturalOrder())) - .compare(namespace, other.namespace, Comparator.nullsFirst(Comparator.naturalOrder())) - .compare(tableName, other.tableName, Comparator.nullsFirst(Comparator.naturalOrder())) - .compare(consistency, other.consistency) - .result() - == 0; + return Objects.equals(partitionKey, other.partitionKey) + && Objects.equals(clusteringKey, other.clusteringKey) + && Objects.equals(namespace, other.namespace) + && Objects.equals(tableName, other.tableName) + && Objects.equals(consistency, other.consistency) + && Objects.equals(attributes, other.attributes); } @Override public int hashCode() { - return Objects.hash(partitionKey, clusteringKey, namespace, tableName, consistency); + return Objects.hash(partitionKey, clusteringKey, namespace, tableName, consistency, attributes); } /** diff --git a/core/src/main/java/com/scalar/db/api/OperationBuilder.java b/core/src/main/java/com/scalar/db/api/OperationBuilder.java index 11c29d5e6d..aa6e53205b 100644 --- a/core/src/main/java/com/scalar/db/api/OperationBuilder.java +++ b/core/src/main/java/com/scalar/db/api/OperationBuilder.java @@ -4,6 +4,7 @@ import com.scalar.db.io.Key; import java.nio.ByteBuffer; import java.util.Collection; +import java.util.Map; import java.util.Set; import javax.annotation.Nullable; @@ -543,6 +544,42 @@ public interface ClearConditions { T clearConditions(); } + public interface Attribute { + /** + * Adds the specified attribute. + * + * @param name the name of the attribute + * @param value the value of the attribute + * @return the operation builder + */ + T attribute(String name, String value); + + /** + * Adds the specified attributes. + * + * @param attributes the attributes to add + * @return the operation builder + */ + T attributes(Map attributes); + } + + public interface ClearAttribute { + /** + * Clears all attributes. + * + * @return the operation builder + */ + T clearAttributes(); + + /** + * Clears the attribute with the specified name. + * + * @param name the name of the attribute + * @return the operation builder + */ + T clearAttribute(String name); + } + public abstract static class TableBuilder implements Table { final String namespace; diff --git a/core/src/main/java/com/scalar/db/api/Put.java b/core/src/main/java/com/scalar/db/api/Put.java index 9356f08987..06e594d6c0 100644 --- a/core/src/main/java/com/scalar/db/api/Put.java +++ b/core/src/main/java/com/scalar/db/api/Put.java @@ -52,11 +52,12 @@ public class Put extends Mutation { Key partitionKey, @Nullable Key clusteringKey, @Nullable Consistency consistency, - Map> columns, + ImmutableMap attributes, @Nullable MutationCondition condition, + Map> columns, boolean implicitPreReadEnabled, boolean insertModeEnabled) { - super(namespace, tableName, partitionKey, clusteringKey, consistency, condition); + super(namespace, tableName, partitionKey, clusteringKey, consistency, attributes, condition); this.columns = columns; this.implicitPreReadEnabled = implicitPreReadEnabled; this.insertModeEnabled = insertModeEnabled; @@ -862,9 +863,10 @@ public String toString() { .add("table", forTable()) .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) - .add("columns", getColumns()) .add("consistency", getConsistency()) + .add("attributes", getAttributes()) .add("condition", getCondition()) + .add("columns", getColumns()) .add("implicitPreReadEnabled", isImplicitPreReadEnabled()) .add("insertModeEnabled", isInsertModeEnabled()) .toString(); diff --git a/core/src/main/java/com/scalar/db/api/PutBuilder.java b/core/src/main/java/com/scalar/db/api/PutBuilder.java index 7f42ab3ab6..08e840e5d4 100644 --- a/core/src/main/java/com/scalar/db/api/PutBuilder.java +++ b/core/src/main/java/com/scalar/db/api/PutBuilder.java @@ -2,6 +2,9 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableMap; +import com.scalar.db.api.OperationBuilder.Attribute; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearCondition; import com.scalar.db.api.OperationBuilder.ClearNamespace; @@ -24,6 +27,7 @@ import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; @@ -77,6 +81,7 @@ public Buildable partitionKey(Key partitionKey) { public static class Buildable extends OperationBuilder.Buildable implements ClusteringKey, Consistency, + Attribute, Condition, Values, ImplicitPreReadEnabled, @@ -84,6 +89,7 @@ public static class Buildable extends OperationBuilder.Buildable final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; + final Map attributes = new HashMap<>(); @Nullable MutationCondition condition; boolean implicitPreReadEnabled; boolean insertModeEnabled; @@ -99,6 +105,28 @@ public Buildable clusteringKey(Key clusteringKey) { return this; } + @Override + public Buildable consistency(com.scalar.db.api.Consistency consistency) { + checkNotNull(consistency); + this.consistency = consistency; + return this; + } + + @Override + public Buildable attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public Buildable attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Buildable condition(MutationCondition condition) { checkNotNull(condition); @@ -249,18 +277,12 @@ public Put build() { partitionKey, clusteringKey, consistency, - columns, + ImmutableMap.copyOf(attributes), condition, + columns, implicitPreReadEnabled, insertModeEnabled); } - - @Override - public Buildable consistency(com.scalar.db.api.Consistency consistency) { - checkNotNull(consistency); - this.consistency = consistency; - return this; - } } public static class BuildableFromExisting extends Buildable @@ -270,7 +292,8 @@ public static class BuildableFromExisting extends Buildable ClearClusteringKey, ClearValues, ClearCondition, - ClearNamespace { + ClearNamespace, + ClearAttribute { BuildableFromExisting(Put put) { super(put.forNamespace().orElse(null), put.forTable().orElse(null), put.getPartitionKey()); @@ -278,6 +301,7 @@ public static class BuildableFromExisting extends Buildable this.columns.putAll(put.getColumns()); this.consistency = put.getConsistency(); this.condition = put.getCondition().orElse(null); + this.attributes.putAll(put.getAttributes()); this.implicitPreReadEnabled = put.isImplicitPreReadEnabled(); this.insertModeEnabled = put.isInsertModeEnabled(); } @@ -315,6 +339,18 @@ public BuildableFromExisting consistency(com.scalar.db.api.Consistency consisten return this; } + @Override + public BuildableFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableFromExisting condition(MutationCondition condition) { super.condition(condition); @@ -435,6 +471,18 @@ public BuildableFromExisting clearNamespace() { return this; } + @Override + public BuildableFromExisting clearAttributes() { + attributes.clear(); + return this; + } + + @Override + public BuildableFromExisting clearAttribute(String name) { + attributes.remove(name); + return this; + } + @Override public BuildableFromExisting disableImplicitPreRead() { super.disableImplicitPreRead(); diff --git a/core/src/main/java/com/scalar/db/api/Scan.java b/core/src/main/java/com/scalar/db/api/Scan.java index 9e198d5a17..538d5253de 100644 --- a/core/src/main/java/com/scalar/db/api/Scan.java +++ b/core/src/main/java/com/scalar/db/api/Scan.java @@ -4,6 +4,7 @@ import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.ScanBuilder.BuildableScanOrScanAllFromExisting; import com.scalar.db.api.ScanBuilder.Namespace; @@ -30,11 +31,11 @@ @NotThreadSafe public class Scan extends Selection { - private final List orderings; @Nullable private Key startClusteringKey; private boolean startInclusive; @Nullable private Key endClusteringKey; private boolean endInclusive; + private final List orderings; private int limit; Scan( @@ -42,6 +43,7 @@ public class Scan extends Selection { String tableName, Key partitionKey, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions, @Nullable Key startClusteringKey, @@ -50,7 +52,15 @@ public class Scan extends Selection { boolean endInclusive, List orderings, int limit) { - super(namespace, tableName, partitionKey, null, consistency, projections, conjunctions); + super( + namespace, + tableName, + partitionKey, + null, + consistency, + attributes, + projections, + conjunctions); this.startClusteringKey = startClusteringKey; this.startInclusive = startInclusive; this.endClusteringKey = endClusteringKey; @@ -366,9 +376,10 @@ public String toString() { .add("namespace", forNamespace()) .add("table", forTable()) .add("partitionKey", getPartitionKey()) + .add("consistency", getConsistency()) + .add("attributes", getAttributes()) .add("projections", getProjections()) .add("conjunctions", getConjunctions()) - .add("consistency", getConsistency()) .add("startClusteringKey", startClusteringKey) .add("startInclusive", startInclusive) .add("endClusteringKey", endClusteringKey) diff --git a/core/src/main/java/com/scalar/db/api/ScanAll.java b/core/src/main/java/com/scalar/db/api/ScanAll.java index ec14c5672f..c2c0b7673d 100644 --- a/core/src/main/java/com/scalar/db/api/ScanAll.java +++ b/core/src/main/java/com/scalar/db/api/ScanAll.java @@ -1,5 +1,7 @@ package com.scalar.db.api; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.io.Key; import java.util.Collection; @@ -22,6 +24,7 @@ public class ScanAll extends Scan { String namespace, String tableName, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions, List orderings, @@ -31,6 +34,7 @@ public class ScanAll extends Scan { tableName, DUMMY_PARTITION_KEY, consistency, + attributes, projections, conjunctions, null, @@ -202,4 +206,18 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(super.hashCode()); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("namespace", forNamespace()) + .add("table", forTable()) + .add("consistency", getConsistency()) + .add("attributes", getAttributes()) + .add("projections", getProjections()) + .add("conjunctions", getConjunctions()) + .add("orderings", getOrderings()) + .add("limit", getLimit()) + .toString(); + } } diff --git a/core/src/main/java/com/scalar/db/api/ScanBuilder.java b/core/src/main/java/com/scalar/db/api/ScanBuilder.java index a412b21faf..13e20020f4 100644 --- a/core/src/main/java/com/scalar/db/api/ScanBuilder.java +++ b/core/src/main/java/com/scalar/db/api/ScanBuilder.java @@ -2,10 +2,13 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.OperationBuilder.All; import com.scalar.db.api.OperationBuilder.And; +import com.scalar.db.api.OperationBuilder.Attribute; import com.scalar.db.api.OperationBuilder.Buildable; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearBoundaries; import com.scalar.db.api.OperationBuilder.ClearConditions; import com.scalar.db.api.OperationBuilder.ClearNamespace; @@ -29,8 +32,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -100,7 +105,8 @@ public static class BuildableScan extends Buildable Ordering, Consistency, Projection, - Limit { + Limit, + Attribute { final List orderings = new ArrayList<>(); final List projections = new ArrayList<>(); @Nullable Key startClusteringKey; @@ -109,6 +115,7 @@ public static class BuildableScan extends Buildable boolean endInclusive; int limit = 0; @Nullable com.scalar.db.api.Consistency consistency; + final Map attributes = new HashMap<>(); private BuildableScan(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -193,6 +200,21 @@ public BuildableScan consistency(com.scalar.db.api.Consistency consistency) { return this; } + @Override + public BuildableScan attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public BuildableScan attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Scan build() { return build(ImmutableSet.of()); @@ -204,6 +226,7 @@ private Scan build(ImmutableSet conjunctions) { tableName, partitionKey, consistency, + ImmutableMap.copyOf(attributes), projections, conjunctions, startClusteringKey, @@ -295,6 +318,18 @@ public BuildableScanWithPartitionKey consistency(com.scalar.db.api.Consistency c return this; } + @Override + public BuildableScanWithPartitionKey attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableScanWithPartitionKey attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableScanWithOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -462,13 +497,15 @@ public static class BuildableScanWithIndex OperationBuilder.Where, WhereAnd, WhereOr, - Limit { + Limit, + Attribute { @Nullable private final String namespaceName; private final String tableName; private final Key indexKey; private final List projections = new ArrayList<>(); private int limit = 0; @Nullable private com.scalar.db.api.Consistency consistency; + private final Map attributes = new HashMap<>(); private BuildableScanWithIndex(@Nullable String namespaceName, String tableName, Key indexKey) { this.namespaceName = namespaceName; @@ -508,6 +545,21 @@ public BuildableScanWithIndex consistency(com.scalar.db.api.Consistency consiste return this; } + @Override + public BuildableScanWithIndex attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public BuildableScanWithIndex attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public BuildableScanWithIndexOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -544,7 +596,14 @@ public Scan build() { private Scan build(ImmutableSet conjunctions) { return new ScanWithIndex( - namespaceName, tableName, indexKey, consistency, projections, conjunctions, limit); + namespaceName, + tableName, + indexKey, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions, + limit); } } @@ -657,7 +716,8 @@ public BuildableScanWithIndexOngoingWhereOr or(AndConditionSet andConditionSet) public static class BuildableScanWithIndexWhere implements Consistency, Projection, - Limit { + Limit, + Attribute { BuildableScanWithIndex buildableScanWithIndex; final Where where; @@ -706,6 +766,18 @@ public BuildableScanWithIndexWhere consistency(com.scalar.db.api.Consistency con return this; } + @Override + public BuildableScanWithIndexWhere attribute(String name, String value) { + buildableScanWithIndex = buildableScanWithIndex.attribute(name, value); + return this; + } + + @Override + public BuildableScanWithIndexWhere attributes(Map attributes) { + buildableScanWithIndex = buildableScanWithIndex.attributes(attributes); + return this; + } + public Scan build() { return buildableScanWithIndex.build(getConjunctions(where)); } @@ -718,13 +790,15 @@ public static class BuildableScanAll OperationBuilder.Where, WhereAnd, WhereOr, - Limit { + Limit, + Attribute { private final String namespaceName; private final String tableName; private final List orderings = new ArrayList<>(); private final List projections = new ArrayList<>(); private int limit = 0; @Nullable private com.scalar.db.api.Consistency consistency; + private final Map attributes = new HashMap<>(); private BuildableScanAll(String namespaceName, String tableName) { this.namespaceName = namespaceName; @@ -782,6 +856,21 @@ public BuildableScanAll consistency(com.scalar.db.api.Consistency consistency) { return this; } + @Override + public BuildableScanAll attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public BuildableScanAll attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public BuildableScanAllWithOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -818,7 +907,14 @@ public Scan build() { private Scan build(ImmutableSet conjunctions) { return new ScanAll( - namespaceName, tableName, consistency, projections, conjunctions, orderings, limit); + namespaceName, + tableName, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions, + orderings, + limit); } } @@ -931,7 +1027,8 @@ public static class BuildableScanAllWithWhere implements Consistency, Projection, Ordering, - Limit { + Limit, + Attribute { final BuildableScanAll buildableScanAll; final Where where; @@ -997,6 +1094,18 @@ public BuildableScanAllWithWhere consistency(com.scalar.db.api.Consistency consi return this; } + @Override + public BuildableScanAllWithWhere attribute(String name, String value) { + buildableScanAll.attribute(name, value); + return this; + } + + @Override + public BuildableScanAllWithWhere attributes(Map attributes) { + buildableScanAll.attributes(attributes); + return this; + } + public Scan build() { return buildableScanAll.build(getConjunctions(where)); } @@ -1014,7 +1123,8 @@ public static class BuildableScanOrScanAllFromExisting extends BuildableScan ClearProjections, ClearOrderings, ClearBoundaries, - ClearNamespace { + ClearNamespace, + ClearAttribute { private final boolean isScanWithIndex; private final boolean isScanAll; @@ -1044,6 +1154,7 @@ public static class BuildableScanOrScanAllFromExisting extends BuildableScan orderings.addAll(scan.getOrderings()); projections.addAll(scan.getProjections()); consistency = scan.getConsistency(); + attributes.putAll(scan.getAttributes()); conjunctions.addAll( scan.getConjunctions().stream() .map(Conjunction::getConditions) @@ -1087,6 +1198,18 @@ public BuildableScanOrScanAllFromExisting consistency( return this; } + @Override + public BuildableScanOrScanAllFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableScanOrScanAllFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableScanOrScanAllFromExisting projection(String projection) { super.projection(projection); @@ -1238,6 +1361,19 @@ public BuildableScanOrScanAllFromExisting clearNamespace() { return this; } + @Override + public BuildableScanOrScanAllFromExisting clearAttributes() { + this.attributes.clear(); + return this; + } + + @Override + public BuildableScanOrScanAllFromExisting clearAttribute(String name) { + checkNotNull(name); + attributes.remove(name); + return this; + } + private void checkNotScanWithIndexOrScanAll() { if (isScanWithIndex || isScanAll) { throw new UnsupportedOperationException( @@ -1282,16 +1418,31 @@ public Scan build() { private Scan build(ImmutableSet conjunctions) { if (isScanWithIndex) { return new ScanWithIndex( - namespaceName, tableName, indexKey, consistency, projections, conjunctions, limit); + namespaceName, + tableName, + indexKey, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions, + limit); } else if (isScanAll) { return new ScanAll( - namespaceName, tableName, consistency, projections, conjunctions, orderings, limit); + namespaceName, + tableName, + consistency, + ImmutableMap.copyOf(attributes), + projections, + conjunctions, + orderings, + limit); } else { return new Scan( namespaceName, tableName, partitionKey, consistency, + ImmutableMap.copyOf(attributes), projections, conjunctions, startClusteringKey, @@ -1314,9 +1465,11 @@ public static class BuildableScanFromExistingWithWhere Projection, Ordering, Limit, + Attribute, ClearProjections, ClearOrderings, - ClearNamespace { + ClearNamespace, + ClearAttribute { private final BuildableScanOrScanAllFromExisting buildableScanFromExisting; final Where where; @@ -1419,6 +1572,18 @@ public BuildableScanFromExistingWithWhere consistency( return this; } + @Override + public BuildableScanFromExistingWithWhere attribute(String name, String value) { + buildableScanFromExisting.attribute(name, value); + return this; + } + + @Override + public BuildableScanFromExistingWithWhere attributes(Map attributes) { + buildableScanFromExisting.attributes(attributes); + return this; + } + @Override public BuildableScanFromExistingWithWhere clearProjections() { buildableScanFromExisting.clearProjections(); @@ -1437,6 +1602,18 @@ public BuildableScanFromExistingWithWhere clearNamespace() { return this; } + @Override + public BuildableScanFromExistingWithWhere clearAttributes() { + buildableScanFromExisting.clearAttributes(); + return this; + } + + @Override + public BuildableScanFromExistingWithWhere clearAttribute(String name) { + buildableScanFromExisting.clearAttribute(name); + return this; + } + public Scan build() { return buildableScanFromExisting.build(getConjunctions(where)); } diff --git a/core/src/main/java/com/scalar/db/api/ScanWithIndex.java b/core/src/main/java/com/scalar/db/api/ScanWithIndex.java index ffc4459616..769fc9f3cf 100644 --- a/core/src/main/java/com/scalar/db/api/ScanWithIndex.java +++ b/core/src/main/java/com/scalar/db/api/ScanWithIndex.java @@ -1,6 +1,8 @@ package com.scalar.db.api; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.io.Key; import java.util.Collection; @@ -21,6 +23,7 @@ public class ScanWithIndex extends Scan { String tableName, Key indexKey, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions, int limit) { @@ -29,6 +32,7 @@ public class ScanWithIndex extends Scan { tableName, indexKey, consistency, + attributes, projections, conjunctions, null, @@ -198,4 +202,18 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(super.hashCode()); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("namespace", forNamespace()) + .add("table", forTable()) + .add("indexKey", getPartitionKey()) + .add("consistency", getConsistency()) + .add("attributes", getAttributes()) + .add("projections", getProjections()) + .add("conjunctions", getConjunctions()) + .add("limit", getLimit()) + .toString(); + } } diff --git a/core/src/main/java/com/scalar/db/api/Selection.java b/core/src/main/java/com/scalar/db/api/Selection.java index 84c21c7293..b8ebe117c1 100644 --- a/core/src/main/java/com/scalar/db/api/Selection.java +++ b/core/src/main/java/com/scalar/db/api/Selection.java @@ -1,6 +1,7 @@ package com.scalar.db.api; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.io.Key; import java.util.ArrayList; @@ -29,9 +30,10 @@ public abstract class Selection extends Operation { Key partitionKey, @Nullable Key clusteringKey, @Nullable Consistency consistency, + ImmutableMap attributes, List projections, ImmutableSet conjunctions) { - super(namespace, tableName, partitionKey, clusteringKey, consistency); + super(namespace, tableName, partitionKey, clusteringKey, consistency, attributes); this.projections = projections; this.conjunctions = conjunctions; } diff --git a/core/src/main/java/com/scalar/db/api/Update.java b/core/src/main/java/com/scalar/db/api/Update.java index 5014b2351d..5bbea1edaf 100644 --- a/core/src/main/java/com/scalar/db/api/Update.java +++ b/core/src/main/java/com/scalar/db/api/Update.java @@ -24,9 +24,10 @@ public class Update extends Mutation { String tableName, Key partitionKey, @Nullable Key clusteringKey, - ImmutableMap> columns, - @Nullable MutationCondition condition) { - super(namespace, tableName, partitionKey, clusteringKey, null, condition); + ImmutableMap attributes, + @Nullable MutationCondition condition, + ImmutableMap> columns) { + super(namespace, tableName, partitionKey, clusteringKey, null, attributes, condition); this.columns = columns; } @@ -97,8 +98,9 @@ public String toString() { .add("table", forTable()) .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) - .add("columns", getColumns()) + .add("attributes", getAttributes()) .add("condition", getCondition()) + .add("columns", getColumns()) .toString(); } diff --git a/core/src/main/java/com/scalar/db/api/UpdateBuilder.java b/core/src/main/java/com/scalar/db/api/UpdateBuilder.java index 561a479cf8..3b9d1fdf03 100644 --- a/core/src/main/java/com/scalar/db/api/UpdateBuilder.java +++ b/core/src/main/java/com/scalar/db/api/UpdateBuilder.java @@ -3,6 +3,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableMap; +import com.scalar.db.api.OperationBuilder.Attribute; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearCondition; import com.scalar.db.api.OperationBuilder.ClearNamespace; @@ -22,6 +24,7 @@ import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; @@ -73,10 +76,14 @@ public Buildable partitionKey(Key partitionKey) { } public static class Buildable extends OperationBuilder.Buildable - implements ClusteringKey, Condition, Values { + implements ClusteringKey, + Condition, + Values, + Attribute { final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; @Nullable MutationCondition condition; + final Map attributes = new HashMap<>(); private Buildable(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -89,6 +96,21 @@ public Buildable clusteringKey(Key clusteringKey) { return this; } + @Override + public Buildable attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public Buildable attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Buildable condition(MutationCondition condition) { checkNotNull(condition); @@ -202,8 +224,9 @@ public Update build() { tableName, partitionKey, clusteringKey, - ImmutableMap.copyOf(columns), - condition); + ImmutableMap.copyOf(attributes), + condition, + ImmutableMap.copyOf(columns)); } } @@ -214,7 +237,8 @@ public static class BuildableFromExisting extends Buildable ClearClusteringKey, ClearValues, ClearCondition, - ClearNamespace { + ClearNamespace, + ClearAttribute { BuildableFromExisting(Update update) { super( @@ -224,6 +248,7 @@ public static class BuildableFromExisting extends Buildable this.clusteringKey = update.getClusteringKey().orElse(null); this.columns.putAll(update.getColumns()); this.condition = update.getCondition().orElse(null); + this.attributes.putAll(update.getAttributes()); } @Override @@ -253,6 +278,18 @@ public BuildableFromExisting clusteringKey(Key clusteringKey) { return this; } + @Override + public BuildableFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableFromExisting condition(MutationCondition condition) { super.condition(condition); @@ -372,5 +409,17 @@ public BuildableFromExisting clearNamespace() { this.namespaceName = null; return this; } + + @Override + public BuildableFromExisting clearAttributes() { + attributes.clear(); + return this; + } + + @Override + public BuildableFromExisting clearAttribute(String name) { + attributes.remove(name); + return this; + } } } diff --git a/core/src/main/java/com/scalar/db/api/Upsert.java b/core/src/main/java/com/scalar/db/api/Upsert.java index ef3f25e7b0..fde8bb8eac 100644 --- a/core/src/main/java/com/scalar/db/api/Upsert.java +++ b/core/src/main/java/com/scalar/db/api/Upsert.java @@ -24,8 +24,9 @@ public class Upsert extends Mutation { String tableName, Key partitionKey, @Nullable Key clusteringKey, + ImmutableMap attributes, ImmutableMap> columns) { - super(namespace, tableName, partitionKey, clusteringKey, null, null); + super(namespace, tableName, partitionKey, clusteringKey, null, attributes, null); this.columns = columns; } @@ -105,6 +106,7 @@ public String toString() { .add("table", forTable()) .add("partitionKey", getPartitionKey()) .add("clusteringKey", getClusteringKey()) + .add("attributes", getAttributes()) .add("columns", getColumns()) .toString(); } diff --git a/core/src/main/java/com/scalar/db/api/UpsertBuilder.java b/core/src/main/java/com/scalar/db/api/UpsertBuilder.java index deace621dd..f5d7189c94 100644 --- a/core/src/main/java/com/scalar/db/api/UpsertBuilder.java +++ b/core/src/main/java/com/scalar/db/api/UpsertBuilder.java @@ -3,6 +3,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableMap; +import com.scalar.db.api.OperationBuilder.Attribute; +import com.scalar.db.api.OperationBuilder.ClearAttribute; import com.scalar.db.api.OperationBuilder.ClearClusteringKey; import com.scalar.db.api.OperationBuilder.ClearNamespace; import com.scalar.db.api.OperationBuilder.ClearValues; @@ -20,6 +22,7 @@ import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; @@ -71,9 +74,10 @@ public Buildable partitionKey(Key partitionKey) { } public static class Buildable extends OperationBuilder.Buildable - implements ClusteringKey, Values { + implements ClusteringKey, Values, Attribute { final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; + final Map attributes = new HashMap<>(); private Buildable(@Nullable String namespace, String table, Key partitionKey) { super(namespace, table, partitionKey); @@ -86,6 +90,21 @@ public Buildable clusteringKey(Key clusteringKey) { return this; } + @Override + public Buildable attribute(String name, String value) { + checkNotNull(name); + checkNotNull(value); + attributes.put(name, value); + return this; + } + + @Override + public Buildable attributes(Map attributes) { + checkNotNull(attributes); + this.attributes.putAll(attributes); + return this; + } + @Override public Buildable booleanValue(String columnName, boolean value) { columns.put(columnName, BooleanColumn.of(columnName, value)); @@ -188,7 +207,12 @@ public Buildable value(Column column) { @Override public Upsert build() { return new Upsert( - namespaceName, tableName, partitionKey, clusteringKey, ImmutableMap.copyOf(columns)); + namespaceName, + tableName, + partitionKey, + clusteringKey, + ImmutableMap.copyOf(attributes), + ImmutableMap.copyOf(columns)); } } @@ -198,7 +222,8 @@ public static class BuildableFromExisting extends Buildable OperationBuilder.PartitionKey, ClearClusteringKey, ClearValues, - ClearNamespace { + ClearNamespace, + ClearAttribute { BuildableFromExisting(Upsert upsert) { super( @@ -207,6 +232,7 @@ public static class BuildableFromExisting extends Buildable upsert.getPartitionKey()); this.clusteringKey = upsert.getClusteringKey().orElse(null); this.columns.putAll(upsert.getColumns()); + this.attributes.putAll(upsert.getAttributes()); } @Override @@ -236,6 +262,18 @@ public BuildableFromExisting clusteringKey(Key clusteringKey) { return this; } + @Override + public BuildableFromExisting attribute(String name, String value) { + super.attribute(name, value); + return this; + } + + @Override + public BuildableFromExisting attributes(Map attributes) { + super.attributes(attributes); + return this; + } + @Override public BuildableFromExisting booleanValue(String columnName, boolean value) { super.booleanValue(columnName, value); @@ -343,5 +381,17 @@ public BuildableFromExisting clearNamespace() { this.namespaceName = null; return this; } + + @Override + public BuildableFromExisting clearAttributes() { + attributes.clear(); + return this; + } + + @Override + public BuildableFromExisting clearAttribute(String name) { + attributes.remove(name); + return this; + } } } diff --git a/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java b/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java index 7a62efdb01..c704c8169e 100644 --- a/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Key; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -63,16 +64,21 @@ public void build_WithAllParameters_ShouldBuildDeleteWithAllParameters() { .clusteringKey(clusteringKey1) .consistency(Consistency.EVENTUAL) .condition(condition1) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert assertThat(delete) .isEqualTo( - new Delete(partitionKey1, clusteringKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withCondition(condition1) - .withConsistency(Consistency.EVENTUAL)); + new Delete( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + condition1)); } @Test @@ -96,11 +102,14 @@ public void build_FromExistingWithoutChange_ShouldCopy() { public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdatedParameters() { // Arrange Delete existingDelete = - new Delete(partitionKey1, clusteringKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withCondition(condition1) - .withConsistency(Consistency.LINEARIZABLE); + new Delete( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.LINEARIZABLE, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + condition1); // Act Delete newDelete = @@ -111,16 +120,23 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdate .table(TABLE_2) .consistency(Consistency.EVENTUAL) .condition(condition2) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert assertThat(newDelete) .isEqualTo( - new Delete(partitionKey2, clusteringKey2) - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withConsistency(Consistency.EVENTUAL) - .withCondition(condition2)); + new Delete( + NAMESPACE_2, + TABLE_2, + partitionKey2, + clusteringKey2, + Consistency.EVENTUAL, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + condition2)); } @Test diff --git a/core/src/test/java/com/scalar/db/api/DeleteTest.java b/core/src/test/java/com/scalar/db/api/DeleteTest.java index 7c022aa3ff..e2840c2a2d 100644 --- a/core/src/test/java/com/scalar/db/api/DeleteTest.java +++ b/core/src/test/java/com/scalar/db/api/DeleteTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Key; import com.scalar.db.io.Value; import java.util.Optional; @@ -137,4 +138,24 @@ public void equals_SameDeleteWithDeleteIfExistsGiven_ShouldReturnTrue() { assertThat(ret).isTrue(); assertThat(delete.hashCode()).isEqualTo(another.hashCode()); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Delete delete = + Delete.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(delete.getAttribute("a1")).hasValue("v1"); + assertThat(delete.getAttribute("a2")).hasValue("v2"); + assertThat(delete.getAttribute("a3")).hasValue("v3"); + assertThat(delete.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/GetBuilderTest.java b/core/src/test/java/com/scalar/db/api/GetBuilderTest.java index 8ff61006db..e4a9bbd1a0 100644 --- a/core/src/test/java/com/scalar/db/api/GetBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/GetBuilderTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.Selection.Conjunction; import com.scalar.db.io.Key; @@ -73,16 +74,22 @@ public void buildGet_WithClusteringKey_ShouldBuildGetWithClusteringKey() { .projection("c2") .projections(Arrays.asList("c3", "c4")) .projections("c5", "c6") + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert assertThat(get) .isEqualTo( - new Get(partitionKey1, clusteringKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withProjections(Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6")) - .withConsistency(Consistency.EVENTUAL)); + new Get( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6"), + ImmutableSet.of())); } @Test @@ -105,6 +112,8 @@ public void buildGet_WithConjunctiveNormalForm_ShouldBuildGetWithConditionsCorre .projection("ck2") .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get get2 = Get.newBuilder() @@ -123,6 +132,8 @@ public void buildGet_WithConjunctiveNormalForm_ShouldBuildGetWithConditionsCorre .projection("ck2") .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get get3 = Get.newBuilder() @@ -141,6 +152,8 @@ public void buildGet_WithConjunctiveNormalForm_ShouldBuildGetWithConditionsCorre .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get get4 = Get.newBuilder() @@ -159,6 +172,8 @@ public void buildGet_WithConjunctiveNormalForm_ShouldBuildGetWithConditionsCorre .or(ConditionBuilder.column("ck4").isGreaterThanInt(10)) .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -169,6 +184,7 @@ public void buildGet_WithConjunctiveNormalForm_ShouldBuildGetWithConditionsCorre partitionKey1, clusteringKey1, Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -217,6 +233,7 @@ public void buildGet_WithConditionAndConditionSet_ShouldBuildGetWithConditionsCo partitionKey1, null, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -313,6 +330,7 @@ public void buildGet_WithDisjunctiveNormalForm_ShouldBuildGetWithConditionsCorre partitionKey1, clusteringKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -352,6 +370,7 @@ public void buildGet_FromExistingAndAddTwoOrConditions_ShouldBuildGetWithUpdated partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -387,6 +406,7 @@ public void buildGet_WithConditionOrConditionSet_ShouldBuildGetWithConditionsCor partitionKey1, null, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -427,6 +447,7 @@ public void buildGet_WithTwoOrConditionSet_ShouldBuildGetWithConditionsCorrectly partitionKey1, null, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -470,6 +491,7 @@ public void buildGet_WithOrConditionSets_ShouldBuildGetWithConditionsCorrectly() partitionKey1, null, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -513,6 +535,7 @@ public void buildGet_WithAndConditionSets_ShouldBuildGetWithConditionsCorrectly( partitionKey1, null, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -611,6 +634,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey1, clusteringKey1, Consistency.LINEARIZABLE, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), Arrays.asList("c1", "c2"), ImmutableSet.of( Conjunction.of( @@ -632,6 +656,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .projections(Arrays.asList("c3", "c4")) .projection("c5") .projections("c6", "c7") + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -643,6 +671,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey2, clusteringKey2, Consistency.EVENTUAL, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("c3", "c4", "c5", "c6", "c7"), ImmutableSet.of( Conjunction.of( @@ -666,6 +695,8 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .where(ConditionBuilder.column("pk1").isGreaterThanInt(10)) .projection("pk1") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get expected = new Get( @@ -674,6 +705,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey2, clusteringKey2, Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -707,6 +739,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet2 = Get.newBuilder(get) @@ -727,6 +763,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet3 = Get.newBuilder(get) @@ -747,6 +787,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet4 = Get.newBuilder(get) @@ -767,6 +811,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet5 = Get.newBuilder(get) @@ -787,6 +835,10 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .or(ConditionBuilder.column("ck4").isGreaterThanInt(10)) .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -826,6 +878,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -867,6 +920,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -906,6 +960,7 @@ public void buildGet_FromExistingAndAddTwoAndConditionSet_ShouldBuildGetWithUpda partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -952,6 +1007,7 @@ public void buildGet_FromExistingAndAddTwoOrConditionSet_ShouldBuildGetWithUpdat partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -994,6 +1050,7 @@ public void buildGet_FromExistingWithOrConditionSets_ShouldBuildGetWithUpdatedPa partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -1036,6 +1093,7 @@ public void buildGet_FromExistingWithAndConditionSets_ShouldBuildGetWithUpdatedP partitionKey1, null, Consistency.SEQUENTIAL, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -1069,6 +1127,7 @@ public void buildGet_FromExistingWithAndConditionSets_ShouldBuildGetWithUpdatedP partitionKey1, null, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))))); @@ -1097,6 +1156,7 @@ public void buildGet_FromExistingAndClearNamespaceAfterWhere_ShouldBuildGetWitho partitionKey1, null, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))))); @@ -1168,16 +1228,21 @@ public void buildGetWithIndex_WithMandatoryParameters_ShouldBuildGetWithMandator .projection("c2") .projections(Arrays.asList("c3", "c4")) .projections("c5", "c6") + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert assertThat(get) .isEqualTo( - new GetWithIndex(indexKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withProjections(Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6")) - .withConsistency(Consistency.EVENTUAL)); + new GetWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6"), + ImmutableSet.of())); } @Test @@ -1199,6 +1264,8 @@ public void buildGetWithIndex_WithConjunctiveNormalForm_ShouldBuildGetWithCondit .projection("ck2") .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get get2 = Get.newBuilder() @@ -1216,6 +1283,8 @@ public void buildGetWithIndex_WithConjunctiveNormalForm_ShouldBuildGetWithCondit .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get get3 = Get.newBuilder() @@ -1233,6 +1302,8 @@ public void buildGetWithIndex_WithConjunctiveNormalForm_ShouldBuildGetWithCondit .or(ConditionBuilder.column("ck4").isGreaterThanInt(10)) .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -1242,6 +1313,7 @@ public void buildGetWithIndex_WithConjunctiveNormalForm_ShouldBuildGetWithCondit TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1289,6 +1361,7 @@ public void buildGetWithIndex_WithConjunctiveNormalForm_ShouldBuildGetWithCondit TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1363,6 +1436,7 @@ public void buildGetWithIndex_WithDisjunctiveNormalForm_ShouldBuildGetWithCondit TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -1406,6 +1480,7 @@ public void buildGetWithIndex_WithDisjunctiveNormalForm_ShouldBuildGetWithCondit TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -1445,6 +1520,7 @@ public void buildGetWithIndex_WithTwoOrConditionSet_ShouldBuildGetWithConditions TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1487,6 +1563,7 @@ public void buildGetWithIndex_WithOrConditionSets_ShouldBuildGetWithConditionsCo TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1529,6 +1606,7 @@ public void buildGetWithIndex_WithAndConditionSets_ShouldBuildGetWithConditionsC TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1629,11 +1707,14 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { buildGetWithIndex_FromExistingAndUpdateAllParameters_ShouldBuildGetWithUpdatedParameters() { // Arrange GetWithIndex existingGet = - new GetWithIndex(indexKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withProjections(Arrays.asList("c1", "c2")) - .withConsistency(Consistency.LINEARIZABLE); + new GetWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("c1", "c2"), + ImmutableSet.of()); // Act Get newGet = @@ -1646,16 +1727,23 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .projections(Arrays.asList("c3", "c4")) .projection("c5") .projections("c6", "c7") + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert assertThat(newGet) .isEqualTo( - new GetWithIndex(indexKey2) - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withConsistency(Consistency.EVENTUAL) - .withProjections(Arrays.asList("c3", "c4", "c5", "c6", "c7"))); + new GetWithIndex( + NAMESPACE_2, + TABLE_2, + indexKey2, + Consistency.EVENTUAL, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + Arrays.asList("c3", "c4", "c5", "c6", "c7"), + ImmutableSet.of())); } @Test @@ -1670,6 +1758,8 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .where(ConditionBuilder.column("pk1").isGreaterThanInt(10)) .projection("pk1") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Get expected = new GetWithIndex( @@ -1677,6 +1767,7 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { TABLE_2, indexKey2, Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -1709,6 +1800,10 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet2 = Get.newBuilder(get) @@ -1728,6 +1823,10 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Get newGet3 = Get.newBuilder(get) @@ -1747,6 +1846,10 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .or(ConditionBuilder.column("ck4").isGreaterThanInt(10)) .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert diff --git a/core/src/test/java/com/scalar/db/api/GetTest.java b/core/src/test/java/com/scalar/db/api/GetTest.java index 342c9a2239..1e9503880a 100644 --- a/core/src/test/java/com/scalar/db/api/GetTest.java +++ b/core/src/test/java/com/scalar/db/api/GetTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Key; import com.scalar.db.io.Value; import java.util.Arrays; @@ -267,4 +268,37 @@ public void equals_AnotherOperationGiven_ShouldReturnFalse() { // Assert assertThat(ret).isFalse(); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Get get = + Get.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + Get getWithIndex = + Get.newBuilder() + .namespace("ns") + .table("tbl") + .indexKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(get.getAttribute("a1")).hasValue("v1"); + assertThat(get.getAttribute("a2")).hasValue("v2"); + assertThat(get.getAttribute("a3")).hasValue("v3"); + assertThat(get.getAttributes()).isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + + assertThat(getWithIndex.getAttribute("a1")).hasValue("v1"); + assertThat(getWithIndex.getAttribute("a2")).hasValue("v2"); + assertThat(getWithIndex.getAttribute("a3")).hasValue("v3"); + assertThat(getWithIndex.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/InsertBuilderTest.java b/core/src/test/java/com/scalar/db/api/InsertBuilderTest.java index 3d0363a4f8..895e3eb751 100644 --- a/core/src/test/java/com/scalar/db/api/InsertBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/InsertBuilderTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.BigIntColumn; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -84,6 +85,8 @@ public void build_WithAllParameters_ShouldBuildInsertCorrectly() { .intValue("int2", Integer.valueOf(Integer.MAX_VALUE)) .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -113,6 +116,8 @@ public void build_WithAllParameters_ShouldBuildInsertCorrectly() { .isEqualTo(Integer.valueOf(Integer.MAX_VALUE)); assertThat(actual.getColumns().get("text").getTextValue()).isEqualTo("a_value"); assertThat(actual.getColumns().get("text2").getTextValue()).isEqualTo("another_value"); + assertThat(actual.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); } @Test @@ -225,6 +230,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildInsertWithUpdate .intValue("int2", Integer.valueOf(Integer.MAX_VALUE)) .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Act @@ -249,6 +256,10 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildInsertWithUpdate .intValue("int2", Integer.valueOf(Integer.MIN_VALUE)) .textValue("text", "another_value") .value(TextColumn.of("text2", "foo")) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -278,6 +289,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildInsertWithUpdate .isEqualTo(Integer.valueOf(Integer.MIN_VALUE)); assertThat(newInsert.getColumns().get("text").getTextValue()).isEqualTo("another_value"); assertThat(newInsert.getColumns().get("text2").getTextValue()).isEqualTo("foo"); + assertThat(newInsert.getAttributes()) + .isEqualTo(ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6")); } @Test diff --git a/core/src/test/java/com/scalar/db/api/InsertTest.java b/core/src/test/java/com/scalar/db/api/InsertTest.java index 145b653a56..e05e4fb1ba 100644 --- a/core/src/test/java/com/scalar/db/api/InsertTest.java +++ b/core/src/test/java/com/scalar/db/api/InsertTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Column; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -151,4 +152,24 @@ public void equals_InsertWithDifferentValuesGiven_ShouldReturnFalse() { assertThat(ret).isFalse(); assertThat(insert.hashCode()).isNotEqualTo(another.hashCode()); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Insert insert = + Insert.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(insert.getAttribute("a1")).hasValue("v1"); + assertThat(insert.getAttribute("a2")).hasValue("v2"); + assertThat(insert.getAttribute("a3")).hasValue("v3"); + assertThat(insert.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/PutBuilderTest.java b/core/src/test/java/com/scalar/db/api/PutBuilderTest.java index 2a0f9be3ee..4737de6fe2 100644 --- a/core/src/test/java/com/scalar/db/api/PutBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/PutBuilderTest.java @@ -2,7 +2,14 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.BigIntColumn; +import com.scalar.db.io.BlobColumn; +import com.scalar.db.io.BooleanColumn; +import com.scalar.db.io.Column; +import com.scalar.db.io.DoubleColumn; +import com.scalar.db.io.FloatColumn; +import com.scalar.db.io.IntColumn; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; @@ -78,9 +85,11 @@ public void build_WithAllParameters_ShouldBuildPutCorrectly() { .floatValue("float2", Float.valueOf(Float.MAX_VALUE)) .intValue("int1", Integer.MAX_VALUE) .intValue("int2", Integer.valueOf(Integer.MAX_VALUE)) - .textValue("text", "a_value") + .textValue("text1", "a_value") .value(TextColumn.of("text2", "another_value")) .condition(condition1) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .disableImplicitPreRead() .disableInsertMode() .build(); @@ -88,27 +97,32 @@ public void build_WithAllParameters_ShouldBuildPutCorrectly() { // Assert assertThat(put) .isEqualTo( - new Put(partitionKey1, clusteringKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withBigIntValue("bigint1", BigIntColumn.MAX_VALUE) - .withBigIntValue("bigint2", Long.valueOf(BigIntColumn.MAX_VALUE)) - .withBlobValue("blob1", "blob".getBytes(StandardCharsets.UTF_8)) - .withBlobValue("blob2", ByteBuffer.allocate(1)) - .withBooleanValue("bool1", true) - .withBooleanValue("bool2", Boolean.TRUE) - .withDoubleValue("double1", Double.MAX_VALUE) - .withDoubleValue("double2", Double.valueOf(Double.MAX_VALUE)) - .withFloatValue("float1", Float.MAX_VALUE) - .withFloatValue("float2", Float.valueOf(Float.MAX_VALUE)) - .withIntValue("int1", Integer.MAX_VALUE) - .withIntValue("int2", Integer.valueOf(Integer.MAX_VALUE)) - .withTextValue("text", "a_value") - .withValue(TextColumn.of("text2", "another_value")) - .withCondition(condition1) - .setImplicitPreReadEnabled(false) - .setInsertModeEnabled(false)); + new Put( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + condition1, + ImmutableMap.>builder() + .put("bigint1", BigIntColumn.of("bigint1", BigIntColumn.MAX_VALUE)) + .put("bigint2", BigIntColumn.of("bigint2", BigIntColumn.MAX_VALUE)) + .put("blob1", BlobColumn.of("blob1", "blob".getBytes(StandardCharsets.UTF_8))) + .put("blob2", BlobColumn.of("blob2", ByteBuffer.allocate(1))) + .put("bool1", BooleanColumn.of("bool1", true)) + .put("bool2", BooleanColumn.of("bool2", true)) + .put("double1", DoubleColumn.of("double1", Double.MAX_VALUE)) + .put("double2", DoubleColumn.of("double2", Double.MAX_VALUE)) + .put("float1", FloatColumn.of("float1", Float.MAX_VALUE)) + .put("float2", FloatColumn.of("float2", Float.MAX_VALUE)) + .put("int1", IntColumn.of("int1", Integer.MAX_VALUE)) + .put("int2", IntColumn.of("int2", Integer.MAX_VALUE)) + .put("text1", TextColumn.of("text1", "a_value")) + .put("text2", TextColumn.of("text2", "another_value")) + .build(), + false, + false)); } @Test @@ -202,25 +216,32 @@ public void build_FromExistingWithoutChange_ShouldCopy() { public void build_FromExistingAndUpdateAllParameters_ShouldBuildPutWithUpdatedParameters() { // Arrange Put existingPut = - new Put(partitionKey1, clusteringKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withBigIntValue("bigint1", BigIntColumn.MAX_VALUE) - .withBigIntValue("bigint2", Long.valueOf(BigIntColumn.MAX_VALUE)) - .withBlobValue("blob1", "blob".getBytes(StandardCharsets.UTF_8)) - .withBlobValue("blob2", ByteBuffer.allocate(1)) - .withBooleanValue("bool1", true) - .withBooleanValue("bool2", Boolean.TRUE) - .withDoubleValue("double1", Double.MAX_VALUE) - .withDoubleValue("double2", Double.valueOf(Double.MAX_VALUE)) - .withFloatValue("float1", Float.MAX_VALUE) - .withFloatValue("float2", Float.valueOf(Float.MAX_VALUE)) - .withIntValue("int1", Integer.MAX_VALUE) - .withIntValue("int2", Integer.valueOf(Integer.MAX_VALUE)) - .withTextValue("text", "a_value") - .withValue(TextColumn.of("text2", "another_value")) - .withCondition(condition1); + new Put( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + condition1, + ImmutableMap.>builder() + .put("bigint1", BigIntColumn.of("bigint1", BigIntColumn.MAX_VALUE)) + .put("bigint2", BigIntColumn.of("bigint2", BigIntColumn.MAX_VALUE)) + .put("blob1", BlobColumn.of("blob1", "blob".getBytes(StandardCharsets.UTF_8))) + .put("blob2", BlobColumn.of("blob2", ByteBuffer.allocate(1))) + .put("bool1", BooleanColumn.of("bool1", true)) + .put("bool2", BooleanColumn.of("bool2", true)) + .put("double1", DoubleColumn.of("double1", Double.MAX_VALUE)) + .put("double2", DoubleColumn.of("double2", Double.MAX_VALUE)) + .put("float1", FloatColumn.of("float1", Float.MAX_VALUE)) + .put("float2", FloatColumn.of("float2", Float.MAX_VALUE)) + .put("int1", IntColumn.of("int1", Integer.MAX_VALUE)) + .put("int2", IntColumn.of("int2", Integer.MAX_VALUE)) + .put("text1", TextColumn.of("text1", "a_value")) + .put("text2", TextColumn.of("text2", "another_value")) + .build(), + false, + false); // Act Put newPut = @@ -243,9 +264,13 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildPutWithUpdatedPa .floatValue("float2", Float.valueOf(Float.MIN_VALUE)) .intValue("int1", Integer.MIN_VALUE) .intValue("int2", Integer.valueOf(Integer.MIN_VALUE)) - .textValue("text", "another_value") + .textValue("text1", "another_value") .value(TextColumn.of("text2", "foo")) .condition(condition2) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .enableImplicitPreRead() .enableInsertMode() .build(); @@ -253,27 +278,32 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildPutWithUpdatedPa // Assert assertThat(newPut) .isEqualTo( - new Put(partitionKey2, clusteringKey2) - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withConsistency(Consistency.LINEARIZABLE) - .withBigIntValue("bigint1", BigIntColumn.MIN_VALUE) - .withBigIntValue("bigint2", Long.valueOf(BigIntColumn.MIN_VALUE)) - .withBlobValue("blob1", "foo".getBytes(StandardCharsets.UTF_8)) - .withBlobValue("blob2", ByteBuffer.allocate(2)) - .withBooleanValue("bool1", false) - .withBooleanValue("bool2", Boolean.FALSE) - .withDoubleValue("double1", Double.MIN_VALUE) - .withDoubleValue("double2", Double.valueOf(Double.MIN_VALUE)) - .withFloatValue("float1", Float.MIN_VALUE) - .withFloatValue("float2", Float.valueOf(Float.MIN_VALUE)) - .withIntValue("int1", Integer.MIN_VALUE) - .withIntValue("int2", Integer.valueOf(Integer.MIN_VALUE)) - .withTextValue("text", "another_value") - .withTextValue("text2", "foo") - .withCondition(condition2) - .setImplicitPreReadEnabled(true) - .setInsertModeEnabled(true)); + new Put( + NAMESPACE_2, + TABLE_2, + partitionKey2, + clusteringKey2, + Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + condition2, + ImmutableMap.>builder() + .put("bigint1", BigIntColumn.of("bigint1", BigIntColumn.MIN_VALUE)) + .put("bigint2", BigIntColumn.of("bigint2", BigIntColumn.MIN_VALUE)) + .put("blob1", BlobColumn.of("blob1", "foo".getBytes(StandardCharsets.UTF_8))) + .put("blob2", BlobColumn.of("blob2", ByteBuffer.allocate(2))) + .put("bool1", BooleanColumn.of("bool1", false)) + .put("bool2", BooleanColumn.of("bool2", false)) + .put("double1", DoubleColumn.of("double1", Double.MIN_VALUE)) + .put("double2", DoubleColumn.of("double2", Double.MIN_VALUE)) + .put("float1", FloatColumn.of("float1", Float.MIN_VALUE)) + .put("float2", FloatColumn.of("float2", Float.MIN_VALUE)) + .put("int1", IntColumn.of("int1", Integer.MIN_VALUE)) + .put("int2", IntColumn.of("int2", Integer.MIN_VALUE)) + .put("text1", TextColumn.of("text1", "another_value")) + .put("text2", TextColumn.of("text2", "foo")) + .build(), + true, + true)); } @Test diff --git a/core/src/test/java/com/scalar/db/api/PutTest.java b/core/src/test/java/com/scalar/db/api/PutTest.java index 0ea6dcdb09..203f6a90de 100644 --- a/core/src/test/java/com/scalar/db/api/PutTest.java +++ b/core/src/test/java/com/scalar/db/api/PutTest.java @@ -618,4 +618,23 @@ public void equals_PutWithDifferentInsertModeGiven_ShouldReturnFalse() { assertThat(ret).isFalse(); assertThat(put.hashCode()).isNotEqualTo(another.hashCode()); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Put put = + Put.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(put.getAttribute("a1")).hasValue("v1"); + assertThat(put.getAttribute("a2")).hasValue("v2"); + assertThat(put.getAttribute("a3")).hasValue("v3"); + assertThat(put.getAttributes()).isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java b/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java index 3d83d2c56a..32b7b159f1 100644 --- a/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.scalar.db.api.Selection.Conjunction; import com.scalar.db.io.Key; @@ -99,24 +100,27 @@ public void buildScan_ScanWithAllParameters_ShouldBuildScanCorrectly() { .projection("ck2") .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert assertThat(scan) .isEqualTo( - new Scan(partitionKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withStart(startClusteringKey1) - .withEnd(endClusteringKey1) - .withOrdering(ordering1) - .withOrdering(ordering2) - .withOrdering(ordering3) - .withOrdering(ordering4) - .withOrdering(ordering5) - .withLimit(10) - .withProjections(Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"))); + new Scan( + NAMESPACE_1, + TABLE_1, + partitionKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), + ImmutableSet.of(), + startClusteringKey1, + true, + endClusteringKey1, + true, + Arrays.asList(ordering1, ordering2, ordering3, ordering4, ordering5), + 10)); } @Test @@ -198,16 +202,20 @@ public void buildScan_FromExistingWithoutChange_ShouldCopy() { public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange Scan existingScan = - new Scan(partitionKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withStart(startClusteringKey1) - .withEnd(endClusteringKey1) - .withOrdering(ordering1) - .withOrdering(ordering2) - .withLimit(10) - .withProjections(Arrays.asList("pk1", "ck1", "ck2")); + new Scan( + NAMESPACE_1, + TABLE_1, + partitionKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("pk1", "ck1", "ck2"), + ImmutableSet.of(), + startClusteringKey1, + true, + endClusteringKey1, + true, + Arrays.asList(ordering1, ordering2), + 10); // Act Scan newScan = @@ -227,24 +235,29 @@ public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpda .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert assertThat(newScan) .isEqualTo( - new Scan(partitionKey2) - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withStart(startClusteringKey2, false) - .withEnd(endClusteringKey2, false) - .withOrdering(ordering3) - .withOrdering(ordering4) - .withOrdering(ordering5) - .withOrdering(ordering1) - .withOrdering(ordering2) - .withLimit(5) - .withProjections(Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5")) - .withConsistency(Consistency.LINEARIZABLE)); + new Scan( + NAMESPACE_2, + TABLE_2, + partitionKey2, + Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), + ImmutableSet.of(), + startClusteringKey2, + false, + endClusteringKey2, + false, + Arrays.asList(ordering3, ordering4, ordering5, ordering1, ordering2), + 5)); } @Test @@ -314,6 +327,8 @@ public void buildScanAll_ScanWithAllParameters_ShouldBuildScanCorrectly() { .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) .where(ConditionBuilder.column("ck1").isGreaterThanInt(10)) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -323,6 +338,7 @@ public void buildScanAll_ScanWithAllParameters_ShouldBuildScanCorrectly() { NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))), @@ -353,12 +369,15 @@ public void buildScanAll_FromExistingWithoutChange_ShouldCopy() { buildScanAll_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange Scan existingScan = - new ScanAll() - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withLimit(10) - .withProjections(Arrays.asList("pk1", "ck1")); + new ScanAll( + NAMESPACE_1, + TABLE_1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("pk1", "ck1"), + ImmutableSet.of(), + ImmutableList.of(ordering1, ordering2), + 10); // Act Scan newScan = @@ -370,18 +389,29 @@ public void buildScanAll_FromExistingWithoutChange_ShouldCopy() { .projections(Arrays.asList("pk2", "ck2")) .projection("ck3") .projections("ck4", "ck5") + .clearOrderings() + .ordering(ordering3) + .orderings(Arrays.asList(ordering4, ordering5)) + .orderings(ordering1, ordering2) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert assertThat(newScan) .isEqualTo( - new ScanAll() - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withLimit(5) - .withProjections(Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5")) - .withConsistency(Consistency.LINEARIZABLE)); + new ScanAll( + NAMESPACE_2, + TABLE_2, + Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), + ImmutableSet.of(), + ImmutableList.of(ordering3, ordering4, ordering5, ordering1, ordering2), + 5)); } @Test @@ -443,17 +473,22 @@ public void buildScanWithIndex_ScanWithAllParameters_ShouldBuildScanCorrectly() .projection("ck2") .projections("ck3", "ck4") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert assertThat(scan) .isEqualTo( - new ScanWithIndex(indexKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withLimit(10) - .withProjections(Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"))); + new ScanWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), + ImmutableSet.of(), + 10)); } @Test @@ -479,12 +514,15 @@ public void buildScanWithIndex_FromExistingWithoutChange_ShouldCopy() { buildScanWithIndex_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange Scan existingScan = - new ScanWithIndex(indexKey1) - .forNamespace(NAMESPACE_1) - .forTable(TABLE_1) - .withConsistency(Consistency.EVENTUAL) - .withLimit(10) - .withProjections(Arrays.asList("pk1", "ck1")); + new ScanWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + Arrays.asList("pk1", "ck1"), + ImmutableSet.of(), + 10); // Act Scan newScan = @@ -498,17 +536,24 @@ public void buildScanWithIndex_FromExistingWithoutChange_ShouldCopy() { .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert assertThat(newScan) .isEqualTo( - new ScanWithIndex(indexKey2) - .forNamespace(NAMESPACE_2) - .forTable(TABLE_2) - .withLimit(5) - .withProjections(Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5")) - .withConsistency(Consistency.LINEARIZABLE)); + new ScanWithIndex( + NAMESPACE_2, + TABLE_2, + indexKey2, + Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), + ImmutableSet.of(), + 5)); } @Test @@ -668,6 +713,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -724,6 +770,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -859,6 +906,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -911,6 +959,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -958,6 +1007,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1008,6 +1058,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1058,6 +1109,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, partitionKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1222,6 +1274,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1272,6 +1325,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1369,6 +1423,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -1415,6 +1470,7 @@ public void buildScanWithIndex_FromExistingAndClearNamespace_ShouldBuildScanWith TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -1456,6 +1512,7 @@ public void buildScanWithIndex_WithTwoOrConditionSet_ShouldBuildScanWithConditio TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1500,6 +1557,7 @@ public void buildScanWithIndex_WithOrConditionSets_ShouldBuildScanWithConditions TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1544,6 +1602,7 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition TABLE_1, indexKey1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -1640,6 +1699,8 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .limit(10) .projection("pk1") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Scan expected = new Scan( @@ -1647,6 +1708,7 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition TABLE_2, partitionKey2, Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -1692,6 +1754,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan2 = Scan.newBuilder(scan) @@ -1718,6 +1784,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan3 = Scan.newBuilder(scan) @@ -1744,6 +1814,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan4 = Scan.newBuilder(scan) @@ -1770,6 +1844,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan5 = Scan.newBuilder(scan) @@ -1796,6 +1874,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan6 = Scan.newBuilder(scan) @@ -1822,6 +1904,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .or(ConditionBuilder.column("ck4").isGreaterThanInt(10)) .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -1857,6 +1943,7 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition TABLE_2, partitionKey2, Consistency.LINEARIZABLE, + ImmutableMap.of(), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -1948,6 +2035,8 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .limit(10) .projection("pk1") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); Scan expected = new ScanWithIndex( @@ -1955,6 +2044,7 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition TABLE_2, indexKey2, Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -1989,6 +2079,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan2 = Scan.newBuilder(scan) @@ -2009,6 +2103,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan3 = Scan.newBuilder(scan) @@ -2029,6 +2127,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan4 = Scan.newBuilder(scan) @@ -2049,6 +2151,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); Scan newScan5 = Scan.newBuilder(scan) @@ -2069,6 +2175,10 @@ public void buildScanWithIndex_WithAndConditionSets_ShouldBuildScanWithCondition .build()) .and(ConditionBuilder.column("col1").isGreaterThanInt(10)) .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -2194,6 +2304,7 @@ public void buildScanAll_ScanWithConjunctiveNormalForm_ShouldBuildScanWithCondit NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2245,6 +2356,7 @@ public void buildScanAll_ScanWithConjunctiveNormalForm_ShouldBuildScanWithCondit NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2289,6 +2401,7 @@ public void buildScanAll_ScanWithTwoAndConditionSet_ShouldBuildScanWithCondition NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2422,6 +2535,7 @@ public void buildScanAll_ScanWithDisjunctiveNormalForm_ShouldBuildScanWithCondit NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -2469,6 +2583,7 @@ public void buildScanAll_ScanWithDisjunctiveNormalForm_ShouldBuildScanWithCondit NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -2510,6 +2625,7 @@ public void buildScanAll_ScanWithTwoOrConditionSet_ShouldBuildScanWithConditions NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2554,6 +2670,7 @@ public void buildScanAll_ScanWithOrConditionSets_ShouldBuildScanWithConditionsCo NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2598,6 +2715,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, + ImmutableMap.of(), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of( @@ -2689,6 +2807,8 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC .limit(10) .projection("pk1") .consistency(Consistency.EVENTUAL) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Act @@ -2714,6 +2834,10 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC .projection("ck3") .projections("ck4", "ck5") .consistency(Consistency.LINEARIZABLE) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -2723,6 +2847,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, Consistency.LINEARIZABLE, + ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), Arrays.asList("ck1", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of( Conjunction.of( @@ -2765,6 +2890,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -2807,6 +2933,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -2847,6 +2974,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -2881,6 +3009,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10)), @@ -2920,6 +3049,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -2962,6 +3092,7 @@ public void buildScanAll_ScanWithAndConditionSets_ShouldBuildScanWithConditionsC NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))), @@ -2998,6 +3129,7 @@ public void buildScanAll_FromExistingWithOrConditionSets_ShouldBuildScanWithUpda NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -3039,6 +3171,7 @@ public void buildScanAll_FromExistingWithAndConditionSets_ShouldBuildScanWithUpd NAMESPACE_1, TABLE_1, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of( @@ -3088,6 +3221,7 @@ public void buildScanAll_FromExistingWithAndConditionSets_ShouldBuildScanWithUpd NAMESPACE_2, TABLE_2, null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))), @@ -3115,7 +3249,8 @@ public void buildScanAll_FromExistingWithAndConditionSets_ShouldBuildScanWithUpd new ScanAll( null, TABLE_1, - Consistency.SEQUENTIAL, + null, + ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))), diff --git a/core/src/test/java/com/scalar/db/api/ScanTest.java b/core/src/test/java/com/scalar/db/api/ScanTest.java index d52dceebc2..5b2670ebae 100644 --- a/core/src/test/java/com/scalar/db/api/ScanTest.java +++ b/core/src/test/java/com/scalar/db/api/ScanTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.api.Selection.Conjunction; import com.scalar.db.io.Key; import com.scalar.db.io.Value; @@ -265,4 +266,51 @@ public void equals_ConjunctionWithDifferentConditionOrderGiven_ShouldReturnTrue( // Assert assertThat(ret).isTrue(); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Scan scan = + Scan.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + Scan scanAll = + Scan.newBuilder() + .namespace("ns") + .table("tbl") + .all() + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + Scan scanWithIndex = + Scan.newBuilder() + .namespace("ns") + .table("tbl") + .indexKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(scan.getAttribute("a1")).hasValue("v1"); + assertThat(scan.getAttribute("a2")).hasValue("v2"); + assertThat(scan.getAttribute("a3")).hasValue("v3"); + assertThat(scan.getAttributes()).isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + + assertThat(scanAll.getAttribute("a1")).hasValue("v1"); + assertThat(scanAll.getAttribute("a2")).hasValue("v2"); + assertThat(scanAll.getAttribute("a3")).hasValue("v3"); + assertThat(scanAll.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + + assertThat(scanWithIndex.getAttribute("a1")).hasValue("v1"); + assertThat(scanWithIndex.getAttribute("a2")).hasValue("v2"); + assertThat(scanWithIndex.getAttribute("a3")).hasValue("v3"); + assertThat(scanWithIndex.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java b/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java index 4e3453da92..92712d7b0c 100644 --- a/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.BigIntColumn; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -89,6 +90,8 @@ public void build_WithAllParameters_ShouldBuildUpdateCorrectly() { .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) .condition(condition1) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -119,6 +122,8 @@ public void build_WithAllParameters_ShouldBuildUpdateCorrectly() { assertThat(actual.getColumns().get("text").getTextValue()).isEqualTo("a_value"); assertThat(actual.getColumns().get("text2").getTextValue()).isEqualTo("another_value"); assertThat(actual.getCondition()).hasValue(condition1); + assertThat(actual.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); } @Test @@ -235,6 +240,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdate .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) .condition(condition1) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Act @@ -260,6 +267,10 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdate .textValue("text", "another_value") .value(TextColumn.of("text2", "foo")) .condition(condition2) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -290,6 +301,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdate assertThat(newUpdate.getColumns().get("text").getTextValue()).isEqualTo("another_value"); assertThat(newUpdate.getColumns().get("text2").getTextValue()).isEqualTo("foo"); assertThat(newUpdate.getCondition()).hasValue(condition2); + assertThat(newUpdate.getAttributes()) + .isEqualTo(ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6")); } @Test diff --git a/core/src/test/java/com/scalar/db/api/UpdateTest.java b/core/src/test/java/com/scalar/db/api/UpdateTest.java index e5fd1b6f96..85d6856db0 100644 --- a/core/src/test/java/com/scalar/db/api/UpdateTest.java +++ b/core/src/test/java/com/scalar/db/api/UpdateTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Column; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -183,4 +184,24 @@ public void equals_UpdateWithDifferentConditionsGiven_ShouldReturnFalse() { assertThat(ret).isFalse(); assertThat(update.hashCode()).isNotEqualTo(another.hashCode()); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Update update = + Update.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(update.getAttribute("a1")).hasValue("v1"); + assertThat(update.getAttribute("a2")).hasValue("v2"); + assertThat(update.getAttribute("a3")).hasValue("v3"); + assertThat(update.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } } diff --git a/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java b/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java index 6333cf0d8b..6fd92fb120 100644 --- a/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.BigIntColumn; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -84,6 +85,8 @@ public void build_WithAllParameters_ShouldBuildUpsertCorrectly() { .intValue("int2", Integer.valueOf(Integer.MAX_VALUE)) .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Assert @@ -113,6 +116,8 @@ public void build_WithAllParameters_ShouldBuildUpsertCorrectly() { .isEqualTo(Integer.valueOf(Integer.MAX_VALUE)); assertThat(actual.getColumns().get("text").getTextValue()).isEqualTo("a_value"); assertThat(actual.getColumns().get("text2").getTextValue()).isEqualTo("another_value"); + assertThat(actual.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); } @Test @@ -225,6 +230,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdate .intValue("int2", Integer.valueOf(Integer.MAX_VALUE)) .textValue("text", "a_value") .value(TextColumn.of("text2", "another_value")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); // Act @@ -249,6 +256,10 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdate .intValue("int2", Integer.valueOf(Integer.MIN_VALUE)) .textValue("text", "another_value") .value(TextColumn.of("text2", "foo")) + .clearAttributes() + .attribute("a4", "v4") + .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) + .clearAttribute("a7") .build(); // Assert @@ -278,6 +289,8 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdate .isEqualTo(Integer.valueOf(Integer.MIN_VALUE)); assertThat(newUpsert.getColumns().get("text").getTextValue()).isEqualTo("another_value"); assertThat(newUpsert.getColumns().get("text2").getTextValue()).isEqualTo("foo"); + assertThat(newUpsert.getAttributes()) + .isEqualTo(ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6")); } @Test diff --git a/core/src/test/java/com/scalar/db/api/UpsertTest.java b/core/src/test/java/com/scalar/db/api/UpsertTest.java index 0d0bb3eaba..e694ef42bd 100644 --- a/core/src/test/java/com/scalar/db/api/UpsertTest.java +++ b/core/src/test/java/com/scalar/db/api/UpsertTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import com.google.common.collect.ImmutableMap; import com.scalar.db.io.Column; import com.scalar.db.io.Key; import com.scalar.db.io.TextColumn; @@ -149,4 +150,24 @@ public void equals_UpsertWithDifferentValuesGiven_ShouldReturnFalse() { assertThat(ret).isFalse(); assertThat(upsert.hashCode()).isNotEqualTo(another.hashCode()); } + + @Test + public void getAttribute_ShouldReturnProperValues() { + // Arrange + Upsert upsert = + Upsert.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofText("pk", "pv")) + .attribute("a1", "v1") + .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .build(); + + // Act Assert + assertThat(upsert.getAttribute("a1")).hasValue("v1"); + assertThat(upsert.getAttribute("a2")).hasValue("v2"); + assertThat(upsert.getAttribute("a3")).hasValue("v3"); + assertThat(upsert.getAttributes()) + .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + } }