mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 10:39:30 +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(); | ||||
| 
 | ||||
|   @CreateSqlObject | ||||
|   DataModelDAO dataModelDAO(); | ||||
|   DataModelDAO dashboardDataModelDAO(); | ||||
| 
 | ||||
|   interface DashboardDAO extends EntityDAO<Dashboard> { | ||||
|     @Override | ||||
|  | ||||
| @ -52,7 +52,7 @@ public class DashboardDataModelRepository extends EntityRepository<DashboardData | ||||
|         DashboardDataModelResource.COLLECTION_PATH, | ||||
|         Entity.DASHBOARD_DATA_MODEL, | ||||
|         DashboardDataModel.class, | ||||
|         dao.dataModelDAO(), | ||||
|         dao.dashboardDataModelDAO(), | ||||
|         dao, | ||||
|         DATA_MODEL_PATCH_FIELDS, | ||||
|         DATA_MODEL_UPDATE_FIELDS, | ||||
|  | ||||
| @ -19,6 +19,7 @@ import java.util.List; | ||||
| import java.util.UUID; | ||||
| import java.util.stream.Collectors; | ||||
| import org.jdbi.v3.sqlobject.transaction.Transaction; | ||||
| import org.openmetadata.schema.ColumnsEntityInterface; | ||||
| import org.openmetadata.schema.api.lineage.AddLineage; | ||||
| import org.openmetadata.schema.entity.data.Table; | ||||
| import org.openmetadata.schema.type.ColumnLineage; | ||||
| @ -89,12 +90,13 @@ public class LineageRepository { | ||||
|     } | ||||
| 
 | ||||
|     List<ColumnLineage> columnsLineage = details.getColumnsLineage(); | ||||
|     if (!from.getType().equals(Entity.TABLE) || !to.getType().equals(Entity.TABLE)) { | ||||
|       throw new IllegalArgumentException("Column level lineage is only allowed between two tables."); | ||||
|     if (areValidEntities(from, to)) { | ||||
|       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 toTable = dao.tableDAO().findEntityById(to.getId()); | ||||
|     ColumnsEntityInterface toTable = getToEntity(to); | ||||
|     if (columnsLineage != null) { | ||||
|       for (ColumnLineage columnLineage : columnsLineage) { | ||||
|         for (String fromColumn : columnLineage.getFromColumns()) { | ||||
| @ -112,6 +114,17 @@ public class LineageRepository { | ||||
|     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 | ||||
|   public boolean deleteLineage(String fromEntity, String fromId, String toEntity, String toId) throws IOException { | ||||
|     // Validate from entity | ||||
|  | ||||
| @ -41,8 +41,11 @@ import org.junit.jupiter.api.Order; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.TestInfo; | ||||
| 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.lineage.AddLineage; | ||||
| import org.openmetadata.schema.entity.data.DashboardDataModel; | ||||
| import org.openmetadata.schema.entity.data.Table; | ||||
| import org.openmetadata.schema.entity.teams.Role; | ||||
| 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.OpenMetadataApplicationTest; | ||||
| 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.RoleResourceTest; | ||||
| import org.openmetadata.service.resources.teams.UserResourceTest; | ||||
| @ -66,9 +70,12 @@ import org.openmetadata.service.util.TestUtils; | ||||
| public class LineageResourceTest extends OpenMetadataApplicationTest { | ||||
|   public static final List<Table> TABLES = new ArrayList<>(); | ||||
|   public static final int TABLE_COUNT = 10; | ||||
| 
 | ||||
|   private static final String DATA_STEWARD_ROLE_NAME = "DataSteward"; | ||||
| 
 | ||||
|   private static DashboardDataModel DATA_MODEL; | ||||
| 
 | ||||
|   private static Table TABLE_DATA_MODEL_LINEAGE; | ||||
| 
 | ||||
|   @BeforeAll | ||||
|   public static void setup(TestInfo test) throws IOException, URISyntaxException { | ||||
|     // Create TABLE_COUNT number of tables | ||||
| @ -78,6 +85,14 @@ public class LineageResourceTest extends OpenMetadataApplicationTest { | ||||
|       CreateTable createTable = tableResourceTest.createRequest(test, i); | ||||
|       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) | ||||
| @ -286,6 +301,32 @@ public class LineageResourceTest extends OpenMetadataApplicationTest { | ||||
|     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) { | ||||
|     return getEdge(from.getId(), to.getId(), null); | ||||
|   } | ||||
| @ -298,7 +339,8 @@ public class LineageResourceTest extends OpenMetadataApplicationTest { | ||||
|     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 { | ||||
|     if (details != null) { | ||||
|       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.", | ||||
|   "type": "object", | ||||
|   "javaType": "org.openmetadata.schema.entity.data.DashboardDataModel", | ||||
|   "javaInterfaces": ["org.openmetadata.schema.EntityInterface"], | ||||
|   "javaInterfaces": ["org.openmetadata.schema.EntityInterface", "org.openmetadata.schema.ColumnsEntityInterface"], | ||||
|   "definitions": { | ||||
|     "dataModelType": { | ||||
|       "javaType": "org.openmetadata.schema.type.DataModelType", | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|   "type": "object", | ||||
|   "javaType": "org.openmetadata.schema.entity.data.Table", | ||||
|   "javaInterfaces": [ | ||||
|     "org.openmetadata.schema.EntityInterface" | ||||
|     "org.openmetadata.schema.EntityInterface", "org.openmetadata.schema.ColumnsEntityInterface" | ||||
|   ], | ||||
|   "definitions": { | ||||
|     "entityName": { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nahuel
						Nahuel