diff --git a/ksql-cli/src/main/java/io/confluent/ksql/cli/console/Console.java b/ksql-cli/src/main/java/io/confluent/ksql/cli/console/Console.java index 1479ea6e0ce1..f5e250625e99 100644 --- a/ksql-cli/src/main/java/io/confluent/ksql/cli/console/Console.java +++ b/ksql-cli/src/main/java/io/confluent/ksql/cli/console/Console.java @@ -40,6 +40,7 @@ import io.confluent.ksql.cli.console.table.builder.TableBuilder; import io.confluent.ksql.cli.console.table.builder.TablesListTableBuilder; import io.confluent.ksql.cli.console.table.builder.TopicDescriptionTableBuilder; +import io.confluent.ksql.cli.console.table.builder.TypeListTableBuilder; import io.confluent.ksql.json.JsonMapper; import io.confluent.ksql.rest.entity.ArgumentInfo; import io.confluent.ksql.rest.entity.CommandStatusEntity; @@ -66,7 +67,6 @@ import io.confluent.ksql.rest.entity.QueryDescriptionEntity; import io.confluent.ksql.rest.entity.QueryDescriptionList; import io.confluent.ksql.rest.entity.RunningQuery; -import io.confluent.ksql.rest.entity.SchemaInfo; import io.confluent.ksql.rest.entity.SourceDescription; import io.confluent.ksql.rest.entity.SourceDescriptionEntity; import io.confluent.ksql.rest.entity.SourceDescriptionList; @@ -74,7 +74,7 @@ import io.confluent.ksql.rest.entity.StreamsList; import io.confluent.ksql.rest.entity.TablesList; import io.confluent.ksql.rest.entity.TopicDescription; -import io.confluent.ksql.schema.ksql.SqlBaseType; +import io.confluent.ksql.rest.entity.TypeList; import io.confluent.ksql.util.CmdLineUtil; import io.confluent.ksql.util.HandlerMaps; import io.confluent.ksql.util.HandlerMaps.ClassHandlerMap1; @@ -157,6 +157,8 @@ public class Console implements Closeable { tablePrinter(ConnectorList.class, ConnectorListTableBuilder::new)) .put(ConnectorDescription.class, Console::printConnectorDescription) + .put(TypeList.class, + tablePrinter(TypeList.class, TypeListTableBuilder::new)) .put(ErrorEntity.class, tablePrinter(ErrorEntity.class, ErrorEntityTableBuilder::new)) .build(); @@ -440,39 +442,13 @@ private void printWarnings(final KsqlEntity entity) { } } - @SuppressWarnings("ConstantConditions") - private static String schemaToTypeString(final SchemaInfo schema) { - switch (schema.getType()) { - case ARRAY: - return SqlBaseType.ARRAY + "<" - + schemaToTypeString(schema.getMemberSchema().get()) - + ">"; - case MAP: - return SqlBaseType.MAP - + "<" - + SqlBaseType.STRING + ", " - + schemaToTypeString(schema.getMemberSchema().get()) - + ">"; - case STRUCT: - return schema.getFields().get() - .stream() - .map(f -> f.getName() + " " + schemaToTypeString(f.getSchema())) - .collect(Collectors.joining(", ", SqlBaseType.STRUCT + "<", ">")); - case STRING: - return "VARCHAR(STRING)"; - default: - return schema.getType().name(); - } - } - private static String formatFieldType(final FieldInfo field, final String keyField) { - if (field.getName().equals("ROWTIME") || field.getName().equals("ROWKEY")) { - return String.format("%-16s %s", schemaToTypeString(field.getSchema()), "(system)"); + return String.format("%-16s %s", field.getSchema().toTypeString(), "(system)"); } else if (keyField != null && keyField.contains("." + field.getName())) { - return String.format("%-16s %s", schemaToTypeString(field.getSchema()), "(key)"); + return String.format("%-16s %s", field.getSchema().toTypeString(), "(key)"); } else { - return schemaToTypeString(field.getSchema()); + return field.getSchema().toTypeString(); } } diff --git a/ksql-cli/src/main/java/io/confluent/ksql/cli/console/table/builder/TypeListTableBuilder.java b/ksql-cli/src/main/java/io/confluent/ksql/cli/console/table/builder/TypeListTableBuilder.java new file mode 100644 index 000000000000..1f33201cdb16 --- /dev/null +++ b/ksql-cli/src/main/java/io/confluent/ksql/cli/console/table/builder/TypeListTableBuilder.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Confluent Inc. + * + * Licensed under the Confluent Community License (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.confluent.io/confluent-community-license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.confluent.ksql.cli.console.table.builder; + +import com.google.common.collect.ImmutableList; +import io.confluent.ksql.cli.console.table.Table; +import io.confluent.ksql.rest.entity.TypeList; +import java.util.Comparator; +import java.util.List; +import java.util.Map.Entry; + +public class TypeListTableBuilder implements TableBuilder { + + private static final List HEADERS = ImmutableList.of("Type Name", "Schema"); + + @Override + public Table buildTable(final TypeList entity) { + return new Table.Builder() + .withColumnHeaders(HEADERS) + .withRows(entity + .getTypes() + .entrySet() + .stream() + .sorted(Comparator.comparing(Entry::getKey)) + .map(entry -> ImmutableList.of(entry.getKey(), entry.getValue().toTypeString()))) + .build(); + } +} diff --git a/ksql-cli/src/test/java/io/confluent/ksql/cli/console/ConsoleTest.java b/ksql-cli/src/test/java/io/confluent/ksql/cli/console/ConsoleTest.java index 787c6c8d204d..026c90c44118 100644 --- a/ksql-cli/src/test/java/io/confluent/ksql/cli/console/ConsoleTest.java +++ b/ksql-cli/src/test/java/io/confluent/ksql/cli/console/ConsoleTest.java @@ -64,6 +64,7 @@ import io.confluent.ksql.rest.entity.StreamsList; import io.confluent.ksql.rest.entity.TablesList; import io.confluent.ksql.rest.entity.TopicDescription; +import io.confluent.ksql.rest.entity.TypeList; import io.confluent.ksql.rest.server.computation.CommandId; import io.confluent.ksql.rest.util.EntityUtil; import io.confluent.ksql.schema.ksql.LogicalSchema; @@ -863,6 +864,67 @@ public void shouldPrintConnectorsList() throws IOException { } } + @Test + public void shouldPrintTypesList() throws IOException { + // Given: + final KsqlEntityList entities = new KsqlEntityList(ImmutableList.of( + new TypeList("statement", ImmutableMap.of( + "typeB", new SchemaInfo( + SqlBaseType.ARRAY, + null, + new SchemaInfo(SqlBaseType.STRING, null, null)), + "typeA", new SchemaInfo( + SqlBaseType.STRUCT, + ImmutableList.of( + new FieldInfo("f1", new SchemaInfo(SqlBaseType.STRING, null, null))), + null) + )) + )); + + // When: + console.printKsqlEntityList(entities); + + // Then: + final String output = terminal.getOutputString(); + if (console.getOutputFormat() == OutputFormat.JSON) { + assertThat(output, is("[ {\n" + + " \"@type\" : \"type_list\",\n" + + " \"statementText\" : \"statement\",\n" + + " \"types\" : {\n" + + " \"typeB\" : {\n" + + " \"type\" : \"ARRAY\",\n" + + " \"fields\" : null,\n" + + " \"memberSchema\" : {\n" + + " \"type\" : \"STRING\",\n" + + " \"fields\" : null,\n" + + " \"memberSchema\" : null\n" + + " }\n" + + " },\n" + + " \"typeA\" : {\n" + + " \"type\" : \"STRUCT\",\n" + + " \"fields\" : [ {\n" + + " \"name\" : \"f1\",\n" + + " \"schema\" : {\n" + + " \"type\" : \"STRING\",\n" + + " \"fields\" : null,\n" + + " \"memberSchema\" : null\n" + + " }\n" + + " } ],\n" + + " \"memberSchema\" : null\n" + + " }\n" + + " },\n" + + " \"warnings\" : [ ]\n" + + "} ]\n")); + } else { + assertThat(output, is("\n" + + " Type Name | Schema \n" + + "----------------------------------------\n" + + " typeA | STRUCT \n" + + " typeB | ARRAY \n" + + "----------------------------------------\n")); + } + } + @Test public void testPrintExecuptionPlan() throws IOException { // Given: diff --git a/ksql-parser/src/main/antlr4/io/confluent/ksql/parser/SqlBase.g4 b/ksql-parser/src/main/antlr4/io/confluent/ksql/parser/SqlBase.g4 index ad36a2f06b10..2f93f3b27ef0 100644 --- a/ksql-parser/src/main/antlr4/io/confluent/ksql/parser/SqlBase.g4 +++ b/ksql-parser/src/main/antlr4/io/confluent/ksql/parser/SqlBase.g4 @@ -39,6 +39,7 @@ statement | (LIST | SHOW) TABLES EXTENDED? #listTables | (LIST | SHOW) FUNCTIONS #listFunctions | (LIST | SHOW) (SOURCE | SINK)? CONNECTORS #listConnectors + | (LIST | SHOW) TYPES #listTypes | DESCRIBE EXTENDED? qualifiedName #showColumns | DESCRIBE FUNCTION qualifiedName #describeFunction | DESCRIBE CONNECTOR identifier #describeConnector @@ -319,7 +320,7 @@ nonReserved | STRUCT | MAP | ARRAY | PARTITION | INTEGER | DATE | TIME | TIMESTAMP | INTERVAL | ZONE | YEAR | MONTH | DAY | HOUR | MINUTE | SECOND - | EXPLAIN | ANALYZE | TYPE + | EXPLAIN | ANALYZE | TYPE | TYPES | SET | RESET | IF | SOURCE | SINK @@ -403,6 +404,7 @@ PRINT: 'PRINT'; EXPLAIN: 'EXPLAIN'; ANALYZE: 'ANALYZE'; TYPE: 'TYPE'; +TYPES: 'TYPES'; CAST: 'CAST'; SHOW: 'SHOW'; LIST: 'LIST'; diff --git a/ksql-parser/src/main/java/io/confluent/ksql/parser/AstBuilder.java b/ksql-parser/src/main/java/io/confluent/ksql/parser/AstBuilder.java index ba3361ffa06e..2f8caaab923e 100644 --- a/ksql-parser/src/main/java/io/confluent/ksql/parser/AstBuilder.java +++ b/ksql-parser/src/main/java/io/confluent/ksql/parser/AstBuilder.java @@ -63,6 +63,7 @@ import io.confluent.ksql.parser.SqlBaseParser.IntervalClauseContext; import io.confluent.ksql.parser.SqlBaseParser.LimitClauseContext; import io.confluent.ksql.parser.SqlBaseParser.ListConnectorsContext; +import io.confluent.ksql.parser.SqlBaseParser.ListTypesContext; import io.confluent.ksql.parser.SqlBaseParser.RegisterTypeContext; import io.confluent.ksql.parser.SqlBaseParser.SingleStatementContext; import io.confluent.ksql.parser.SqlBaseParser.TablePropertiesContext; @@ -99,6 +100,7 @@ import io.confluent.ksql.parser.tree.ListStreams; import io.confluent.ksql.parser.tree.ListTables; import io.confluent.ksql.parser.tree.ListTopics; +import io.confluent.ksql.parser.tree.ListTypes; import io.confluent.ksql.parser.tree.PrintTopic; import io.confluent.ksql.parser.tree.Query; import io.confluent.ksql.parser.tree.RegisterType; @@ -623,6 +625,11 @@ public Node visitDropType(final DropTypeContext ctx) { return new DropType(getLocation(ctx), getIdentifierText(ctx.identifier())); } + @Override + public Node visitListTypes(final ListTypesContext ctx) { + return new ListTypes(getLocation(ctx)); + } + @Override public Node visitTerminateQuery(final SqlBaseParser.TerminateQueryContext context) { return new TerminateQuery(getLocation(context), context.qualifiedName().getText()); diff --git a/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/AstVisitor.java b/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/AstVisitor.java index 3a0362df2163..f232dda4adc3 100644 --- a/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/AstVisitor.java +++ b/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/AstVisitor.java @@ -168,6 +168,10 @@ protected R visitListTables(final ListTables node, final C context) { return visitStatement(node, context); } + protected R visitListTypes(final ListTypes listTypes, final C context) { + return visitStatement(listTypes, context); + } + protected R visitUnsetProperty(final UnsetProperty node, final C context) { return visitStatement(node, context); } diff --git a/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/ListTypes.java b/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/ListTypes.java new file mode 100644 index 000000000000..5828116460fd --- /dev/null +++ b/ksql-parser/src/main/java/io/confluent/ksql/parser/tree/ListTypes.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Confluent Inc. + * + * Licensed under the Confluent Community License (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.confluent.io/confluent-community-license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.confluent.ksql.parser.tree; + +import com.google.errorprone.annotations.Immutable; +import io.confluent.ksql.parser.NodeLocation; +import java.util.Objects; +import java.util.Optional; + +@Immutable +public class ListTypes extends Statement { + + public ListTypes(final Optional location) { + super(location); + } + + @Override + public R accept(final AstVisitor visitor, final C context) { + return visitor.visitListTypes(this, context); + } + + @Override + public int hashCode() { + return Objects.hashCode(getClass()); + } + + @Override + public boolean equals(final Object obj) { + return this == obj || (obj != null && obj.getClass().equals(getClass())); + } + + @Override + public String toString() { + return "ListTypes{}"; + } +} diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/KsqlEntity.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/KsqlEntity.java index ede661d7f1c9..c3d8b67db3c9 100644 --- a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/KsqlEntity.java +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/KsqlEntity.java @@ -47,6 +47,7 @@ @JsonSubTypes.Type(value = DropConnectorEntity.class, name = "drop_connector"), @JsonSubTypes.Type(value = ConnectorList.class, name = "connector_list"), @JsonSubTypes.Type(value = ConnectorDescription.class, name = "connector_description"), + @JsonSubTypes.Type(value = TypeList.class, name = "type_list"), @JsonSubTypes.Type(value = ErrorEntity.class, name = "error_entity") }) public abstract class KsqlEntity { diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/SchemaInfo.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/SchemaInfo.java index 8b7eafd747c4..9ed6a3325bc5 100644 --- a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/SchemaInfo.java +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/SchemaInfo.java @@ -19,11 +19,15 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.Immutable; import io.confluent.ksql.schema.ksql.SqlBaseType; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; @Immutable @JsonIgnoreProperties(ignoreUnknown = true) @@ -75,4 +79,30 @@ public boolean equals(final Object other) { public int hashCode() { return Objects.hash(type, fields, memberSchema); } + + private static final Map> TO_TYPE_STRING = + ImmutableMap.>builder() + .put(SqlBaseType.STRING, si -> "VARCHAR(STRING)") + .put( + SqlBaseType.ARRAY, + si -> SqlBaseType.ARRAY + "<" + si.memberSchema.toTypeString() + ">") + .put( + SqlBaseType.MAP, + si -> SqlBaseType.MAP + + "<" + SqlBaseType.STRING + + ", " + si.memberSchema.toTypeString() + + ">") + .put( + SqlBaseType.STRUCT, + si -> si.fields + .stream() + .map(f -> f.getName() + " " + f.getSchema().toTypeString()) + .collect(Collectors.joining(", ", SqlBaseType.STRUCT + "<", ">"))) + .build(); + + public String toTypeString() { + // needs a map instead of switch because for some reason switch creates an + // internal class with no annotations that messes up EntityTest + return TO_TYPE_STRING.getOrDefault(type, si -> si.type.name()).apply(this); + } } diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/TypeList.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/TypeList.java new file mode 100644 index 000000000000..45a7b691948b --- /dev/null +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/entity/TypeList.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019 Confluent Inc. + * + * Licensed under the Confluent Community License (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.confluent.io/confluent-community-license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.confluent.ksql.rest.entity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.collect.ImmutableMap; +import com.google.errorprone.annotations.Immutable; +import java.util.Map; +import java.util.Objects; + +@Immutable +@JsonIgnoreProperties(ignoreUnknown = true) +public class TypeList extends KsqlEntity { + + private final ImmutableMap types; + + @JsonCreator + public TypeList( + @JsonProperty("statementText") final String statementText, + @JsonProperty("types") final Map types + ) { + super(statementText); + this.types = ImmutableMap.copyOf(Objects.requireNonNull(types, "types")); + } + + public Map getTypes() { + return types; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final TypeList typeList = (TypeList) o; + return Objects.equals(types, typeList.types); + } + + @Override + public int hashCode() { + return Objects.hash(types); + } +} diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/CustomExecutors.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/CustomExecutors.java index 857b242283db..72bb188964fd 100644 --- a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/CustomExecutors.java +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/CustomExecutors.java @@ -31,6 +31,7 @@ import io.confluent.ksql.parser.tree.ListStreams; import io.confluent.ksql.parser.tree.ListTables; import io.confluent.ksql.parser.tree.ListTopics; +import io.confluent.ksql.parser.tree.ListTypes; import io.confluent.ksql.parser.tree.SetProperty; import io.confluent.ksql.parser.tree.ShowColumns; import io.confluent.ksql.parser.tree.Statement; @@ -60,6 +61,7 @@ public enum CustomExecutors { LIST_QUERIES(ListQueries.class, ListQueriesExecutor::execute), LIST_PROPERTIES(ListProperties.class, ListPropertiesExecutor::execute), LIST_CONNECTORS(ListConnectors.class, ListConnectorsExecutor::execute), + LIST_TYPES(ListTypes.class, ListTypesExecutor::execute), SHOW_COLUMNS(ShowColumns.class, ListSourceExecutor::columns), EXPLAIN(Explain.class, ExplainExecutor::execute), diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/ListTypesExecutor.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/ListTypesExecutor.java new file mode 100644 index 000000000000..51d76eea7d9c --- /dev/null +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/execution/ListTypesExecutor.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Confluent Inc. + * + * Licensed under the Confluent Community License (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.confluent.io/confluent-community-license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.confluent.ksql.rest.server.execution; + +import com.google.common.collect.ImmutableMap; +import io.confluent.ksql.KsqlExecutionContext; +import io.confluent.ksql.metastore.TypeRegistry.CustomType; +import io.confluent.ksql.parser.tree.ListTypes; +import io.confluent.ksql.rest.entity.KsqlEntity; +import io.confluent.ksql.rest.entity.SchemaInfo; +import io.confluent.ksql.rest.entity.TypeList; +import io.confluent.ksql.rest.util.EntityUtil; +import io.confluent.ksql.services.ServiceContext; +import io.confluent.ksql.statement.ConfiguredStatement; +import java.util.Iterator; +import java.util.Optional; + +public final class ListTypesExecutor { + + private ListTypesExecutor() { } + + public static Optional execute( + final ConfiguredStatement configuredStatement, + final KsqlExecutionContext executionContext, + final ServiceContext serviceContext + ) { + final ImmutableMap.Builder types = ImmutableMap.builder(); + + final Iterator customTypes = executionContext.getMetaStore().types(); + while (customTypes.hasNext()) { + final CustomType customType = customTypes.next(); + types.put(customType.getName(), EntityUtil.schemaInfo(customType.getType())); + } + + return Optional.of(new TypeList(configuredStatement.getStatementText(), types.build())); + } +} diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/validation/CustomValidators.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/validation/CustomValidators.java index fd9b65df34c1..05a3623a64c3 100644 --- a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/validation/CustomValidators.java +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/server/validation/CustomValidators.java @@ -31,6 +31,7 @@ import io.confluent.ksql.parser.tree.ListStreams; import io.confluent.ksql.parser.tree.ListTables; import io.confluent.ksql.parser.tree.ListTopics; +import io.confluent.ksql.parser.tree.ListTypes; import io.confluent.ksql.parser.tree.PrintTopic; import io.confluent.ksql.parser.tree.Query; import io.confluent.ksql.parser.tree.SetProperty; @@ -70,6 +71,7 @@ public enum CustomValidators { LIST_QUERIES(ListQueries.class, StatementValidator.NO_VALIDATION), LIST_PROPERTIES(ListProperties.class, StatementValidator.NO_VALIDATION), LIST_CONNECTORS(ListConnectors.class, StatementValidator.NO_VALIDATION), + LIST_TYPES(ListTypes.class, StatementValidator.NO_VALIDATION), CREATE_CONNECTOR(CreateConnector.class, StatementValidator.NO_VALIDATION), DROP_CONNECTOR(DropConnector.class, StatementValidator.NO_VALIDATION), diff --git a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/util/EntityUtil.java b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/util/EntityUtil.java index e457debefaf1..55aefd46aba2 100644 --- a/ksql-rest-app/src/main/java/io/confluent/ksql/rest/util/EntityUtil.java +++ b/ksql-rest-app/src/main/java/io/confluent/ksql/rest/util/EntityUtil.java @@ -59,7 +59,7 @@ private static List getFields(final List fields, final String .collect(Collectors.toList()); } - private static SchemaInfo getSchema(final SqlType type) { + public static SchemaInfo schemaInfo(final SqlType type) { return SqlTypeWalker.visit(type, new Converter()); } diff --git a/ksql-rest-app/src/test/java/io/confluent/ksql/rest/server/execution/ListTypesExecutorTest.java b/ksql-rest-app/src/test/java/io/confluent/ksql/rest/server/execution/ListTypesExecutorTest.java new file mode 100644 index 000000000000..ff501bda0b8d --- /dev/null +++ b/ksql-rest-app/src/test/java/io/confluent/ksql/rest/server/execution/ListTypesExecutorTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2019 Confluent Inc. + * + * Licensed under the Confluent Community License (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.confluent.io/confluent-community-license + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package io.confluent.ksql.rest.server.execution; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.confluent.ksql.KsqlExecutionContext; +import io.confluent.ksql.metastore.MetaStore; +import io.confluent.ksql.metastore.TypeRegistry.CustomType; +import io.confluent.ksql.parser.KsqlParser.PreparedStatement; +import io.confluent.ksql.parser.tree.ListTypes; +import io.confluent.ksql.rest.entity.KsqlEntity; +import io.confluent.ksql.rest.entity.TypeList; +import io.confluent.ksql.rest.util.EntityUtil; +import io.confluent.ksql.schema.ksql.SqlBaseType; +import io.confluent.ksql.schema.ksql.types.SqlPrimitiveType; +import io.confluent.ksql.statement.ConfiguredStatement; +import io.confluent.ksql.util.KsqlConfig; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ListTypesExecutorTest { + + private static final KsqlConfig KSQL_CONFIG = new KsqlConfig(ImmutableMap.of()); + + @Mock + private KsqlExecutionContext context; + @Mock + private MetaStore metaStore; + + @Before + public void setUp() { + when(context.getMetaStore()).thenReturn(metaStore); + when(metaStore.types()) + .thenReturn( + ImmutableList.of( + new CustomType("foo", SqlPrimitiveType.of(SqlBaseType.STRING)) + ).iterator()); + } + + @Test + public void shouldListTypes() { + // When: + final Optional entity = ListTypesExecutor.execute( + ConfiguredStatement.of( + PreparedStatement.of("statement", new ListTypes(Optional.empty())), + ImmutableMap.of(), + KSQL_CONFIG), + context, + null); + + // Then: + assertThat("expected a response", entity.isPresent()); + assertThat(((TypeList) entity.get()).getTypes(), is(ImmutableMap.of( + "foo", EntityUtil.schemaInfo(SqlPrimitiveType.of(SqlBaseType.STRING)) + ))); + } + +} \ No newline at end of file