Skip to content

Commit

Permalink
[apache#6493] feat(CLI): Support table format output for Schema and T…
Browse files Browse the repository at this point in the history
…able command

Support table format output for Schema and Table command
  • Loading branch information
Abyss-lord committed Feb 22, 2025
1 parent 4ffe56c commit 9666434
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

package org.apache.gravitino.cli.commands;

import com.google.common.base.Joiner;
import org.apache.gravitino.cli.CommandContext;
import org.apache.gravitino.cli.ErrorMessages;
import org.apache.gravitino.client.GravitinoClient;
Expand Down Expand Up @@ -60,8 +59,11 @@ public void handle() {
exitWithError(exp.getMessage());
}

String all = schemas.length == 0 ? "No schemas exist." : Joiner.on(",").join(schemas);
if (schemas.length == 0) {
printInformation("No schemas found in catalog " + catalog);
return;
}

printInformation(all);
printResults(schemas);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@

package org.apache.gravitino.cli.commands;

import com.google.common.base.Joiner;
import java.util.ArrayList;
import java.util.List;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.cli.CommandContext;
import org.apache.gravitino.rel.Table;
import org.apache.gravitino.rel.TableCatalog;

/** List the names of all tables in a schema. */
public class ListTables extends TableCommand {
Expand All @@ -49,22 +50,32 @@ public ListTables(CommandContext context, String metalake, String catalog, Strin
public void handle() {
NameIdentifier[] tables = null;
Namespace name = Namespace.of(schema);
TableCatalog tableCatalog = null;

try {
tables = tableCatalog().listTables(name);
tableCatalog = tableCatalog();
tables = tableCatalog.listTables(name);
} catch (Exception exp) {
exitWithError(exp.getMessage());
}

List<String> tableNames = new ArrayList<>();
for (int i = 0; i < tables.length; i++) {
tableNames.add(tables[i].name());
for (NameIdentifier table : tables) {
tableNames.add(table.name());
}
// PERF load table may cause performance issue
Table[] tableObjects = new Table[tableNames.size()];
int i = 0;
for (NameIdentifier tableIdent : tables) {
tableObjects[i] = tableCatalog.loadTable(tableIdent);
i++;
}

String all =
tableNames.isEmpty()
? "No tables exist."
: Joiner.on(System.lineSeparator()).join(tableNames);
if (tableNames.isEmpty()) {
printInformation("No tables exist.");
return;
}

printResults(all);
printResults(tableObjects);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void handle() {
}

if (result != null) {
printInformation(result.name() + "," + result.comment());
printResults(result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public void handle() {
exitWithError(exp.getMessage());
}

printInformation(gTable.name() + "," + gTable.comment());
if (gTable != null) {
printResults(gTable);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
import java.util.Objects;
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;

/**
* Abstract base class for formatting entity information into ASCII-art tables. Provides
Expand Down Expand Up @@ -75,6 +77,14 @@ public static void output(Object entity, CommandContext context) {
new CatalogTableFormat(context).output((Catalog) entity);
} else if (entity instanceof Catalog[]) {
new CatalogListTableFormat(context).output((Catalog[]) entity);
} else if (entity instanceof Schema) {
new SchemaTableFormat(context).output((Schema) entity);
} else if (entity instanceof Schema[]) {
new SchemaListTableFormat(context).output((Schema[]) entity);
} else if (entity instanceof Table) {
new TableDetailsTableFormat(context).output((Table) entity);
} else if (entity instanceof Table[]) {
new TableListTableFormat(context).output((Table[]) entity);
} else {
throw new IllegalArgumentException("Unsupported object type");
}
Expand Down Expand Up @@ -540,4 +550,96 @@ public String getOutput(Catalog[] catalogs) {
return getTableFormat(columnName);
}
}

/**
* Formats a single {@link Schema} instance into a two-column table display. Displays catalog
* details including name and comment information.
*/
static final class SchemaTableFormat extends TableFormat<Schema> {
public SchemaTableFormat(CommandContext context) {
super(context);
}

/** {@inheritDoc} */
@Override
public String getOutput(Schema schema) {
Column columnName = new Column(context, "schema");
Column columnComment = new Column(context, "comment");

columnName.addCell(schema.name());
columnComment.addCell(schema.comment());

return getTableFormat(columnName, columnComment);
}
}

/**
* Formats an array of Schemas into a single-column table display. Lists all schema names in a
* vertical format.
*/
static final class SchemaListTableFormat extends TableFormat<Schema[]> {
public SchemaListTableFormat(CommandContext context) {
super(context);
}

/** {@inheritDoc} */
@Override
public String getOutput(Schema[] schemas) {
Column column = new Column(context, "schema");
Arrays.stream(schemas).forEach(schema -> column.addCell(schema.name()));

return getTableFormat(column);
}
}

/**
* Formats a single {@link Table} instance into a two-column table display. Displays table details
* including name and comment information.
*/
static final class TableDetailsTableFormat extends TableFormat<Table> {
public TableDetailsTableFormat(CommandContext context) {
super(context);
}

/** {@inheritDoc} */
@Override
public String getOutput(Table table) {
Column columnName = new Column(context, "name");
Column columnType = new Column(context, "type");
Column columnAutoIncrement = new Column(context, "AutoIncrement");
Column columnNullable = new Column(context, "nullable");
Column columnComment = new Column(context, "comment");

org.apache.gravitino.rel.Column[] columns = table.columns();
for (org.apache.gravitino.rel.Column column : columns) {
columnName.addCell(column.name());
columnType.addCell(column.dataType().simpleString());
columnAutoIncrement.addCell(column.autoIncrement());
columnNullable.addCell(column.nullable());
columnComment.addCell(column.comment().isEmpty() ? "N/A" : column.comment());
}

return getTableFormat(
columnName, columnType, columnAutoIncrement, columnNullable, columnComment);
}
}

/**
* Formats an array of {@link Table} into a single-column table display. Lists all table names in
* a vertical format.
*/
static final class TableListTableFormat extends TableFormat<Table[]> {
public TableListTableFormat(CommandContext context) {
super(context);
}

/** {@inheritDoc} */
@Override
public String getOutput(Table[] tables) {
Column column = new Column(context, "name");
Arrays.stream(tables).forEach(table -> column.addCell(table.name()));

return getTableFormat(column);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@
import java.nio.charset.StandardCharsets;
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.cli.outputs.Column;
import org.apache.gravitino.cli.outputs.TableFormat;
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;
Expand Down Expand Up @@ -295,6 +299,75 @@ void testListCatalogWithTableFormat() {
output);
}

@Test
void testSchemaDetailsWithTableFormat() {
CommandContext mockContext = getMockContext();
Schema mockSchema = getMockSchema();

TableFormat.output(mockSchema, mockContext);
String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim();
Assertions.assertEquals(
"+-------------+-----------------------+\n"
+ "| Schema | Comment |\n"
+ "+-------------+-----------------------+\n"
+ "| demo_schema | This is a demo schema |\n"
+ "+-------------+-----------------------+",
output);
}

@Test
void testListSchemaWithTableFormat() {
CommandContext mockContext = getMockContext();
Schema mockSchema1 = getMockSchema("schema1", "This is a schema");
Schema mockSchema2 = getMockSchema("schema2", "This is another schema");

TableFormat.output(new Schema[] {mockSchema1, mockSchema2}, mockContext);
String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim();
Assertions.assertEquals(
"+---------+\n"
+ "| Schema |\n"
+ "+---------+\n"
+ "| schema1 |\n"
+ "| schema2 |\n"
+ "+---------+",
output);
}

@Test
void testTableDetailsWithTableFormat() {
CommandContext mockContext = getMockContext();
Table mockTable = getMockTable();

TableFormat.output(mockTable, mockContext);
String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim();
Assertions.assertEquals(
"+------+---------+---------------+----------+-------------------------+\n"
+ "| Name | Type | AutoIncrement | Nullable | Comment |\n"
+ "+------+---------+---------------+----------+-------------------------+\n"
+ "| id | integer | true | false | This is a int column |\n"
+ "| name | string | false | true | This is a string column |\n"
+ "+------+---------+---------------+----------+-------------------------+",
output);
}

@Test
void testListTableWithTableFormat() {
CommandContext mockContext = getMockContext();
Table mockTable1 = getMockTable("table1", "This is a table");
Table mockTable2 = getMockTable("table2", "This is another table");

TableFormat.output(new Table[] {mockTable1, mockTable2}, mockContext);
String output = new String(outContent.toByteArray(), StandardCharsets.UTF_8).trim();
Assertions.assertEquals(
"+--------+\n"
+ "| Name |\n"
+ "+--------+\n"
+ "| table1 |\n"
+ "| table2 |\n"
+ "+--------+",
output);
}

@Test
void testOutputWithUnsupportType() {
CommandContext mockContext = getMockContext();
Expand All @@ -307,12 +380,6 @@ void testOutputWithUnsupportType() {
});
}

private void addRepeatedCells(Column column, int count) {
for (int i = 0; i < count; i++) {
column.addCell(column.getHeader() + "-" + (i + 1));
}
}

private CommandContext getMockContext() {
CommandContext mockContext = mock(CommandContext.class);

Expand Down Expand Up @@ -345,4 +412,48 @@ private Catalog getMockCatalog(String name, Catalog.Type type, String provider,

return mockCatalog;
}

private Schema getMockSchema() {
return getMockSchema("demo_schema", "This is a demo schema");
}

private Schema getMockSchema(String name, String comment) {
Schema mockSchema = mock(Schema.class);
when(mockSchema.name()).thenReturn(name);
when(mockSchema.comment()).thenReturn(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;
}
}

0 comments on commit 9666434

Please sign in to comment.