This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 682e5a277 [#4795] feat(core): Add column entity in Gravitino (#4866)
682e5a277 is described below
commit 682e5a2773851acfe1252d4d2061a11e4687e775
Author: Jerry Shao <[email protected]>
AuthorDate: Fri Sep 13 15:26:59 2024 -0700
[#4795] feat(core): Add column entity in Gravitino (#4866)
### What changes were proposed in this pull request?
This PR adds a basic implementation of ColumnEntity in Gravitino.
### Why are the changes needed?
This is the first PR to let Gravitino to manage columns in its store.
Fix: #4795
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Add UTs to test.
---
.../org/apache/gravitino/meta/ColumnEntity.java | 204 +++++++++++++++++++++
.../org/apache/gravitino/meta/TableEntity.java | 20 +-
.../apache/gravitino/meta/TestColumnEntity.java | 195 ++++++++++++++++++++
3 files changed, 417 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/apache/gravitino/meta/ColumnEntity.java
b/core/src/main/java/org/apache/gravitino/meta/ColumnEntity.java
new file mode 100644
index 000000000..eb5663617
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/meta/ColumnEntity.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.meta;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.Map;
+import lombok.ToString;
+import org.apache.gravitino.Audit;
+import org.apache.gravitino.Auditable;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.Field;
+import org.apache.gravitino.rel.expressions.Expression;
+import org.apache.gravitino.rel.types.Type;
+
+/**
+ * A class representing a column entity in Apache Gravitino. Columns belong to
table, it uses table
+ * name identifier and column name as identifier.
+ */
+@ToString
+public class ColumnEntity implements Entity, Auditable {
+
+ public static final Field ID = Field.required("id", Long.class, "The
column's unique identifier");
+ public static final Field NAME = Field.required("name", String.class, "The
column's name");
+ public static final Field TYPE = Field.required("dataType", Type.class, "The
column's data type");
+ public static final Field COMMENT =
+ Field.optional("comment", String.class, "The column's comment");
+ public static final Field NULLABLE =
+ Field.required("nullable", Boolean.class, "The column's nullable
property");
+ public static final Field AUTO_INCREMENT =
+ Field.required("auto_increment", Boolean.class, "The column's auto
increment property");
+ public static final Field DEFAULT_VALUE =
+ Field.optional("default_value", Expression.class, "The column's default
value");
+ public static final Field AUDIT_INFO =
+ Field.required("audit_info", Audit.class, "The column's audit
information");
+
+ private Long id;
+
+ private String name;
+
+ private Type dataType;
+
+ private String comment;
+
+ private boolean nullable;
+
+ private boolean autoIncrement;
+
+ private Expression defaultValue;
+
+ private AuditInfo auditInfo;
+
+ private ColumnEntity() {}
+
+ @Override
+ public Map<Field, Object> fields() {
+ Map<Field, Object> fields = Maps.newHashMap();
+ fields.put(ID, id);
+ fields.put(NAME, name);
+ fields.put(TYPE, dataType);
+ fields.put(COMMENT, comment);
+ fields.put(NULLABLE, nullable);
+ fields.put(AUTO_INCREMENT, autoIncrement);
+ fields.put(DEFAULT_VALUE, defaultValue);
+ fields.put(AUDIT_INFO, auditInfo);
+
+ return Collections.unmodifiableMap(fields);
+ }
+
+ @Override
+ public EntityType type() {
+ return EntityType.COLUMN;
+ }
+
+ @Override
+ public Audit auditInfo() {
+ return auditInfo;
+ }
+
+ public Long id() {
+ return id;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public Type dataType() {
+ return dataType;
+ }
+
+ public String comment() {
+ return comment;
+ }
+
+ public boolean nullable() {
+ return nullable;
+ }
+
+ public boolean autoIncrement() {
+ return autoIncrement;
+ }
+
+ public Expression defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ColumnEntity)) return false;
+
+ ColumnEntity that = (ColumnEntity) o;
+ return Objects.equal(id, that.id)
+ && Objects.equal(name, that.name)
+ && Objects.equal(dataType, that.dataType)
+ && Objects.equal(comment, that.comment)
+ && Objects.equal(nullable, that.nullable)
+ && Objects.equal(autoIncrement, that.autoIncrement)
+ && Objects.equal(defaultValue, that.defaultValue)
+ && Objects.equal(auditInfo, that.auditInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ id, name, dataType, comment, nullable, autoIncrement, defaultValue,
auditInfo);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private final ColumnEntity columnEntity;
+
+ public Builder() {
+ columnEntity = new ColumnEntity();
+ }
+
+ public Builder withId(Long id) {
+ columnEntity.id = id;
+ return this;
+ }
+
+ public Builder withName(String name) {
+ columnEntity.name = name;
+ return this;
+ }
+
+ public Builder withDataType(Type dataType) {
+ columnEntity.dataType = dataType;
+ return this;
+ }
+
+ public Builder withComment(String comment) {
+ columnEntity.comment = comment;
+ return this;
+ }
+
+ public Builder withNullable(boolean nullable) {
+ columnEntity.nullable = nullable;
+ return this;
+ }
+
+ public Builder withAutoIncrement(boolean autoIncrement) {
+ columnEntity.autoIncrement = autoIncrement;
+ return this;
+ }
+
+ public Builder withDefaultValue(Expression defaultValue) {
+ columnEntity.defaultValue = defaultValue;
+ return this;
+ }
+
+ public Builder withAuditInfo(AuditInfo auditInfo) {
+ columnEntity.auditInfo = auditInfo;
+ return this;
+ }
+
+ public ColumnEntity build() {
+ columnEntity.validate();
+ return columnEntity;
+ }
+ }
+}
diff --git a/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
b/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
index eba1e60f5..e5a662770 100644
--- a/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/TableEntity.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.meta;
import com.google.common.base.Objects;
import com.google.common.collect.Maps;
+import java.util.Arrays;
import java.util.Map;
import lombok.ToString;
import org.apache.gravitino.Auditable;
@@ -36,6 +37,8 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
public static final Field NAME = Field.required("name", String.class, "The
table's name");
public static final Field AUDIT_INFO =
Field.required("audit_info", AuditInfo.class, "The audit details of the
table");
+ public static final Field COLUMNS =
+ Field.optional("columns", ColumnEntity[].class, "The columns of the
table");
private Long id;
@@ -45,6 +48,8 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
private Namespace namespace;
+ private ColumnEntity[] columns;
+
/**
* Returns a map of the fields and their corresponding values for this table.
*
@@ -56,6 +61,7 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
fields.put(ID, id);
fields.put(NAME, name);
fields.put(AUDIT_INFO, auditInfo);
+ fields.put(COLUMNS, columns);
return fields;
}
@@ -110,6 +116,10 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
return namespace;
}
+ public ColumnEntity[] columns() {
+ return columns;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -123,12 +133,13 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
return Objects.equal(id, baseTable.id)
&& Objects.equal(name, baseTable.name)
&& Objects.equal(namespace, baseTable.namespace)
- && Objects.equal(auditInfo, baseTable.auditInfo);
+ && Objects.equal(auditInfo, baseTable.auditInfo)
+ && Arrays.equals(columns, baseTable.columns);
}
@Override
public int hashCode() {
- return Objects.hashCode(id, name, auditInfo);
+ return Objects.hashCode(id, name, auditInfo, Arrays.hashCode(columns));
}
public static class Builder {
@@ -159,6 +170,11 @@ public class TableEntity implements Entity, Auditable,
HasIdentifier {
return this;
}
+ public Builder withColumns(ColumnEntity[] columns) {
+ tableEntity.columns = columns;
+ return this;
+ }
+
public TableEntity build() {
tableEntity.validate();
return tableEntity;
diff --git a/core/src/test/java/org/apache/gravitino/meta/TestColumnEntity.java
b/core/src/test/java/org/apache/gravitino/meta/TestColumnEntity.java
new file mode 100644
index 000000000..2bae86a50
--- /dev/null
+++ b/core/src/test/java/org/apache/gravitino/meta/TestColumnEntity.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.meta;
+
+import java.time.Instant;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestColumnEntity {
+
+ @Test
+ public void testColumnEntityFields() {
+ ColumnEntity columnEntity =
+ ColumnEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+
+ Assertions.assertEquals(1L, columnEntity.id());
+ Assertions.assertEquals("test", columnEntity.name());
+ Assertions.assertEquals("test comment", columnEntity.comment());
+ Assertions.assertEquals(Types.IntegerType.get(), columnEntity.dataType());
+ Assertions.assertTrue(columnEntity.nullable());
+ Assertions.assertTrue(columnEntity.autoIncrement());
+ Assertions.assertEquals(Literals.integerLiteral(1),
columnEntity.defaultValue());
+
+ ColumnEntity columnEntity2 =
+ ColumnEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+ Assertions.assertNull(columnEntity2.comment());
+
+ ColumnEntity columnEntity3 =
+ ColumnEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+ Assertions.assertNull(columnEntity3.defaultValue());
+ }
+
+ @Test
+ public void testWithoutRequiredFields() {
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> {
+ ColumnEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+ });
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> {
+ ColumnEntity.builder()
+ .withId(1L)
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+ });
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> {
+ ColumnEntity.builder()
+ .withId(1L)
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+ });
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> {
+ ColumnEntity.builder()
+ .withId(1L)
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .build();
+ });
+ }
+
+ @Test
+ public void testTableColumnEntity() {
+ ColumnEntity columnEntity1 =
+ ColumnEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withComment("test comment")
+ .withDataType(Types.IntegerType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.integerLiteral(1))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+
+ ColumnEntity columnEntity2 =
+ ColumnEntity.builder()
+ .withId(2L)
+ .withName("test2")
+ .withComment("test comment2")
+ .withDataType(Types.StringType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.stringLiteral("2"))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test2").withCreateTime(Instant.now()).build())
+ .build();
+
+ ColumnEntity columnEntity3 =
+ ColumnEntity.builder()
+ .withId(3L)
+ .withName("test3")
+ .withComment("test comment3")
+ .withDataType(Types.BooleanType.get())
+ .withNullable(true)
+ .withAutoIncrement(true)
+ .withDefaultValue(Literals.booleanLiteral(true))
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test3").withCreateTime(Instant.now()).build())
+ .build();
+
+ ColumnEntity[] columns = new ColumnEntity[] {columnEntity1, columnEntity2,
columnEntity3};
+ TableEntity tableEntity =
+ TableEntity.builder()
+ .withId(1L)
+ .withName("test")
+ .withNamespace(Namespace.of("catalog", "schema"))
+ .withColumns(columns)
+ .withAuditInfo(
+
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
+ .build();
+
+ Assertions.assertEquals(1L, tableEntity.id());
+ Assertions.assertEquals("test", tableEntity.name());
+ Assertions.assertEquals(Namespace.of("catalog", "schema"),
tableEntity.namespace());
+ Assertions.assertArrayEquals(columns, tableEntity.columns());
+ Assertions.assertEquals(3, tableEntity.columns().length);
+ }
+}