diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DashboardDataModelRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DashboardDataModelRepository.java index 4de5ddcc84d..25add8603b3 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DashboardDataModelRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DashboardDataModelRepository.java @@ -68,6 +68,9 @@ public class DashboardDataModelRepository extends EntityRepository columns) { + for (Column column : columns) { + checkMutuallyExclusive(column.getTags()); + if (column.getChildren() != null) { + validateColumnTags(column.getChildren()); + } + } + } + public class DataModelUpdater extends ColumnEntityUpdater { public DataModelUpdater(DashboardDataModel original, DashboardDataModel updated, Operation operation) { diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/MlModelRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/MlModelRepository.java index 4d833a88636..05250f10b68 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/MlModelRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/MlModelRepository.java @@ -131,6 +131,7 @@ public class MlModelRepository extends EntityRepository { populateService(mlModel); if (!nullOrEmpty(mlModel.getMlFeatures())) { validateReferences(mlModel.getMlFeatures()); + mlModel.getMlFeatures().forEach(feature -> checkMutuallyExclusive(feature.getTags())); } // Check that the dashboard exists diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/datamodels/DashboardDataModelResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/datamodels/DashboardDataModelResourceTest.java index 80adbc00b39..08f7aa99d68 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/datamodels/DashboardDataModelResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/datamodels/DashboardDataModelResourceTest.java @@ -16,6 +16,10 @@ package org.openmetadata.service.resources.datamodels; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.openmetadata.common.utils.CommonUtil.listOf; +import static org.openmetadata.schema.type.ColumnDataType.INT; +import static org.openmetadata.schema.type.ColumnDataType.STRUCT; +import static org.openmetadata.service.resources.databases.TableResourceTest.getColumn; import static org.openmetadata.service.util.TestUtils.ADMIN_AUTH_HEADERS; import static org.openmetadata.service.util.TestUtils.assertListNotEmpty; import static org.openmetadata.service.util.TestUtils.assertListNotNull; @@ -24,6 +28,7 @@ import static org.openmetadata.service.util.TestUtils.assertResponse; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.http.client.HttpResponseException; @@ -33,9 +38,11 @@ import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.openmetadata.schema.api.data.CreateDashboardDataModel; import org.openmetadata.schema.entity.data.DashboardDataModel; +import org.openmetadata.schema.type.Column; import org.openmetadata.schema.type.DataModelType; import org.openmetadata.schema.type.EntityReference; import org.openmetadata.service.Entity; +import org.openmetadata.service.exception.CatalogExceptionMessage; import org.openmetadata.service.resources.EntityResourceTest; import org.openmetadata.service.util.ResultList; @@ -80,6 +87,34 @@ public class DashboardDataModelResourceTest extends EntityResourceTest createEntity(create, ADMIN_AUTH_HEADERS), + BAD_REQUEST, + CatalogExceptionMessage.mutuallyExclusiveLabels(TIER2_TAG_LABEL, TIER1_TAG_LABEL)); + + // Apply mutually exclusive tags to a dataModel column + CreateDashboardDataModel createDashboardDataModel = createRequest(testInfo, 1); + Column column = getColumn("test", INT, null).withTags(listOf(TIER1_TAG_LABEL, TIER2_TAG_LABEL)); + createDashboardDataModel.setColumns(listOf(column)); + assertResponse( + () -> createEntity(createDashboardDataModel, ADMIN_AUTH_HEADERS), + BAD_REQUEST, + CatalogExceptionMessage.mutuallyExclusiveLabels(TIER2_TAG_LABEL, TIER1_TAG_LABEL)); + + // Apply mutually exclusive tags to a dataModel's nested column + CreateDashboardDataModel createDashboardDataModel1 = createRequest(testInfo, 1); + Column nestedColumns = getColumn("testNested", INT, null).withTags(listOf(TIER1_TAG_LABEL, TIER2_TAG_LABEL)); + Column column1 = getColumn("test", STRUCT, null).withChildren(List.of(nestedColumns)); + createDashboardDataModel1.setColumns(listOf(column1)); + assertResponse( + () -> createEntity(createDashboardDataModel1, ADMIN_AUTH_HEADERS), + BAD_REQUEST, + CatalogExceptionMessage.mutuallyExclusiveLabels(TIER2_TAG_LABEL, TIER1_TAG_LABEL)); + } + @Override @Execution(ExecutionMode.CONCURRENT) public DashboardDataModel validateGetWithDifferentFields(DashboardDataModel dashboardDataModel, boolean byName) diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/mlmodels/MlModelResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/mlmodels/MlModelResourceTest.java index 5600c922560..c266df6231d 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/mlmodels/MlModelResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/mlmodels/MlModelResourceTest.java @@ -13,8 +13,10 @@ package org.openmetadata.service.resources.mlmodels; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.openmetadata.common.utils.CommonUtil.listOf; import static org.openmetadata.service.util.EntityUtil.fieldAdded; import static org.openmetadata.service.util.EntityUtil.fieldDeleted; import static org.openmetadata.service.util.EntityUtil.fieldUpdated; @@ -57,6 +59,7 @@ import org.openmetadata.schema.type.MlFeatureSource; import org.openmetadata.schema.type.MlHyperParameter; import org.openmetadata.schema.type.MlStore; import org.openmetadata.service.Entity; +import org.openmetadata.service.exception.CatalogExceptionMessage; import org.openmetadata.service.resources.EntityResourceTest; import org.openmetadata.service.resources.dashboards.DashboardResourceTest; import org.openmetadata.service.resources.databases.TableResourceTest; @@ -83,12 +86,14 @@ public class MlModelResourceTest extends EntityResourceTest ML_FEATURES = Arrays.asList( new MlFeature() + .withTags(null) .withName("age") .withDataType(MlFeatureDataType.Numerical) .withFeatureSources( Collections.singletonList( new MlFeatureSource().withName("age").withDataType(FeatureSourceDataType.INTEGER))), new MlFeature() + .withTags(null) .withName("persona") .withDataType(MlFeatureDataType.Categorical) .withFeatureSources( @@ -341,6 +346,43 @@ public class MlModelResourceTest extends EntityResourceTest createEntity(create, ADMIN_AUTH_HEADERS), + BAD_REQUEST, + CatalogExceptionMessage.mutuallyExclusiveLabels(TIER2_TAG_LABEL, TIER1_TAG_LABEL)); + List mlFeatureList = + Arrays.asList( + new MlFeature() + .withTags(null) + .withName("age") + .withDataType(MlFeatureDataType.Numerical) + .withFeatureSources( + Collections.singletonList( + new MlFeatureSource().withName("age").withDataType(FeatureSourceDataType.INTEGER))), + new MlFeature() + .withTags(null) + .withName("persona") + .withDataType(MlFeatureDataType.Categorical) + .withFeatureSources( + Arrays.asList( + new MlFeatureSource().withName("age").withDataType(FeatureSourceDataType.INTEGER), + new MlFeatureSource().withName("education").withDataType(FeatureSourceDataType.STRING))) + .withFeatureAlgorithm("PCA")); + // Apply mutually exclusive tags to a MlModel feature + CreateMlModel createMlModel = createRequest(testInfo, 1); + for (MlFeature mlFeature : mlFeatureList) { + mlFeature.withTags(listOf(TIER1_TAG_LABEL, TIER2_TAG_LABEL)); + } + createMlModel.setMlFeatures(mlFeatureList); + assertResponse( + () -> createEntity(createMlModel, ADMIN_AUTH_HEADERS), + BAD_REQUEST, + CatalogExceptionMessage.mutuallyExclusiveLabels(TIER2_TAG_LABEL, TIER1_TAG_LABEL)); + } + @Override public MlModel validateGetWithDifferentFields(MlModel model, boolean byName) throws HttpResponseException { // .../models?fields=owner