diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/SchemaId.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/SchemaId.java index 0fe9305..56e4ca8 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/SchemaId.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/SchemaId.java @@ -16,6 +16,7 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; +import javax.annotation.Nonnull; import java.io.IOException; import static com.google.common.base.Strings.lenientFormat; @@ -26,7 +27,7 @@ import static com.google.common.base.Strings.lenientFormat; */ @JsonDeserialize(using = SchemaId.JsonDeserializer.class) @JsonSerialize(using = SchemaId.JsonSerializer.class) -public final class SchemaId { +public final class SchemaId implements Comparable { public static final int BYTES = Integer.BYTES; public static final SchemaId INVALID = null; @@ -46,9 +47,21 @@ public final class SchemaId { this.value = value; } + @Override + public int compareTo(@Nonnull SchemaId other) { + return Integer.compare(this.value, other.value); + } + @Override public boolean equals(Object other) { - return other instanceof SchemaId && this.equals((SchemaId) other); + if (this == other) { + return true; + } + if (other == null || this.getClass() != other.getClass()) { + return false; + } + SchemaId schemaId = (SchemaId) other; + return this.value == schemaId.value; } /** diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutCompiler.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutCompiler.java index c611420..9992744 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutCompiler.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/layouts/LayoutCompiler.java @@ -20,7 +20,6 @@ import com.azure.data.cosmos.serialization.hybridrow.schemas.TuplePropertyType; import com.azure.data.cosmos.serialization.hybridrow.schemas.TypeKind; import com.azure.data.cosmos.serialization.hybridrow.schemas.UdtPropertyType; import com.google.common.base.Strings; -import tangible.ListHelper; import javax.annotation.Nonnull; import java.util.List; @@ -46,7 +45,7 @@ public final class LayoutCompiler { checkNotNull(ns, "expected non-null ns"); checkNotNull(schema, "expected non-null schema"); - checkArgument(schema.type() == TypeKind.Schema); + checkArgument(schema.type() == TypeKind.SCHEMA); checkArgument(!Strings.isNullOrEmpty(schema.name())); checkArgument(ns.schemas().contains(schema)); @@ -162,82 +161,82 @@ public final class LayoutCompiler { switch (logicalType.type()) { - case Null: + case NULL: return LayoutTypes.NULL; - case Boolean: + case BOOLEAN: return LayoutTypes.BOOLEAN; - case Int8: + case INT_8: return LayoutTypes.INT_8; - case Int16: + case INT_16: return LayoutTypes.INT_16; - case Int32: + case INT_32: return LayoutTypes.INT_32; - case Int64: + case INT_64: return LayoutTypes.INT_64; - case UInt8: + case UINT_8: return LayoutTypes.UINT_8; - case UInt16: + case UINT_16: return LayoutTypes.UINT_16; - case UInt32: + case UINT_32: return LayoutTypes.UINT_32; - case UInt64: + case UINT_64: return LayoutTypes.UINT_64; - case Float32: + case FLOAT_32: return LayoutTypes.FLOAT_32; - case Float64: + case FLOAT_64: return LayoutTypes.FLOAT_64; - case Float128: + case FLOAT_128: return LayoutTypes.FLOAT_128; - case Decimal: + case DECIMAL: return LayoutTypes.DECIMAL; - case DateTime: + case DATE_TIME: return LayoutTypes.DATE_TIME; - case UnixDateTime: + case UNIX_DATE_TIME: return LayoutTypes.UNIX_DATE_TIME; - case Guid: + case GUID: return LayoutTypes.GUID; - case MongoDbObjectId: + case MONGODB_OBJECT_ID: throw new UnsupportedOperationException(); // return LayoutTypes.MONGO_DB_OBJECT_ID; - case Utf8: + case UTF_8: return LayoutTypes.UTF_8; - case Binary: + case BINARY: return LayoutTypes.BINARY; - case VarInt: + case VAR_INT: return LayoutTypes.VAR_INT; - case VarUInt: + case VAR_UINT: return LayoutTypes.VAR_UINT; - case Object: + case OBJECT: return immutable ? LayoutTypes.IMMUTABLE_OBJECT : LayoutTypes.OBJECT; - case Array: { + case ARRAY: { assert logicalType instanceof ArrayPropertyType; ArrayPropertyType ap = (ArrayPropertyType) logicalType; - if (ap.items() != null && (ap.items().type() != TypeKind.Any)) { + if (ap.items() != null && (ap.items().type() != TypeKind.ANY)) { final Out out = new Out<>(); @@ -260,7 +259,7 @@ public final class LayoutCompiler { assert logicalType instanceof SetPropertyType; SetPropertyType sp = (SetPropertyType) logicalType; - if ((sp.items() != null) && (sp.items().type() != TypeKind.Any)) { + if ((sp.items() != null) && (sp.items().type() != TypeKind.ANY)) { final Out out = new Out<>(); @@ -288,7 +287,7 @@ public final class LayoutCompiler { assert logicalType instanceof MapPropertyType; MapPropertyType mp = (MapPropertyType) logicalType; - if (mp.keys() != null && (mp.keys().type() != TypeKind.Any) && (mp.values() != null) && (mp.values().type() != TypeKind.Any)) { + if (mp.keys() != null && (mp.keys().type() != TypeKind.ANY) && (mp.values() != null) && (mp.values().type() != TypeKind.ANY)) { final Out out = new Out<>(); @@ -322,7 +321,7 @@ public final class LayoutCompiler { "Unknown property type: %s", logicalType.type()) ); } - case Tuple: { + case TUPLE: { assert logicalType instanceof TuplePropertyType; final TuplePropertyType tp = (TuplePropertyType) logicalType; @@ -389,7 +388,7 @@ public final class LayoutCompiler { throw new LayoutCompilationException("Unexpected tagged arity"); } } - case Schema: { + case SCHEMA: { assert logicalType instanceof UdtPropertyType; UdtPropertyType up = (UdtPropertyType) logicalType; diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/MapPropertyType.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/MapPropertyType.java index 2065596..56ff1fb 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/MapPropertyType.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/MapPropertyType.java @@ -9,7 +9,7 @@ package com.azure.data.cosmos.serialization.hybridrow.schemas; * Maps are typed or untyped. Within typed maps, all key MUST be the same type, and all values MUST be the same type. * The type of both key and values is specified via {@link #keys} and {@link #values} respectively. Typed maps may be * stored more efficiently than untyped maps. When {@link #keys} or {@link #values} is unspecified or marked - * {@link TypeKind#Any}, the map is untyped and its key and/or values may be heterogeneous. + * {@link TypeKind#ANY}, the map is untyped and its key and/or values may be heterogeneous. */ public class MapPropertyType extends ScopePropertyType { diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Namespace.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Namespace.java index 8260b47..a41520f 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Namespace.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Namespace.java @@ -25,12 +25,13 @@ public class Namespace { /** * The fully qualified identifier of the namespace. */ - public final String getName() { + public final String name() { return this.name; } - public final void setName(String value) { + public final Namespace name(String value) { this.name = value; + return this; } /** diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Schema.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Schema.java index 6eb4eef..11a766f 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Schema.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/Schema.java @@ -42,7 +42,7 @@ public class Schema { * Initializes a new instance of the {@link Schema} class. */ public Schema() { - this.type(TypeKind.Schema); + this.type(TypeKind.SCHEMA); this.properties = Collections.emptyList(); this.partitionKeys = Collections.emptyList(); this.primaryKeys = Collections.emptyList(); @@ -209,7 +209,7 @@ public class Schema { /** * The type of this schema *

- * This value MUST be {@link TypeKind#Schema}. + * This value MUST be {@link TypeKind#SCHEMA}. */ public final TypeKind type() { return this.type; diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaValidator.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaValidator.java index d62de26..3ef1979 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaValidator.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/SchemaValidator.java @@ -3,126 +3,222 @@ package com.azure.data.cosmos.serialization.hybridrow.schemas; +import com.azure.data.cosmos.core.Json; import com.azure.data.cosmos.serialization.hybridrow.SchemaId; +import com.google.common.base.Strings; +import org.checkerframework.checker.nullness.qual.NonNull; +import javax.annotation.Nonnull; import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.lenientFormat; public final class SchemaValidator { -HashMap ids -HashMap ids>schemas, - HashMap ids) -HashMap ids - { - for (Schema s : ns.getSchemas()) { - SchemaValidator.Visit(s, schemas, ids); - } - }>schemas, + private static class SchemaIdentification implements Comparable { - { - ValidateAssert.AreEqual(s.getType(), TypeKind.Schema, String.format("The type of a schema MUST be %1$s: %2$s" - , TypeKind.Schema, s.getType())); - HashMap pathDupCheck = new HashMap(s.getProperties().size()); - for (Property p : s.getProperties()) { - ValidateAssert.DuplicateCheck(p.path(), p, pathDupCheck, "Property path", "Schema"); + private final SchemaId id; + private final String name; + + private SchemaIdentification(@Nonnull final String name, @Nonnull final SchemaId id) { + checkNotNull(name, "expected non-null name"); + checkNotNull(id, "expected non-null id"); + this.name = name; + this.id = id; } - for (PartitionKey pk : s.getPartitionKeys()) { - ValidateAssert.Exists(pk.path(), pathDupCheck, "Partition key column", "Schema"); + @Override + public int compareTo(@Nonnull SchemaIdentification other) { + checkNotNull(other, "expected non-null other"); + int result = Integer.compare(this.id.value(), other.id.value()); + return result == 0 ? this.name().compareTo(other.name()) : result; } - for (PrimarySortKey ps : s.getPrimarySortKeys()) { - ValidateAssert.Exists(ps.path(), pathDupCheck, "Primary sort key column", "Schema"); + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (null == other || this.getClass() != other.getClass()) { + return false; + } + SchemaIdentification that = (SchemaIdentification) other; + return this.id.equals(that.id) && this.name.equals(that.name); } - for (StaticKey sk : s.getStaticKeys()) { - ValidateAssert.Exists(sk.path(), pathDupCheck, "Static key column", "Schema"); + @Override + public int hashCode() { + return Objects.hash(this.id, this.name); } - for (Property p : s.getProperties()) { - SchemaValidator.Visit(p, s, schemas, ids); + public SchemaId id() { + return this.id; } - }) - { - ValidateAssert.IsValidIdentifier(p.getPath(), "Property path"); - SchemaValidator.Visit(p.getPropertyType(), null, schemas, ids); + public String name() { + return this.name; + } + + @Override + public String toString() { + return Json.toString(this); + } + + public static SchemaIdentification of(@NonNull String name, @NonNull SchemaId id) { + return new SchemaIdentification(name, id); + } } + public static void Validate(@NonNull final Namespace namespace) { + + checkNotNull(namespace, "expected non-null namespace"); + + final int initialCapacity = namespace.schemas().size(); + + final Map nameDupCheck = new HashMap<>(initialCapacity); + final Map nameVersioningCheck = new HashMap<>(initialCapacity); + final Map idDupCheck = new HashMap<>(initialCapacity); + + for (Schema schema : namespace.schemas()) { + + SchemaIdentification identification = SchemaIdentification.of(schema.name(), schema.schemaId()); + + Assert.isValidIdentifier(identification.name(), "Schema name"); + Assert.isValidSchemaId(identification.id(), "Schema id"); + Assert.duplicateCheck(identification.id(), schema, idDupCheck, "Schema id", "Namespace"); + Assert.duplicateCheck(identification, schema, nameDupCheck, "Schema reference", "Namespace"); + + // Count the versions of each schema by name. + nameVersioningCheck.TryGetValue(schema.name(), out int count); + nameVersioningCheck.put(schema.name(), count + 1); + } + + // Enable id-less Schema references for all types with a unique version in the namespace + + for (Schema schema : namespace.schemas()) { + if (nameVersioningCheck.get(schema.name()) == 1) { + Assert.duplicateCheck(SchemaIdentification.of(schema.name(), SchemaId.INVALID), schema, nameDupCheck, "Schema reference", "Namespace"); + } + } + + SchemaValidator.visit(namespace, nameDupCheck, idDupCheck); + } + + ///

Visit an entire namespace and validate its constraints. + /// The to validate. + /// A map from schema names within the namespace to their schemas. + /// A map from schema ids within the namespace to their schemas. + private static void visit(Namespace ns, Map schemas, Map ids) { + for (Schema schema : ns.schemas()) { + SchemaValidator.visit(schema, schemas, ids); + } + } + + /// Visit a single schema and validate its constraints. + /// The to validate. + /// A map from schema names within the namespace to their schemas. + /// A map from schema ids within the namespace to their schemas. + private static void visit(Schema schema, Map schemas, Map ids) { + + Assert.areEqual( + schema.type(), TypeKind.SCHEMA, lenientFormat("The type of a schema MUST be %s: %s", TypeKind.SCHEMA, schema.type()) + ); + + HashMap pathDupCheck = new HashMap<>(schema.properties().size()); + + for (Property p : schema.properties()) { + Assert.duplicateCheck(p.path(), p, pathDupCheck, "Property path", "Schema"); + } + + for (PartitionKey pk : schema.partitionKeys()) { + Assert.exists(pk.path(), pathDupCheck, "Partition key column", "Schema"); + } + + for (PrimarySortKey ps : schema.primarySortKeys()) { + Assert.exists(ps.path(), pathDupCheck, "Primary sort key column", "Schema"); + } + + for (StaticKey sk : schema.staticKeys()) { + Assert.exists(sk.path(), pathDupCheck, "Static key column", "Schema"); + } + + for (Property p : schema.properties()) { + SchemaValidator.visit(p, schema, schemas, ids); + } + } + + private static void visit( + Property p, Schema s, Map schemas, Map ids) { + + Assert.isValidIdentifier(p.path(), "Property path"); + SchemaValidator.visit(p.propertyType(), null, schemas, ids); + } + + private static void visit( + PropertyType p, + PropertyType parent, + Map schemas, + Map ids) + { + switch (p) { - switch (p) { - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case PrimitivePropertyType pp: - case PrimitivePropertyType - pp: - ValidateAssert.IsTrue(pp.Length >= 0, "Length MUST be positive"); - if (parent != null) { - ValidateAssert.AreEqual(pp.Storage, StorageKind.SPARSE, String.format("Nested fields MUST have " + - "storage %1$s", StorageKind.SPARSE)); + case PrimitivePropertyType pp: + Assert.isTrue(pp.Length >= 0, "Length MUST be positive"); + if (parent != null) + { + Assert.areEqual(pp.Storage, StorageKind.Sparse, $"Nested fields MUST have storage {StorageKind.Sparse}"); } break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case ArrayPropertyType ap: - case ArrayPropertyType - ap: - if (ap.Items != null) { - SchemaValidator.Visit(ap.Items, p, schemas, ids); - } + case ArrayPropertyType ap: + if (ap.Items != null) + { + SchemaValidator.visit(ap.Items, p, schemas, ids); + } break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case MapPropertyType mp: - case MapPropertyType - mp: - SchemaValidator.Visit(mp.keySet(), p, schemas, ids); - SchemaValidator.Visit(mp.Values, p, schemas, ids); + case MapPropertyType mp: + SchemaValidator.visit(mp.Keys, p, schemas, ids); + SchemaValidator.visit(mp.Values, p, schemas, ids); break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case SetPropertyType sp: - case SetPropertyType - sp: - SchemaValidator.Visit(sp.Items, p, schemas, ids); + case SetPropertyType sp: + SchemaValidator.visit(sp.Items, p, schemas, ids); break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case TaggedPropertyType gp: - case TaggedPropertyType - gp: - for (PropertyType item : gp.Items) { - SchemaValidator.Visit(item, p, schemas, ids); - } + case TaggedPropertyType gp: + for (PropertyType item : gp.Items) + { + SchemaValidator.visit(item, p, schemas, ids); + } - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case TuplePropertyType tp: - case TuplePropertyType - tp: - for (PropertyType item : tp.Items) { - SchemaValidator.Visit(item, p, schemas, ids); - } + break; + case TuplePropertyType tp: + for (PropertyType item : tp.Items) + { + SchemaValidator.visit(item, p, schemas, ids); + } - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case ObjectPropertyType op: - case ObjectPropertyType - op: - HashMap pathDupCheck = new HashMap(op.Properties.Count); - for (Property nested : op.Properties) { - ValidateAssert.DuplicateCheck(nested.path(), nested, pathDupCheck, "Property path", "Object"); - SchemaValidator.Visit(nested.propertyType(), p, schemas, ids); - } + break; + case ObjectPropertyType op: + Map pathDupCheck = new HashMap<>(op.Properties.Count); + for (Property nested : op.Properties) + { + Assert.duplicateCheck(nested.path(), nested, pathDupCheck, "Property path", "Object"); + SchemaValidator.visit(nested.propertyType(), p, schemas, ids); + } - break; - // TODO: C# TO JAVA CONVERTER: Java has no equivalent to C# pattern variables in 'case' statements: - //ORIGINAL LINE: case UdtPropertyType up: - case UdtPropertyType - up: - ValidateAssert.Exists((up.Name, up.SchemaId), schemas, "Schema reference", "Namespace") - if (SchemaId.opNotEquals(up.SchemaId, - SchemaId.INVALID)) { - Schema s = ValidateAssert.Exists(up.SchemaId, ids, "Schema id", "Namespace"); - ValidateAssert.AreEqual(up.Name, s.name(), String.format("Schema name '%1$s' does not match " + - "the name of schema with id '%2$s': %3$s", up.Name, up.SchemaId, s.name())); + break; + case UdtPropertyType up: + Assert.exists((up.Name, up.SchemaId), schemas, "Schema reference", "Namespace"); + if (up.SchemaId != SchemaId.Invalid) + { + Schema s = Assert.exists(up.SchemaId, ids, "Schema id", "Namespace"); + Assert.areEqual( + up.Name, + s.Name, + $"Schema name '{up.Name}' does not match the name of schema with id '{up.SchemaId}': {s.Name}"); } break; @@ -130,146 +226,79 @@ HashMap ids Contract.Fail("Unknown property type"); break; } - }>schemas, + } - public static void Validate(Namespace ns) { - HashMap nameVersioningCheck = new HashMap(ns.schemas().size()); - HashMap< (String, SchemaId), - Schema > nameDupCheck = new HashMap<(String, SchemaId), Schema > (ns.schemas().size()); - HashMap idDupCheck = new HashMap(ns.schemas().size()); - for (Schema s : ns.schemas()) { - ValidateAssert.IsValidSchemaId(s.schemaId().clone(), "Schema id"); - ValidateAssert.IsValidIdentifier(s.name(), "Schema name"); - ValidateAssert.DuplicateCheck(s.schemaId().clone(), s, idDupCheck, "Schema id", "Namespace"); - ValidateAssert.DuplicateCheck((s.name(), s.schemaId().clone()), s, nameDupCheck, "Schema reference" - , "Namespace") + private static class Assert { - // Count the versions of each schema by name. - int count; - count = nameVersioningCheck.get(s.name()); - nameVersioningCheck.put(s.name(), count + 1); - } - - // Enable id-less Schema references for all types with a unique version in the namespace. - for (Schema s : ns.schemas()) { - if (nameVersioningCheck.get(s.name()).equals(1)) { - ValidateAssert.DuplicateCheck((s.name(), SchemaId.INVALID), s, nameDupCheck, "Schema reference", - "Namespace") + /// Validate does not already appear within the given scope. + /// The type of the keys within the scope. + /// The type of the values within the scope. + /// The key to check. + /// The value to add to the scope if there is no duplicate. + /// The set of existing values within the scope. + /// Diagnostic label describing . + /// Diagnostic label describing . + static void duplicateCheck( + TKey key, TValue value, Map scope, String label, String scopeLabel) { + if (scope.containsKey(key)) { + throw new SchemaException(lenientFormat("%s must be unique within a %s: %s", label, scopeLabel, key)); } + scope.put(key, value); } - SchemaValidator.Visit(ns, nameDupCheck, idDupCheck); - }) + /// Validate does appear within the given scope. + /// The type of the keys within the scope. + /// The type of the values within the scope. + /// The key to check. + /// The set of existing values within the scope. + /// Diagnostic label describing . + /// Diagnostic label describing . + static TValue exists(TKey key, Map scope, String label, String scopeLabel) { + TValue value = scope.get(key); + if (value == null) { + throw new SchemaException(lenientFormat("%s must exist within a %s: %s", label, scopeLabel, key)); + } + return value; + } -/** - * Visit an entire namespace and validate its constraints. - * - * @param ns The {@link Namespace} to validate. - * @param schemas A map from schema names within the namespace to their schemas. - * @param ids A map from schema ids within the namespace to their schemas. - */ - private static void Visit(Namespace ns, HashMap<(String, SchemaId),Schema - - /** - * Visit a single schema and validate its constraints. - * - * @param s The {@link Schema} to validate. - * @param schemas A map from schema names within the namespace to their schemas. - * @param ids A map from schema ids within the namespace to their schemas. - */ - private static void Visit(Schema s, HashMap<(String, SchemaId),Schema>schemas, - -private static void Visit(Property p, Schema s, HashMap<(String, SchemaId),Schema) - -private static void Visit(PropertyType p, PropertyType parent, HashMap<(String, SchemaId),Schema - - private static class ValidateAssert { - /** - * Validate two values are equal. - * Type of the values to compare. - * - * @param left The left value to compare. - * @param right The right value to compare. - * @param message Diagnostic message if the comparison fails. - */ - public static void AreEqual(T left, T right, String message) { + /// Validate two values are equal. + /// Type of the values to compare. + /// The left value to compare. + /// The right value to compare. + /// Diagnostic message if the comparison fails. + static void areEqual(T left, T right, String message) { if (!left.equals(right)) { throw new SchemaException(message); } } - /** - * Validate does not already appear within the given scope. - * The type of the keys within the scope. - * The type of the values within the scope. - * - * @param key The key to check. - * @param value The value to add to the scope if there is no duplicate. - * @param scope The set of existing values within the scope. - * @param label Diagnostic label describing . - * @param scopeLabel Diagnostic label describing . - */ - public static void DuplicateCheck(TKey key, TValue value, HashMap scope, String label, String scopeLabel) { - if (scope.containsKey(key)) { - throw new SchemaException(String.format("%1$s must be unique within a %2$s: %3$s", label, scopeLabel, key)); - } - - scope.put(key, value); - } - - /** - * Validate does appear within the given scope. - * The type of the keys within the scope. - * The type of the values within the scope. - * - * @param key The key to check. - * @param scope The set of existing values within the scope. - * @param label Diagnostic label describing . - * @param scopeLabel Diagnostic label describing . - */ - public static TValue Exists(TKey key, HashMap scope, String label, String scopeLabel) { - TValue value; - if (!(scope.containsKey(key) && (value = scope.get(key)) == value)) { - throw new SchemaException(String.format("%1$s must exist within a %2$s: %3$s", label, scopeLabel, key)); - } - - return value; - } - - /** - * Validate a predicate is true. - * - * @param predicate The predicate to check. - * @param message Diagnostic message if the comparison fails. - */ - public static void IsTrue(boolean predicate, String message) { + /// Validate a predicate is true. + /// The predicate to check. + /// Diagnostic message if the comparison fails. + static void isTrue(boolean predicate, String message) { if (!predicate) { throw new SchemaException(message); } } - /** - * Validate contains only characters valid in a schema - * identifier. - * - * @param identifier The identifier to check. - * @param label Diagnostic label describing . - */ - public static void IsValidIdentifier(String identifier, String label) { - if (tangible.StringHelper.isNullOrWhiteSpace(identifier)) { - throw new SchemaException(String.format("%1$s must be a valid identifier: %2$s", label, identifier)); + /// + /// Validate contains only characters valid in a schema + /// identifier. + /// + /// The identifier to check. + /// Diagnostic label describing . + static void isValidIdentifier(String identifier, String label) { + if (Strings.isNullOrEmpty(identifier)) { + throw new SchemaException(lenientFormat("%s must be a valid identifier: %s", label, identifier)); } } - /** - * Validate is a valid {@link SchemaId}. - * - * @param id The id to check. - * @param label Diagnostic label describing . - */ - public static void IsValidSchemaId(SchemaId id, String label) { - if (SchemaId.opEquals(id.clone(), SchemaId.INVALID)) { - throw new SchemaException(String.format("%1$s cannot be 0", label)); + /// Validate is a valid . + /// The id to check. + /// Diagnostic label describing . + static void isValidSchemaId(SchemaId id, String label) { + if (id == SchemaId.INVALID) { + throw new SchemaException(lenientFormat("%s cannot be 0", label)); } } } diff --git a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/TypeKind.java b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/TypeKind.java index 580ccb4..5e5b0cf 100644 --- a/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/TypeKind.java +++ b/java/src/main/java/com/azure/data/cosmos/serialization/hybridrow/schemas/TypeKind.java @@ -3,166 +3,150 @@ package com.azure.data.cosmos.serialization.hybridrow.schemas; +// TODO: DANOBLE: Fixup JSON-serialized naming for agreement with the dotnet code + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + /** * Describes the logical type of a property. */ -// TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: -//ORIGINAL LINE: [JsonConverter(typeof(StringEnumConverter), true)] public enum TypeKind public enum TypeKind { /** * Reserved. */ - Invalid(0), + INVALID(0), /** * The literal null. *

- * When used as a fixed column, only a presence bit is allocated. When used as a sparse - * column, a sparse value with 0-length payload is written. + * When used as a fixed column, only a presence bit is allocated. When used as a sparse column, a sparse value with + * 0-length payload is written. */ - Null(1), + NULL(1), /** - * A boolean property. Boolean properties are allocated a single bit when schematized within - * a row. + * A boolean property. + *

+ * Boolean properties are allocated a single bit when schematized within a row. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "bool")] Boolean, - Boolean(2), + BOOLEAN(2), /** * 8-bit signed integer. */ - Int8(3), + INT_8(3), /** * 16-bit signed integer. */ - Int16(4), + INT_16(4), /** * 32-bit signed integer. */ - Int32(5), + INT_32(5), /** * 64-bit signed integer. */ - Int64(6), + INT_64(6), /** * 8-bit unsigned integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "uint8")] UInt8, - UInt8(7), + UINT_8(7), /** * 16-bit unsigned integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "uint16")] UInt16, - //C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java: - //ORIGINAL LINE: [EnumMember(Value = "uint16")] UInt16, - UInt16(8), + UINT_16(8), /** * 32-bit unsigned integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "uint32")] UInt32, - //C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java: - //ORIGINAL LINE: [EnumMember(Value = "uint32")] UInt32, - UInt32(9), + UINT_32(9), /** * 64-bit unsigned integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "uint64")] UInt64, - //C# TO JAVA CONVERTER WARNING: Unsigned integer types have no direct equivalent in Java: - //ORIGINAL LINE: [EnumMember(Value = "uint64")] UInt64, - UInt64(10), + UINT_64(10), /** * Variable length encoded signed integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "varint")] VarInt, - VarInt(11), + VAR_INT(11), /** * Variable length encoded unsigned integer. */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "varuint")] VarUInt, - VarUInt(12), + VAR_UINT(12), /** * 32-bit IEEE 754 floating point value. */ - Float32(13), + FLOAT_32(13), /** * 64-bit IEEE 754 floating point value. */ - Float64(14), + FLOAT_64(14), /** * 128-bit IEEE 754-2008 floating point value. */ - Float128(15), + FLOAT_128(15), /** - * 128-bit floating point value. See {@link decimal} + * 128-bit floating point value. + * + * @see java.math.BigDecimal */ - Decimal(16), + DECIMAL(16), /** - * 64-bit date/time value in 100ns increments from C# epoch. See {@link System.DateTime} + * 64-bit date/time value in 100ns increments from C# epoch. + * + * @see java.time.OffsetDateTime */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "datetime")] DateTime, - DateTime(17), + DATE_TIME(17), /** - * 64-bit date/time value in milliseconds increments from Unix epoch. See {@link UnixDateTime} + * 64-bit date/time value in milliseconds increments from Unix epoch. + * + * @see com.azure.data.cosmos.serialization.hybridrow.UnixDateTime */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "unixdatetime")] UnixDateTime, - UnixDateTime(18), + UNIX_DATE_TIME(18), /** * 128-bit globally unique identifier (in little-endian byte order). */ - Guid(19), + GUID(19), /** * 12-byte MongoDB Object Identifier (in little-endian byte order). */ - // TODO: C# TO JAVA CONVERTER: Java annotations will not correspond to .NET attributes: - //ORIGINAL LINE: [EnumMember(Value = "mongodbobjectid")] MongoDbObjectId, - MongoDbObjectId(20), + MONGODB_OBJECT_ID(20), /** * Zero to MAX_ROW_SIZE bytes encoded as UTF-8 code points. */ - Utf8(21), + UTF_8(21), /** * Zero to MAX_ROW_SIZE untyped bytes. */ - Binary(22), + BINARY(22), /** * An object property. */ - Object(23), + OBJECT(23), /** * An array property, either typed or untyped. */ - Array(24), + ARRAY(24), /** * A set property, either typed or untyped. @@ -177,50 +161,54 @@ public enum TypeKind { /** * A tuple property. Tuples are typed, finite, ordered, sets. */ - Tuple(27), + TUPLE(27), /** - * A tagged property. Tagged properties pair one or more typed values with an API-specific uint8 type code. + * A tagged property. + *

+ * Tagged properties pair one or more typed values with an API-specific uint8 type code. */ TAGGED(28), /** * A row with schema. + *

* May define either a top-level table schema or a UDT (nested row). */ - Schema(29), + SCHEMA(29), /** * An untyped sparse field. - * May only be used to define the type within a nested scope (e.g. {@link Object} or {@link Array}. + *

+ * May only be used to define the type within a nested scope. */ - Any(30); + ANY(30); - public static final int SIZE = java.lang.Integer.SIZE; - private static java.util.HashMap mappings; - private int intValue; + public static final int BYTES = Integer.BYTES; + private static Int2ObjectMap mappings; + private int value; TypeKind(int value) { - intValue = value; - getMappings().put(value, this); + this.value = value; + mappings().put(value, this); } - public int getValue() { - return intValue; + public int value() { + return this.value; } - public static TypeKind forValue(int value) { - return getMappings().get(value); + public static TypeKind from(int value) { + return mappings().get(value); } - private static java.util.HashMap getMappings() { + private static Int2ObjectMap mappings() { if (mappings == null) { synchronized (TypeKind.class) { if (mappings == null) { - mappings = new java.util.HashMap(); + mappings = new Int2ObjectOpenHashMap<>(); } } } return mappings; } -} \ No newline at end of file +} diff --git a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/SchemaUnitTests.java b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/SchemaUnitTests.java index e3ac29e..e906618 100644 --- a/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/SchemaUnitTests.java +++ b/java/src/test/java/com/azure/data/cosmos/serialization/hybridrow/unit/SchemaUnitTests.java @@ -84,7 +84,7 @@ public class SchemaUnitTests { Assert.AreEqual(1, n1.getSchemas().size(), "Json: {0}", json); Assert.AreEqual("emptyTable", n1.getSchemas().get(0).getName(), "Json: {0}", json); Assert.AreEqual(new SchemaId(-1), n1.getSchemas().get(0).getSchemaId().clone(), "Json: {0}", json); - Assert.AreEqual(TypeKind.Schema, n1.getSchemas().get(0).getType(), "Json: {0}", json); + Assert.AreEqual(TypeKind.SCHEMA, n1.getSchemas().get(0).getType(), "Json: {0}", json); Assert.AreEqual(true, n1.getSchemas().get(0).getOptions().getDisallowUnschematized(), "Json: {0}", json); Assert.IsNotNull(n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json); Assert.AreEqual(0, n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json); @@ -106,7 +106,7 @@ public class SchemaUnitTests { Assert.AreEqual(1, n1.getSchemas().size(), "Json: {0}", json); Assert.AreEqual("myUDT", n1.getSchemas().get(0).getName(), "Json: {0}", json); Assert.AreEqual(new SchemaId(1), n1.getSchemas().get(0).getSchemaId().clone(), "Json: {0}", json); - Assert.AreEqual(TypeKind.Schema, n1.getSchemas().get(0).getType(), "Json: {0}", json); + Assert.AreEqual(TypeKind.SCHEMA, n1.getSchemas().get(0).getType(), "Json: {0}", json); Assert.AreEqual(false, n1.getSchemas().get(0).getOptions().getDisallowUnschematized(), "Json: {0}", json); Assert.AreEqual(2, n1.getSchemas().get(0).getProperties().size(), "Json: {0}", json); @@ -136,8 +136,8 @@ public class SchemaUnitTests { Storage = _Storage; } } - Object[] expectedProps = new Object[] { AnonymousType("a", TypeKind.Int8, StorageKind.FIXED), - AnonymousType2("b", TypeKind.Utf8, StorageKind.VARIABLE) }; + Object[] expectedProps = new Object[] { AnonymousType("a", TypeKind.INT_8, StorageKind.FIXED), + AnonymousType2("b", TypeKind.UTF_8, StorageKind.VARIABLE) }; for (int i = 0; i < n1.getSchemas().get(0).getProperties().size(); i++) { Property p = n1.getSchemas().get(0).getProperties().get(i); @@ -448,27 +448,27 @@ public class SchemaUnitTests { } } // TODO: C# TO JAVA CONVERTER: There is no Java equivalent to the C# 'dynamic' keyword: - dynamic[] expectedSchemas = { AnonymousType("{'type': 'bool', 'storage': 'fixed'}", TypeKind.Boolean), - AnonymousType2("{'type': 'int8', 'storage': 'fixed'}", TypeKind.Int8), AnonymousType3("{'type': 'int16', " + - "'storage': 'fixed'}", TypeKind.Int16), AnonymousType4("{'type': 'int32', 'storage': 'fixed'}", - TypeKind.Int32), AnonymousType5("{'type': 'int64', 'storage': 'fixed'}", TypeKind.Int64), AnonymousType6( - "{'type': 'uint8', 'storage': 'fixed'}", TypeKind.UInt8), AnonymousType7("{'type': 'uint16', " + - "'storage': 'fixed'}", TypeKind.UInt16), AnonymousType8("{'type': 'uint32', 'storage': 'fixed'}", - TypeKind.UInt32), AnonymousType9("{'type': 'uint64', 'storage': 'fixed'}", TypeKind.UInt64), - AnonymousType10("{'type': 'float32', 'storage': 'fixed'}", TypeKind.Float32), AnonymousType11("{'type': " + - "'float64', 'storage': 'fixed'}", TypeKind.Float64), AnonymousType12("{'type': 'float128', 'storage': " + - "'fixed'}", TypeKind.Float128), AnonymousType13("{'type': 'decimal', 'storage': 'fixed'}", - TypeKind.Decimal), AnonymousType14("{'type': 'datetime', 'storage': 'fixed'}", TypeKind.DateTime), - AnonymousType15("{'type': 'unixdatetime', 'storage': 'fixed'}", TypeKind.UnixDateTime), AnonymousType16( - "{'type': 'guid', 'storage': 'fixed'}", TypeKind.Guid), AnonymousType17("{'type': 'mongodbobjectid', " + - "'storage': 'fixed'}", TypeKind.MongoDbObjectId), AnonymousType18("{'type': 'varint', 'storage': " + - "'variable'}", TypeKind.VarInt), AnonymousType19("{'type': 'varuint', 'storage': 'variable'}", - TypeKind.VarUInt), AnonymousType20("{'type': 'utf8', 'storage': 'fixed', 'length': 2}", TypeKind.Utf8, 2) - , AnonymousType21("{'type': 'binary', 'storage': 'fixed', 'length': 2}", TypeKind.Binary, 2), - AnonymousType22("{'type': 'utf8', 'storage': 'variable', 'length': 100}", TypeKind.Utf8, 100), - AnonymousType23("{'type': 'binary', 'storage': 'variable', 'length': 100}", TypeKind.Binary, 100), - AnonymousType24("{'type': 'utf8', 'sparse': 'variable', 'length': 1000}", TypeKind.Utf8, 1000), - AnonymousType25("{'type': 'binary', 'sparse': 'variable', 'length': 1000}", TypeKind.Binary, 1000) }; + dynamic[] expectedSchemas = { AnonymousType("{'type': 'bool', 'storage': 'fixed'}", TypeKind.BOOLEAN), + AnonymousType2("{'type': 'int8', 'storage': 'fixed'}", TypeKind.INT_8), AnonymousType3("{'type': 'int16', " + + "'storage': 'fixed'}", TypeKind.INT_16), AnonymousType4("{'type': 'int32', 'storage': 'fixed'}", + TypeKind.INT_32), AnonymousType5("{'type': 'int64', 'storage': 'fixed'}", TypeKind.INT_64), AnonymousType6( + "{'type': 'uint8', 'storage': 'fixed'}", TypeKind.UINT_8), AnonymousType7("{'type': 'uint16', " + + "'storage': 'fixed'}", TypeKind.UINT_16), AnonymousType8("{'type': 'uint32', 'storage': 'fixed'}", + TypeKind.UINT_32), AnonymousType9("{'type': 'uint64', 'storage': 'fixed'}", TypeKind.UINT_64), + AnonymousType10("{'type': 'float32', 'storage': 'fixed'}", TypeKind.FLOAT_32), AnonymousType11("{'type': " + + "'float64', 'storage': 'fixed'}", TypeKind.FLOAT_64), AnonymousType12("{'type': 'float128', 'storage': " + + "'fixed'}", TypeKind.FLOAT_128), AnonymousType13("{'type': 'decimal', 'storage': 'fixed'}", + TypeKind.DECIMAL), AnonymousType14("{'type': 'datetime', 'storage': 'fixed'}", TypeKind.DATE_TIME), + AnonymousType15("{'type': 'unixdatetime', 'storage': 'fixed'}", TypeKind.UNIX_DATE_TIME), AnonymousType16( + "{'type': 'guid', 'storage': 'fixed'}", TypeKind.GUID), AnonymousType17("{'type': 'mongodbobjectid', " + + "'storage': 'fixed'}", TypeKind.MONGODB_OBJECT_ID), AnonymousType18("{'type': 'varint', 'storage': " + + "'variable'}", TypeKind.VAR_INT), AnonymousType19("{'type': 'varuint', 'storage': 'variable'}", + TypeKind.VAR_UINT), AnonymousType20("{'type': 'utf8', 'storage': 'fixed', 'length': 2}", TypeKind.UTF_8, 2) + , AnonymousType21("{'type': 'binary', 'storage': 'fixed', 'length': 2}", TypeKind.BINARY, 2), + AnonymousType22("{'type': 'utf8', 'storage': 'variable', 'length': 100}", TypeKind.UTF_8, 100), + AnonymousType23("{'type': 'binary', 'storage': 'variable', 'length': 100}", TypeKind.BINARY, 100), + AnonymousType24("{'type': 'utf8', 'sparse': 'variable', 'length': 1000}", TypeKind.UTF_8, 1000), + AnonymousType25("{'type': 'binary', 'sparse': 'variable', 'length': 1000}", TypeKind.BINARY, 1000) }; for (dynamic expected : expectedSchemas) { String columnSchema = String.format("{'path': 'a', 'type': %1$s", expected.Json @@ -517,8 +517,8 @@ class AnonymousType4 { public String Json; public String Name; // TODO: C# TO JAVA CONVERTER: There is no Java equivalent to the C# 'dynamic' keyword: - dynamic[] expectedSchemas = { AnonymousType("{'type': 'int8' }", TypeKind.Int8), AnonymousType2("{'type': " + - "'array', 'items': {'type': 'int32'}}", TypeKind.Int32), AnonymousType3("{'type': 'object', 'properties': " + + dynamic[] expectedSchemas = { AnonymousType("{'type': 'int8' }", TypeKind.INT_8), AnonymousType2("{'type': " + + "'array', 'items': {'type': 'int32'}}", TypeKind.INT_32), AnonymousType3("{'type': 'object', 'properties': " + "null}", 0), AnonymousType4("{'type': 'schema', 'name': 'myUDT'}", "myUDT") }; public AnonymousType4(String _Json, String _Name) { @@ -601,8 +601,8 @@ class AnonymousType4 { publ TO JAVA CONVERTER TODO TASK: There is no Java equivalent to the C# 'dynamic' keyword: dynamic[] expectedSchemas = { AnonymousType("{'path': 'b', 'type': {'type': 'int8', 'storage': 'fixed'}}", - TypeKind.Int8), AnonymousType2("{'path': 'b', 'type': {'type': 'array', 'items': {'type': 'int32'}}}", - TypeKind.Int32), AnonymousType3("{'path': 'b', 'type': {'type': 'object', 'properties': [{'path': 'c', " + + TypeKind.INT_8), AnonymousType2("{'path': 'b', 'type': {'type': 'array', 'items': {'type': 'int32'}}}", + TypeKind.INT_32), AnonymousType3("{'path': 'b', 'type': {'type': 'object', 'properties': [{'path': 'c', " + "'type': {'type': 'bool'}}]}}", 1), AnonymousType4("{'path': 'b', 'type': {'type': 'schema', 'name': " + "'myUDT'}}", "myUDT") };