mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-11-03 20:19:31 +00:00 
			
		
		
		
	Add Lineage Export Async endpoint using Search (#18553)
* Add Lineage Export Async endpoint using Search * Lineage api (#18593) * add api for lineage export * update API call for lineage async * use JsonUtils instead of objectMapper to read lineage search response --------- Co-authored-by: Karan Hotchandani <33024356+karanh37@users.noreply.github.com> Co-authored-by: Sweta Agarwalla <105535990+sweta1308@users.noreply.github.com> Co-authored-by: sonikashah <sonikashah94@gmail.com>
This commit is contained in:
		
							parent
							
								
									71f93633ac
								
							
						
					
					
						commit
						783ec62e4c
					
				@ -1,13 +0,0 @@
 | 
			
		||||
<component name="ProjectRunConfigurationManager">
 | 
			
		||||
  <configuration default="true" type="JUnit" factoryName="JUnit">
 | 
			
		||||
    <module name="openmetadata-service" />
 | 
			
		||||
    <option name="PACKAGE_NAME" value="" />
 | 
			
		||||
    <option name="MAIN_CLASS_NAME" value="" />
 | 
			
		||||
    <option name="METHOD_NAME" value="" />
 | 
			
		||||
    <option name="TEST_OBJECT" value="package" />
 | 
			
		||||
    <option name="VM_PARAMETERS" value="-ea -DjdbcContainerClassName=org.testcontainers.containers.MySQLContainer -DjdbcContainerImage=mysql:8 -DelasticSearchContainerClassName=docker.elastic.co/elasticsearch/elasticsearch:8.11.4 -DopenSearchContainerClassName=opensearchproject/opensearch:1.3.0 -DrunESTestCases=false"/>
 | 
			
		||||
    <method v="2">
 | 
			
		||||
      <option name="Make" enabled="true" />
 | 
			
		||||
    </method>
 | 
			
		||||
  </configuration>
 | 
			
		||||
</component>
 | 
			
		||||
@ -577,6 +577,11 @@
 | 
			
		||||
      <artifactId>commons-csv</artifactId>
 | 
			
		||||
      <version>1.12.0</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.opencsv</groupId>
 | 
			
		||||
      <artifactId>opencsv</artifactId>
 | 
			
		||||
      <version>5.9</version>
 | 
			
		||||
    </dependency>
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>com.onelogin</groupId>
 | 
			
		||||
      <artifactId>java-saml</artifactId>
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,10 @@ import static org.openmetadata.service.Entity.TOPIC;
 | 
			
		||||
import static org.openmetadata.service.search.SearchClient.GLOBAL_SEARCH_ALIAS;
 | 
			
		||||
import static org.openmetadata.service.search.SearchClient.REMOVE_LINEAGE_SCRIPT;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.JsonNode;
 | 
			
		||||
import com.opencsv.CSVWriter;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.StringWriter;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
@ -66,6 +69,7 @@ import org.openmetadata.schema.type.Relationship;
 | 
			
		||||
import org.openmetadata.schema.type.csv.CsvDocumentation;
 | 
			
		||||
import org.openmetadata.schema.type.csv.CsvFile;
 | 
			
		||||
import org.openmetadata.schema.type.csv.CsvHeader;
 | 
			
		||||
import org.openmetadata.sdk.exception.CSVExportException;
 | 
			
		||||
import org.openmetadata.service.Entity;
 | 
			
		||||
import org.openmetadata.service.exception.CatalogExceptionMessage;
 | 
			
		||||
import org.openmetadata.service.exception.EntityNotFoundException;
 | 
			
		||||
@ -254,6 +258,231 @@ public class LineageRepository {
 | 
			
		||||
    return CsvUtil.formatCsv(csvFile);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public final String exportCsvAsync(
 | 
			
		||||
      String fqn,
 | 
			
		||||
      int upstreamDepth,
 | 
			
		||||
      int downstreamDepth,
 | 
			
		||||
      String queryFilter,
 | 
			
		||||
      String entityType,
 | 
			
		||||
      boolean deleted)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    Response response =
 | 
			
		||||
        Entity.getSearchRepository()
 | 
			
		||||
            .searchLineage(fqn, upstreamDepth, downstreamDepth, queryFilter, deleted, entityType);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      String jsonResponse = JsonUtils.pojoToJson(response.getEntity());
 | 
			
		||||
      JsonNode rootNode = JsonUtils.readTree(jsonResponse);
 | 
			
		||||
 | 
			
		||||
      Map<String, JsonNode> entityMap = new HashMap<>();
 | 
			
		||||
      JsonNode nodes = rootNode.path("nodes");
 | 
			
		||||
      for (JsonNode node : nodes) {
 | 
			
		||||
        String id = node.path("id").asText();
 | 
			
		||||
        entityMap.put(id, node);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      StringWriter csvContent = new StringWriter();
 | 
			
		||||
      CSVWriter csvWriter = new CSVWriter(csvContent);
 | 
			
		||||
      String[] headers = {
 | 
			
		||||
        "fromEntityFQN", "fromServiceName", "fromServiceType", "fromOwners", "fromDomain",
 | 
			
		||||
        "toEntityFQN", "toServiceName", "toServiceType", "toOwners", "toDomain",
 | 
			
		||||
        "fromChildEntityFQN", "toChildEntityFQN"
 | 
			
		||||
      };
 | 
			
		||||
      csvWriter.writeNext(headers);
 | 
			
		||||
      JsonNode edges = rootNode.path("edges");
 | 
			
		||||
      for (JsonNode edge : edges) {
 | 
			
		||||
        String fromEntityId = edge.path("fromEntity").path("id").asText();
 | 
			
		||||
        String toEntityId = edge.path("toEntity").path("id").asText();
 | 
			
		||||
 | 
			
		||||
        JsonNode fromEntity = entityMap.getOrDefault(fromEntityId, null);
 | 
			
		||||
        JsonNode toEntity = entityMap.getOrDefault(toEntityId, null);
 | 
			
		||||
 | 
			
		||||
        Map<String, String> baseRow = new HashMap<>();
 | 
			
		||||
        baseRow.put("fromEntityFQN", getText(fromEntity, "fullyQualifiedName"));
 | 
			
		||||
        baseRow.put("fromServiceName", getText(fromEntity.path("service"), "name"));
 | 
			
		||||
        baseRow.put("fromServiceType", getText(fromEntity, "serviceType"));
 | 
			
		||||
        baseRow.put("fromOwners", getOwners(fromEntity.path("owners")));
 | 
			
		||||
        baseRow.put("fromDomain", getText(fromEntity, "domain"));
 | 
			
		||||
 | 
			
		||||
        baseRow.put("toEntityFQN", getText(toEntity, "fullyQualifiedName"));
 | 
			
		||||
        baseRow.put("toServiceName", getText(toEntity.path("service"), "name"));
 | 
			
		||||
        baseRow.put("toServiceType", getText(toEntity, "serviceType"));
 | 
			
		||||
        baseRow.put("toOwners", getOwners(toEntity.path("owners")));
 | 
			
		||||
        baseRow.put("toDomain", getText(toEntity, "domain"));
 | 
			
		||||
 | 
			
		||||
        List<String> fromChildFQNs = new ArrayList<>();
 | 
			
		||||
        List<String> toChildFQNs = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        extractChildEntities(fromEntity, fromChildFQNs);
 | 
			
		||||
        extractChildEntities(toEntity, toChildFQNs);
 | 
			
		||||
 | 
			
		||||
        JsonNode columns = edge.path("columns");
 | 
			
		||||
        if (columns.isArray() && !columns.isEmpty()) {
 | 
			
		||||
          for (JsonNode columnMapping : columns) {
 | 
			
		||||
            JsonNode fromColumns = columnMapping.path("fromColumns");
 | 
			
		||||
            String toColumn = columnMapping.path("toColumn").asText();
 | 
			
		||||
 | 
			
		||||
            for (JsonNode fromColumn : fromColumns) {
 | 
			
		||||
              String fromChildFQN = fromColumn.asText();
 | 
			
		||||
              String toChildFQN = toColumn;
 | 
			
		||||
              writeCsvRow(csvWriter, baseRow, fromChildFQN, toChildFQN);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } else if (!fromChildFQNs.isEmpty() || !toChildFQNs.isEmpty()) {
 | 
			
		||||
          if (!fromChildFQNs.isEmpty() && !toChildFQNs.isEmpty()) {
 | 
			
		||||
            for (String fromChildFQN : fromChildFQNs) {
 | 
			
		||||
              for (String toChildFQN : toChildFQNs) {
 | 
			
		||||
                writeCsvRow(csvWriter, baseRow, fromChildFQN, toChildFQN);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          } else if (!fromChildFQNs.isEmpty()) {
 | 
			
		||||
            for (String fromChildFQN : fromChildFQNs) {
 | 
			
		||||
              writeCsvRow(csvWriter, baseRow, fromChildFQN, "");
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            for (String toChildFQN : toChildFQNs) {
 | 
			
		||||
              writeCsvRow(csvWriter, baseRow, "", toChildFQN);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          writeCsvRow(csvWriter, baseRow, "", "");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      csvWriter.close();
 | 
			
		||||
      return csvContent.toString();
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      throw CSVExportException.byMessage("Failed to export lineage data to CSV", e.getMessage());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void writeCsvRow(
 | 
			
		||||
      CSVWriter csvWriter, Map<String, String> baseRow, String fromChildFQN, String toChildFQN) {
 | 
			
		||||
    String[] row = {
 | 
			
		||||
      baseRow.get("fromEntityFQN"),
 | 
			
		||||
      baseRow.get("fromServiceName"),
 | 
			
		||||
      baseRow.get("fromServiceType"),
 | 
			
		||||
      baseRow.get("fromOwners"),
 | 
			
		||||
      baseRow.get("fromDomain"),
 | 
			
		||||
      baseRow.get("toEntityFQN"),
 | 
			
		||||
      baseRow.get("toServiceName"),
 | 
			
		||||
      baseRow.get("toServiceType"),
 | 
			
		||||
      baseRow.get("toOwners"),
 | 
			
		||||
      baseRow.get("toDomain"),
 | 
			
		||||
      fromChildFQN,
 | 
			
		||||
      toChildFQN
 | 
			
		||||
    };
 | 
			
		||||
    csvWriter.writeNext(row);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String getText(JsonNode node, String fieldName) {
 | 
			
		||||
    if (node != null && node.has(fieldName)) {
 | 
			
		||||
      JsonNode fieldNode = node.get(fieldName);
 | 
			
		||||
      return fieldNode.isNull() ? "" : fieldNode.asText();
 | 
			
		||||
    }
 | 
			
		||||
    return "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String getOwners(JsonNode ownersNode) {
 | 
			
		||||
    if (ownersNode != null && ownersNode.isArray()) {
 | 
			
		||||
      List<String> ownersList = new ArrayList<>();
 | 
			
		||||
      for (JsonNode owner : ownersNode) {
 | 
			
		||||
        String ownerName = getText(owner, "name");
 | 
			
		||||
        if (!ownerName.isEmpty()) {
 | 
			
		||||
          ownersList.add(ownerName);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return String.join(";", ownersList);
 | 
			
		||||
    }
 | 
			
		||||
    return "";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractChildEntities(JsonNode entityNode, List<String> childFQNs) {
 | 
			
		||||
    if (entityNode == null) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    String entityType = getText(entityNode, "entityType");
 | 
			
		||||
    switch (entityType) {
 | 
			
		||||
      case TABLE:
 | 
			
		||||
        extractColumns(entityNode.path("columns"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      case DASHBOARD:
 | 
			
		||||
        extractCharts(entityNode.path("charts"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      case SEARCH_INDEX:
 | 
			
		||||
        extractFields(entityNode.path("fields"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      case CONTAINER:
 | 
			
		||||
        extractContainers(entityNode.path("children"), childFQNs);
 | 
			
		||||
        extractColumns(entityNode.path("dataModel").path("columns"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      case TOPIC:
 | 
			
		||||
        extractSchemaFields(entityNode.path("messageSchema").path("schemaFields"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      case DASHBOARD_DATA_MODEL:
 | 
			
		||||
        extractColumns(entityNode.path("columns"), childFQNs);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractColumns(JsonNode columnsNode, List<String> childFQNs) {
 | 
			
		||||
    if (columnsNode != null && columnsNode.isArray()) {
 | 
			
		||||
      for (JsonNode column : columnsNode) {
 | 
			
		||||
        if (column != null) {
 | 
			
		||||
          String columnFQN = getText(column, "fullyQualifiedName");
 | 
			
		||||
          childFQNs.add(columnFQN);
 | 
			
		||||
          extractColumns(column.path("children"), childFQNs);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractCharts(JsonNode chartsNode, List<String> childFQNs) {
 | 
			
		||||
    if (chartsNode != null && chartsNode.isArray()) {
 | 
			
		||||
      for (JsonNode chart : chartsNode) {
 | 
			
		||||
        String chartFQN = getText(chart, "fullyQualifiedName");
 | 
			
		||||
        childFQNs.add(chartFQN);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractFields(JsonNode fieldsNode, List<String> childFQNs) {
 | 
			
		||||
    if (fieldsNode != null && fieldsNode.isArray()) {
 | 
			
		||||
      for (JsonNode field : fieldsNode) {
 | 
			
		||||
        if (field != null) {
 | 
			
		||||
          String fieldFQN = getText(field, "fullyQualifiedName");
 | 
			
		||||
          childFQNs.add(fieldFQN);
 | 
			
		||||
          extractFields(field.path("children"), childFQNs);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractContainers(JsonNode containersNode, List<String> childFQNs) {
 | 
			
		||||
    if (containersNode != null && containersNode.isArray()) {
 | 
			
		||||
      for (JsonNode container : containersNode) {
 | 
			
		||||
        if (container != null) {
 | 
			
		||||
          String containerFQN = getText(container, "fullyQualifiedName");
 | 
			
		||||
          childFQNs.add(containerFQN);
 | 
			
		||||
          extractContainers(container.path("children"), childFQNs);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void extractSchemaFields(JsonNode schemaFieldsNode, List<String> childFQNs) {
 | 
			
		||||
    if (schemaFieldsNode != null && schemaFieldsNode.isArray()) {
 | 
			
		||||
      for (JsonNode field : schemaFieldsNode) {
 | 
			
		||||
        if (field != null) {
 | 
			
		||||
          String fieldFQN = getText(field, "fullyQualifiedName");
 | 
			
		||||
          childFQNs.add(fieldFQN);
 | 
			
		||||
          extractSchemaFields(field.path("children"), childFQNs);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private String getStringOrNull(HashMap map, String key) {
 | 
			
		||||
    return nullOrEmpty(map.get(key)) ? "" : map.get(key).toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.concurrent.ExecutorService;
 | 
			
		||||
import javax.json.JsonPatch;
 | 
			
		||||
import javax.validation.Valid;
 | 
			
		||||
import javax.validation.constraints.Max;
 | 
			
		||||
@ -60,6 +61,10 @@ import org.openmetadata.service.resources.Collection;
 | 
			
		||||
import org.openmetadata.service.security.Authorizer;
 | 
			
		||||
import org.openmetadata.service.security.policyevaluator.OperationContext;
 | 
			
		||||
import org.openmetadata.service.security.policyevaluator.ResourceContextInterface;
 | 
			
		||||
import org.openmetadata.service.util.AsyncService;
 | 
			
		||||
import org.openmetadata.service.util.CSVExportMessage;
 | 
			
		||||
import org.openmetadata.service.util.CSVExportResponse;
 | 
			
		||||
import org.openmetadata.service.util.WebsocketNotificationHandler;
 | 
			
		||||
 | 
			
		||||
@Path("/v1/lineage")
 | 
			
		||||
@Tag(
 | 
			
		||||
@ -273,10 +278,61 @@ public class LineageResource {
 | 
			
		||||
          boolean deleted,
 | 
			
		||||
      @Parameter(description = "entity type") @QueryParam("type") String entityType)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
 | 
			
		||||
    Entity.getSearchRepository()
 | 
			
		||||
        .searchLineage(fqn, upstreamDepth, downstreamDepth, queryFilter, deleted, entityType);
 | 
			
		||||
    return dao.exportCsv(fqn, upstreamDepth, downstreamDepth, queryFilter, deleted, entityType);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @GET
 | 
			
		||||
  @Path("/exportAsync")
 | 
			
		||||
  @Produces(MediaType.APPLICATION_JSON)
 | 
			
		||||
  @Operation(
 | 
			
		||||
      operationId = "exportLineage",
 | 
			
		||||
      summary = "Export lineage",
 | 
			
		||||
      responses = {
 | 
			
		||||
        @ApiResponse(
 | 
			
		||||
            responseCode = "200",
 | 
			
		||||
            description = "search response",
 | 
			
		||||
            content =
 | 
			
		||||
                @Content(
 | 
			
		||||
                    mediaType = "application/json",
 | 
			
		||||
                    schema = @Schema(implementation = CSVExportMessage.class)))
 | 
			
		||||
      })
 | 
			
		||||
  public Response exportLineageAsync(
 | 
			
		||||
      @Context UriInfo uriInfo,
 | 
			
		||||
      @Context SecurityContext securityContext,
 | 
			
		||||
      @Parameter(description = "fqn") @QueryParam("fqn") String fqn,
 | 
			
		||||
      @Parameter(description = "upstreamDepth") @QueryParam("upstreamDepth") int upstreamDepth,
 | 
			
		||||
      @Parameter(description = "downstreamDepth") @QueryParam("downstreamDepth")
 | 
			
		||||
          int downstreamDepth,
 | 
			
		||||
      @Parameter(
 | 
			
		||||
              description =
 | 
			
		||||
                  "Elasticsearch query that will be combined with the query_string query generator from the `query` argument")
 | 
			
		||||
          @QueryParam("query_filter")
 | 
			
		||||
          String queryFilter,
 | 
			
		||||
      @Parameter(description = "Filter documents by deleted param. By default deleted is false")
 | 
			
		||||
          @QueryParam("includeDeleted")
 | 
			
		||||
          boolean deleted,
 | 
			
		||||
      @Parameter(description = "entity type") @QueryParam("type") String entityType) {
 | 
			
		||||
    String jobId = UUID.randomUUID().toString();
 | 
			
		||||
    ExecutorService executorService = AsyncService.getInstance().getExecutorService();
 | 
			
		||||
    executorService.submit(
 | 
			
		||||
        () -> {
 | 
			
		||||
          try {
 | 
			
		||||
            String csvData =
 | 
			
		||||
                dao.exportCsvAsync(
 | 
			
		||||
                    fqn, upstreamDepth, downstreamDepth, queryFilter, entityType, deleted);
 | 
			
		||||
            WebsocketNotificationHandler.sendCsvExportCompleteNotification(
 | 
			
		||||
                jobId, securityContext, csvData);
 | 
			
		||||
          } catch (Exception e) {
 | 
			
		||||
            WebsocketNotificationHandler.sendCsvExportFailedNotification(
 | 
			
		||||
                jobId, securityContext, e.getMessage());
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
    CSVExportResponse response = new CSVExportResponse(jobId, "Export initiated successfully.");
 | 
			
		||||
    return Response.accepted().entity(response).type(MediaType.APPLICATION_JSON).build();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @PUT
 | 
			
		||||
  @Operation(
 | 
			
		||||
      operationId = "addLineageEdge",
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
package org.openmetadata.sdk.exception;
 | 
			
		||||
 | 
			
		||||
import javax.ws.rs.core.Response;
 | 
			
		||||
 | 
			
		||||
public class CSVExportException extends WebServiceException {
 | 
			
		||||
  private static final String BY_NAME_MESSAGE = "CSVExport Exception [%s] due to [%s].";
 | 
			
		||||
  private static final String ERROR_TYPE = "CSV_EXPORT_ERROR";
 | 
			
		||||
 | 
			
		||||
  public CSVExportException(String message) {
 | 
			
		||||
    super(Response.Status.BAD_REQUEST, ERROR_TYPE, message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public CSVExportException(Response.Status status, String message) {
 | 
			
		||||
    super(status, ERROR_TYPE, message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static CSVExportException byMessage(
 | 
			
		||||
      String name, String errorMessage, Response.Status status) {
 | 
			
		||||
    return new CSVExportException(status, buildMessageByName(name, errorMessage));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static CSVExportException byMessage(String name, String errorMessage) {
 | 
			
		||||
    return new CSVExportException(
 | 
			
		||||
        Response.Status.BAD_REQUEST, buildMessageByName(name, errorMessage));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static String buildMessageByName(String name, String errorMessage) {
 | 
			
		||||
    return String.format(BY_NAME_MESSAGE, name, errorMessage);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -80,6 +80,7 @@ import { useApplicationStore } from '../../hooks/useApplicationStore';
 | 
			
		||||
import useCustomLocation from '../../hooks/useCustomLocation/useCustomLocation';
 | 
			
		||||
import { useFqn } from '../../hooks/useFqn';
 | 
			
		||||
import {
 | 
			
		||||
  exportLineageAsync,
 | 
			
		||||
  getDataQualityLineage,
 | 
			
		||||
  getLineageDataByFQN,
 | 
			
		||||
  updateLineageEdge,
 | 
			
		||||
@ -96,7 +97,6 @@ import {
 | 
			
		||||
  getChildMap,
 | 
			
		||||
  getClassifiedEdge,
 | 
			
		||||
  getConnectedNodesEdges,
 | 
			
		||||
  getExportData,
 | 
			
		||||
  getLayoutedElements,
 | 
			
		||||
  getLineageEdge,
 | 
			
		||||
  getLineageEdgeForAPI,
 | 
			
		||||
@ -338,20 +338,14 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
 | 
			
		||||
 | 
			
		||||
  const exportLineageData = useCallback(
 | 
			
		||||
    async (_: string) => {
 | 
			
		||||
      if (
 | 
			
		||||
        entityType === EntityType.PIPELINE ||
 | 
			
		||||
        entityType === EntityType.STORED_PROCEDURE
 | 
			
		||||
      ) {
 | 
			
		||||
        // Since pipeline is an edge, we cannot create a tree, hence we take the nodes from the lineage response
 | 
			
		||||
        // to get the export data.
 | 
			
		||||
        return getExportData(entityLineage.nodes ?? []);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const { exportResult } = getChildMap(entityLineage, decodedFqn);
 | 
			
		||||
 | 
			
		||||
      return exportResult;
 | 
			
		||||
      return exportLineageAsync(
 | 
			
		||||
        decodedFqn,
 | 
			
		||||
        entityType,
 | 
			
		||||
        lineageConfig,
 | 
			
		||||
        queryFilter
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    [entityType, decodedFqn, entityLineage]
 | 
			
		||||
    [entityType, decodedFqn, lineageConfig, queryFilter]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const onExportClick = useCallback(() => {
 | 
			
		||||
@ -361,7 +355,7 @@ const LineageProvider = ({ children }: LineageProviderProps) => {
 | 
			
		||||
        onExport: exportLineageData,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }, [entityType, decodedFqn, entityLineage]);
 | 
			
		||||
  }, [entityType, decodedFqn, lineageConfig, queryFilter]);
 | 
			
		||||
 | 
			
		||||
  const loadChildNodesHandler = useCallback(
 | 
			
		||||
    async (node: SourceType, direction: EdgeTypeEnum) => {
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@
 | 
			
		||||
 *  limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { CSVExportResponse } from '../components/Entity/EntityExportModalProvider/EntityExportModalProvider.interface';
 | 
			
		||||
import { LineageConfig } from '../components/Entity/EntityLineage/EntityLineage.interface';
 | 
			
		||||
import { EntityLineageResponse } from '../components/Lineage/Lineage.interface';
 | 
			
		||||
import { AddLineage } from '../generated/api/lineage/addLineage';
 | 
			
		||||
@ -22,6 +23,30 @@ export const updateLineageEdge = async (edge: AddLineage) => {
 | 
			
		||||
  return response.data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const exportLineageAsync = async (
 | 
			
		||||
  fqn: string,
 | 
			
		||||
  entityType: string,
 | 
			
		||||
  config?: LineageConfig,
 | 
			
		||||
  queryFilter?: string
 | 
			
		||||
) => {
 | 
			
		||||
  const { upstreamDepth = 1, downstreamDepth = 1 } = config ?? {};
 | 
			
		||||
  const response = await APIClient.get<CSVExportResponse>(
 | 
			
		||||
    `/lineage/exportAsync`,
 | 
			
		||||
    {
 | 
			
		||||
      params: {
 | 
			
		||||
        fqn,
 | 
			
		||||
        type: entityType,
 | 
			
		||||
        upstreamDepth,
 | 
			
		||||
        downstreamDepth,
 | 
			
		||||
        query_filter: queryFilter,
 | 
			
		||||
        includeDeleted: false,
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return response.data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getLineageDataByFQN = async (
 | 
			
		||||
  fqn: string,
 | 
			
		||||
  entityType: string,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user