GEN-1434: Improvement : Show displayName for database and databaseSchema in explore tree (#17876)

* Show displayName for database and databaseSchema in explore tree

* use display name for database and schema

* add playwright

* resync indexes of dataAssets based on database & databaseSchema displayName change

---------

Co-authored-by: karanh37 <karanh37@gmail.com>
Co-authored-by: Karan Hotchandani <33024356+karanh37@users.noreply.github.com>
This commit is contained in:
sonika-shah 2024-09-26 16:18:16 +05:30 committed by GitHub
parent d2bce8adf4
commit a99fbb2eb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 239 additions and 15 deletions

View File

@ -24,6 +24,7 @@ import java.io.IOException;
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 class DatabaseRepository extends EntityRepository<Database> {
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

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
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 @@ public class DatabaseSchemaRepository extends EntityRepository<DatabaseSchema> {
.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

View File

@ -1311,6 +1311,14 @@ public class ElasticSearchClient implements SearchClient {
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);
}

View File

@ -1291,6 +1291,14 @@ public class OpenSearchClient implements SearchClient {
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);
}

View File

@ -403,6 +403,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "text"
},

View File

@ -308,6 +308,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "keyword",
"normalizer": "lowercase_normalizer"

View File

@ -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
}
}

View File

@ -402,6 +402,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "text"
},

View File

@ -307,6 +307,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "keyword",
"normalizer": "lowercase_normalizer"

View File

@ -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
}
}

View File

@ -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"
},

View File

@ -375,6 +375,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "text"
},

View File

@ -282,6 +282,16 @@
}
}
},
"displayName": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "keyword",
"normalizer": "lowercase_normalizer"

View File

@ -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
}
}

View File

@ -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"
},

View File

@ -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,

View File

@ -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();
});
});

View File

@ -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,
},
{

View File

@ -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',

View File

@ -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,