From 43e3cd9602dc1e70f15b5f611ea4c86fac645a5d Mon Sep 17 00:00:00 2001 From: Shirshanka Das Date: Tue, 30 Jul 2024 09:45:57 -0700 Subject: [PATCH] feat(propagation): Add graphql API (#11030) Co-authored-by: Chris Collins --- .../linkedin/datahub/graphql/Constants.java | 1 + .../datahub/graphql/GmsGraphQLEngine.java | 27 ++++++++-- .../common/mappers/DocumentationMapper.java | 54 +++++++++++++++++++ .../mappers/MetadataAttributionMapper.java | 35 ++++++++++++ .../types/schemafield/SchemaFieldMapper.java | 9 +++- .../types/schemafield/SchemaFieldType.java | 7 ++- .../src/main/resources/common.graphql | 49 +++++++++++++++++ .../src/main/resources/entity.graphql | 5 ++ .../src/app/home/AcrylDemoBanner.tsx | 4 +- .../src/graphql/fragments.graphql | 31 +++++++++++ datahub-web-react/src/graphql/search.graphql | 6 +++ .../java/com/linkedin/metadata/Constants.java | 10 ++-- 12 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DocumentationMapper.java create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/MetadataAttributionMapper.java create mode 100644 datahub-graphql-core/src/main/resources/common.graphql diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/Constants.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/Constants.java index f70c46ba943a5a..69306862a46ef7 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/Constants.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/Constants.java @@ -24,6 +24,7 @@ private Constants() {} public static final String PROPERTIES_SCHEMA_FILE = "properties.graphql"; public static final String FORMS_SCHEMA_FILE = "forms.graphql"; public static final String ASSERTIONS_SCHEMA_FILE = "assertions.graphql"; + public static final String COMMON_SCHEMA_FILE = "common.graphql"; public static final String INCIDENTS_SCHEMA_FILE = "incident.graphql"; public static final String CONTRACTS_SCHEMA_FILE = "contract.graphql"; public static final String CONNECTIONS_SCHEMA_FILE = "connection.graphql"; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java index cba214365fdacf..d991493186351d 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java @@ -96,6 +96,7 @@ import com.linkedin.datahub.graphql.generated.MLPrimaryKey; import com.linkedin.datahub.graphql.generated.MLPrimaryKeyProperties; import com.linkedin.datahub.graphql.generated.MatchedField; +import com.linkedin.datahub.graphql.generated.MetadataAttribution; import com.linkedin.datahub.graphql.generated.Notebook; import com.linkedin.datahub.graphql.generated.Owner; import com.linkedin.datahub.graphql.generated.OwnershipTypeEntity; @@ -695,7 +696,8 @@ public GmsGraphQLEngine(final GmsGraphQLEngineArgs args) { businessAttributeType)); this.loadableTypes = new ArrayList<>(entityTypes); // Extend loadable types with types from the plugins - // This allows us to offer search and browse capabilities out of the box for those types + // This allows us to offer search and browse capabilities out of the box for + // those types for (GmsGraphQLPlugin plugin : this.graphQLPlugins) { this.entityTypes.addAll(plugin.getEntityTypes()); Collection> pluginLoadableTypes = plugin.getLoadableTypes(); @@ -790,6 +792,7 @@ public void configureRuntimeWiring(final RuntimeWiring.Builder builder) { configureBusinessAttributeAssociationResolver(builder); configureConnectionResolvers(builder); configureDeprecationResolvers(builder); + configureMetadataAttributionResolver(builder); } private void configureOrganisationRoleResolvers(RuntimeWiring.Builder builder) { @@ -843,7 +846,8 @@ public GraphQLEngine.Builder builder() { .addSchema(fileBasedSchema(CONNECTIONS_SCHEMA_FILE)) .addSchema(fileBasedSchema(ASSERTIONS_SCHEMA_FILE)) .addSchema(fileBasedSchema(INCIDENTS_SCHEMA_FILE)) - .addSchema(fileBasedSchema(CONTRACTS_SCHEMA_FILE)); + .addSchema(fileBasedSchema(CONTRACTS_SCHEMA_FILE)) + .addSchema(fileBasedSchema(COMMON_SCHEMA_FILE)); for (GmsGraphQLPlugin plugin : this.graphQLPlugins) { List pluginSchemaFiles = plugin.getSchemaFiles(); @@ -2823,7 +2827,8 @@ private void configureContractResolvers(final RuntimeWiring.Builder builder) { } private void configurePolicyResolvers(final RuntimeWiring.Builder builder) { - // Register resolvers for "resolvedUsers" and "resolvedGroups" field of the Policy type. + // Register resolvers for "resolvedUsers" and "resolvedGroups" field of the + // Policy type. builder.type( "ActorFilter", typeWiring -> @@ -3176,4 +3181,20 @@ private void configureDeprecationResolvers(final RuntimeWiring.Builder builder) new EntityTypeResolver( entityTypes, (env) -> ((Deprecation) env.getSource()).getActorEntity()))); } + + private void configureMetadataAttributionResolver(final RuntimeWiring.Builder builder) { + builder.type( + "MetadataAttribution", + typeWiring -> + typeWiring + .dataFetcher( + "actor", + new EntityTypeResolver( + entityTypes, (env) -> ((MetadataAttribution) env.getSource()).getActor())) + .dataFetcher( + "source", + new EntityTypeResolver( + entityTypes, + (env) -> ((MetadataAttribution) env.getSource()).getSource()))); + } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DocumentationMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DocumentationMapper.java new file mode 100644 index 00000000000000..dcb4921d353981 --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/DocumentationMapper.java @@ -0,0 +1,54 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import com.linkedin.common.urn.Urn; +import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.generated.DataHubConnection; +import com.linkedin.datahub.graphql.generated.Documentation; +import com.linkedin.datahub.graphql.generated.DocumentationAssociation; +import com.linkedin.datahub.graphql.generated.EntityType; +import com.linkedin.datahub.graphql.types.mappers.ModelMapper; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class DocumentationMapper + implements ModelMapper { + + public static final DocumentationMapper INSTANCE = new DocumentationMapper(); + + public static Documentation map( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.Documentation metadata) { + return INSTANCE.apply(context, metadata); + } + + @Override + public Documentation apply( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.Documentation input) { + final Documentation result = new Documentation(); + result.setDocumentations( + input.getDocumentations().stream() + .map(docAssociation -> mapDocAssociation(context, docAssociation)) + .collect(Collectors.toList())); + return result; + } + + private DocumentationAssociation mapDocAssociation( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.DocumentationAssociation association) { + final DocumentationAssociation result = new DocumentationAssociation(); + result.setDocumentation(association.getDocumentation()); + if (association.getAttribution() != null) { + result.setAttribution(MetadataAttributionMapper.map(context, association.getAttribution())); + } + return result; + } + + private DataHubConnection mapConnectionEntity(@Nonnull final Urn urn) { + DataHubConnection connection = new DataHubConnection(); + connection.setUrn(urn.toString()); + connection.setType(EntityType.DATAHUB_CONNECTION); + return connection; + } +} diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/MetadataAttributionMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/MetadataAttributionMapper.java new file mode 100644 index 00000000000000..55fb7ad6f3a2b8 --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/common/mappers/MetadataAttributionMapper.java @@ -0,0 +1,35 @@ +package com.linkedin.datahub.graphql.types.common.mappers; + +import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.generated.MetadataAttribution; +import com.linkedin.datahub.graphql.types.mappers.ModelMapper; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class MetadataAttributionMapper + implements ModelMapper { + + public static final MetadataAttributionMapper INSTANCE = new MetadataAttributionMapper(); + + public static MetadataAttribution map( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.MetadataAttribution metadata) { + return INSTANCE.apply(context, metadata); + } + + @Override + public MetadataAttribution apply( + @Nullable final QueryContext context, + @Nonnull final com.linkedin.common.MetadataAttribution input) { + final MetadataAttribution result = new MetadataAttribution(); + result.setTime(input.getTime()); + result.setActor(UrnToEntityMapper.map(context, input.getActor())); + if (input.getSource() != null) { + result.setSource(UrnToEntityMapper.map(context, input.getSource())); + } + if (input.getSourceDetail() != null) { + result.setSourceDetail(StringMapMapper.map(context, input.getSourceDetail())); + } + return result; + } +} diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldMapper.java index 85a6b9108cb54e..b1f27357d45504 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldMapper.java @@ -1,14 +1,15 @@ package com.linkedin.datahub.graphql.types.schemafield; -import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT; -import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTIES_ASPECT_NAME; +import static com.linkedin.metadata.Constants.*; import com.linkedin.businessattribute.BusinessAttributes; +import com.linkedin.common.Documentation; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.SchemaFieldEntity; import com.linkedin.datahub.graphql.types.businessattribute.mappers.BusinessAttributesMapper; +import com.linkedin.datahub.graphql.types.common.mappers.DocumentationMapper; import com.linkedin.datahub.graphql.types.common.mappers.UrnToEntityMapper; import com.linkedin.datahub.graphql.types.common.mappers.util.MappingHelper; import com.linkedin.datahub.graphql.types.mappers.ModelMapper; @@ -46,6 +47,10 @@ public SchemaFieldEntity apply( (((schemaField, dataMap) -> schemaField.setBusinessAttributes( BusinessAttributesMapper.map(new BusinessAttributes(dataMap), entityUrn))))); + mappingHelper.mapToResult( + DOCUMENTATION_ASPECT_NAME, + (entity, dataMap) -> + entity.setDocumentation(DocumentationMapper.map(context, new Documentation(dataMap)))); return result; } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldType.java index f9fd7c7b819c56..2fa26d8cf2cdd7 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/schemafield/SchemaFieldType.java @@ -1,8 +1,6 @@ package com.linkedin.datahub.graphql.types.schemafield; -import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT; -import static com.linkedin.metadata.Constants.SCHEMA_FIELD_ENTITY_NAME; -import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTIES_ASPECT_NAME; +import static com.linkedin.metadata.Constants.*; import com.google.common.collect.ImmutableSet; import com.linkedin.common.urn.Urn; @@ -32,7 +30,8 @@ public class SchemaFieldType implements com.linkedin.datahub.graphql.types.EntityType { public static final Set ASPECTS_TO_FETCH = - ImmutableSet.of(STRUCTURED_PROPERTIES_ASPECT_NAME, BUSINESS_ATTRIBUTE_ASPECT); + ImmutableSet.of( + STRUCTURED_PROPERTIES_ASPECT_NAME, BUSINESS_ATTRIBUTE_ASPECT, DOCUMENTATION_ASPECT_NAME); private final EntityClient _entityClient; private final FeatureFlags _featureFlags; diff --git a/datahub-graphql-core/src/main/resources/common.graphql b/datahub-graphql-core/src/main/resources/common.graphql new file mode 100644 index 00000000000000..bac56c97f61cf7 --- /dev/null +++ b/datahub-graphql-core/src/main/resources/common.graphql @@ -0,0 +1,49 @@ +""" +Object containing the documentation aspect for an entity +""" +type Documentation { + """ + Structured properties on this entity + """ + documentations: [DocumentationAssociation!]! +} + +""" +Object containing the documentation aspect for an entity +""" +type DocumentationAssociation { + """ + Structured properties on this entity + """ + documentation: String! + + """ + Information about who, why, and how this metadata was applied + """ + attribution: MetadataAttribution +} + +""" +Information about who, why, and how this metadata was applied +""" +type MetadataAttribution { + """ + The time this metadata was applied + """ + time: Long! + + """ + The actor responsible for this metadata application + """ + actor: Entity! + + """ + The source of this metadata application. If propagated, this will be an action. + """ + source: Entity + + """ + Extra details about how this metadata was applied + """ + sourceDetail: [StringMapEntry!] +} diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index 50ec9c5f079932..a2440f7e3928ee 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -3225,6 +3225,11 @@ type SchemaFieldEntity implements Entity { Business Attribute associated with the field """ businessAttributes: BusinessAttributes + + """ + Documentation aspect for this schema field + """ + documentation: Documentation } """ diff --git a/datahub-web-react/src/app/home/AcrylDemoBanner.tsx b/datahub-web-react/src/app/home/AcrylDemoBanner.tsx index d567e82cb5bbbd..debcaab879ba94 100644 --- a/datahub-web-react/src/app/home/AcrylDemoBanner.tsx +++ b/datahub-web-react/src/app/home/AcrylDemoBanner.tsx @@ -52,8 +52,8 @@ export default function AcrylDemoBanner() { > Schedule a demo {' '} - of DataHub Cloud to see the advanced features that take it to the next level or purchase DataHub Cloud - on{' '} + of DataHub Cloud to see the advanced features that take it to the next level or purchase DataHub + Cloud on{' '}