From c536536ee2a85ddfcb11f96149ac6933dd4b7522 Mon Sep 17 00:00:00 2001 From: pancx Date: Sat, 22 Feb 2025 12:48:33 +0800 Subject: [PATCH] [#6496] feat(CLI): Support plain format output for Schema and Table command Support plain format output for Schema and Table command --- .../gravitino/cli/outputs/PlainFormat.java | 100 ++++++++++++++++-- .../gravitino/cli/output/TestPlainFormat.java | 86 +++++++++++++++ 2 files changed, 178 insertions(+), 8 deletions(-) diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java index f61578ffc6f..f74b786eb7d 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/PlainFormat.java @@ -23,7 +23,9 @@ import java.util.stream.Collectors; import org.apache.gravitino.Catalog; import org.apache.gravitino.Metalake; +import org.apache.gravitino.Schema; import org.apache.gravitino.cli.CommandContext; +import org.apache.gravitino.rel.Table; /** Plain format to print a pretty string to standard out. */ public abstract class PlainFormat extends BaseOutputFormat { @@ -45,6 +47,14 @@ public static void output(Object entity, CommandContext context) { new CatalogPlainFormat(context).output((Catalog) entity); } else if (entity instanceof Catalog[]) { new CatalogListPlainFormat(context).output((Catalog[]) entity); + } else if (entity instanceof Schema) { + new SchemaPlainFormat(context).output((Schema) entity); + } else if (entity instanceof Schema[]) { + new SchemaListPlainFormat(context).output((Schema[]) entity); + } else if (entity instanceof Table) { + new TablePlainFormat(context).output((Table) entity); + } else if (entity instanceof Table[]) { + new TableListPlainFormat(context).output((Table[]) entity); } else { throw new IllegalArgumentException("Unsupported object type"); } @@ -124,14 +134,88 @@ public CatalogListPlainFormat(CommandContext context) { /** {@inheritDoc} */ @Override public String getOutput(Catalog[] catalogs) { - if (catalogs == null || catalogs.length == 0) { - output("No catalogs exist.", System.out); - return null; - } else { - List catalogNames = - Arrays.stream(catalogs).map(Catalog::name).collect(Collectors.toList()); - return NEWLINE_JOINER.join(catalogNames); - } + + List catalogNames = + Arrays.stream(catalogs).map(Catalog::name).collect(Collectors.toList()); + return NEWLINE_JOINER.join(catalogNames); + } + } + + /** + * Formats a single {@link Schema} instance as a comma-separated string. Output format: name, + * comment + */ + static final class SchemaPlainFormat extends PlainFormat { + public SchemaPlainFormat(CommandContext context) { + super(context); + } + + /** {@inheritDoc} */ + @Override + public String getOutput(Schema schema) { + return COMMA_JOINER.join(schema.name(), schema.comment()); + } + } + + /** + * Formats an array of Schemas, outputting one name per line. Returns null if the array is empty + * or null. + */ + static final class SchemaListPlainFormat extends PlainFormat { + public SchemaListPlainFormat(CommandContext context) { + super(context); + } + + /** {@inheritDoc} */ + @Override + public String getOutput(Schema[] schemas) { + List schemaNames = + Arrays.stream(schemas).map(Schema::name).collect(Collectors.toList()); + return NEWLINE_JOINER.join(schemaNames); + } + } + + /** + * Formats a single Table instance with detailed column information. Output format: table_name + * column1_name, column1_type, column1_comment column2_name, column2_type, column2_comment ... + * table_comment + */ + static final class TablePlainFormat extends PlainFormat { + public TablePlainFormat(CommandContext context) { + super(context); + } + + /** {@inheritDoc} */ + @Override + public String getOutput(Table table) { + StringBuilder output = new StringBuilder(); + List columnOutput = + Arrays.stream(table.columns()) + .map( + column -> + COMMA_JOINER.join( + column.name(), column.dataType().simpleString(), column.comment())) + .collect(Collectors.toList()); + output.append(NEWLINE_JOINER.join(columnOutput)); + output.append(System.lineSeparator()); + return output.toString(); + } + } + + /** + * Formats an array of Tables, outputting one name per line. Returns null if the array is empty or + * null. + */ + static final class TableListPlainFormat extends PlainFormat { + public TableListPlainFormat(CommandContext context) { + super(context); + } + + /** {@inheritDoc} */ + @Override + public String getOutput(Table[] tables) { + List tableNames = Arrays.stream(tables).map(Table::name).collect(Collectors.toList()); + return NEWLINE_JOINER.join(tableNames); } } } diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java index 300a12e9d57..428cfba15e7 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/output/TestPlainFormat.java @@ -33,6 +33,9 @@ import org.apache.gravitino.Schema; import org.apache.gravitino.cli.CommandContext; import org.apache.gravitino.cli.outputs.PlainFormat; +import org.apache.gravitino.rel.Table; +import org.apache.gravitino.rel.types.Type; +import org.apache.gravitino.rel.types.Types; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -102,6 +105,57 @@ void testListCatalogWithPlainFormat() { Assertions.assertEquals("catalog1\n" + "catalog2", output); } + @Test + void testSchemaDetailsWithPlainFormat() { + CommandContext mockContext = getMockContext(); + Schema mockSchema = getMockSchema(); + PlainFormat.output(mockSchema, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals("demo_schema, This is a demo schema", output); + } + + @Test + void testListSchemaWithPlainFormat() { + CommandContext mockContext = getMockContext(); + Schema mockSchema1 = getMockSchema("schema1", "This is a schema"); + Schema mockSchema2 = getMockSchema("schema2", "This is another schema"); + + PlainFormat.output(new Schema[] {mockSchema1, mockSchema2}, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals("schema1\n" + "schema2", output); + } + + @Test + void testTableDetailsWithPlainFormat() { + CommandContext mockContext = getMockContext(); + Table mockTable = getMockTable(); + PlainFormat.output(mockTable, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals( + "id, integer, This is a int column\n" + "name, string, This is a string column", output); + } + + @Test + void testListTableWithPlainFormat() { + CommandContext mockContext = getMockContext(); + Table mockTable1 = getMockTable("table1", "This is a table"); + Table mockTable2 = getMockTable("table2", "This is another table"); + + PlainFormat.output(new Table[] {mockTable1, mockTable2}, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals("table1\n" + "table2", output); + } + + @Test + void testTableDetailsWithAuditWithPlainFormat() { + CommandContext mockContext = getMockContext(); + Table mockTable = getMockTable(); + PlainFormat.output(mockTable, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals( + "id, integer, This is a int column\n" + "name, string, This is a string column", output); + } + @Test void testOutputWithUnsupportType() { CommandContext mockContext = getMockContext(); @@ -159,6 +213,38 @@ private Schema getMockSchema(String name, String comment) { return mockSchema; } + private Table getMockTable() { + return getMockTable("demo_table", "This is a demo table"); + } + + private Table getMockTable(String name, String comment) { + Table mockTable = mock(Table.class); + org.apache.gravitino.rel.Column mockColumnInt = + getMockColumn("id", Types.IntegerType.get(), "This is a int column", false, true); + org.apache.gravitino.rel.Column mockColumnString = + getMockColumn("name", Types.StringType.get(), "This is a string column", true, false); + + when(mockTable.name()).thenReturn(name); + when(mockTable.comment()).thenReturn(comment); + when(mockTable.columns()) + .thenReturn(new org.apache.gravitino.rel.Column[] {mockColumnInt, mockColumnString}); + + return mockTable; + } + + private org.apache.gravitino.rel.Column getMockColumn( + String name, Type dataType, String comment, boolean nullable, boolean autoIncrement) { + + org.apache.gravitino.rel.Column mockColumn = mock(org.apache.gravitino.rel.Column.class); + when(mockColumn.name()).thenReturn(name); + when(mockColumn.dataType()).thenReturn(dataType); + when(mockColumn.comment()).thenReturn(comment); + when(mockColumn.nullable()).thenReturn(nullable); + when(mockColumn.autoIncrement()).thenReturn(autoIncrement); + + return mockColumn; + } + private Audit getMockAudit() { Audit mockAudit = mock(Audit.class); when(mockAudit.creator()).thenReturn("demo_user");