Progressed on deserializing schemas.

This commit is contained in:
David Noble
2019-09-17 20:29:21 -07:00
parent 5a73b29347
commit 60d7d73b14
16 changed files with 411 additions and 136 deletions

View File

@@ -3,29 +3,53 @@
package com.azure.data.cosmos.core;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import static com.google.common.base.Strings.lenientFormat;
public final class Json {
private static final ObjectMapper mapper = new ObjectMapper();
private static final ObjectReader reader = mapper.reader();
private static final ObjectWriter writer = mapper.writer();
private static final Logger logger = LoggerFactory.getLogger(Json.class);
private static final ObjectMapper mapper = new ObjectMapper(new JsonFactory()
.enable(JsonParser.Feature.ALLOW_COMMENTS));
private static final ObjectReader reader = mapper.reader()
.withFeatures(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
private static final ObjectWriter writer = mapper.writer()
.withFeatures(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
private Json() {
}
public static <T> Optional<T> parse(String value) {
public static <T> Optional<T> parse(InputStream stream, Class<T> type) {
try {
return Optional.of(reader.<T>readValue(value));
} catch (IOException e) {
return Optional.of(reader.forType(type).readValue(stream));
} catch (IOException error) {
logger.error("", error);
return Optional.empty();
}
}
public static <T> Optional<T> parse(String value, Class<T> type) {
try {
return Optional.of(reader.forType(type).readValue(value));
} catch (IOException error) {
logger.error("", error);
return Optional.empty();
}
}

View File

@@ -61,15 +61,15 @@ public final class LayoutCompiler {
for (Property p : properties) {
LayoutType type = LayoutCompiler.logicalToPhysicalType(ns, p.propertyType(), typeArgs);
LayoutType type = LayoutCompiler.logicalToPhysicalType(ns, p.type(), typeArgs);
switch (LayoutCodeTraits.clearImmutableBit(type.layoutCode())) {
case OBJECT_SCOPE: {
if (!p.propertyType().nullable()) {
if (!p.type().nullable()) {
throw new LayoutCompilationException("Non-nullable sparse column are not supported.");
}
ObjectPropertyType op = (ObjectPropertyType)p.propertyType();
ObjectPropertyType op = (ObjectPropertyType)p.type();
builder.addObjectScope(p.path(), type);
LayoutCompiler.addProperties(builder, ns, type.layoutCode(), op.properties());
builder.EndObjectScope();
@@ -87,7 +87,7 @@ public final class LayoutCompiler {
case TAGGED_SCOPE:
case TAGGED2_SCOPE:
case SCHEMA: {
if (!p.propertyType().nullable()) {
if (!p.type().nullable()) {
throw new LayoutCompilationException("Non-nullable sparse column are not supported.");
}
builder.addTypedScope(p.path(), type, typeArgs.get());
@@ -100,9 +100,9 @@ public final class LayoutCompiler {
default: {
if (p.propertyType() instanceof PrimitivePropertyType) {
if (p.type() instanceof PrimitivePropertyType) {
PrimitivePropertyType pp = (PrimitivePropertyType) p.propertyType();
PrimitivePropertyType pp = (PrimitivePropertyType) p.type();
switch (pp.storage()) {

View File

@@ -9,9 +9,13 @@ import com.google.common.base.Suppliers;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.CodeSource;
import java.util.Enumeration;
import java.util.Optional;
import java.util.function.Supplier;
@@ -41,17 +45,20 @@ public final class SystemSchema {
final String json;
try (final InputStream stream = SystemSchema.class.getResourceAsStream("SystemSchema.json")) {
try (final InputStream stream = getResourceAsStream("SystemSchema.json")) {
Optional<Namespace> namespace = Namespace.parse(stream);
ByteBuf buffer = Unpooled.buffer();
while (buffer.writeBytes(stream, 8192) == 8192) { }
json = buffer.readCharSequence(buffer.readableBytes(), StandardCharsets.UTF_8).toString();
} catch (IOException cause) {
String message = lenientFormat("failed to load SystemSchema.json due to %s", cause);
String message = lenientFormat("Failed to load SystemSchema.json due to %s", cause);
throw new IllegalStateException(message, cause);
}
Optional<Namespace> namespace = Namespace.parse(json);
checkState(namespace.isPresent(), "failed to load SystemSchema.json");
checkState(namespace.isPresent(), "Failed to parse SystemSchema.json");
return new LayoutResolverNamespace(namespace.get());
});
@@ -62,4 +69,23 @@ public final class SystemSchema {
public static LayoutResolver layoutResolver() {
return layoutResolver.get();
}
private static InputStream getResourceAsStream(final String name) throws IOException {
final CodeSource codeSource = SystemSchema.class.getProtectionDomain().getCodeSource();
final ClassLoader classLoader = SystemSchema.class.getClassLoader();
final String location = codeSource.getLocation().toString();
final Enumeration<URL> urls;
urls = classLoader.getResources(name);
while (urls.hasMoreElements()) {
final URL url = urls.nextElement();
if (url.toString().startsWith(location)) {
return url.openStream();
}
}
throw new FileNotFoundException(lenientFormat("cannot find resource at code source location %s", location));
}
}

View File

@@ -4,31 +4,39 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
import com.azure.data.cosmos.core.Json;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class Namespace {
@JsonProperty(required = true)
private String name;
private SchemaLanguageVersion version = SchemaLanguageVersion.values()[0];
@JsonProperty(required = true)
private ArrayList<Schema> schemas;
/**
* Initializes a new instance of the {@link Namespace} class.
*/
public Namespace() {
this.schemas(new ArrayList<Schema>());
}
@JsonProperty(required = true)
private SchemaLanguageVersion version;
/**
* The fully qualified identifier of the namespace.
* The fully qualified name of the namespace.
*
* @return fully qualified name of the {@linkplain Namespace namespace}.
*/
public final String name() {
return this.name;
}
/**
* Sets the fully qualified name of the namespace.
*
* @param value fully qualified name of the {@linkplain Namespace namespace}.
* @return a reference to this {@linkplain Namespace namespace}.
*/
public final Namespace name(String value) {
this.name = value;
return this;
@@ -54,11 +62,21 @@ public class Namespace {
/**
* The version of the HybridRow Schema Definition Language used to encode this namespace.
*
* @return {linkplain SchemaLanguageVersion version} of the HybridRow Schema Definition Language used to encode this
* {@linkplain Namespace namespace}.
*/
public final SchemaLanguageVersion version() {
return this.version;
}
/**
* Sets the version of the HybridRow Schema Definition Language used to encode this namespace.
*
* @param value {linkplain SchemaLanguageVersion version} of the HybridRow Schema Definition Language that will be
* used to encode this {@linkplain Namespace namespace}.
* @return a reference to this {@linkplain Namespace namespace}.
*/
public final Namespace version(SchemaLanguageVersion value) {
this.version = value;
return this;
@@ -67,12 +85,24 @@ public class Namespace {
/**
* Parse a JSON document and return a full namespace.
*
* @param value The JSON text to parse
* @param value The JSON text to parse.
* @return A namespace containing a set of logical schemas.
*/
public static Optional<Namespace> parse(String value) {
Optional<Namespace> ns = Json.<Namespace>parse(value);
ns.ifPresent(SchemaValidator::validate);
return ns;
Optional<Namespace> namespace = Json.parse(value, Namespace.class);
namespace.ifPresent(SchemaValidator::validate);
return namespace;
}
/**
* Parse a JSON document and return a full namespace.
*
* @param stream The JSON input stream to parse.
* @return A namespace containing a set of logical schemas.
*/
public static Optional<Namespace> parse(InputStream stream) {
Optional<Namespace> namespace = Json.parse(stream, Namespace.class);
namespace.ifPresent(SchemaValidator::validate);
return namespace;
}
}

View File

@@ -3,22 +3,26 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* A primitive property.
* <p>
* Primitive properties map to columns one-to-one. Primitive properties indicate how the
* column should be represented within the row.
* Primitive properties map to columns one-to-one. Primitive properties indicate how the column should be represented
* within the row.
*/
public class PrimitivePropertyType extends PropertyType {
@JsonProperty
private int length;
private StorageKind storage = StorageKind.values()[0];
@JsonProperty
private StorageKind storage;
/**
* The maximum allowable length in bytes.
* <p>
* This annotation is only valid for non-fixed length types. A value of 0 means the maximum
* allowable length.
* This annotation is only valid for non-fixed length types. A value of 0 means the maximum allowable length.
*/
public final int length() {
return this.length;

View File

@@ -3,56 +3,102 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;
/**
* Describes a single property definition.
*/
public class Property {
@JsonProperty(required = false)
private String comment;
@JsonProperty(required = true)
private String path;
private PropertyType propertyType;
@JsonProperty(required = true)
private PropertyType type;
/**
* An (optional) comment describing the purpose of this property
* An (optional) comment describing the purpose of this {@linkplain Property property}.
* <p>
* Comments are for documentary purpose only and do not affect the property at runtime.
*
* @return the comment on this {@linkplain Schema property} or {@code null}, if there is no comment.
*/
public final String comment() {
return this.comment;
}
/**
* Sets the (optional) comment describing the purpose of this {@linkplain Property property}.
* <p>
* Comments are for documentary purpose only and do not affect the property at runtime.
*
* @param value a comment on this {@linkplain Property property} or {@code null} to remove the comment, if any, on
* this {@linkplain Property property}.
* @return a reference to this {@linkplain Property property}.
*/
public final Property comment(String value) {
this.comment = value;
return this;
}
/**
* The logical path of this property.
* <p>
* The logical path of this {@linkplain Property property}.
* <p>.
* For complex properties (e.g. objects) the logical path forms a prefix to relative paths of properties defined
* within nested structures.
* <p>
* See the logical path specification for full details on both relative and absolute paths.
*
* @return the logical path of this {@linkplain Property property}.
*/
public final String path() {
return this.path;
}
public final void setPath(String value) {
/**
* Sets the logical path of this {@linkplain Property property}.
* <p>.
* For complex properties (e.g. objects) the logical path forms a prefix to relative paths of properties defined
* within nested structures.
* <p>
* See the logical path specification for full details on both relative and absolute paths.
*
* @param value the logical path of this {@linkplain Property property}.
* @return a reference to this {@linkplain Property property}.
*/
public final Property path(@Nonnull String value) {
this.path = value;
return this;
}
/**
* The type of the property.
* The type of this {@linkplain Property property}.
* <p>
* Types may be simple (e.g. int8) or complex (e.g. object). Simple types always define a single column. Complex
* Types may be simple (e.g. int8) or complex (e.g. object). Simple types always define a single column. Complex
* types may define one or more columns depending on their structure.
*
* @return the type of this {@linkplain Property property}.
*/
public final PropertyType propertyType() {
return this.propertyType;
public final PropertyType type() {
return this.type;
}
public final void setPropertyType(PropertyType value) {
this.propertyType = value;
/**
* Sets the type of this {@linkplain Property property}.
* <p>
* Types may be simple (e.g. int8) or complex (e.g. object). Simple types always define a single column. Complex
* types may define one or more columns depending on their structure.
*
* @param value the type of this {@linkplain Property property}.
* @return a reference to this {@linkplain Property property}.
*/
public final Property type(PropertyType value) {
this.type = value;
return this;
}
}
}

View File

@@ -3,54 +3,106 @@
package com.azure.data.cosmos.serialization.hybridrow.schemas;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import java.util.PrimitiveIterator;
/**
* The base class for property types both primitive and complex.
*/
@JsonTypeInfo(use = Id.NAME, property = "type")
@JsonSubTypes({
// Composite types
@Type(value = ArrayPropertyType.class, name = "array"),
@Type(value = MapPropertyType.class, name = "map"),
@Type(value = ObjectPropertyType.class, name="object"),
@Type(value = ScopePropertyType.class, name="scope"),
@Type(value = SetPropertyType.class, name="set"),
@Type(value = TaggedPropertyType.class, name="tagged"),
@Type(value = TuplePropertyType.class, name="tuple"),
// Primitive types
@Type(value = PrimitivePropertyType.class, name="int32"),
@Type(value = PrimitivePropertyType.class, name="uint32"),
@Type(value = PrimitivePropertyType.class, name="utf8")
})
public abstract class PropertyType {
@JsonProperty(required = true)
private TypeKind type;
@JsonProperty
private String apiType;
@JsonProperty(defaultValue = "true")
private boolean nullable;
private TypeKind type = TypeKind.values()[0];
protected PropertyType() {
this.nullable(true);
}
/**
* Api-specific type annotations for the property.
* API-specific type annotations for this {@linkplain Property property}.
*
* @return API-specific type annotations for this {@linkplain Property property}.
*/
public final String apiType() {
return this.apiType;
}
/**
* Sets API-specific type annotations for this {@linkplain Property property}.
*
* @param value API-specific type annotations for this {@linkplain Property property}.
* @return a reference to this {@linkplain Property property}.
*/
public final PropertyType apiType(String value) {
this.apiType = value;
return this;
}
/**
* {@code true} if the property can be {@code null}
* {@code true} if the {@linkplain Property property} can be {@code null}.
* <p>
* Default: {@code true}
*
* @return {@code true} if the {@linkplain Property property} can be {@code null, otherwise {@code false}}.
*/
public final boolean nullable() {
return this.nullable;
}
/**
* Sets a flag indicating whether the {@linkplain Property property} can be {@code null}.
*
* @param value {@code true} indicates that this {@linkplain Property property} can be {@code null}.
* @return a reference to this {@linkplain Property property}.
*/
public final PropertyType nullable(boolean value) {
this.nullable = value;
return this;
}
/**
* The logical type of the property
* The logical type of this {@linkplain Property property}.
*
* @return the logical type of this {@linkplain Property property}.
*/
public final TypeKind type() {
return this.type;
}
/**
* Sets the logical type of this {@linkplain Property property}.
*
* @param value the logical type of this {@linkplain Property property}.
* @return a reference to this {@linkplain Property property}.
*/
public final PropertyType type(TypeKind value) {
this.type = value;
return this;
}
}
}

View File

@@ -7,6 +7,7 @@ import com.azure.data.cosmos.core.Json;
import com.azure.data.cosmos.serialization.hybridrow.SchemaId;
import com.azure.data.cosmos.serialization.hybridrow.layouts.Layout;
import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutCompiler;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -27,23 +28,42 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class Schema {
private String comment;
// Required fields
@JsonProperty(required = true)
private SchemaId id;
@JsonProperty(required = true)
private String name;
@JsonProperty(defaultValue = "schema", required = true)
private TypeKind type;
// Optional fields
@JsonProperty
private String comment;
@JsonProperty
private SchemaOptions options;
@JsonProperty
private List<Property> properties;
@JsonProperty
private SchemaLanguageVersion version;
// TODO: DANOBLE: how do these properties serialize?
private List<PartitionKey> partitionKeys;
private List<PrimarySortKey> primaryKeys;
private List<Property> properties;
private SchemaId schemaId = SchemaId.NONE;
private List<StaticKey> staticKeys;
private TypeKind type = TypeKind.values()[0];
private SchemaLanguageVersion version = SchemaLanguageVersion.values()[0];
/**
* Initializes a new instance of the {@link Schema} class.
*/
public Schema() {
this.type(TypeKind.SCHEMA);
this.properties = Collections.emptyList();
private Schema() {
this.type = TypeKind.SCHEMA;
this.partitionKeys = Collections.emptyList();
this.primaryKeys = Collections.emptyList();
this.staticKeys = Collections.emptyList();
@@ -51,12 +71,24 @@ public class Schema {
/**
* An (optional) comment describing the purpose of this schema.
* <p>
* Comments are for documentary purpose only and do not affect the schema at runtime.
*
* @return the comment on this {@linkplain Schema schema} or {@code null}, if there is no comment.
*/
public final String comment() {
return this.comment;
}
/**
* Sets the (optional) comment describing the purpose of this schema.
* <p>
* Comments are for documentary purpose only and do not affect the schema at runtime.
*
* @param value a comment on this {@linkplain Schema schema} or {@code null} to remove the comment, if any, on this
* {@linkplain Schema schema}.
* @return a reference to this {@linkplain Schema schema}.
*/
public final Schema comment(String value) {
this.comment = value;
return this;
@@ -65,30 +97,41 @@ public class Schema {
/**
* Compiles this logical schema into a physical layout that can be used to read and write rows.
*
* @param ns The namespace within which this schema is defined.
* @param namespace The namespace within which this schema is defined.
* @return The layout for the schema.
*/
public final Layout compile(Namespace ns) {
public final Layout compile(Namespace namespace) {
checkNotNull(ns, "expected non-null ns");
checkArgument(ns.schemas().contains(this));
checkNotNull(namespace, "expected non-null ns");
checkArgument(namespace.schemas().contains(this));
return LayoutCompiler.compile(ns, this);
return LayoutCompiler.compile(namespace, this);
}
/**
* The name of the schema.
* The name of this {@linkplain Schema schema}.
* <p>
* The name of a schema MUST be unique within its namespace.
* <para />
* Names must begin with an alpha-numeric character and can only contain alpha-numeric characters and
* underscores.
* The name of a schema MUST be unique within its namespace. Names must begin with an alpha-numeric character and
* can only contain alpha-numeric characters and underscores.
*
* @return the name of this {@linkplain Schema schema} or {@code null}, if the name has not yet been set.
*/
public final String name() {
return this.name;
}
public final Schema name(String value) {
/**
* Sets the name of this {@linkplain Schema schema}.
* <p>
* The name of a schema MUST be unique within its namespace. Names must begin with an alpha-numeric character and
* can only contain alpha-numeric characters and underscores.
*
* @param value a name for this {@linkplain Schema schema}.
* @return a reference to this {@linkplain Schema schema}.
*/
@Nonnull
public final Schema name(@Nonnull String value) {
checkNotNull(value);
this.name = value;
return this;
}
@@ -112,8 +155,8 @@ public class Schema {
* @return A logical schema, if the value parses.
*/
public static Optional<Schema> parse(String value) {
return Json.<Schema>parse(value); // TODO: DANOBLE: perform structural validation on the Schema after JSON
// parsing
return Json.parse(value, Schema.class);
// TODO: DANOBLE: perform structural validation on the Schema after JSON parsing
}
/**
@@ -173,11 +216,11 @@ public class Schema {
* Identifiers must be unique within the scope of the database in which they are used.
*/
public final SchemaId schemaId() {
return this.schemaId;
return this.id;
}
public final Schema schemaId(SchemaId value) {
this.schemaId = value;
this.id = value;
return this;
}

View File

@@ -73,7 +73,7 @@ public final class SchemaHash {
HashCode128 hash = seed;
hash = Murmur3Hash.Hash128(p.path(), hash);
hash = SchemaHash.computeHash(ns, p.propertyType(), hash);
hash = SchemaHash.computeHash(ns, p.type(), hash);
return hash;
}

View File

@@ -12,26 +12,49 @@ public enum SchemaLanguageVersion {
/**
* Initial version of the HybridRow Schema Description Lanauge.
*/
V1((byte)0);
V1((byte) 0, "v1");
public static final int BYTES = Byte.BYTES;
private static HashMap<Byte, SchemaLanguageVersion> mappings;
private String friendlyName;
private byte value;
SchemaLanguageVersion(byte value) {
SchemaLanguageVersion(byte value, String text) {
this.value = value;
this.friendlyName = text;
mappings().put(value, this);
}
public byte getValue() {
return this.value;
/**
* Returns the friendly name of this enum constant.
*
* @return the friendly name of this enum constant.
* @see #toString()
*/
public String friendlyName() {
return this.friendlyName;
}
public static SchemaLanguageVersion forValue(byte value) {
public static SchemaLanguageVersion from(byte value) {
return mappings().get(value);
}
/**
* Returns the friendly name of this enum constant.
*
* @return the friendly name of this enum constant.
* @see #friendlyName()
*/
@Override
public String toString() {
return this.friendlyName;
}
public byte value() {
return this.value;
}
private static HashMap<Byte, SchemaLanguageVersion> mappings() {
if (mappings == null) {
synchronized (SchemaLanguageVersion.class) {
@@ -42,4 +65,6 @@ public enum SchemaLanguageVersion {
}
return mappings;
}
}

View File

@@ -110,7 +110,7 @@ public final class SchemaValidator {
Property p, Schema s, Map<SchemaIdentification, Schema> schemas, Map<SchemaId, Schema> ids) {
Assert.isValidIdentifier(p.path(), "Property path");
SchemaValidator.visit(p.propertyType(), null, schemas, ids);
SchemaValidator.visit(p.type(), null, schemas, ids);
}
private static void visit(
@@ -164,7 +164,7 @@ public final class SchemaValidator {
Map<String, Property> pathDupCheck = new HashMap<>(op.properties().size());
for (Property nested : op.properties()) {
Assert.duplicateCheck(nested.path(), nested, pathDupCheck, "Property path", "Object");
SchemaValidator.visit(nested.propertyType(), p, schemas, ids);
SchemaValidator.visit(nested.type(), p, schemas, ids);
}
return;
}

View File

@@ -19,7 +19,7 @@ public enum StorageKind {
* <p>
* This is indicative of an error in the the column specification.
*/
NONE(-1),
NONE(-1, "none"),
/**
* The property defines a sparse column
@@ -28,14 +28,14 @@ public enum StorageKind {
* linked list at the end of the row. Access time for sparse columns is proportional to the number of sparse columns
* in the row.
*/
SPARSE(0),
SPARSE(0, "sparse"),
/**
* The property is a fixed-length, space-reserved column
* <p>
* The column will consume 1 null-bit, and its byte-width regardless of whether the value is present in the row.
*/
FIXED(1),
FIXED(1, "fixed"),
/**
* The property is a variable-length column.
@@ -46,7 +46,7 @@ public enum StorageKind {
* When a <em>long</em> value is marked variable then a null-bit is reserved and the value is optionally encoded as
* variable if small enough to fit, otherwise the null-bit is set and the value is encoded as sparse.
*/
VARIABLE(2);
VARIABLE(2, "variable");
public static final int BYTES = Integer.BYTES;
@@ -57,17 +57,28 @@ public enum StorageKind {
return new Int2ObjectArrayMap<StorageKind>(values, storageKinds);
});
private int value;
private final String friendlyName;
private final int value;
StorageKind(int value) {
StorageKind(int value, String friendlyName) {
this.friendlyName = friendlyName;
this.value = value;
}
public int value() {
return this.value;
public String friendlyName() {
return this.friendlyName;
}
public static StorageKind from(int value) {
return mappings.get().get(value);
}
@Override
public String toString() {
return this.friendlyName;
}
public int value() {
return this.value;
}
}

View File

@@ -5,6 +5,7 @@ package com.azure.data.cosmos.serialization.hybridrow.schemas;
// TODO: DANOBLE: Fixup JSON-serialized naming for agreement with the dotnet code
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
import com.google.common.base.Suppliers;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@@ -19,7 +20,8 @@ public enum TypeKind {
/**
* Reserved.
*/
INVALID(0),
@JsonEnumDefaultValue
INVALID(0, "invalid"),
/**
* The literal null.
@@ -27,166 +29,166 @@ public enum TypeKind {
* 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, "null"),
/**
* A boolean property.
* <p>
* Boolean properties are allocated a single bit when schematized within a row.
*/
BOOLEAN(2),
BOOLEAN(2, "bool"),
/**
* 8-bit signed integer.
*/
INT_8(3),
INT_8(3, "int8"),
/**
* 16-bit signed integer.
*/
INT_16(4),
INT_16(4, "int16"),
/**
* 32-bit signed integer.
*/
INT_32(5),
INT_32(5, "int32"),
/**
* 64-bit signed integer.
*/
INT_64(6),
INT_64(6, "int64"),
/**
* 8-bit unsigned integer.
*/
UINT_8(7),
UINT_8(7, "uint8"),
/**
* 16-bit unsigned integer.
*/
UINT_16(8),
UINT_16(8, "uint16"),
/**
* 32-bit unsigned integer.
*/
UINT_32(9),
UINT_32(9, "uint32"),
/**
* 64-bit unsigned integer.
*/
UINT_64(10),
UINT_64(10, "uint64"),
/**
* Variable length encoded signed integer.
*/
VAR_INT(11),
VAR_INT(11, "varint"),
/**
* Variable length encoded unsigned integer.
*/
VAR_UINT(12),
VAR_UINT(12, "varuint"),
/**
* 32-bit IEEE 754 floating point value.
*/
FLOAT_32(13),
FLOAT_32(13, "float32"),
/**
* 64-bit IEEE 754 floating point value.
*/
FLOAT_64(14),
FLOAT_64(14, "float64"),
/**
* 128-bit IEEE 754-2008 floating point value.
*/
FLOAT_128(15),
FLOAT_128(15, "float128"),
/**
* 128-bit floating point value.
*
* @see java.math.BigDecimal
*/
DECIMAL(16),
DECIMAL(16, "decimal"),
/**
* 64-bit date/time value in 100ns increments from C# epoch.
*
* @see java.time.OffsetDateTime
*/
DATE_TIME(17),
DATE_TIME(17, "datetime"),
/**
* 64-bit date/time value in milliseconds increments from Unix epoch.
*
* @see com.azure.data.cosmos.serialization.hybridrow.UnixDateTime
*/
UNIX_DATE_TIME(18),
UNIX_DATE_TIME(18, "unixdatetime"),
/**
* 128-bit globally unique identifier (in little-endian byte order).
*/
GUID(19),
GUID(19, "guid"),
/**
* 12-byte MongoDB Object Identifier (in little-endian byte order).
*/
MONGODB_OBJECT_ID(20),
MONGODB_OBJECT_ID(20, "mongodb.objectid"),
/**
* Zero to MAX_ROW_SIZE bytes encoded as UTF-8 code points.
*/
UTF_8(21),
UTF_8(21, "utf8"),
/**
* Zero to MAX_ROW_SIZE untyped bytes.
*/
BINARY(22),
BINARY(22, "binary"),
/**
* An object property.
*/
OBJECT(23),
OBJECT(23, "object"),
/**
* An array property, either typed or untyped.
*/
ARRAY(24),
ARRAY(24, "array"),
/**
* A set property, either typed or untyped.
*/
SET(25),
SET(25, "set"),
/**
* A map property, either typed or untyped.
*/
MAP(26),
MAP(26, "map"),
/**
* A tuple property. Tuples are typed, finite, ordered, sets.
*/
TUPLE(27),
TUPLE(27, "tuple"),
/**
* A tagged property.
* <p>
* Tagged properties pair one or more typed values with an API-specific uint8 type code.
*/
TAGGED(28),
TAGGED(28, "tagged"),
/**
* A row with schema.
* <p>
* May define either a top-level table schema or a UDT (nested row).
*/
SCHEMA(29),
SCHEMA(29, "schema"),
/**
* An untyped sparse field.
* <p>
* May only be used to define the type within a nested scope.
*/
ANY(30);
ANY(30, "any");
public static final int BYTES = Integer.BYTES;
@@ -197,12 +199,35 @@ public enum TypeKind {
return new Int2ObjectOpenHashMap<>(values, typeKinds);
});
private int value;
private final String friendlyName;
private final int value;
TypeKind(int value) {
TypeKind(final int value, final String friendlyName) {
this.friendlyName = friendlyName;
this.value = value;
}
/**
* Returns the friendly name of this enum constant.
*
* @return the friendly name of this enum constant.
* @see #toString()
*/
public String friendlyName() {
return this.friendlyName;
}
/**
* Returns the friendly name of this enum constant.
*
* @return the friendly name of this enum constant.
* @see #friendlyName()
*/
@Override
public String toString() {
return this.friendlyName;
}
public int value() {
return this.value;
}

View File

@@ -27,8 +27,7 @@ public class UdtPropertyType extends ScopePropertyType {
/**
* The identifier of the UDT schema defining the structure for the nested row.
* <p>
* The UDT schema MUST be defined within the same {@link Namespace} as the schema that
* references it.
* The UDT schema MUST be defined within the same {@link Namespace} as the schema that references it.
*/
public final String name() {
return this.name;

View File

@@ -13,9 +13,9 @@ import static org.testng.Assert.*;
@Test(groups = "unit")
public class SystemSchemaTest {
private static final Path SchemaFile = Paths.get("data", "CustomerSchema.json");
private static final Path SCHEMA_FILE = Paths.get("test-data", "CustomerSchema.json");
@Test(enabled = false)
@Test
public void testLoadSchema() {
final LayoutResolver layoutResolver = SystemSchema.layoutResolver();

View File

@@ -1,16 +1,6 @@
# this is the log4j configuration for tests
# log4j configuration for tests
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1
# Set HTTP components' logger to INFO
log4j.category.io.netty=INFO
log4j.category.io.reactivex=INFO
log4j.category.com.microsoft.azure.cosmosdb=INFO
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n