mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-07-23 09:22:18 +00:00
Fix#10584: Update Lineage API to support lineage from table to dashboard data model (#11489)
* Fix: Update Lineage API to support lineage from table to dashboard data model * Minor change
This commit is contained in:
parent
8607d30b1e
commit
b2f2320145
@ -265,7 +265,7 @@ public interface CollectionDAO {
|
|||||||
WorkflowDAO workflowDAO();
|
WorkflowDAO workflowDAO();
|
||||||
|
|
||||||
@CreateSqlObject
|
@CreateSqlObject
|
||||||
DataModelDAO dataModelDAO();
|
DataModelDAO dashboardDataModelDAO();
|
||||||
|
|
||||||
interface DashboardDAO extends EntityDAO<Dashboard> {
|
interface DashboardDAO extends EntityDAO<Dashboard> {
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,7 +52,7 @@ public class DashboardDataModelRepository extends EntityRepository<DashboardData
|
|||||||
DashboardDataModelResource.COLLECTION_PATH,
|
DashboardDataModelResource.COLLECTION_PATH,
|
||||||
Entity.DASHBOARD_DATA_MODEL,
|
Entity.DASHBOARD_DATA_MODEL,
|
||||||
DashboardDataModel.class,
|
DashboardDataModel.class,
|
||||||
dao.dataModelDAO(),
|
dao.dashboardDataModelDAO(),
|
||||||
dao,
|
dao,
|
||||||
DATA_MODEL_PATCH_FIELDS,
|
DATA_MODEL_PATCH_FIELDS,
|
||||||
DATA_MODEL_UPDATE_FIELDS,
|
DATA_MODEL_UPDATE_FIELDS,
|
||||||
|
@ -19,6 +19,7 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.jdbi.v3.sqlobject.transaction.Transaction;
|
import org.jdbi.v3.sqlobject.transaction.Transaction;
|
||||||
|
import org.openmetadata.schema.ColumnsEntityInterface;
|
||||||
import org.openmetadata.schema.api.lineage.AddLineage;
|
import org.openmetadata.schema.api.lineage.AddLineage;
|
||||||
import org.openmetadata.schema.entity.data.Table;
|
import org.openmetadata.schema.entity.data.Table;
|
||||||
import org.openmetadata.schema.type.ColumnLineage;
|
import org.openmetadata.schema.type.ColumnLineage;
|
||||||
@ -89,12 +90,13 @@ public class LineageRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<ColumnLineage> columnsLineage = details.getColumnsLineage();
|
List<ColumnLineage> columnsLineage = details.getColumnsLineage();
|
||||||
if (!from.getType().equals(Entity.TABLE) || !to.getType().equals(Entity.TABLE)) {
|
if (areValidEntities(from, to)) {
|
||||||
throw new IllegalArgumentException("Column level lineage is only allowed between two tables.");
|
throw new IllegalArgumentException(
|
||||||
|
"Column level lineage is only allowed between two tables or from table to dashboard.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Table fromTable = dao.tableDAO().findEntityById(from.getId());
|
Table fromTable = dao.tableDAO().findEntityById(from.getId());
|
||||||
Table toTable = dao.tableDAO().findEntityById(to.getId());
|
ColumnsEntityInterface toTable = getToEntity(to);
|
||||||
if (columnsLineage != null) {
|
if (columnsLineage != null) {
|
||||||
for (ColumnLineage columnLineage : columnsLineage) {
|
for (ColumnLineage columnLineage : columnsLineage) {
|
||||||
for (String fromColumn : columnLineage.getFromColumns()) {
|
for (String fromColumn : columnLineage.getFromColumns()) {
|
||||||
@ -112,6 +114,17 @@ public class LineageRepository {
|
|||||||
return JsonUtils.pojoToJson(details);
|
return JsonUtils.pojoToJson(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ColumnsEntityInterface getToEntity(EntityReference from) throws IOException {
|
||||||
|
return from.getType().equals(Entity.TABLE)
|
||||||
|
? dao.tableDAO().findEntityById(from.getId())
|
||||||
|
: dao.dashboardDataModelDAO().findEntityById(from.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areValidEntities(EntityReference from, EntityReference to) {
|
||||||
|
return !from.getType().equals(Entity.TABLE)
|
||||||
|
|| !(to.getType().equals(Entity.TABLE) || to.getType().equals(Entity.DASHBOARD_DATA_MODEL));
|
||||||
|
}
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public boolean deleteLineage(String fromEntity, String fromId, String toEntity, String toId) throws IOException {
|
public boolean deleteLineage(String fromEntity, String fromId, String toEntity, String toId) throws IOException {
|
||||||
// Validate from entity
|
// Validate from entity
|
||||||
|
@ -41,8 +41,11 @@ import org.junit.jupiter.api.Order;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.TestInfo;
|
import org.junit.jupiter.api.TestInfo;
|
||||||
import org.junit.jupiter.api.TestMethodOrder;
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
|
import org.openmetadata.schema.EntityInterface;
|
||||||
|
import org.openmetadata.schema.api.data.CreateDashboardDataModel;
|
||||||
import org.openmetadata.schema.api.data.CreateTable;
|
import org.openmetadata.schema.api.data.CreateTable;
|
||||||
import org.openmetadata.schema.api.lineage.AddLineage;
|
import org.openmetadata.schema.api.lineage.AddLineage;
|
||||||
|
import org.openmetadata.schema.entity.data.DashboardDataModel;
|
||||||
import org.openmetadata.schema.entity.data.Table;
|
import org.openmetadata.schema.entity.data.Table;
|
||||||
import org.openmetadata.schema.entity.teams.Role;
|
import org.openmetadata.schema.entity.teams.Role;
|
||||||
import org.openmetadata.schema.entity.teams.User;
|
import org.openmetadata.schema.entity.teams.User;
|
||||||
@ -56,6 +59,7 @@ import org.openmetadata.schema.type.MetadataOperation;
|
|||||||
import org.openmetadata.service.Entity;
|
import org.openmetadata.service.Entity;
|
||||||
import org.openmetadata.service.OpenMetadataApplicationTest;
|
import org.openmetadata.service.OpenMetadataApplicationTest;
|
||||||
import org.openmetadata.service.resources.databases.TableResourceTest;
|
import org.openmetadata.service.resources.databases.TableResourceTest;
|
||||||
|
import org.openmetadata.service.resources.datamodels.DashboardDataModelResourceTest;
|
||||||
import org.openmetadata.service.resources.teams.RoleResource;
|
import org.openmetadata.service.resources.teams.RoleResource;
|
||||||
import org.openmetadata.service.resources.teams.RoleResourceTest;
|
import org.openmetadata.service.resources.teams.RoleResourceTest;
|
||||||
import org.openmetadata.service.resources.teams.UserResourceTest;
|
import org.openmetadata.service.resources.teams.UserResourceTest;
|
||||||
@ -66,9 +70,12 @@ import org.openmetadata.service.util.TestUtils;
|
|||||||
public class LineageResourceTest extends OpenMetadataApplicationTest {
|
public class LineageResourceTest extends OpenMetadataApplicationTest {
|
||||||
public static final List<Table> TABLES = new ArrayList<>();
|
public static final List<Table> TABLES = new ArrayList<>();
|
||||||
public static final int TABLE_COUNT = 10;
|
public static final int TABLE_COUNT = 10;
|
||||||
|
|
||||||
private static final String DATA_STEWARD_ROLE_NAME = "DataSteward";
|
private static final String DATA_STEWARD_ROLE_NAME = "DataSteward";
|
||||||
|
|
||||||
|
private static DashboardDataModel DATA_MODEL;
|
||||||
|
|
||||||
|
private static Table TABLE_DATA_MODEL_LINEAGE;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setup(TestInfo test) throws IOException, URISyntaxException {
|
public static void setup(TestInfo test) throws IOException, URISyntaxException {
|
||||||
// Create TABLE_COUNT number of tables
|
// Create TABLE_COUNT number of tables
|
||||||
@ -78,6 +85,14 @@ public class LineageResourceTest extends OpenMetadataApplicationTest {
|
|||||||
CreateTable createTable = tableResourceTest.createRequest(test, i);
|
CreateTable createTable = tableResourceTest.createRequest(test, i);
|
||||||
TABLES.add(tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS));
|
TABLES.add(tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entities to test lineage DashboardDataModel <-> Table
|
||||||
|
DashboardDataModelResourceTest dashboardResourceTest = new DashboardDataModelResourceTest();
|
||||||
|
CreateDashboardDataModel createDashboardDataModel = dashboardResourceTest.createRequest(test);
|
||||||
|
DATA_MODEL = dashboardResourceTest.createEntity(createDashboardDataModel, ADMIN_AUTH_HEADERS);
|
||||||
|
CreateTable createTable = tableResourceTest.createRequest(test, TABLE_COUNT);
|
||||||
|
createTable.setColumns(createDashboardDataModel.getColumns());
|
||||||
|
TABLE_DATA_MODEL_LINEAGE = tableResourceTest.createEntity(createTable, ADMIN_AUTH_HEADERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Order(1)
|
@Order(1)
|
||||||
@ -286,6 +301,32 @@ public class LineageResourceTest extends OpenMetadataApplicationTest {
|
|||||||
addEdge(TABLES.get(0), TABLES.get(1), details, ADMIN_AUTH_HEADERS);
|
addEdge(TABLES.get(0), TABLES.get(1), details, ADMIN_AUTH_HEADERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Order(4)
|
||||||
|
@Test
|
||||||
|
void putLineageFromDashboardDataModelToTable() throws HttpResponseException {
|
||||||
|
|
||||||
|
// Add column lineage dashboard.d1 -> table.c1
|
||||||
|
LineageDetails details = new LineageDetails();
|
||||||
|
String d1c1FQN = DATA_MODEL.getColumns().get(0).getFullyQualifiedName();
|
||||||
|
String d1c2FQN = DATA_MODEL.getColumns().get(1).getFullyQualifiedName();
|
||||||
|
String d1c3FQN = DATA_MODEL.getColumns().get(2).getFullyQualifiedName();
|
||||||
|
String c1c1FQN = TABLE_DATA_MODEL_LINEAGE.getColumns().get(0).getFullyQualifiedName();
|
||||||
|
String c1c2FQN = TABLE_DATA_MODEL_LINEAGE.getColumns().get(1).getFullyQualifiedName();
|
||||||
|
String c1c3FQN = TABLE_DATA_MODEL_LINEAGE.getColumns().get(2).getFullyQualifiedName();
|
||||||
|
|
||||||
|
List<ColumnLineage> lineage = details.getColumnsLineage();
|
||||||
|
lineage.add(new ColumnLineage().withFromColumns(List.of(c1c1FQN)).withToColumn(d1c1FQN));
|
||||||
|
lineage.add(new ColumnLineage().withFromColumns(List.of(c1c2FQN)).withToColumn(d1c2FQN));
|
||||||
|
lineage.add(new ColumnLineage().withFromColumns(List.of(c1c3FQN)).withToColumn(d1c3FQN));
|
||||||
|
|
||||||
|
addEdge(TABLE_DATA_MODEL_LINEAGE, DATA_MODEL, details, ADMIN_AUTH_HEADERS);
|
||||||
|
|
||||||
|
assertResponse(
|
||||||
|
() -> addEdge(DATA_MODEL, TABLE_DATA_MODEL_LINEAGE, details, ADMIN_AUTH_HEADERS),
|
||||||
|
BAD_REQUEST,
|
||||||
|
"Column level lineage is only allowed between two tables or from table to dashboard.");
|
||||||
|
}
|
||||||
|
|
||||||
public Edge getEdge(Table from, Table to) {
|
public Edge getEdge(Table from, Table to) {
|
||||||
return getEdge(from.getId(), to.getId(), null);
|
return getEdge(from.getId(), to.getId(), null);
|
||||||
}
|
}
|
||||||
@ -298,7 +339,8 @@ public class LineageResourceTest extends OpenMetadataApplicationTest {
|
|||||||
addEdge(from, to, null, ADMIN_AUTH_HEADERS);
|
addEdge(from, to, null, ADMIN_AUTH_HEADERS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEdge(Table from, Table to, LineageDetails details, Map<String, String> authHeaders)
|
private void addEdge(
|
||||||
|
EntityInterface from, EntityInterface to, LineageDetails details, Map<String, String> authHeaders)
|
||||||
throws HttpResponseException {
|
throws HttpResponseException {
|
||||||
if (details != null) {
|
if (details != null) {
|
||||||
details.setSqlQuery("select *;");
|
details.setSqlQuery("select *;");
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Collate
|
||||||
|
* Licensed 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.openmetadata.schema;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.openmetadata.schema.type.Column;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to be implemented by entities with a list of Column and FullyQualifiedName. It is used when adding lineage
|
||||||
|
* between different entities.
|
||||||
|
*/
|
||||||
|
public interface ColumnsEntityInterface {
|
||||||
|
|
||||||
|
String getFullyQualifiedName();
|
||||||
|
|
||||||
|
List<Column> getColumns();
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
"description": "Dashboard Data Model entity definition. Data models are the schemas used to build dashboards, charts, or other data assets.",
|
"description": "Dashboard Data Model entity definition. Data models are the schemas used to build dashboards, charts, or other data assets.",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"javaType": "org.openmetadata.schema.entity.data.DashboardDataModel",
|
"javaType": "org.openmetadata.schema.entity.data.DashboardDataModel",
|
||||||
"javaInterfaces": ["org.openmetadata.schema.EntityInterface"],
|
"javaInterfaces": ["org.openmetadata.schema.EntityInterface", "org.openmetadata.schema.ColumnsEntityInterface"],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"dataModelType": {
|
"dataModelType": {
|
||||||
"javaType": "org.openmetadata.schema.type.DataModelType",
|
"javaType": "org.openmetadata.schema.type.DataModelType",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"javaType": "org.openmetadata.schema.entity.data.Table",
|
"javaType": "org.openmetadata.schema.entity.data.Table",
|
||||||
"javaInterfaces": [
|
"javaInterfaces": [
|
||||||
"org.openmetadata.schema.EntityInterface"
|
"org.openmetadata.schema.EntityInterface", "org.openmetadata.schema.ColumnsEntityInterface"
|
||||||
],
|
],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"entityName": {
|
"entityName": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user