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);
+  }
+}

Reply via email to