diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogEntity.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogEntity.java index 99d8557f0b..165bcb2561 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogEntity.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogEntity.java @@ -34,12 +34,9 @@ import org.apache.polaris.core.admin.model.AwsStorageConfigInfo; import org.apache.polaris.core.admin.model.AzureStorageConfigInfo; import org.apache.polaris.core.admin.model.Catalog; -import org.apache.polaris.core.admin.model.CatalogProperties; import org.apache.polaris.core.admin.model.ConnectionConfigInfo; -import org.apache.polaris.core.admin.model.ExternalCatalog; import org.apache.polaris.core.admin.model.FileStorageConfigInfo; import org.apache.polaris.core.admin.model.GcpStorageConfigInfo; -import org.apache.polaris.core.admin.model.PolarisCatalog; import org.apache.polaris.core.admin.model.StorageConfigInfo; import org.apache.polaris.core.config.BehaviorChangeConfiguration; import org.apache.polaris.core.connection.ConnectionConfigInfoDpo; @@ -95,39 +92,6 @@ public static CatalogEntity fromCatalog(CallContext callContext, Catalog catalog return builder.build(); } - public Catalog asCatalog() { - Map internalProperties = getInternalPropertiesAsMap(); - Catalog.TypeEnum catalogType = - Optional.ofNullable(internalProperties.get(CATALOG_TYPE_PROPERTY)) - .map(Catalog.TypeEnum::valueOf) - .orElseGet(() -> getName().equalsIgnoreCase("ROOT") ? Catalog.TypeEnum.INTERNAL : null); - Map propertiesMap = getPropertiesAsMap(); - CatalogProperties catalogProps = - CatalogProperties.builder(propertiesMap.get(DEFAULT_BASE_LOCATION_KEY)) - .putAll(propertiesMap) - .build(); - return catalogType == Catalog.TypeEnum.INTERNAL - ? PolarisCatalog.builder() - .setType(Catalog.TypeEnum.INTERNAL) - .setName(getName()) - .setProperties(catalogProps) - .setCreateTimestamp(getCreateTimestamp()) - .setLastUpdateTimestamp(getLastUpdateTimestamp()) - .setEntityVersion(getEntityVersion()) - .setStorageConfigInfo(getStorageInfo(internalProperties)) - .build() - : ExternalCatalog.builder() - .setType(Catalog.TypeEnum.EXTERNAL) - .setName(getName()) - .setProperties(catalogProps) - .setCreateTimestamp(getCreateTimestamp()) - .setLastUpdateTimestamp(getLastUpdateTimestamp()) - .setEntityVersion(getEntityVersion()) - .setStorageConfigInfo(getStorageInfo(internalProperties)) - .setConnectionConfigInfo(getConnectionInfo(internalProperties)) - .build(); - } - private StorageConfigInfo getStorageInfo(Map internalProperties) { if (internalProperties.containsKey(PolarisEntityConstants.getStorageConfigInfoPropertyName())) { PolarisStorageConfigurationInfo configInfo = getStorageConfigurationInfo(); diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogRoleEntity.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogRoleEntity.java index 3fcb183719..e8a2797d53 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogRoleEntity.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/CatalogRoleEntity.java @@ -40,17 +40,6 @@ public static CatalogRoleEntity fromCatalogRole(CatalogRole catalogRole) { .build(); } - public CatalogRole asCatalogRole() { - CatalogRole catalogRole = - new CatalogRole( - getName(), - getPropertiesAsMap(), - getCreateTimestamp(), - getLastUpdateTimestamp(), - getEntityVersion()); - return catalogRole; - } - public static class Builder extends PolarisEntity.BaseBuilder { public Builder() { super(); diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/EntityConverter.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/EntityConverter.java new file mode 100644 index 0000000000..ec13bac826 --- /dev/null +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/EntityConverter.java @@ -0,0 +1,177 @@ +/* + * 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.polaris.core.entity; + +import static org.apache.polaris.core.admin.model.StorageConfigInfo.StorageTypeEnum.AZURE; +import static org.apache.polaris.core.entity.CatalogEntity.CATALOG_TYPE_PROPERTY; +import static org.apache.polaris.core.entity.CatalogEntity.DEFAULT_BASE_LOCATION_KEY; + +import java.util.Map; +import java.util.Optional; +import org.apache.iceberg.catalog.Namespace; +import org.apache.polaris.core.admin.model.AwsStorageConfigInfo; +import org.apache.polaris.core.admin.model.AzureStorageConfigInfo; +import org.apache.polaris.core.admin.model.Catalog; +import org.apache.polaris.core.admin.model.CatalogProperties; +import org.apache.polaris.core.admin.model.CatalogRole; +import org.apache.polaris.core.admin.model.ConnectionConfigInfo; +import org.apache.polaris.core.admin.model.ExternalCatalog; +import org.apache.polaris.core.admin.model.FileStorageConfigInfo; +import org.apache.polaris.core.admin.model.GcpStorageConfigInfo; +import org.apache.polaris.core.admin.model.PolarisCatalog; +import org.apache.polaris.core.admin.model.Principal; +import org.apache.polaris.core.admin.model.PrincipalRole; +import org.apache.polaris.core.admin.model.StorageConfigInfo; +import org.apache.polaris.core.connection.ConnectionConfigInfoDpo; +import org.apache.polaris.core.entity.table.federated.FederatedEntities; +import org.apache.polaris.core.storage.FileStorageConfigurationInfo; +import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo; +import org.apache.polaris.core.storage.aws.AwsStorageConfigurationInfo; +import org.apache.polaris.core.storage.azure.AzureStorageConfigurationInfo; +import org.apache.polaris.core.storage.gcp.GcpStorageConfigurationInfo; + +public final class EntityConverter { + + public static Catalog toCatalog(CatalogEntity entity) { + Map internalProperties = entity.getInternalPropertiesAsMap(); + Catalog.TypeEnum catalogType = + Optional.ofNullable(internalProperties.get(CATALOG_TYPE_PROPERTY)) + .map(Catalog.TypeEnum::valueOf) + .orElseGet( + () -> entity.getName().equalsIgnoreCase("ROOT") ? Catalog.TypeEnum.INTERNAL : null); + Map propertiesMap = entity.getPropertiesAsMap(); + CatalogProperties catalogProps = + CatalogProperties.builder(propertiesMap.get(DEFAULT_BASE_LOCATION_KEY)) + .putAll(propertiesMap) + .build(); + return catalogType == Catalog.TypeEnum.INTERNAL + ? PolarisCatalog.builder() + .setType(Catalog.TypeEnum.INTERNAL) + .setName(entity.getName()) + .setProperties(catalogProps) + .setCreateTimestamp(entity.getCreateTimestamp()) + .setLastUpdateTimestamp(entity.getLastUpdateTimestamp()) + .setEntityVersion(entity.getEntityVersion()) + .setStorageConfigInfo(getEntityStorageInfo(internalProperties, entity)) + .build() + : ExternalCatalog.builder() + .setType(Catalog.TypeEnum.EXTERNAL) + .setName(entity.getName()) + .setProperties(catalogProps) + .setCreateTimestamp(entity.getCreateTimestamp()) + .setLastUpdateTimestamp(entity.getLastUpdateTimestamp()) + .setEntityVersion(entity.getEntityVersion()) + .setStorageConfigInfo(getEntityStorageInfo(internalProperties, entity)) + .setConnectionConfigInfo(getEntityConnectionInfo(internalProperties, entity)) + .build(); + } + + public static CatalogRole toCatalogRole(CatalogRoleEntity entity) { + return new CatalogRole( + entity.getName(), + entity.getPropertiesAsMap(), + entity.getCreateTimestamp(), + entity.getLastUpdateTimestamp(), + entity.getEntityVersion()); + } + + public static Namespace toNamespace(NamespaceEntity entity) { + Namespace parent = entity.getParentNamespace(); + String[] levels = new String[parent.length() + 1]; + for (int i = 0; i < parent.length(); ++i) { + levels[i] = parent.level(i); + } + levels[levels.length - 1] = entity.getName(); + return Namespace.of(levels); + } + + public static Principal toPrincipal(PrincipalEntity entity) { + return new Principal( + entity.getName(), + entity.getClientId(), + entity.getPropertiesAsMap(), + entity.getCreateTimestamp(), + entity.getLastUpdateTimestamp(), + entity.getEntityVersion()); + } + + public static PrincipalRole toPrincipalRole(PrincipalRoleEntity entity) { + return new PrincipalRole( + entity.getName(), + FederatedEntities.isFederated(entity), + entity.getPropertiesAsMap(), + entity.getCreateTimestamp(), + entity.getLastUpdateTimestamp(), + entity.getEntityVersion()); + } + + private static StorageConfigInfo getEntityStorageInfo( + Map internalProperties, CatalogEntity entity) { + if (internalProperties.containsKey(PolarisEntityConstants.getStorageConfigInfoPropertyName())) { + PolarisStorageConfigurationInfo configInfo = entity.getStorageConfigurationInfo(); + if (configInfo instanceof AwsStorageConfigurationInfo) { + AwsStorageConfigurationInfo awsConfig = (AwsStorageConfigurationInfo) configInfo; + return AwsStorageConfigInfo.builder() + .setRoleArn(awsConfig.getRoleARN()) + .setExternalId(awsConfig.getExternalId()) + .setUserArn(awsConfig.getUserARN()) + .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) + .setAllowedLocations(awsConfig.getAllowedLocations()) + .setRegion(awsConfig.getRegion()) + .build(); + } + if (configInfo instanceof AzureStorageConfigurationInfo) { + AzureStorageConfigurationInfo azureConfig = (AzureStorageConfigurationInfo) configInfo; + return AzureStorageConfigInfo.builder() + .setTenantId(azureConfig.getTenantId()) + .setMultiTenantAppName(azureConfig.getMultiTenantAppName()) + .setConsentUrl(azureConfig.getConsentUrl()) + .setStorageType(AZURE) + .setAllowedLocations(azureConfig.getAllowedLocations()) + .build(); + } + if (configInfo instanceof GcpStorageConfigurationInfo) { + GcpStorageConfigurationInfo gcpConfigModel = (GcpStorageConfigurationInfo) configInfo; + return GcpStorageConfigInfo.builder() + .setGcsServiceAccount(gcpConfigModel.getGcpServiceAccount()) + .setStorageType(StorageConfigInfo.StorageTypeEnum.GCS) + .setAllowedLocations(gcpConfigModel.getAllowedLocations()) + .build(); + } + if (configInfo instanceof FileStorageConfigurationInfo) { + FileStorageConfigurationInfo fileConfigModel = (FileStorageConfigurationInfo) configInfo; + return new FileStorageConfigInfo( + StorageConfigInfo.StorageTypeEnum.FILE, fileConfigModel.getAllowedLocations()); + } + return null; + } + return null; + } + + private static ConnectionConfigInfo getEntityConnectionInfo( + Map internalProperties, CatalogEntity entity) { + if (internalProperties.containsKey( + PolarisEntityConstants.getConnectionConfigInfoPropertyName())) { + ConnectionConfigInfoDpo configInfo = entity.getConnectionConfigInfoDpo(); + return configInfo.asConnectionConfigInfoModel(); + } + return null; + } +} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/NamespaceEntity.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/NamespaceEntity.java index b1fb3dae0a..0576ff4f27 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/NamespaceEntity.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/NamespaceEntity.java @@ -50,16 +50,6 @@ public Namespace getParentNamespace() { return RESTUtil.decodeNamespace(encodedNamespace); } - public Namespace asNamespace() { - Namespace parent = getParentNamespace(); - String[] levels = new String[parent.length() + 1]; - for (int i = 0; i < parent.length(); ++i) { - levels[i] = parent.level(i); - } - levels[levels.length - 1] = getName(); - return Namespace.of(levels); - } - @Override @JsonIgnore public String getBaseLocation() { diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalEntity.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalEntity.java index ba0cfe3f53..3632e32887 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalEntity.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalEntity.java @@ -41,16 +41,6 @@ public static PrincipalEntity fromPrincipal(Principal principal) { .build(); } - public Principal asPrincipal() { - return new Principal( - getName(), - getClientId(), - getPropertiesAsMap(), - getCreateTimestamp(), - getLastUpdateTimestamp(), - getEntityVersion()); - } - public String getClientId() { return getInternalPropertiesAsMap().get(PolarisEntityConstants.getClientIdPropertyName()); } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalRoleEntity.java b/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalRoleEntity.java index 3eb2d00506..a2c302307b 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalRoleEntity.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/entity/PrincipalRoleEntity.java @@ -44,16 +44,6 @@ public static PrincipalRoleEntity fromPrincipalRole(PrincipalRole principalRole) .build(); } - public PrincipalRole asPrincipalRole() { - return new PrincipalRole( - getName(), - FederatedEntities.isFederated(this), - getPropertiesAsMap(), - getCreateTimestamp(), - getLastUpdateTimestamp(), - getEntityVersion()); - } - public static class Builder extends PolarisEntity.BaseBuilder { public Builder() { super(); diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAdminServiceAuthzTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAdminServiceAuthzTest.java index d74447b538..63a568133e 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAdminServiceAuthzTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAdminServiceAuthzTest.java @@ -18,6 +18,8 @@ */ package org.apache.polaris.service.quarkus.admin; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; + import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.TestProfile; import java.util.List; @@ -133,7 +135,7 @@ public void testCreateCatalogSufficientPrivileges() { PRINCIPAL_ROLE2, PolarisPrivilege.CATALOG_DROP)) .isTrue(); final CatalogEntity newCatalog = new CatalogEntity.Builder().setName("new_catalog").build(); - final CreateCatalogRequest createRequest = new CreateCatalogRequest(newCatalog.asCatalog()); + final CreateCatalogRequest createRequest = new CreateCatalogRequest(toCatalog(newCatalog)); doTestSufficientPrivileges( List.of( @@ -152,7 +154,7 @@ public void testCreateCatalogSufficientPrivileges() { @Test public void testCreateCatalogInsufficientPrivileges() { final CatalogEntity newCatalog = new CatalogEntity.Builder().setName("new_catalog").build(); - final CreateCatalogRequest createRequest = new CreateCatalogRequest(newCatalog.asCatalog()); + final CreateCatalogRequest createRequest = new CreateCatalogRequest(toCatalog(newCatalog)); doTestInsufficientPrivileges( List.of( @@ -288,7 +290,7 @@ public void testDeleteCatalogSufficientPrivileges() { PRINCIPAL_ROLE2, PolarisPrivilege.CATALOG_CREATE)) .isTrue(); final CatalogEntity newCatalog = new CatalogEntity.Builder().setName("new_catalog").build(); - final CreateCatalogRequest createRequest = new CreateCatalogRequest(newCatalog.asCatalog()); + final CreateCatalogRequest createRequest = new CreateCatalogRequest(toCatalog(newCatalog)); adminService.createCatalog(createRequest); doTestSufficientPrivileges( @@ -308,7 +310,7 @@ public void testDeleteCatalogSufficientPrivileges() { @Test public void testDeleteCatalogInsufficientPrivileges() { final CatalogEntity newCatalog = new CatalogEntity.Builder().setName("new_catalog").build(); - final CreateCatalogRequest createRequest = new CreateCatalogRequest(newCatalog.asCatalog()); + final CreateCatalogRequest createRequest = new CreateCatalogRequest(toCatalog(newCatalog)); adminService.createCatalog(createRequest); doTestInsufficientPrivileges( diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java index 1c232bf54c..d537ac71a6 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/admin/PolarisAuthzTestBase.java @@ -19,6 +19,7 @@ package org.apache.polaris.service.quarkus.admin; import static org.apache.iceberg.types.Types.NestedField.required; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; @@ -280,13 +281,14 @@ public void before(TestInfo testInfo) { catalogEntity = adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(CATALOG_NAME) - .setCatalogType("INTERNAL") - .setDefaultBaseLocation(storageLocation) - .setStorageConfigurationInfo(callContext, storageConfigModel, storageLocation) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(CATALOG_NAME) + .setCatalogType("INTERNAL") + .setDefaultBaseLocation(storageLocation) + .setStorageConfigurationInfo( + callContext, storageConfigModel, storageLocation) + .build()))); initBaseCatalog(); diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogHandlerAuthzTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogHandlerAuthzTest.java index 4d89d55234..decd8c552e 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogHandlerAuthzTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogHandlerAuthzTest.java @@ -18,6 +18,8 @@ */ package org.apache.polaris.service.quarkus.catalog; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; + import com.google.common.collect.ImmutableMap; import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.TestProfile; @@ -1723,13 +1725,13 @@ public void testSendNotificationSufficientPrivileges() { .build(); adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(externalCatalog) - .setDefaultBaseLocation(storageLocation) - .setStorageConfigurationInfo(callContext, storageConfigModel, storageLocation) - .setCatalogType("EXTERNAL") - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(externalCatalog) + .setDefaultBaseLocation(storageLocation) + .setStorageConfigurationInfo(callContext, storageConfigModel, storageLocation) + .setCatalogType("EXTERNAL") + .build()))); adminService.createCatalogRole( externalCatalog, new CatalogRoleEntity.Builder().setName(CATALOG_ROLE1).build()); adminService.createCatalogRole( diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java index 05c2642f16..97bc0cdaaa 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogTest.java @@ -19,6 +19,7 @@ package org.apache.polaris.service.quarkus.catalog; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; import static org.mockito.ArgumentMatchers.any; @@ -340,24 +341,26 @@ public void before(TestInfo testInfo) { .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) .setAllowedLocations(List.of(storageLocation, "s3://externally-owned-bucket")) .build(); + catalogEntity = adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(CATALOG_NAME) - .setDefaultBaseLocation(storageLocation) - .setReplaceNewLocationPrefixWithCatalogDefault("file:") - .addProperty( - FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") - .addProperty( - FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), - "true") - .addProperty( - FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") - .setStorageConfigurationInfo( - polarisContext, storageConfigModel, storageLocation) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(CATALOG_NAME) + .setDefaultBaseLocation(storageLocation) + .setReplaceNewLocationPrefixWithCatalogDefault("file:") + .addProperty( + FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") + .setStorageConfigurationInfo( + polarisContext, storageConfigModel, storageLocation) + .build()))); RealmEntityManagerFactory realmEntityManagerFactory = new RealmEntityManagerFactory(createMockMetaStoreManagerFactory()); @@ -1351,14 +1354,15 @@ public void testUpdateNotificationCreateTableWithLocalFilePrefix() { // The location of the metadata JSON file specified in the create will be forbidden. final String metadataLocation = "file:///etc/metadata.json/../passwd"; String catalogWithoutStorage = "catalogWithoutStorage"; + PolarisEntity catalogEntity = adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setDefaultBaseLocation("file://") - .setName(catalogWithoutStorage) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setDefaultBaseLocation("file://") + .setName(catalogWithoutStorage) + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( @@ -1417,13 +1421,14 @@ public void testUpdateNotificationCreateTableWithHttpPrefix() { supportsNotifications(), "Only applicable if notifications are supported"); String catalogName = "catalogForMaliciousDomain"; + adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setDefaultBaseLocation("http://maliciousdomain.com") - .setName(catalogName) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setDefaultBaseLocation("http://maliciousdomain.com") + .setName(catalogName) + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( @@ -1949,19 +1954,21 @@ public void testDropTableWithPurgeDisabled() { .build(); adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(noPurgeCatalogName) - .setDefaultBaseLocation(storageLocation) - .setReplaceNewLocationPrefixWithCatalogDefault("file:") - .addProperty( - FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") - .addProperty( - FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), "true") - .addProperty(FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "false") - .setStorageConfigurationInfo( - polarisContext, noPurgeStorageConfigModel, storageLocation) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(noPurgeCatalogName) + .setDefaultBaseLocation(storageLocation) + .setReplaceNewLocationPrefixWithCatalogDefault("file:") + .addProperty( + FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") + .addProperty( + FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "false") + .setStorageConfigurationInfo( + polarisContext, noPurgeStorageConfigModel, storageLocation) + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( polarisContext, entityManager, securityContext, noPurgeCatalogName); @@ -2265,12 +2272,12 @@ public void createCatalogWithReservedProperty() { () -> { adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setDefaultBaseLocation("file://") - .setName("createCatalogWithReservedProperty") - .setProperties(ImmutableMap.of("polaris.reserved", "true")) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setDefaultBaseLocation("file://") + .setName("createCatalogWithReservedProperty") + .setProperties(ImmutableMap.of("polaris.reserved", "true")) + .build()))); }) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("reserved prefix"); @@ -2280,12 +2287,12 @@ public void createCatalogWithReservedProperty() { public void updateCatalogWithReservedProperty() { adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setDefaultBaseLocation("file://") - .setName("updateCatalogWithReservedProperty") - .setProperties(ImmutableMap.of("a", "b")) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setDefaultBaseLocation("file://") + .setName("updateCatalogWithReservedProperty") + .setProperties(ImmutableMap.of("a", "b")) + .build()))); Assertions.assertThatCode( () -> { adminService.updateCatalog( diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java index 6ea276cc09..b8094dde5b 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/IcebergCatalogViewTest.java @@ -18,6 +18,7 @@ */ package org.apache.polaris.service.quarkus.catalog; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableMap; @@ -213,23 +214,26 @@ public void before(TestInfo testInfo) { securityContext, new PolarisAuthorizerImpl(new PolarisConfigurationStore() {}), reservedProperties); + adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(CATALOG_NAME) - .addProperty( - FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") - .addProperty( - FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), "true") - .addProperty(FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") - .setDefaultBaseLocation("file://tmp") - .setStorageConfigurationInfo( - polarisContext, - new FileStorageConfigInfo( - StorageConfigInfo.StorageTypeEnum.FILE, List.of("file://", "/", "*")), - "file://tmp") - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(CATALOG_NAME) + .addProperty( + FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") + .addProperty( + FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") + .setDefaultBaseLocation("file://tmp") + .setStorageConfigurationInfo( + polarisContext, + new FileStorageConfigInfo( + StorageConfigInfo.StorageTypeEnum.FILE, List.of("file://", "/", "*")), + "file://tmp") + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogTest.java index c9196f1750..6741968847 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolarisGenericTableCatalogTest.java @@ -19,6 +19,7 @@ package org.apache.polaris.service.quarkus.catalog; import static org.apache.iceberg.types.Types.NestedField.required; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.when; @@ -219,24 +220,26 @@ public void before(TestInfo testInfo) { .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) .setAllowedLocations(List.of(storageLocation, "s3://externally-owned-bucket")) .build(); + catalogEntity = adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(CATALOG_NAME) - .setDefaultBaseLocation(storageLocation) - .setReplaceNewLocationPrefixWithCatalogDefault("file:") - .addProperty( - FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") - .addProperty( - FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), - "true") - .addProperty( - FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") - .setStorageConfigurationInfo( - polarisContext, storageConfigModel, storageLocation) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(CATALOG_NAME) + .setDefaultBaseLocation(storageLocation) + .setReplaceNewLocationPrefixWithCatalogDefault("file:") + .addProperty( + FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.DROP_WITH_PURGE_ENABLED.catalogConfig(), "true") + .setStorageConfigurationInfo( + polarisContext, storageConfigModel, storageLocation) + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( diff --git a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java index c0d4b8b463..cb1427ad29 100644 --- a/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java +++ b/runtime/service/src/test/java/org/apache/polaris/service/quarkus/catalog/PolicyCatalogTest.java @@ -19,6 +19,7 @@ package org.apache.polaris.service.quarkus.catalog; import static org.apache.iceberg.types.Types.NestedField.required; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; import static org.apache.polaris.core.policy.PredefinedPolicyTypes.DATA_COMPACTION; import static org.apache.polaris.core.policy.PredefinedPolicyTypes.METADATA_COMPACTION; import static org.apache.polaris.core.policy.PredefinedPolicyTypes.ORPHAN_FILE_REMOVAL; @@ -247,22 +248,24 @@ public void before(TestInfo testInfo) { .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) .setAllowedLocations(List.of(storageLocation, "s3://externally-owned-bucket")) .build(); + catalogEntity = adminService.createCatalog( new CreateCatalogRequest( - new CatalogEntity.Builder() - .setName(CATALOG_NAME) - .setDefaultBaseLocation(storageLocation) - .setReplaceNewLocationPrefixWithCatalogDefault("file:") - .addProperty( - FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), "true") - .addProperty( - FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), - "true") - .setStorageConfigurationInfo( - polarisContext, storageConfigModel, storageLocation) - .build() - .asCatalog())); + toCatalog( + new CatalogEntity.Builder() + .setName(CATALOG_NAME) + .setDefaultBaseLocation(storageLocation) + .setReplaceNewLocationPrefixWithCatalogDefault("file:") + .addProperty( + FeatureConfiguration.ALLOW_EXTERNAL_TABLE_LOCATION.catalogConfig(), + "true") + .addProperty( + FeatureConfiguration.ALLOW_UNSTRUCTURED_TABLE_LOCATION.catalogConfig(), + "true") + .setStorageConfigurationInfo( + polarisContext, storageConfigModel, storageLocation) + .build()))); PolarisPassthroughResolutionView passthroughView = new PolarisPassthroughResolutionView( diff --git a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java index a023025cc9..3e145936fb 100644 --- a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java +++ b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java @@ -19,6 +19,8 @@ package org.apache.polaris.service.admin; import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.polaris.core.entity.EntityConverter.toNamespace; +import static org.apache.polaris.core.entity.EntityConverter.toPrincipal; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -981,7 +983,7 @@ public PrincipalWithCredentials createPrincipal(PolarisEntity entity) { entity.getName()); } return new PrincipalWithCredentials( - new PrincipalEntity(principalResult.getPrincipal()).asPrincipal(), + toPrincipal(new PrincipalEntity(principalResult.getPrincipal())), new PrincipalWithCredentialsCredentials( principalResult.getPrincipalSecrets().getPrincipalClientId(), principalResult.getPrincipalSecrets().getMainSecret())); @@ -1100,7 +1102,7 @@ public void deletePrincipal(String name) { currentPrincipalEntity.getId(), currentPrincipalEntity.getType())); return new PrincipalWithCredentials( - PrincipalEntity.of(newPrincipal).asPrincipal(), + toPrincipal(PrincipalEntity.of(newPrincipal)), new PrincipalWithCredentialsCredentials( newSecrets.getPrincipalClientId(), newSecrets.getMainSecret())); } @@ -1875,7 +1877,7 @@ public List listGrantsForCatalogRole(String catalogName, String c { NamespaceGrant grant = new NamespaceGrant( - List.of(NamespaceEntity.of(baseEntity).asNamespace().levels()), + List.of(toNamespace(NamespaceEntity.of(baseEntity)).levels()), NamespacePrivilege.valueOf(privilege.toString()), GrantResource.TypeEnum.NAMESPACE); namespaceGrants.add(grant); diff --git a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java index 071e6b61aa..a07f8bd1cc 100644 --- a/service/common/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java +++ b/service/common/src/main/java/org/apache/polaris/service/admin/PolarisServiceImpl.java @@ -18,6 +18,11 @@ */ package org.apache.polaris.service.admin; +import static org.apache.polaris.core.entity.EntityConverter.toCatalog; +import static org.apache.polaris.core.entity.EntityConverter.toCatalogRole; +import static org.apache.polaris.core.entity.EntityConverter.toPrincipal; +import static org.apache.polaris.core.entity.EntityConverter.toPrincipalRole; + import jakarta.enterprise.context.RequestScoped; import jakarta.inject.Inject; import jakarta.ws.rs.core.Response; @@ -67,6 +72,7 @@ import org.apache.polaris.core.context.RealmContext; import org.apache.polaris.core.entity.CatalogEntity; import org.apache.polaris.core.entity.CatalogRoleEntity; +import org.apache.polaris.core.entity.EntityConverter; import org.apache.polaris.core.entity.PolarisPrivilege; import org.apache.polaris.core.entity.PrincipalEntity; import org.apache.polaris.core.entity.PrincipalRoleEntity; @@ -148,7 +154,7 @@ public Response createCatalog( Catalog catalog = request.getCatalog(); validateStorageConfig(catalog.getStorageConfigInfo()); validateExternalCatalog(catalog); - Catalog newCatalog = new CatalogEntity(adminService.createCatalog(request)).asCatalog(); + Catalog newCatalog = toCatalog(new CatalogEntity(adminService.createCatalog(request))); LOGGER.info("Created new catalog {}", newCatalog); return Response.status(Response.Status.CREATED).build(); } @@ -233,7 +239,7 @@ public Response deleteCatalog( public Response getCatalog( String catalogName, RealmContext realmContext, SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); - return Response.ok(adminService.getCatalog(catalogName).asCatalog()).build(); + return Response.ok(toCatalog(adminService.getCatalog(catalogName))).build(); } /** From PolarisCatalogsApiService */ @@ -247,7 +253,7 @@ public Response updateCatalog( if (updateRequest.getStorageConfigInfo() != null) { validateStorageConfig(updateRequest.getStorageConfigInfo()); } - return Response.ok(adminService.updateCatalog(catalogName, updateRequest).asCatalog()).build(); + return Response.ok(toCatalog(adminService.updateCatalog(catalogName, updateRequest))).build(); } /** From PolarisCatalogsApiService */ @@ -257,7 +263,7 @@ public Response listCatalogs(RealmContext realmContext, SecurityContext security List catalogList = adminService.listCatalogs().stream() .map(CatalogEntity::new) - .map(CatalogEntity::asCatalog) + .map(EntityConverter::toCatalog) .toList(); Catalogs catalogs = new Catalogs(catalogList); LOGGER.debug("listCatalogs returning: {}", catalogs); @@ -299,7 +305,7 @@ public Response deletePrincipal( public Response getPrincipal( String principalName, RealmContext realmContext, SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); - return Response.ok(adminService.getPrincipal(principalName).asPrincipal()).build(); + return Response.ok(toPrincipal(adminService.getPrincipal(principalName))).build(); } /** From PolarisPrincipalsApiService */ @@ -310,7 +316,7 @@ public Response updatePrincipal( RealmContext realmContext, SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); - return Response.ok(adminService.updatePrincipal(principalName, updateRequest).asPrincipal()) + return Response.ok(toPrincipal(adminService.updatePrincipal(principalName, updateRequest))) .build(); } @@ -329,7 +335,7 @@ public Response listPrincipals(RealmContext realmContext, SecurityContext securi List principalList = adminService.listPrincipals().stream() .map(PrincipalEntity::new) - .map(PrincipalEntity::asPrincipal) + .map(EntityConverter::toPrincipal) .toList(); Principals principals = new Principals(principalList); LOGGER.debug("listPrincipals returning: {}", principals); @@ -351,7 +357,7 @@ public Response createPrincipalRole( request.getPrincipalRole().getProperties())) .build(); PrincipalRole newPrincipalRole = - new PrincipalRoleEntity(adminService.createPrincipalRole(entity)).asPrincipalRole(); + toPrincipalRole(new PrincipalRoleEntity(adminService.createPrincipalRole(entity))); LOGGER.info("Created new principalRole {}", newPrincipalRole); return Response.status(Response.Status.CREATED).build(); } @@ -370,7 +376,7 @@ public Response deletePrincipalRole( public Response getPrincipalRole( String principalRoleName, RealmContext realmContext, SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); - return Response.ok(adminService.getPrincipalRole(principalRoleName).asPrincipalRole()).build(); + return Response.ok(toPrincipalRole(adminService.getPrincipalRole(principalRoleName))).build(); } /** From PolarisPrincipalRolesApiService */ @@ -382,7 +388,7 @@ public Response updatePrincipalRole( SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); return Response.ok( - adminService.updatePrincipalRole(principalRoleName, updateRequest).asPrincipalRole()) + toPrincipalRole(adminService.updatePrincipalRole(principalRoleName, updateRequest))) .build(); } @@ -393,7 +399,7 @@ public Response listPrincipalRoles(RealmContext realmContext, SecurityContext se List principalRoleList = adminService.listPrincipalRoles().stream() .map(PrincipalRoleEntity::new) - .map(PrincipalRoleEntity::asPrincipalRole) + .map(EntityConverter::toPrincipalRole) .toList(); PrincipalRoles principalRoles = new PrincipalRoles(principalRoleList); LOGGER.debug("listPrincipalRoles returning: {}", principalRoles); @@ -416,7 +422,7 @@ public Response createCatalogRole( request.getCatalogRole().getProperties())) .build(); CatalogRole newCatalogRole = - new CatalogRoleEntity(adminService.createCatalogRole(catalogName, entity)).asCatalogRole(); + toCatalogRole(new CatalogRoleEntity(adminService.createCatalogRole(catalogName, entity))); LOGGER.info("Created new catalogRole {}", newCatalogRole); return Response.status(Response.Status.CREATED).build(); } @@ -441,7 +447,7 @@ public Response getCatalogRole( RealmContext realmContext, SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); - return Response.ok(adminService.getCatalogRole(catalogName, catalogRoleName).asCatalogRole()) + return Response.ok(toCatalogRole(adminService.getCatalogRole(catalogName, catalogRoleName))) .build(); } @@ -455,9 +461,8 @@ public Response updateCatalogRole( SecurityContext securityContext) { PolarisAdminService adminService = newAdminService(realmContext, securityContext); return Response.ok( - adminService - .updateCatalogRole(catalogName, catalogRoleName, updateRequest) - .asCatalogRole()) + toCatalogRole( + adminService.updateCatalogRole(catalogName, catalogRoleName, updateRequest))) .build(); } @@ -469,7 +474,7 @@ public Response listCatalogRoles( List catalogRoleList = adminService.listCatalogRoles(catalogName).stream() .map(CatalogRoleEntity::new) - .map(CatalogRoleEntity::asCatalogRole) + .map(EntityConverter::toCatalogRole) .toList(); CatalogRoles catalogRoles = new CatalogRoles(catalogRoleList); LOGGER.debug("listCatalogRoles returning: {}", catalogRoles); @@ -513,7 +518,7 @@ public Response listPrincipalRolesAssigned( List principalRoleList = adminService.listPrincipalRolesAssigned(principalName).stream() .map(PrincipalRoleEntity::new) - .map(PrincipalRoleEntity::asPrincipalRole) + .map(EntityConverter::toPrincipalRole) .toList(); PrincipalRoles principalRoles = new PrincipalRoles(principalRoleList); LOGGER.debug("listPrincipalRolesAssigned returning: {}", principalRoles); @@ -566,7 +571,7 @@ public Response listAssigneePrincipalsForPrincipalRole( List principalList = adminService.listAssigneePrincipalsForPrincipalRole(principalRoleName).stream() .map(PrincipalEntity::new) - .map(PrincipalEntity::asPrincipal) + .map(EntityConverter::toPrincipal) .toList(); Principals principals = new Principals(principalList); LOGGER.debug("listAssigneePrincipalsForPrincipalRole returning: {}", principals); @@ -584,7 +589,7 @@ public Response listCatalogRolesForPrincipalRole( List catalogRoleList = adminService.listCatalogRolesForPrincipalRole(principalRoleName, catalogName).stream() .map(CatalogRoleEntity::new) - .map(CatalogRoleEntity::asCatalogRole) + .map(EntityConverter::toCatalogRole) .toList(); CatalogRoles catalogRoles = new CatalogRoles(catalogRoleList); LOGGER.debug("listCatalogRolesForPrincipalRole returning: {}", catalogRoles); @@ -774,7 +779,7 @@ public Response listAssigneePrincipalRolesForCatalogRole( List principalRoleList = adminService.listAssigneePrincipalRolesForCatalogRole(catalogName, catalogRoleName).stream() .map(PrincipalRoleEntity::new) - .map(PrincipalRoleEntity::asPrincipalRole) + .map(EntityConverter::toPrincipalRole) .toList(); PrincipalRoles principalRoles = new PrincipalRoles(principalRoleList); LOGGER.debug("listAssigneePrincipalRolesForCatalogRole returning: {}", principalRoles); diff --git a/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java b/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java index f8b7edf337..8f4cfa7bfd 100644 --- a/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java +++ b/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java @@ -18,6 +18,7 @@ */ package org.apache.polaris.service.catalog.iceberg; +import static org.apache.polaris.core.entity.EntityConverter.toNamespace; import static org.apache.polaris.service.exception.IcebergExceptionMapper.isStorageProviderRetryableException; import com.google.common.annotations.VisibleForTesting; @@ -1136,7 +1137,7 @@ private void validateNoLocationO "Unable to resolve siblings entities to validate location - could not list tables"); } return siblingTablesResult.getEntities().stream() - .map(tbl -> TableIdentifier.of(ns.asNamespace(), tbl.getName())) + .map(tbl -> TableIdentifier.of(toNamespace(ns), tbl.getName())) .collect(Collectors.toList()); }) .orElse(List.of()); @@ -1147,7 +1148,7 @@ private void validateNoLocationO ns -> { String[] nsLevels = parentNamespace - .map(parent -> parent.asNamespace().levels()) + .map(parent -> toNamespace(parent).levels()) .orElse(new String[0]); String[] newLevels = Arrays.copyOf(nsLevels, nsLevels.length + 1); newLevels[nsLevels.length] = ns.getName();