This is an automated email from the ASF dual-hosted git repository. jmclean 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 4c886eb290 [#5755] Add List and Map types to table/columns in Gravitino CLI (#6098) 4c886eb290 is described below commit 4c886eb290bf1aec5a72734ad4a583a60717f7f8 Author: Vincent Chee Jia Hong <33974196+jhc...@users.noreply.github.com> AuthorDate: Sun Jan 5 22:06:11 2025 +0000 [#5755] Add List and Map types to table/columns in Gravitino CLI (#6098) ### What changes were proposed in this pull request? - Supporting list and map types in Gravitino CLI operations. ### Why are the changes needed? Fix: # (issue) https://github.com/apache/gravitino/issues/5755 ### Does this PR introduce _any_ user-facing change? No ### How was this patch tested? Unit test to verify ParseType class can handle list and map input. --- .../java/org/apache/gravitino/cli/ParseType.java | 39 +++++++++- .../org/apache/gravitino/cli/TestParseType.java | 84 +++++++++++++++------- 2 files changed, 96 insertions(+), 27 deletions(-) diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/ParseType.java b/clients/cli/src/main/java/org/apache/gravitino/cli/ParseType.java index e797d0552a..9442175ef8 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/ParseType.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/ParseType.java @@ -22,6 +22,7 @@ package org.apache.gravitino.cli; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.gravitino.rel.types.Type; +import org.apache.gravitino.rel.types.Types; public class ParseType { @@ -36,7 +37,7 @@ public class ParseType { * @return a {@link org.apache.gravitino.cli.ParsedType} object representing the parsed type name. * @throws IllegalArgumentException if the data type format is unsupported or malformed */ - public static ParsedType parse(String datatype) { + public static ParsedType parseBasicType(String datatype) { Pattern pattern = Pattern.compile("^(\\w+)\\((\\d+)(?:,(\\d+))?\\)$"); Matcher matcher = pattern.matcher(datatype); @@ -57,8 +58,8 @@ public class ParseType { return null; } - public static Type toType(String datatype) { - ParsedType parsed = parse(datatype); + private static Type toBasicType(String datatype) { + ParsedType parsed = parseBasicType(datatype); if (parsed != null) { if (parsed.getPrecision() != null && parsed.getScale() != null) { @@ -70,4 +71,36 @@ public class ParseType { return TypeConverter.convert(datatype); } + + private static Type toListType(String datatype) { + Pattern pattern = Pattern.compile("^list\\((.+)\\)$"); + Matcher matcher = pattern.matcher(datatype); + if (matcher.matches()) { + Type elementType = toBasicType(matcher.group(1)); + return Types.ListType.of(elementType, false); + } + throw new IllegalArgumentException("Malformed list type: " + datatype); + } + + private static Type toMapType(String datatype) { + Pattern pattern = Pattern.compile("^map\\((.+),(.+)\\)$"); + Matcher matcher = pattern.matcher(datatype); + if (matcher.matches()) { + Type keyType = toBasicType(matcher.group(1)); + Type valueType = toBasicType(matcher.group(2)); + return Types.MapType.of(keyType, valueType, false); + } + throw new IllegalArgumentException("Malformed map type: " + datatype); + } + + public static Type toType(String datatype) { + if (datatype.startsWith("list")) { + return toListType(datatype); + } else if (datatype.startsWith("map")) { + return toMapType(datatype); + } + + // fallback: if not complex type, parse as primitive type + return toBasicType(datatype); + } } diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestParseType.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestParseType.java index c53d3c2bdc..6c9132dbf4 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestParseType.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestParseType.java @@ -19,49 +19,85 @@ package org.apache.gravitino.cli; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.apache.gravitino.rel.types.Type; +import org.apache.gravitino.rel.types.Types; import org.junit.jupiter.api.Test; public class TestParseType { @Test - public void testParseVarcharWithLength() { - ParsedType parsed = ParseType.parse("varchar(10)"); - assertNotNull(parsed); - assertEquals("varchar", parsed.getTypeName()); - assertEquals(10, parsed.getLength()); - assertNull(parsed.getScale()); - assertNull(parsed.getPrecision()); + public void testParseTypeVarcharWithLength() { + Type type = ParseType.toType("varchar(10)"); + assertThat(type, instanceOf(Types.VarCharType.class)); + assertEquals(10, ((Types.VarCharType) type).length()); } @Test - public void testParseDecimalWithPrecisionAndScale() { - ParsedType parsed = ParseType.parse("decimal(10,5)"); - assertNotNull(parsed); - assertEquals("decimal", parsed.getTypeName()); - assertEquals(10, parsed.getPrecision()); - assertEquals(5, parsed.getScale()); - assertNull(parsed.getLength()); + public void testParseTypeDecimalWithPrecisionAndScale() { + Type type = ParseType.toType("decimal(10,5)"); + assertThat(type, instanceOf(Types.DecimalType.class)); + assertEquals(10, ((Types.DecimalType) type).precision()); + assertEquals(5, ((Types.DecimalType) type).scale()); } @Test - public void testParseIntegerWithoutParameters() { - ParsedType parsed = ParseType.parse("int()"); - assertNull(parsed); // Expect null because the format is unsupported + public void testParseTypeListValidInput() { + Type type = ParseType.toType("list(integer)"); + assertThat(type, instanceOf(Types.ListType.class)); + Type elementType = ((Types.ListType) type).elementType(); + assertThat(elementType, instanceOf(Types.IntegerType.class)); } @Test - public void testParseOrdinaryInput() { - assertNull(ParseType.parse("string")); - assertNull(ParseType.parse("int")); + public void testParseTypeListMalformedInput() { + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("list()")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("list(10)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("list(unknown)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("list(integer,integer)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("list(integer")); } @Test - public void testParseMalformedInput() { - assertNull(ParseType.parse("varchar(-10)")); - assertNull(ParseType.parse("decimal(10,abc)")); + public void testParseTypeMapValidInput() { + Type type = ParseType.toType("map(string,integer)"); + assertThat(type, instanceOf(Types.MapType.class)); + Type keyType = ((Types.MapType) type).keyType(); + Type valueType = ((Types.MapType) type).valueType(); + assertThat(keyType, instanceOf(Types.StringType.class)); + assertThat(valueType, instanceOf(Types.IntegerType.class)); + } + + @Test + public void testParseTypeMapMalformedInput() { + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("map()")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("map(10,10)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("map(unknown,unknown)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("map(string)")); + assertThrows( + IllegalArgumentException.class, () -> ParseType.toType("map(string,integer,integer)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("map(string,integer")); + } + + @Test + public void testParseTypeIntegerWithoutParameters() { + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("int()")); + } + + @Test + public void testParseTypeOrdinaryInput() { + assertNull(ParseType.parseBasicType("string")); + assertNull(ParseType.parseBasicType("int")); + } + + @Test + public void testParseTypeMalformedInput() { + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("varchar(-10)")); + assertThrows(IllegalArgumentException.class, () -> ParseType.toType("decimal(10,abc)")); } }