/* * (c) 2022 Collibra Inc. This software is protected under international copyright law. * You may only install and use this software subject to the license agreement available * at https://marketplace.collibra.com/binary-code-license-agreement/. If such an agreement * is not in place, you may not use the software. */ package com.collibra.dbt.component; import com.collibra.dbt.config.IntegrationConfig; import com.collibra.dbt.model.assets.GenericAssetType; import com.collibra.dbt.model.attributes.GenericAttributeType; import com.collibra.dbt.model.explosures.ExposureData; import com.collibra.dbt.model.graphql.CompiledSqlModel; import com.collibra.dbt.model.metrics.Data; import com.collibra.dbt.model.relations.GenericRelationType; import com.collibra.dbt.util.Utils; import com.collibra.marketplace.library.integration.CollibraAsset; import com.collibra.marketplace.library.integration.CollibraRelation; import com.collibra.marketplace.library.integration.constants.CollibraConstants; import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; @AllArgsConstructor @Slf4j @Component public class DBTLineageTransformer implements LineageTransformer { public static final String FULL_NAME = "%s>%s"; public static final String DOMAIN_NAME = "%s > %s > %s"; public static final String SCHEMA_FULL_NAME = "%s>%s>%s"; public static final String FILTERS = "%s %s %s"; public static final String EXPOSURES_FULLNAME = "%s>%s>%s>%s"; private final IntegrationConfig integrationConfig; private final CollibraOperations collibraOperations; public JsonNode createDatabaseAssets(List graphQlResponse) { log.info("Transforms DBT database entities are performing"); List assets = new ArrayList<>(); graphQlResponse.forEach( graphQLData -> { String dbName = graphQLData.getDatabase().toUpperCase(Locale.ROOT); String dbNameFullName = String.format(FULL_NAME, integrationConfig.getCollibraSystemAssetName(), dbName.toUpperCase(Locale.ROOT)); String schemaName = graphQLData.getSchema().toUpperCase(Locale.ROOT); String tableName = graphQLData.getName().toUpperCase(Locale.ROOT); String schemaFullName = String.format(FULL_NAME, dbNameFullName, schemaName.toUpperCase(Locale.ROOT)); String tableFullName = String.format(FULL_NAME, schemaFullName, tableName.toUpperCase(Locale.ROOT)); String domainName = String.format(DOMAIN_NAME, integrationConfig.getCollibraSystemAssetName(), graphQLData.getDatabase().toUpperCase(Locale.ROOT), graphQLData.getSchema().toUpperCase(Locale.ROOT)); UUID uuid = collibraOperations.findDomain(domainName); if (uuid == null) { uuid = UUID.fromString( collibraOperations.createDomain(domainName, integrationConfig.getCollibraDatabaseDomainType())); } integrationConfig.setCollibraDatabaseDomain(uuid.toString()); assets.add(new CollibraAsset.Builder() .displayName(dbName) .name(dbNameFullName) .domainId(integrationConfig.getCollibraDatabaseDomain()) .addRelationByDomainId( CollibraConstants.RelationType.TECHNOLOGYASSET_GROUPS_TECHNOLOGYASSET, CollibraRelation.Direction.SOURCE, integrationConfig.getCollibraSystemAssetName(), integrationConfig.getCollibraSystemAssetDomain()) .type(CollibraConstants.AssetType.DATABASE) .status(CollibraConstants.Status.IMPLEMENTED) .build()); assets.add(new CollibraAsset.Builder() .displayName(schemaName) .name(schemaFullName) .domainId(integrationConfig.getCollibraDatabaseDomain()) .addRelationByDomainId( CollibraConstants.RelationType.TECHNOLOGYASSET_HAS_SCHEMA, CollibraRelation.Direction.SOURCE, dbNameFullName, integrationConfig.getCollibraDatabaseDomain()) .type(CollibraConstants.AssetType.SCHEMA) .status(CollibraConstants.Status.IMPLEMENTED) .build()); CollibraAsset.Builder collibraTableAsset = new CollibraAsset.Builder() .displayName(tableName) .name(tableFullName) .domainId(integrationConfig.getCollibraDatabaseDomain()) .addAttributeValue( CollibraConstants.AttributeType.DESCRIPTION, graphQLData.getDescription()) .addRelationByDomainId( CollibraConstants.RelationType.SCHEMA_CONTAINS_TABLE, CollibraRelation.Direction.SOURCE, schemaFullName, integrationConfig.getCollibraDatabaseDomain()) .type(CollibraConstants.AssetType.TABLE) .status(CollibraConstants.Status.IMPLEMENTED); addMetaAttributeAndTag(collibraTableAsset, graphQLData.getMeta()); assets.add(collibraTableAsset.build()); graphQLData .getColumns() .forEach( column -> { String columnName = column.getName(); String columnFullName = String.format(FULL_NAME, tableFullName, columnName.toUpperCase( Locale.ROOT)); CollibraAsset.Builder collibraColumnAsset = new CollibraAsset.Builder() .displayName(columnName) .name(columnFullName) .domainId(integrationConfig.getCollibraDatabaseDomain()) .addAttributeValue( CollibraConstants.AttributeType.DESCRIPTION, column.getDescription()) .addRelationByDomainId( CollibraConstants.RelationType.COLUMN_ISPARTOF_TABLE, CollibraRelation.Direction.TARGET, tableFullName, integrationConfig.getCollibraDatabaseDomain()) .type(CollibraConstants.AssetType.COLUMN) .status(CollibraConstants.Status.IMPLEMENTED); addMetaAttributeAndTag(collibraColumnAsset, column.getMeta()); assets.add(collibraColumnAsset.build()); }); }); log.info("Database assets transformer operation has been completed"); return collibraOperations.createAssets(assets); } public JsonNode createMetricsAssets(Data extractMetrics, CompiledSqlModel compiledSqlModel) { log.info("Transforms DBT metrics assets are performing"); List assets = new ArrayList<>(); String schemaFullName = String.format(SCHEMA_FULL_NAME, integrationConfig.getCollibraSystemAssetName(), compiledSqlModel.getDatabase().toUpperCase(Locale.ROOT), compiledSqlModel.getSchema().toUpperCase(Locale.ROOT)); extractMetrics.getMetrics().forEach(metrics -> { String tableFullName = String.format(FULL_NAME, schemaFullName, metrics.getModel().getName().toUpperCase( Locale.ROOT)); String metricFullName = String.format(FULL_NAME, tableFullName, metrics.getUniqueId().toUpperCase( Locale.ROOT)); CollibraAsset.Builder collibraAsset = new CollibraAsset.Builder() .displayName(metrics.getName()) .name(metricFullName) .domainId(integrationConfig.getCollibraMetricsDomain()) .tags(metrics.getTags().stream().map(obj -> Objects.toString(obj, null)).collect (Collectors.toList())) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeUniqueId()).name( integrationConfig.getCollibraAttributeTypeUniqueIdName()).build(), metrics.getUniqueId()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeExternalLabelId()).name( integrationConfig.getCollibraAttributeTypeExternalLabelName()).build(), metrics.getLabel()) .addAttributeValue(CollibraConstants.AttributeType.DESCRIPTION, metrics.getDescription()) .addAttributeValue(CollibraConstants.AttributeType.CALCULATION_RULE, metrics.getType()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeTimestampId()).name( integrationConfig.getCollibraAttributeTypeTimestampName()).build(), metrics.getTimestamp()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypePackageNameId()).name( integrationConfig.getCollibraAttributeTypePackageName()).build(), metrics.getPackageName()) .addAttributeValue(CollibraConstants.AttributeType.SOURCE_TYPE, metrics.getResourceType()) .addAttributeValues( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeTimeGrainsId()).name( integrationConfig.getCollibraAttributeTypeTimeGrainsName()).build(), metrics.getTimeGrains()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeSqlId()).name( integrationConfig.getCollibraAttributeTypeSqlName()).build(), metrics.getSql()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeRunId()).name( integrationConfig.getCollibraAttributeTypeRunIdName()).build(), metrics.getRunId()) .addAttributeValues( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeFiltersId()).name( integrationConfig.getCollibraAttributeTypeFiltersName()).build(), metrics.getFilters().stream().map( filter -> String.format(FILTERS, filter.getField(), filter.getOperator(), filter.getValue())).filter(Objects::nonNull).collect( Collectors.toList())); metrics.getDimensions().forEach(dimension -> { String columnFullName = String.format(FULL_NAME, tableFullName, dimension.toUpperCase(Locale.ROOT)); collibraAsset.addRelationByDomainId( GenericRelationType.builder().id( integrationConfig.getCollibraMeasureHasSupportDimensionColumn()).build(), CollibraRelation.Direction.TARGET, collibraOperations.findAssetName(columnFullName), integrationConfig.getCollibraDatabaseDomain()); }); collibraAsset.addRelationByDomainId( GenericRelationType.builder().id(integrationConfig.getCollibraMeasureHasModelTable()).build(), CollibraRelation.Direction.TARGET, collibraOperations.findAssetName(tableFullName), integrationConfig.getCollibraDatabaseDomain()) .type(CollibraConstants.AssetType.KPI) .status(CollibraConstants.Status.IMPLEMENTED); assets.add(collibraAsset.build()); }); log.info("Metric assets transformer operation has been completed"); return collibraOperations.createAssets(assets); } public JsonNode createExposureAssets(ExposureData extractExposures, CompiledSqlModel compiledSqlModel) { log.info("Transforms DBT exposure assets are performing"); List assets = new ArrayList<>(); String schemaFullName = String.format(SCHEMA_FULL_NAME, integrationConfig.getCollibraSystemAssetName(), compiledSqlModel.getDatabase().toUpperCase(Locale.ROOT), compiledSqlModel.getSchema().toUpperCase(Locale.ROOT)); extractExposures.getExposures().forEach(exposures -> { String exposureFullName = String.format(EXPOSURES_FULLNAME, integrationConfig.getCollibraSystemAssetName(), exposures.getAccountId(), exposures.getProjectId(), exposures.getUniqueId().toUpperCase(Locale.ROOT)); CollibraAsset.Builder collibraAsset = new CollibraAsset.Builder() .displayName(exposures.getName()) .name(exposureFullName) .domainId(integrationConfig.getCollibraExposuresDomain()); /* .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeUniqueId()).name( integrationConfig.getCollibraAttributeTypeUniqueIdName()).build(), exposures.getUniqueId()) .addAttributeValue(CollibraConstants.AttributeType.URL, exposures.getUrl()) .addAttributeValue(CollibraConstants.AttributeType.DESCRIPTION, exposures.getDescription()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeMaturityId()).name( integrationConfig.getCollibraAttributeTypeMaturityName()).build(), exposures.getMaturity()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeOwnerNameId()).name( integrationConfig.getCollibraAttributeTypeOwnerName()).build(), exposures.getOwnerName()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeOwnerEmailId()).name( integrationConfig.getCollibraAttributeTypeOwnerEmailName()).build(), exposures.getOwnerEmail()) .addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeExposureTypeId()).name( integrationConfig.getCollibraAttributeTypeExposureTypeName()).build(), exposures.getExposureType()) .addAttributeValue(CollibraConstants.AttributeType.SOURCE_TYPE, exposures.getResourceType()); */ if(exposures.getUniqueId() != null && exposures.getUniqueId().isEmpty()) { collibraAsset.addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeUniqueId()).name( integrationConfig.getCollibraAttributeTypeUniqueIdName()).build(), exposures.getUniqueId()); } if(exposures.getUrl() != null && exposures.getUrl().isEmpty()) { collibraAsset.addAttributeValue(CollibraConstants.AttributeType.URL, exposures.getUrl()); } if(exposures.getDescription() != null && exposures.getDescription().isEmpty()) { collibraAsset.addAttributeValue(CollibraConstants.AttributeType.DESCRIPTION, exposures.getDescription()); } if(exposures.getMaturity() != null && exposures.getMaturity().isEmpty()) { collibraAsset.addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeMaturityId()).name( integrationConfig.getCollibraAttributeTypeMaturityName()).build(), exposures.getMaturity()); } if(exposures.getOwnerName() != null && exposures.getOwnerName().isEmpty()) { collibraAsset.addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeOwnerNameId()).name( integrationConfig.getCollibraAttributeTypeOwnerName()).build(), exposures.getOwnerName()); } if(exposures.getOwnerEmail() != null && exposures.getOwnerEmail().isEmpty()) { collibraAsset.addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeOwnerEmailId()).name( integrationConfig.getCollibraAttributeTypeOwnerEmailName()).build(), exposures.getOwnerEmail()); } if(exposures.getExposureType() != null && exposures.getExposureType().isEmpty()) { collibraAsset.addAttributeValue( GenericAttributeType.builder().id(integrationConfig.getCollibraAttributeTypeExposureTypeId()).name( integrationConfig.getCollibraAttributeTypeExposureTypeName()).build(), exposures.getExposureType()); } if(exposures.getResourceType() != null && exposures.getResourceType().isEmpty()) { collibraAsset.addAttributeValue(CollibraConstants.AttributeType.SOURCE_TYPE, exposures.getResourceType()); } exposures.getDependsOn().forEach(dimension -> { String tableFullName = String.format(FULL_NAME, schemaFullName, Utils.findTableName(dimension).toUpperCase(Locale.ROOT)); collibraAsset.addRelationByDomainId( GenericRelationType.builder().id(integrationConfig.getCollibraExposureRelationType()).build(), CollibraRelation.Direction.TARGET, tableFullName, integrationConfig.getCollibraDatabaseDomain()) .type(GenericAssetType.builder().id(integrationConfig.getCollibraExposureAssetTypeId()) .name(integrationConfig.getCollibraExposureAssetTypeName()).build()) .status(CollibraConstants.Status.NEW); }); assets.add(collibraAsset.build()); }); log.info("Exposure assets transformer operation has been completed"); return collibraOperations.createAssets(assets); } public JsonNode createTestAssets(List graphQlResponse) { log.info("Transforms DBT tests performing"); List assets = new ArrayList<>(); graphQlResponse.forEach( graphQLData -> { String dbNameFullName = String.format(FULL_NAME, integrationConfig.getCollibraSystemAssetName(), graphQLData.getDatabase().toUpperCase(Locale.ROOT)); String schemaName = graphQLData.getSchema(); String tableName = graphQLData.getName(); String schemaFullName = String.format(FULL_NAME, dbNameFullName, schemaName.toUpperCase(Locale.ROOT)); String tableFullName = String.format(FULL_NAME, schemaFullName, tableName.toUpperCase(Locale.ROOT)); if (graphQLData.getTests() != null) { graphQLData.getTests() .forEach(test -> assets.add(new CollibraAsset.Builder() .displayName(test.getName()) .name(test.getUniqueId()) .domainId( integrationConfig.getCollibraTestsDomain()) .addAttributeValue( CollibraConstants.AttributeType.DESCRIPTION, test.getDescription() != null ? test.getDescription() : StringUtils.EMPTY) .addAttributeValue( CollibraConstants.AttributeType.PREDICATE, test.getRawCode()).addRelationByDomainId( CollibraConstants.RelationType.ASSET_COMPLIESTO_GOVERNANCEASSET, CollibraRelation.Direction.SOURCE, test.getColumnName() != null ? String.format(FULL_NAME, tableFullName, test.getColumnName().toUpperCase( Locale.ROOT)) : tableFullName, integrationConfig.getCollibraDatabaseDomain()) .type( CollibraConstants.AssetType.DATA_QUALITY_RULE) .status(CollibraConstants.Status.IMPLEMENTED) .build())); } }); log.info("Test assets transformer operation has been completed"); return collibraOperations.createAssets(assets); } private void addMetaAttributeAndTag(CollibraAsset.Builder collibraAsset, Object graphQLData) { collibraOperations.createAttributes((LinkedHashMap) graphQLData, collibraAsset); } }