mchades commented on code in PR #11207: URL: https://github.com/apache/gravitino/pull/11207#discussion_r3295840398
########## catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/integration/test/CatalogPostgreSqlViewReadIT.java: ########## @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.catalog.postgresql.integration.test; + +import com.google.common.collect.Maps; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.catalog.jdbc.config.JdbcConfig; +import org.apache.gravitino.catalog.postgresql.integration.test.service.PostgreSqlService; +import org.apache.gravitino.client.GravitinoMetalake; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchViewException; +import org.apache.gravitino.integration.test.container.ContainerSuite; +import org.apache.gravitino.integration.test.container.PGImageName; +import org.apache.gravitino.integration.test.container.PostgreSQLContainer; +import org.apache.gravitino.integration.test.util.BaseIT; +import org.apache.gravitino.integration.test.util.GravitinoITUtils; +import org.apache.gravitino.integration.test.util.TestDatabaseName; +import org.apache.gravitino.rel.View; +import org.apache.gravitino.rel.ViewCatalog; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; + +/** Integration tests for PostgreSQL view read operations (list/load). */ +@Tag("gravitino-docker-test") +@TestInstance(Lifecycle.PER_CLASS) +public class CatalogPostgreSqlViewReadIT extends BaseIT { + + private static final ContainerSuite containerSuite = ContainerSuite.getInstance(); + private static final String provider = "jdbc-postgresql"; + + private final String metalakeName = GravitinoITUtils.genRandomName("pg_view_it_metalake"); + private final String catalogName = GravitinoITUtils.genRandomName("pg_view_it_catalog"); + private final String schemaName = GravitinoITUtils.genRandomName("pg_view_it_schema"); + + private GravitinoMetalake metalake; + private Catalog catalog; + private PostgreSqlService postgreSqlService; + private PostgreSQLContainer postgresContainer; + private final TestDatabaseName testDbName = TestDatabaseName.PG_CATALOG_POSTGRESQL_IT; + + @BeforeAll + public void startup() throws IOException, SQLException { + containerSuite.startPostgreSQLContainer(testDbName, PGImageName.VERSION_13); + postgresContainer = containerSuite.getPostgreSQLContainer(PGImageName.VERSION_13); + postgreSqlService = new PostgreSqlService(postgresContainer, testDbName); + + createMetalake(); + catalog = createCatalog(); + createSchema(); + createBaseTableAndViews(); + } + + @AfterAll + public void stop() { + cleanupViewsAndTables(); + catalog.asSchemas().dropSchema(schemaName, false); + metalake.disableCatalog(catalogName); + metalake.dropCatalog(catalogName); + client.disableMetalake(metalakeName); + client.dropMetalake(metalakeName); + postgreSqlService.close(); + } + + @AfterEach + public void resetSchema() { + cleanupViewsAndTables(); + catalog.asSchemas().dropSchema(schemaName, false); + createSchema(); + createBaseTableAndViews(); + } + + @Test + public void testListViews() { + ViewCatalog viewCatalog = catalog.asViewCatalog(); + NameIdentifier[] views = viewCatalog.listViews(Namespace.of(schemaName)); + + List<String> names = + Arrays.stream(views).map(NameIdentifier::name).sorted().collect(Collectors.toList()); + Assertions.assertEquals(Arrays.asList("test_view_1", "test_view_2"), names); + } + + @Test + public void testListViewsInEmptySchema() { + String emptySchema = GravitinoITUtils.genRandomName("empty_schema"); + catalog.asSchemas().createSchema(emptySchema, null, Collections.emptyMap()); + try { + NameIdentifier[] views = catalog.asViewCatalog().listViews(Namespace.of(emptySchema)); + Assertions.assertEquals(0, views.length); + } finally { + catalog.asSchemas().dropSchema(emptySchema, false); + } + } + + @Test + public void testListViewsInNonExistentSchema() { + Assertions.assertThrows( + NoSuchSchemaException.class, + () -> catalog.asViewCatalog().listViews(Namespace.of("no_such_schema_xyz"))); + } + + @Test + public void testLoadView() { + View view = + catalog + .asViewCatalog() + .loadView(NameIdentifier.of(Namespace.of(schemaName), "test_view_1")); + + Assertions.assertEquals("test_view_1", view.name()); + Assertions.assertNotNull(view.representations()); + Assertions.assertTrue(view.representations().length > 0); + } + + @Test + public void testLoadViewColumns() { + View view = + catalog + .asViewCatalog() + .loadView(NameIdentifier.of(Namespace.of(schemaName), "test_view_1")); + + Assertions.assertTrue(view.columns().length >= 2, "View should have at least 2 columns"); + } Review Comment: these two UTs can be merged, and also need to assert the attributions for columns and representations ########## catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcView.java: ########## @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.catalog.jdbc; + +import java.util.Collections; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.apache.gravitino.annotation.Unstable; +import org.apache.gravitino.meta.AuditInfo; +import org.apache.gravitino.rel.Column; +import org.apache.gravitino.rel.Representation; +import org.apache.gravitino.rel.SQLRepresentation; +import org.apache.gravitino.rel.View; + +/** Represents a view stored in a JDBC-compatible database. */ +@Unstable +@EqualsAndHashCode +@ToString +public class JdbcView implements View { + + private String name; + private String comment; + private Column[] columns; + private Map<String, String> properties; + private AuditInfo auditInfo; + private SQLRepresentation[] representations; + private String defaultCatalog; + private String defaultSchema; + + private JdbcView() {} + + @Override + public String name() { + return name; + } + + @Override + public String comment() { + return comment; + } + + @Override + public Column[] columns() { + return columns == null ? new Column[0] : columns; + } + + @Override + public Representation[] representations() { + return representations == null ? new SQLRepresentation[0] : representations; + } + + @Override + public String defaultCatalog() { + return defaultCatalog; + } + + @Override + public String defaultSchema() { + return defaultSchema; + } + + @Override + public Map<String, String> properties() { + return properties == null ? Collections.emptyMap() : properties; + } + + @Override + public AuditInfo auditInfo() { + return auditInfo; + } + + /** + * Returns a new {@link Builder} for constructing a {@code JdbcView}. + * + * @return A fresh builder instance. + */ + public static Builder builder() { + return new Builder(); + } + + /** Builder for {@link JdbcView}. */ + public static class Builder { + private final JdbcView view; + + private Builder() { + view = new JdbcView(); + } + + /** + * Sets the view name. + * + * @param name The view name. + * @return This builder. + */ + public Builder withName(String name) { + view.name = name; + return this; + } + + /** + * Sets the view comment. + * + * @param comment The view comment. + * @return This builder. + */ + public Builder withComment(String comment) { + view.comment = comment; + return this; + } + + /** + * Sets the output columns. + * + * @param columns The view output columns. + * @return This builder. + */ + public Builder withColumns(Column[] columns) { + view.columns = columns; + return this; + } + + /** + * Sets the view properties. + * + * @param properties The properties map. + * @return This builder. + */ + public Builder withProperties(Map<String, String> properties) { + view.properties = properties; + return this; + } + + /** + * Sets the audit info. + * + * @param auditInfo The audit info. + * @return This builder. + */ + public Builder withAuditInfo(AuditInfo auditInfo) { + view.auditInfo = auditInfo; + return this; + } + + /** + * Sets the SQL representations. + * + * @param representations The representations array. + * @return This builder. + */ + public Builder withRepresentations(SQLRepresentation[] representations) { + view.representations = representations; + return this; + } + + /** + * Sets the default catalog for unqualified identifier resolution. + * + * @param defaultCatalog The default catalog name, may be {@code null}. + * @return This builder. + */ + public Builder withDefaultCatalog(String defaultCatalog) { + view.defaultCatalog = defaultCatalog; + return this; + } + + /** + * Sets the default schema for unqualified identifier resolution. + * + * @param defaultSchema The default schema name, may be {@code null}. + * @return This builder. + */ + public Builder withDefaultSchema(String defaultSchema) { + view.defaultSchema = defaultSchema; + return this; + } + + /** + * Builds the {@link JdbcView} instance. + * + * @return The constructed view. + */ + public JdbcView build() { + return view; Review Comment: Some validations are needed for the view. ########## catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/integration/test/CatalogMysqlViewReadIT.java: ########## @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.gravitino.catalog.mysql.integration.test; + +import com.google.common.collect.Maps; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.apache.gravitino.Catalog; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.Namespace; +import org.apache.gravitino.catalog.jdbc.config.JdbcConfig; +import org.apache.gravitino.catalog.mysql.integration.test.service.MysqlService; +import org.apache.gravitino.client.GravitinoMetalake; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchViewException; +import org.apache.gravitino.integration.test.container.ContainerSuite; +import org.apache.gravitino.integration.test.container.MySQLContainer; +import org.apache.gravitino.integration.test.util.BaseIT; +import org.apache.gravitino.integration.test.util.GravitinoITUtils; +import org.apache.gravitino.integration.test.util.TestDatabaseName; +import org.apache.gravitino.rel.View; +import org.apache.gravitino.rel.ViewCatalog; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; + +/** Integration tests for MySQL view read operations (list/load). */ +@Tag("gravitino-docker-test") +@TestInstance(Lifecycle.PER_CLASS) +public class CatalogMysqlViewReadIT extends BaseIT { + + private static final ContainerSuite containerSuite = ContainerSuite.getInstance(); + private static final String provider = "jdbc-mysql"; + + private final String metalakeName = GravitinoITUtils.genRandomName("mysql_view_it_metalake"); + private final String catalogName = GravitinoITUtils.genRandomName("mysql_view_it_catalog"); + private final String schemaName = GravitinoITUtils.genRandomName("mysql_view_it_schema"); + + private GravitinoMetalake metalake; + private Catalog catalog; + private MysqlService mysqlService; + private MySQLContainer mysqlContainer; + private TestDatabaseName testDbName; + + @BeforeAll + public void startup() throws IOException, SQLException { + testDbName = TestDatabaseName.MYSQL_CATALOG_MYSQL_IT; + containerSuite.startMySQLContainer(testDbName); + mysqlContainer = containerSuite.getMySQLContainer(); + mysqlService = new MysqlService(mysqlContainer, testDbName); + + createMetalake(); + catalog = createCatalog(); + createSchema(); + createBaseTableAndViews(); + } + + @AfterAll + public void stop() { + cleanupViewsAndTables(); + catalog.asSchemas().dropSchema(schemaName, false); + metalake.disableCatalog(catalogName); + metalake.dropCatalog(catalogName); + client.disableMetalake(metalakeName); + client.dropMetalake(metalakeName); + mysqlService.close(); + } + + @AfterEach + public void resetSchema() { + cleanupViewsAndTables(); + catalog.asSchemas().dropSchema(schemaName, false); + createSchema(); + createBaseTableAndViews(); + } + + @Test + public void testListViews() { + ViewCatalog viewCatalog = catalog.asViewCatalog(); + NameIdentifier[] views = viewCatalog.listViews(Namespace.of(schemaName)); + + List<String> names = + Arrays.stream(views).map(NameIdentifier::name).sorted().collect(Collectors.toList()); + Assertions.assertEquals(Arrays.asList("test_view_1", "test_view_2"), names); + } + + @Test + public void testListViewsInEmptySchema() { + String emptySchema = GravitinoITUtils.genRandomName("empty_schema"); + catalog.asSchemas().createSchema(emptySchema, null, Collections.emptyMap()); + try { + NameIdentifier[] views = catalog.asViewCatalog().listViews(Namespace.of(emptySchema)); + Assertions.assertEquals(0, views.length); + } finally { + catalog.asSchemas().dropSchema(emptySchema, false); + } + } + + @Test + public void testListViewsInNonExistentSchema() { + Assertions.assertThrows( + NoSuchSchemaException.class, + () -> catalog.asViewCatalog().listViews(Namespace.of("no_such_schema_xyz"))); + } + + @Test + public void testLoadView() { + View view = + catalog + .asViewCatalog() + .loadView(NameIdentifier.of(Namespace.of(schemaName), "test_view_1")); + + Assertions.assertEquals("test_view_1", view.name()); + Assertions.assertNotNull(view.representations()); + Assertions.assertTrue(view.representations().length > 0); + } + + @Test + public void testLoadViewColumns() { + View view = + catalog + .asViewCatalog() + .loadView(NameIdentifier.of(Namespace.of(schemaName), "test_view_1")); + + Assertions.assertTrue(view.columns().length >= 2, "View should have at least 2 columns"); + } Review Comment: these two UTs can be merged, and also need to assert the attributions for columns and representations -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
