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 7faab1e44b1..805f7e9079d 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 @@ -284,21 +284,21 @@ public class DashboardDataModelRepository extends EntityRepository getDataModelColumns( UUID dataModelId, int limit, int offset, String fieldsParam, Include include) { DashboardDataModel dataModel = find(dataModelId, include); - return getDataModelColumnsInternal(dataModel, limit, offset, fieldsParam); + return getDataModelColumnsInternal(dataModel, limit, offset, fieldsParam, include); } public ResultList getDataModelColumnsByFQN( String fqn, int limit, int offset, String fieldsParam, Include include) { DashboardDataModel dataModel = findByName(fqn, include); - return getDataModelColumnsInternal(dataModel, limit, offset, fieldsParam); + return getDataModelColumnsInternal(dataModel, limit, offset, fieldsParam, include); } private ResultList getDataModelColumnsInternal( - DashboardDataModel dataModel, int limit, int offset, String fieldsParam) { + DashboardDataModel dataModel, int limit, int offset, String fieldsParam, Include include) { // For paginated column access, we need to load the data model with columns // but we'll optimize the field loading to only process what we need DashboardDataModel fullDataModel = - get(null, dataModel.getId(), getFields(Set.of("columns")), Include.NON_DELETED, false); + get(null, dataModel.getId(), getFields(Set.of("columns")), include, false); List allColumns = fullDataModel.getColumns(); if (allColumns == null || allColumns.isEmpty()) { diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java index 76b66a138ae..410398ec940 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/TableRepository.java @@ -1820,7 +1820,8 @@ public class TableRepository extends EntityRepository { Authorizer authorizer, SecurityContext securityContext) { Table table = find(tableId, include); - return getTableColumnsInternal(table, limit, offset, fieldsParam, authorizer, securityContext); + return getTableColumnsInternal( + table, limit, offset, fieldsParam, include, authorizer, securityContext); } public ResultList getTableColumnsByFQN( @@ -1832,7 +1833,8 @@ public class TableRepository extends EntityRepository
{ Authorizer authorizer, SecurityContext securityContext) { Table table = findByName(fqn, include); - return getTableColumnsInternal(table, limit, offset, fieldsParam, authorizer, securityContext); + return getTableColumnsInternal( + table, limit, offset, fieldsParam, include, authorizer, securityContext); } private org.openmetadata.service.util.ResultList getTableColumnsInternal( @@ -1840,11 +1842,12 @@ public class TableRepository extends EntityRepository
{ int limit, int offset, String fieldsParam, + Include include, Authorizer authorizer, SecurityContext securityContext) { // For paginated column access, we need to load the table with columns // but we'll optimize the field loading to only process what we need - Table fullTable = get(null, table.getId(), getFields(Set.of(COLUMN_FIELD)), NON_DELETED, false); + Table fullTable = get(null, table.getId(), getFields(Set.of(COLUMN_FIELD)), include, false); List allColumns = fullTable.getColumns(); if (allColumns == null || allColumns.isEmpty()) { diff --git a/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java b/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java index e1b119b0b80..cdf11978588 100644 --- a/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java +++ b/openmetadata-service/src/test/java/org/openmetadata/service/resources/databases/TableResourceTest.java @@ -5140,4 +5140,76 @@ public class TableResourceTest extends EntityResourceTest { // Verify table no longer exists in RDF after hard delete RdfTestUtils.verifyEntityNotInRdf(table.getFullyQualifiedName()); } + + @Test + void test_getColumnsForSoftDeletedTable_200() throws IOException { + // Create database and schema with simple names for clean FQN + Database db = + dbTest.createEntity( + dbTest + .createRequest("test_soft_delete_db") + .withService(SNOWFLAKE_REFERENCE.getFullyQualifiedName()), + ADMIN_AUTH_HEADERS); + DatabaseSchema schema = + schemaTest.createEntity( + schemaTest + .createRequest("test_soft_delete_schema") + .withDatabase(db.getFullyQualifiedName()), + ADMIN_AUTH_HEADERS); + + // Create a table with columns for testing soft-delete column retrieval + List columns = new ArrayList<>(); + for (int i = 1; i <= 5; i++) { + columns.add(getColumn("col" + i, STRING, null).withOrdinalPosition(i)); + } + + CreateTable create = + new CreateTable() + .withName("test_soft_delete_columns") + .withDatabaseSchema(schema.getFullyQualifiedName()) + .withColumns(columns); + Table table = createAndCheckEntity(create, ADMIN_AUTH_HEADERS); + + // Verify columns can be retrieved for active table + WebTarget target = + getResource("tables/" + table.getId() + "/columns").queryParam("include", "all"); + TableResource.TableColumnList response = + TestUtils.get(target, TableResource.TableColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Soft delete the table + deleteEntity(table.getId(), ADMIN_AUTH_HEADERS); + + // Verify columns can still be retrieved for soft-deleted table using include=all + target = getResource("tables/" + table.getId() + "/columns").queryParam("include", "all"); + response = TestUtils.get(target, TableResource.TableColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Also test by FQN for soft-deleted table (now with clean FQN) + target = + getResource( + "tables/name/" + + URLEncoder.encode(table.getFullyQualifiedName(), StandardCharsets.UTF_8) + + "/columns") + .queryParam("include", "all"); + response = TestUtils.get(target, TableResource.TableColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Verify that without include=all parameter, it should fail + WebTarget targetWithoutInclude = getResource("tables/" + table.getId() + "/columns"); + assertResponse( + () -> + TestUtils.get( + targetWithoutInclude, TableResource.TableColumnList.class, ADMIN_AUTH_HEADERS), + NOT_FOUND, + entityNotFound("table", table.getId())); + + // Cleanup: Hard delete the test entities we created to avoid affecting other tests + deleteEntity(table.getId(), false, true, ADMIN_AUTH_HEADERS); + schemaTest.deleteEntity(schema.getId(), false, true, ADMIN_AUTH_HEADERS); + dbTest.deleteEntity(db.getId(), false, true, ADMIN_AUTH_HEADERS); + } } 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 f1f76a3c29d..b62cddcd847 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 @@ -35,6 +35,8 @@ import static org.openmetadata.service.util.TestUtils.assertResponse; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.Response.Status; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -424,4 +426,68 @@ public class DashboardDataModelResourceTest column3.getTags() == null || column3.getTags().isEmpty(), "column3 should not have tags"); } } + + @Test + void test_getColumnsForSoftDeletedDataModel_200() throws IOException { + // Create a dashboard data model with columns for testing soft-delete column retrieval + List columns = new ArrayList<>(); + for (int i = 1; i <= 5; i++) { + columns.add(getColumn("datamodel_col" + i, INT, null)); + } + + CreateDashboardDataModel create = + createRequest("test_soft_delete_datamodel_columns").withColumns(columns); + DashboardDataModel dataModel = createAndCheckEntity(create, ADMIN_AUTH_HEADERS); + + // Verify columns can be retrieved for active data model using the columns endpoint + WebTarget target = + getResource("dashboard/datamodels/" + dataModel.getId() + "/columns") + .queryParam("include", "all"); + DashboardDataModelResource.DataModelColumnList response = + TestUtils.get( + target, DashboardDataModelResource.DataModelColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Soft delete the data model + deleteEntity(dataModel.getId(), ADMIN_AUTH_HEADERS); + + // Verify columns can still be retrieved for soft-deleted data model using include=all + target = + getResource("dashboard/datamodels/" + dataModel.getId() + "/columns") + .queryParam("include", "all"); + response = + TestUtils.get( + target, DashboardDataModelResource.DataModelColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Also test by FQN for soft-deleted data model + target = + getResource( + "dashboard/datamodels/name/" + + URLEncoder.encode(dataModel.getFullyQualifiedName(), StandardCharsets.UTF_8) + + "/columns") + .queryParam("include", "all"); + response = + TestUtils.get( + target, DashboardDataModelResource.DataModelColumnList.class, ADMIN_AUTH_HEADERS); + assertEquals(5, response.getData().size()); + assertEquals(5, response.getPaging().getTotal()); + + // Verify that without include=all parameter, it should fail for soft-deleted data model + WebTarget targetWithoutInclude = + getResource("dashboard/datamodels/" + dataModel.getId() + "/columns"); + assertResponse( + () -> + TestUtils.get( + targetWithoutInclude, + DashboardDataModelResource.DataModelColumnList.class, + ADMIN_AUTH_HEADERS), + NOT_FOUND, + CatalogExceptionMessage.entityNotFound("dashboardDataModel", dataModel.getId())); + + // Cleanup: Hard delete the test entity to avoid affecting other tests + deleteEntity(dataModel.getId(), false, true, ADMIN_AUTH_HEADERS); + } }