Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#16] feat(schema) add JSON serialize and deserialize support for schema #20

Merged
merged 2 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {
implementation(libs.jackson.databind)
implementation(libs.jackson.annotations)
implementation(libs.jackson.datatype.jdk8)
implementation(libs.jackson.datatype.jsr310)
implementation(libs.guava)

compileOnly(libs.lombok)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public final class AuditInfo implements Entity {
public static final Field CREATOR =
Field.required("creator", String.class, "The name of user who creates the entity");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.datastrato.unified_catalog.schema;

import com.datastrato.unified_catalog.schema.json.JsonUtils;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.substrait.type.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public final class Column implements Entity, Auditable {

public static final Field ID =
Expand Down Expand Up @@ -47,6 +52,8 @@ public final class Column implements Entity, Auditable {
private String name;

@JsonProperty("type")
@JsonSerialize(using = JsonUtils.TypeSerializer.class)
@JsonDeserialize(using = JsonUtils.TypeDeserializer.class)
private Type type;

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public class Lakehouse implements Entity, Auditable {

public static final Field ID =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
package com.datastrato.unified_catalog.schema;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum SchemaVersion {
V_0_1(0, 1);

@JsonProperty("major_version")
public final int majorVersion;

@JsonProperty("minor_version")
public final int minorVersion;

@JsonCreator
public static SchemaVersion forValues(
@JsonProperty("major_version") int majorVersion,
@JsonProperty("minor_version") int minorVersion) {
for (SchemaVersion schemaVersion : SchemaVersion.values()) {
if (schemaVersion.majorVersion == majorVersion
&& schemaVersion.minorVersion == minorVersion) {
return schemaVersion;
}
}

throw new IllegalArgumentException(
String.format(
"No schema version found for major version %d and minor version %d",
majorVersion, minorVersion));
}

SchemaVersion(int majorVersion, int minorVersion) {
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public class Table implements Entity, Auditable, hasExtraInfo {
enum TableType {
public enum TableType {
VIRTUAL("VIRTUAL"),
VIEW("VIEW"),
EXTERNAL("EXTERNAL"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public final class Tenant implements Entity, Auditable {

public static final Field ID =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import java.util.Map;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public final class VirtualTableInfo implements hasExtraInfo.ExtraInfo {

public static final Field CONNECTION_ID =
Expand All @@ -22,6 +24,12 @@ public final class VirtualTableInfo implements hasExtraInfo.ExtraInfo {
@JsonProperty("identifier")
private final List<String> identifier;

// Only for Jackson deserialization
private VirtualTableInfo() {
this.connectionId = null;
this.identifier = null;
}

public VirtualTableInfo(Integer connectionId, List<String> identifier) {
this.connectionId = connectionId;
this.identifier = identifier;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@EqualsAndHashCode
@ToString
public class Zone implements Entity, Auditable {

public static final Field ID =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package com.datastrato.unified_catalog.schema;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

/** Interface for entities that have extra info. */
public interface hasExtraInfo {

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = VirtualTableInfo.class, name = "VIRTUAL")})
interface ExtraInfo extends Entity {}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.datastrato.unified_catalog.schema.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.substrait.type.StringTypeVisitor;
import io.substrait.type.Type;
import io.substrait.type.parser.ParseToPojo;
import io.substrait.type.parser.TypeStringParser;
import java.io.IOException;

public class JsonUtils {
private static ObjectMapper mapper = null;

public static ObjectMapper objectMapper() {
if (mapper == null) {
synchronized (JsonUtils.class) {
if (mapper == null) {
mapper =
new ObjectMapper()
.registerModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
}
}

return mapper;
}

public static class TypeSerializer extends JsonSerializer<io.substrait.type.Type> {
private final StringTypeVisitor visitor = new StringTypeVisitor();

@Override
public void serialize(Type value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
try {
gen.writeString(value.accept(visitor));
} catch (Exception e) {
throw new IOException("Unable to serialize type " + value, e);
}
}
}

public static class TypeDeserializer extends JsonDeserializer<io.substrait.type.Type> {

@Override
public Type deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String s = p.getValueAsString();
try {
return TypeStringParser.parse(s, ParseToPojo::type);
} catch (Exception e) {
throw new IOException("Unable to parse string " + s.replace("\n", " \\n"), e);
}
}
}
}
Loading