From c536536ee2a85ddfcb11f96149ac6933dd4b7522 Mon Sep 17 00:00:00 2001 From: pancx Date: Sat, 22 Feb 2025 12:48:33 +0800 Subject: [PATCH 1/4] [#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"); From 8aa40bfbe78fc255b9693dfe41176f770a13fd21 Mon Sep 17 00:00:00 2001 From: pancx Date: Sat, 22 Feb 2025 13:10:34 +0800 Subject: [PATCH 2/4] [#6496] feat(CLI): Support plain format output for Schema and Table command fix some bugs. --- .../apache/gravitino/cli/outputs/PlainFormat.java | 6 +++++- .../gravitino/cli/output/TestPlainFormat.java | 14 +++----------- 2 files changed, 8 insertions(+), 12 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 f74b786eb7d..8520ba7f366 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 @@ -194,7 +194,11 @@ public String getOutput(Table table) { .map( column -> COMMA_JOINER.join( - column.name(), column.dataType().simpleString(), column.comment())) + column.name(), + column.dataType().simpleString(), + column.autoIncrement(), + column.nullable(), + column.comment() == null ? "N/A" : column.comment())) .collect(Collectors.toList()); output.append(NEWLINE_JOINER.join(columnOutput)); output.append(System.lineSeparator()); 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 428cfba15e7..093b8535e0f 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 @@ -132,7 +132,9 @@ void testTableDetailsWithPlainFormat() { 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); + "id, integer, true, false, This is a int column\n" + + "name, string, false, true, This is a string column", + output); } @Test @@ -146,16 +148,6 @@ void testListTableWithPlainFormat() { 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(); From b587c72d3b55710bc50c7a00f4044c38fcf1de32 Mon Sep 17 00:00:00 2001 From: pancx Date: Tue, 25 Feb 2025 16:17:08 +0800 Subject: [PATCH 3/4] [#6496] feat(CLI): Support plain format output for Schema and Table command fix some bugs. --- .../gravitino/cli/outputs/PlainFormat.java | 43 +++++++++++-------- .../gravitino/cli/output/TestPlainFormat.java | 42 ++++++++++++------ 2 files changed, 55 insertions(+), 30 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 8520ba7f366..ed35c9fe46f 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 @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import org.apache.gravitino.Audit; import org.apache.gravitino.Catalog; import org.apache.gravitino.Metalake; import org.apache.gravitino.Schema; @@ -55,6 +56,8 @@ public static void output(Object entity, CommandContext context) { new TablePlainFormat(context).output((Table) entity); } else if (entity instanceof Table[]) { new TableListPlainFormat(context).output((Table[]) entity); + } else if (entity instanceof Audit) { + new AuditPlainFormat(context).output((Audit) entity); } else { throw new IllegalArgumentException("Unsupported object type"); } @@ -176,8 +179,7 @@ public String getOutput(Schema[] schemas) { } /** - * 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 ... + * Formats a single Table instance with detailed column information. Output format: table_name, * table_comment */ static final class TablePlainFormat extends PlainFormat
{ @@ -188,21 +190,8 @@ public TablePlainFormat(CommandContext 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.autoIncrement(), - column.nullable(), - column.comment() == null ? "N/A" : column.comment())) - .collect(Collectors.toList()); - output.append(NEWLINE_JOINER.join(columnOutput)); - output.append(System.lineSeparator()); - return output.toString(); + String comment = table.comment() == null ? "N/A" : table.comment(); + return COMMA_JOINER.join(new String[] {table.name(), comment}); } } @@ -222,4 +211,24 @@ public String getOutput(Table[] tables) { return NEWLINE_JOINER.join(tableNames); } } + + /** + * Formats an instance of {@link Audit} , outputting the audit information. Output format: + * creator, create_time, modified, modified_time + */ + static final class AuditPlainFormat extends PlainFormat { + public AuditPlainFormat(CommandContext context) { + super(context); + } + + /** {@inheritDoc} */ + @Override + public String getOutput(Audit audit) { + return COMMA_JOINER.join( + audit.creator(), + audit.createTime() == null ? "N/A" : audit.createTime(), + audit.lastModifier() == null ? "N/A" : audit.lastModifier(), + audit.lastModifiedTime() == null ? "N/A" : audit.lastModifiedTime()); + } + } } 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 093b8535e0f..32e9e7dbc86 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 @@ -131,10 +131,36 @@ void testTableDetailsWithPlainFormat() { Table mockTable = getMockTable(); PlainFormat.output(mockTable, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals("demo_table, This is a demo table", output); + } + + @Test + void testAuditWithTableFormat() { + CommandContext mockContext = getMockContext(); + Audit mockAudit = mock(Audit.class); + when(mockAudit.creator()).thenReturn("demo_user"); + when(mockAudit.createTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); + when(mockAudit.lastModifier()).thenReturn("demo_user"); + when(mockAudit.lastModifiedTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); + + PlainFormat.output(mockAudit, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); Assertions.assertEquals( - "id, integer, true, false, This is a int column\n" - + "name, string, false, true, This is a string column", - output); + "demo_user, 2021-01-20T02:51:51.111Z, demo_user, 2021-01-20T02:51:51.111Z", output); + } + + @Test + void testAuditWithTableFormatWithNullValues() { + CommandContext mockContext = getMockContext(); + Audit mockAudit = mock(Audit.class); + when(mockAudit.creator()).thenReturn("demo_user"); + when(mockAudit.createTime()).thenReturn(null); + when(mockAudit.lastModifier()).thenReturn(null); + when(mockAudit.lastModifiedTime()).thenReturn(null); + + PlainFormat.output(mockAudit, mockContext); + String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); + Assertions.assertEquals("demo_user, N/A, N/A, N/A", output); } @Test @@ -236,14 +262,4 @@ private org.apache.gravitino.rel.Column getMockColumn( return mockColumn; } - - private Audit getMockAudit() { - Audit mockAudit = mock(Audit.class); - when(mockAudit.creator()).thenReturn("demo_user"); - when(mockAudit.createTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); - when(mockAudit.lastModifier()).thenReturn("demo_user"); - when(mockAudit.lastModifiedTime()).thenReturn(Instant.ofEpochMilli(1611111111111L)); - - return mockAudit; - } } From 41986a7e8f4a9c9b475d0302816c667eb96021f7 Mon Sep 17 00:00:00 2001 From: pancx Date: Tue, 25 Feb 2025 16:27:36 +0800 Subject: [PATCH 4/4] [#6496] feat(CLI): Support plain format output for Schema and Table command fix COMMA_JOINER. --- .../apache/gravitino/cli/outputs/OutputFormat.java | 2 +- .../gravitino/cli/output/TestPlainFormat.java | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java index fe0d7b7c9e0..378fdf746bb 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/outputs/OutputFormat.java @@ -26,7 +26,7 @@ */ public interface OutputFormat { /** Joiner for creating comma-separated output strings, ignoring null values */ - Joiner COMMA_JOINER = Joiner.on(", ").skipNulls(); + Joiner COMMA_JOINER = Joiner.on(",").skipNulls(); /** Joiner for creating line-separated output strings, ignoring null values */ Joiner NEWLINE_JOINER = Joiner.on(System.lineSeparator()).skipNulls(); 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 32e9e7dbc86..33836588f83 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 @@ -67,7 +67,7 @@ void testMetalakeDetailsWithPlainFormat() { PlainFormat.output(mockMetalake, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); - Assertions.assertEquals("demo_metalake, This is a demo metalake", output); + Assertions.assertEquals("demo_metalake,This is a demo metalake", output); } @Test @@ -88,8 +88,7 @@ void testCatalogDetailsWithPlainFormat() { PlainFormat.output(mockCatalog, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); - Assertions.assertEquals( - "demo_catalog, RELATIONAL, demo_provider, This is a demo catalog", output); + Assertions.assertEquals("demo_catalog,RELATIONAL,demo_provider,This is a demo catalog", output); } @Test @@ -111,7 +110,7 @@ void testSchemaDetailsWithPlainFormat() { 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); + Assertions.assertEquals("demo_schema,This is a demo schema", output); } @Test @@ -131,7 +130,7 @@ void testTableDetailsWithPlainFormat() { Table mockTable = getMockTable(); PlainFormat.output(mockTable, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); - Assertions.assertEquals("demo_table, This is a demo table", output); + Assertions.assertEquals("demo_table,This is a demo table", output); } @Test @@ -146,7 +145,7 @@ void testAuditWithTableFormat() { PlainFormat.output(mockAudit, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); Assertions.assertEquals( - "demo_user, 2021-01-20T02:51:51.111Z, demo_user, 2021-01-20T02:51:51.111Z", output); + "demo_user,2021-01-20T02:51:51.111Z,demo_user,2021-01-20T02:51:51.111Z", output); } @Test @@ -160,7 +159,7 @@ void testAuditWithTableFormatWithNullValues() { PlainFormat.output(mockAudit, mockContext); String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim(); - Assertions.assertEquals("demo_user, N/A, N/A, N/A", output); + Assertions.assertEquals("demo_user,N/A,N/A,N/A", output); } @Test