diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseRepository.java index 71a8adb2e0e6..8ab1f826591a 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseRepository.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.apache.commons.csv.CSVPrinter; @@ -105,6 +106,18 @@ public EntityInterface getParentEntity(Database entity, String fields) { return Entity.getEntity(entity.getService(), fields, Include.ALL); } + @Override + public void entityRelationshipReindex(Database original, Database updated) { + super.entityRelationshipReindex(original, updated); + + // Update search indexes of assets and entity on database displayName change + if (!Objects.equals(original.getDisplayName(), updated.getDisplayName())) { + searchRepository + .getSearchClient() + .reindexAcrossIndices("database.fullyQualifiedName", original.getEntityReference()); + } + } + @Override public String exportToCsv(String name, String user) throws IOException { Database database = getByName(null, name, Fields.EMPTY_FIELDS); // Validate database name diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseSchemaRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseSchemaRepository.java index 8f477f20aaea..252681ca3d35 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseSchemaRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/DatabaseSchemaRepository.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.apache.commons.csv.CSVPrinter; @@ -179,6 +180,18 @@ private void populateDatabase(DatabaseSchema schema) { .withServiceType(database.getServiceType()); } + @Override + public void entityRelationshipReindex(DatabaseSchema original, DatabaseSchema updated) { + super.entityRelationshipReindex(original, updated); + + // Update search indexes of assets and entity on databaseSchema displayName change + if (!Objects.equals(original.getDisplayName(), updated.getDisplayName())) { + searchRepository + .getSearchClient() + .reindexAcrossIndices("databaseSchema.fullyQualifiedName", original.getEntityReference()); + } + } + @Override public String exportToCsv(String name, String user) throws IOException { DatabaseSchema schema = getByName(null, name, Fields.EMPTY_FIELDS); // Validate database schema diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchClient.java b/openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchClient.java index 94950f5f2506..c65cab8de183 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchClient.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/search/elasticsearch/ElasticSearchClient.java @@ -1311,6 +1311,14 @@ private static SearchSourceBuilder buildSearchAcrossIndexesBuilder( AggregationBuilders.terms("databaseSchema.name.keyword") .field("databaseSchema.name.keyword") .size(MAX_AGGREGATE_SIZE)); + searchSourceBuilder.aggregation( + AggregationBuilders.terms("database.displayName") + .field("database.displayName") + .size(MAX_AGGREGATE_SIZE)); + searchSourceBuilder.aggregation( + AggregationBuilders.terms("databaseSchema.displayName") + .field("databaseSchema.displayName") + .size(MAX_AGGREGATE_SIZE)); return addAggregation(searchSourceBuilder); } diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchClient.java b/openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchClient.java index bb9d954eea2a..8a1c5b93b461 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchClient.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/search/opensearch/OpenSearchClient.java @@ -1291,6 +1291,14 @@ private static SearchSourceBuilder buildSearchAcrossIndexesBuilder( AggregationBuilders.terms("databaseSchema.name.keyword") .field("databaseSchema.name.keyword") .size(MAX_AGGREGATE_SIZE)); + searchSourceBuilder.aggregation( + AggregationBuilders.terms("database.displayName") + .field("database.displayName") + .size(MAX_AGGREGATE_SIZE)); + searchSourceBuilder.aggregation( + AggregationBuilders.terms("databaseSchema.displayName") + .field("databaseSchema.displayName") + .size(MAX_AGGREGATE_SIZE)); return addAggregation(searchSourceBuilder); } diff --git a/openmetadata-service/src/main/resources/elasticsearch/en/database_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/en/database_index_mapping.json index f63e833ce390..609d87096e14 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/en/database_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/en/database_index_mapping.json @@ -403,6 +403,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, diff --git a/openmetadata-service/src/main/resources/elasticsearch/en/database_schema_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/en/database_schema_index_mapping.json index 5feee13f6b49..4a1a16d2dc29 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/en/database_schema_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/en/database_schema_index_mapping.json @@ -308,6 +308,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "keyword", "normalizer": "lowercase_normalizer" diff --git a/openmetadata-service/src/main/resources/elasticsearch/en/stored_procedure_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/en/stored_procedure_index_mapping.json index 1251645f483d..6781f639e2cf 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/en/stored_procedure_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/en/stored_procedure_index_mapping.json @@ -189,6 +189,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } @@ -235,6 +236,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } diff --git a/openmetadata-service/src/main/resources/elasticsearch/jp/database_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/jp/database_index_mapping.json index 69e8aed271fd..1614b4dd7d83 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/jp/database_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/jp/database_index_mapping.json @@ -402,6 +402,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, diff --git a/openmetadata-service/src/main/resources/elasticsearch/jp/database_schema_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/jp/database_schema_index_mapping.json index 9a1cd0f65626..f5d2d5f3b512 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/jp/database_schema_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/jp/database_schema_index_mapping.json @@ -307,6 +307,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "keyword", "normalizer": "lowercase_normalizer" diff --git a/openmetadata-service/src/main/resources/elasticsearch/jp/stored_procedure_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/jp/stored_procedure_index_mapping.json index 607435b948eb..69cec532a3a6 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/jp/stored_procedure_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/jp/stored_procedure_index_mapping.json @@ -185,6 +185,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } @@ -231,6 +232,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } diff --git a/openmetadata-service/src/main/resources/elasticsearch/jp/table_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/jp/table_index_mapping.json index cb77aef9f826..76e6674d4a86 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/jp/table_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/jp/table_index_mapping.json @@ -190,6 +190,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, @@ -228,6 +238,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, diff --git a/openmetadata-service/src/main/resources/elasticsearch/zh/database_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/zh/database_index_mapping.json index ae0d47b21e1e..e7eafeb1935b 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/zh/database_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/zh/database_index_mapping.json @@ -375,6 +375,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, diff --git a/openmetadata-service/src/main/resources/elasticsearch/zh/database_schema_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/zh/database_schema_index_mapping.json index e04ade9afbdf..8a6aea6c5d43 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/zh/database_schema_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/zh/database_schema_index_mapping.json @@ -282,6 +282,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "keyword", "normalizer": "lowercase_normalizer" diff --git a/openmetadata-service/src/main/resources/elasticsearch/zh/stored_procedure_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/zh/stored_procedure_index_mapping.json index 3cb9cbaeaefc..b8e5057fbc23 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/zh/stored_procedure_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/zh/stored_procedure_index_mapping.json @@ -165,6 +165,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } @@ -211,6 +212,7 @@ "fields": { "keyword": { "type": "keyword", + "normalizer": "lowercase_normalizer", "ignore_above": 256 } } diff --git a/openmetadata-service/src/main/resources/elasticsearch/zh/table_index_mapping.json b/openmetadata-service/src/main/resources/elasticsearch/zh/table_index_mapping.json index ab507c21bd0c..022b91d620ac 100644 --- a/openmetadata-service/src/main/resources/elasticsearch/zh/table_index_mapping.json +++ b/openmetadata-service/src/main/resources/elasticsearch/zh/table_index_mapping.json @@ -164,6 +164,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, @@ -204,6 +214,16 @@ } } }, + "displayName": { + "type": "keyword", + "fields": { + "keyword": { + "type": "keyword", + "normalizer": "lowercase_normalizer", + "ignore_above": 256 + } + } + }, "fullyQualifiedName": { "type": "text" }, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/AdvancedSearch.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/AdvancedSearch.spec.ts index 76bc735b9bde..dc8ab42bd0ab 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/AdvancedSearch.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/AdvancedSearch.spec.ts @@ -96,14 +96,8 @@ test.describe('Advanced Search', { tag: '@advanced-search' }, () => { tierTag2.responseData.fullyQualifiedName, ], 'service.displayName.keyword': [table1.service.name, table2.service.name], - 'database.displayName.keyword': [ - table1.database.name, - table2.database.name, - ], - 'databaseSchema.displayName.keyword': [ - table1.schema.name, - table2.schema.name, - ], + 'database.displayName': [table1.database.name, table2.database.name], + 'databaseSchema.displayName': [table1.schema.name, table2.schema.name], 'columns.name.keyword': ['email', 'shop_id'], 'displayName.keyword': [ table1.entity.displayName, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ExploreTree.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ExploreTree.spec.ts index 3c8ec2604ff8..9f0ba1bacd5b 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ExploreTree.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ExploreTree.spec.ts @@ -11,8 +11,12 @@ * limitations under the License. */ import test, { expect } from '@playwright/test'; +import { get } from 'lodash'; import { SidebarItem } from '../../constant/sidebar'; -import { redirectToHomePage } from '../../utils/common'; +import { EntityTypeEndpoint } from '../../support/entity/Entity.interface'; +import { TableClass } from '../../support/entity/TableClass'; +import { getApiContext, redirectToHomePage } from '../../utils/common'; +import { updateDisplayNameForEntity } from '../../utils/entity'; import { sidebarClick } from '../../utils/sidebar'; // use the admin user to login @@ -107,4 +111,82 @@ test.describe('Explore Tree scenarios ', () => { } ); }); + + test('Verify Database and Database schema after rename', async ({ page }) => { + const { apiContext, afterAction } = await getApiContext(page); + const table = new TableClass(); + await table.create(apiContext); + await table.visitEntityPage(page); + const schemaName = get(table.schemaResponseData, 'name', ''); + const dbName = get(table.databaseResponseData, 'name', ''); + const serviceName = get(table.serviceResponseData, 'name', ''); + const updatedSchemaName = `Test ${schemaName} updated`; + const updatedDbName = `Test ${dbName} updated`; + + const schemaRes = page.waitForResponse('/api/v1/databaseSchemas/name/*'); + await page.getByRole('link', { name: schemaName }).click(); + // Rename Schema Page + await schemaRes; + await updateDisplayNameForEntity( + page, + updatedSchemaName, + EntityTypeEndpoint.DatabaseSchema + ); + + const dbRes = page.waitForResponse('/api/v1/databases/name/*'); + await page.getByRole('link', { name: dbName }).click(); + // Rename Database Page + await dbRes; + await updateDisplayNameForEntity( + page, + updatedDbName, + EntityTypeEndpoint.Database + ); + + await sidebarClick(page, SidebarItem.EXPLORE); + await page.waitForLoadState('networkidle'); + const serviceNameRes = page.waitForResponse( + '/api/v1/search/query?q=&index=database_search_index&from=0&size=0*mysql*' + ); + await page + .locator('div') + .filter({ hasText: /^mysql$/ }) + .locator('svg') + .first() + .click(); + await serviceNameRes; + + const databaseRes = page.waitForResponse( + '/api/v1/search/query?q=&index=dataAsset*serviceType*' + ); + + await page + .locator('.ant-tree-treenode') + .filter({ hasText: serviceName }) + .locator('.ant-tree-switcher svg') + .click(); + await databaseRes; + + await expect( + page.getByTestId(`explore-tree-title-${updatedDbName}`) + ).toBeVisible(); + + const databaseSchemaRes = page.waitForResponse( + '/api/v1/search/query?q=&index=dataAsset*database.displayName*' + ); + + await page + .locator('.ant-tree-treenode') + .filter({ hasText: updatedDbName }) + .locator('.ant-tree-switcher svg') + .click(); + await databaseSchemaRes; + + await expect( + page.getByTestId(`explore-tree-title-${updatedSchemaName}`) + ).toBeVisible(); + + await table.delete(apiContext); + await afterAction(); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/advancedSearch.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/advancedSearch.ts index c71f1750166c..f2b4e53d41cb 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/advancedSearch.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/advancedSearch.ts @@ -44,12 +44,12 @@ export const FIELDS: EntityFields[] = [ }, { id: 'Database', - name: 'database.displayName.keyword', + name: 'database.displayName', localSearch: false, }, { id: 'Database Schema', - name: 'databaseSchema.displayName.keyword', + name: 'databaseSchema.displayName', localSearch: false, }, { diff --git a/openmetadata-ui/src/main/resources/ui/src/enums/AdvancedSearch.enum.ts b/openmetadata-ui/src/main/resources/ui/src/enums/AdvancedSearch.enum.ts index e0d141a4d10a..99984cd66979 100644 --- a/openmetadata-ui/src/main/resources/ui/src/enums/AdvancedSearch.enum.ts +++ b/openmetadata-ui/src/main/resources/ui/src/enums/AdvancedSearch.enum.ts @@ -53,8 +53,8 @@ export enum EntityFields { TAG = 'tags.tagFQN', TIER = 'tier.tagFQN', SERVICE = 'service.displayName.keyword', - DATABASE = 'database.name.keyword', - DATABASE_SCHEMA = 'databaseSchema.name.keyword', + DATABASE = 'database.displayName', + DATABASE_SCHEMA = 'databaseSchema.displayName', COLUMN = 'columns.name.keyword', CHART = 'charts.displayName.keyword', TASK = 'tasks.displayName.keyword', diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts index fb5017d409d4..c7c57bc8e472 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchClassBase.ts @@ -139,7 +139,7 @@ class AdvancedSearchClassBase { * Fields specific to tables */ tableQueryBuilderFields: Fields = { - 'database.displayName.keyword': { + [EntityFields.DATABASE]: { label: t('label.database'), type: 'select', mainWidgetProps: this.mainWidgetProps, @@ -152,7 +152,7 @@ class AdvancedSearchClassBase { }, }, - 'databaseSchema.displayName.keyword': { + [EntityFields.DATABASE_SCHEMA]: { label: t('label.database-schema'), type: 'select', mainWidgetProps: this.mainWidgetProps,