mirror of
https://github.com/datahub-project/datahub.git
synced 2025-06-27 05:03:31 +00:00
feat(structuredProperties) Add new settings aspect plus graphql changes for structured props (#12052)
This commit is contained in:
parent
b091e4615d
commit
f1ef4f8e5f
@ -1,7 +1,8 @@
|
|||||||
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
||||||
|
|
||||||
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
|
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
|
||||||
import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTY_ENTITY_NAME;
|
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn;
|
||||||
|
import static com.linkedin.metadata.Constants.*;
|
||||||
|
|
||||||
import com.linkedin.common.urn.Urn;
|
import com.linkedin.common.urn.Urn;
|
||||||
import com.linkedin.data.template.SetMode;
|
import com.linkedin.data.template.SetMode;
|
||||||
@ -12,20 +13,24 @@ import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
|||||||
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
||||||
import com.linkedin.datahub.graphql.generated.CreateStructuredPropertyInput;
|
import com.linkedin.datahub.graphql.generated.CreateStructuredPropertyInput;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
||||||
|
import com.linkedin.datahub.graphql.generated.StructuredPropertySettingsInput;
|
||||||
import com.linkedin.datahub.graphql.types.structuredproperty.StructuredPropertyMapper;
|
import com.linkedin.datahub.graphql.types.structuredproperty.StructuredPropertyMapper;
|
||||||
import com.linkedin.entity.EntityResponse;
|
import com.linkedin.entity.EntityResponse;
|
||||||
import com.linkedin.entity.client.EntityClient;
|
import com.linkedin.entity.client.EntityClient;
|
||||||
import com.linkedin.metadata.aspect.patch.builder.StructuredPropertyDefinitionPatchBuilder;
|
import com.linkedin.metadata.aspect.patch.builder.StructuredPropertyDefinitionPatchBuilder;
|
||||||
|
import com.linkedin.metadata.models.StructuredPropertyUtils;
|
||||||
import com.linkedin.metadata.utils.EntityKeyUtils;
|
import com.linkedin.metadata.utils.EntityKeyUtils;
|
||||||
import com.linkedin.mxe.MetadataChangeProposal;
|
import com.linkedin.mxe.MetadataChangeProposal;
|
||||||
import com.linkedin.structured.PrimitivePropertyValue;
|
import com.linkedin.structured.PrimitivePropertyValue;
|
||||||
import com.linkedin.structured.PropertyCardinality;
|
import com.linkedin.structured.PropertyCardinality;
|
||||||
import com.linkedin.structured.PropertyValue;
|
import com.linkedin.structured.PropertyValue;
|
||||||
import com.linkedin.structured.StructuredPropertyKey;
|
import com.linkedin.structured.StructuredPropertyKey;
|
||||||
|
import com.linkedin.structured.StructuredPropertySettings;
|
||||||
import graphql.schema.DataFetcher;
|
import graphql.schema.DataFetcher;
|
||||||
import graphql.schema.DataFetchingEnvironment;
|
import graphql.schema.DataFetchingEnvironment;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@ -54,40 +59,28 @@ public class CreateStructuredPropertyResolver
|
|||||||
"Unable to create structured property. Please contact your admin.");
|
"Unable to create structured property. Please contact your admin.");
|
||||||
}
|
}
|
||||||
final StructuredPropertyKey key = new StructuredPropertyKey();
|
final StructuredPropertyKey key = new StructuredPropertyKey();
|
||||||
final String id = input.getId() != null ? input.getId() : UUID.randomUUID().toString();
|
final String id =
|
||||||
|
StructuredPropertyUtils.getPropertyId(input.getId(), input.getQualifiedName());
|
||||||
key.setId(id);
|
key.setId(id);
|
||||||
final Urn propertyUrn =
|
final Urn propertyUrn =
|
||||||
EntityKeyUtils.convertEntityKeyToUrn(key, STRUCTURED_PROPERTY_ENTITY_NAME);
|
EntityKeyUtils.convertEntityKeyToUrn(key, STRUCTURED_PROPERTY_ENTITY_NAME);
|
||||||
StructuredPropertyDefinitionPatchBuilder builder =
|
|
||||||
new StructuredPropertyDefinitionPatchBuilder().urn(propertyUrn);
|
|
||||||
|
|
||||||
builder.setQualifiedName(input.getQualifiedName());
|
if (_entityClient.exists(context.getOperationContext(), propertyUrn)) {
|
||||||
builder.setValueType(input.getValueType());
|
throw new IllegalArgumentException(
|
||||||
input.getEntityTypes().forEach(builder::addEntityType);
|
"A structured property already exists with this urn");
|
||||||
if (input.getDisplayName() != null) {
|
|
||||||
builder.setDisplayName(input.getDisplayName());
|
|
||||||
}
|
}
|
||||||
if (input.getDescription() != null) {
|
|
||||||
builder.setDescription(input.getDescription());
|
|
||||||
}
|
|
||||||
if (input.getImmutable() != null) {
|
|
||||||
builder.setImmutable(input.getImmutable());
|
|
||||||
}
|
|
||||||
if (input.getTypeQualifier() != null) {
|
|
||||||
buildTypeQualifier(input, builder);
|
|
||||||
}
|
|
||||||
if (input.getAllowedValues() != null) {
|
|
||||||
buildAllowedValues(input, builder);
|
|
||||||
}
|
|
||||||
if (input.getCardinality() != null) {
|
|
||||||
builder.setCardinality(
|
|
||||||
PropertyCardinality.valueOf(input.getCardinality().toString()));
|
|
||||||
}
|
|
||||||
builder.setCreated(context.getOperationContext().getAuditStamp());
|
|
||||||
builder.setLastModified(context.getOperationContext().getAuditStamp());
|
|
||||||
|
|
||||||
MetadataChangeProposal mcp = builder.build();
|
List<MetadataChangeProposal> mcps = new ArrayList<>();
|
||||||
_entityClient.ingestProposal(context.getOperationContext(), mcp, false);
|
|
||||||
|
// first, create the property definition itself
|
||||||
|
mcps.add(createPropertyDefinition(context, propertyUrn, id, input));
|
||||||
|
|
||||||
|
// then add the settings aspect if we're adding any settings inputs
|
||||||
|
if (input.getSettings() != null) {
|
||||||
|
mcps.add(createPropertySettings(context, propertyUrn, input.getSettings()));
|
||||||
|
}
|
||||||
|
|
||||||
|
_entityClient.batchIngestProposals(context.getOperationContext(), mcps, false);
|
||||||
|
|
||||||
EntityResponse response =
|
EntityResponse response =
|
||||||
_entityClient.getV2(
|
_entityClient.getV2(
|
||||||
@ -103,6 +96,72 @@ public class CreateStructuredPropertyResolver
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MetadataChangeProposal createPropertySettings(
|
||||||
|
@Nonnull final QueryContext context,
|
||||||
|
@Nonnull final Urn propertyUrn,
|
||||||
|
final StructuredPropertySettingsInput settingsInput)
|
||||||
|
throws Exception {
|
||||||
|
StructuredPropertySettings settings = new StructuredPropertySettings();
|
||||||
|
|
||||||
|
if (settingsInput.getIsHidden() != null) {
|
||||||
|
settings.setIsHidden(settingsInput.getIsHidden());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInSearchFilters() != null) {
|
||||||
|
settings.setShowInSearchFilters(settingsInput.getShowInSearchFilters());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInAssetSummary() != null) {
|
||||||
|
settings.setShowInAssetSummary(settingsInput.getShowInAssetSummary());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowAsAssetBadge() != null) {
|
||||||
|
settings.setShowAsAssetBadge(settingsInput.getShowAsAssetBadge());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInColumnsTable() != null) {
|
||||||
|
settings.setShowInColumnsTable(settingsInput.getShowInColumnsTable());
|
||||||
|
}
|
||||||
|
settings.setLastModified(context.getOperationContext().getAuditStamp());
|
||||||
|
|
||||||
|
StructuredPropertyUtils.validatePropertySettings(settings, true);
|
||||||
|
|
||||||
|
return buildMetadataChangeProposalWithUrn(
|
||||||
|
propertyUrn, STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MetadataChangeProposal createPropertyDefinition(
|
||||||
|
@Nonnull final QueryContext context,
|
||||||
|
@Nonnull final Urn propertyUrn,
|
||||||
|
@Nonnull final String id,
|
||||||
|
final CreateStructuredPropertyInput input)
|
||||||
|
throws Exception {
|
||||||
|
StructuredPropertyDefinitionPatchBuilder builder =
|
||||||
|
new StructuredPropertyDefinitionPatchBuilder().urn(propertyUrn);
|
||||||
|
|
||||||
|
builder.setQualifiedName(id);
|
||||||
|
builder.setValueType(input.getValueType());
|
||||||
|
input.getEntityTypes().forEach(builder::addEntityType);
|
||||||
|
if (input.getDisplayName() != null) {
|
||||||
|
builder.setDisplayName(input.getDisplayName());
|
||||||
|
}
|
||||||
|
if (input.getDescription() != null) {
|
||||||
|
builder.setDescription(input.getDescription());
|
||||||
|
}
|
||||||
|
if (input.getImmutable() != null) {
|
||||||
|
builder.setImmutable(input.getImmutable());
|
||||||
|
}
|
||||||
|
if (input.getTypeQualifier() != null) {
|
||||||
|
buildTypeQualifier(input, builder);
|
||||||
|
}
|
||||||
|
if (input.getAllowedValues() != null) {
|
||||||
|
buildAllowedValues(input, builder);
|
||||||
|
}
|
||||||
|
if (input.getCardinality() != null) {
|
||||||
|
builder.setCardinality(PropertyCardinality.valueOf(input.getCardinality().toString()));
|
||||||
|
}
|
||||||
|
builder.setCreated(context.getOperationContext().getAuditStamp());
|
||||||
|
builder.setLastModified(context.getOperationContext().getAuditStamp());
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
private void buildTypeQualifier(
|
private void buildTypeQualifier(
|
||||||
@Nonnull final CreateStructuredPropertyInput input,
|
@Nonnull final CreateStructuredPropertyInput input,
|
||||||
@Nonnull final StructuredPropertyDefinitionPatchBuilder builder) {
|
@Nonnull final StructuredPropertyDefinitionPatchBuilder builder) {
|
||||||
|
@ -6,6 +6,7 @@ import com.linkedin.common.urn.Urn;
|
|||||||
import com.linkedin.common.urn.UrnUtils;
|
import com.linkedin.common.urn.UrnUtils;
|
||||||
import com.linkedin.datahub.graphql.QueryContext;
|
import com.linkedin.datahub.graphql.QueryContext;
|
||||||
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
||||||
|
import com.linkedin.datahub.graphql.concurrency.GraphQLConcurrencyUtils;
|
||||||
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
||||||
import com.linkedin.datahub.graphql.generated.DeleteStructuredPropertyInput;
|
import com.linkedin.datahub.graphql.generated.DeleteStructuredPropertyInput;
|
||||||
import com.linkedin.entity.client.EntityClient;
|
import com.linkedin.entity.client.EntityClient;
|
||||||
@ -42,6 +43,23 @@ public class DeleteStructuredPropertyResolver implements DataFetcher<Completable
|
|||||||
"Unable to delete structured property. Please contact your admin.");
|
"Unable to delete structured property. Please contact your admin.");
|
||||||
}
|
}
|
||||||
_entityClient.deleteEntity(context.getOperationContext(), propertyUrn);
|
_entityClient.deleteEntity(context.getOperationContext(), propertyUrn);
|
||||||
|
// Asynchronously Delete all references to the entity (to return quickly)
|
||||||
|
GraphQLConcurrencyUtils.supplyAsync(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
_entityClient.deleteEntityReferences(
|
||||||
|
context.getOperationContext(), propertyUrn);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(
|
||||||
|
String.format(
|
||||||
|
"Caught exception while attempting to clear all entity references for Structured Property with urn %s",
|
||||||
|
propertyUrn),
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
this.getClass().getSimpleName(),
|
||||||
|
"get");
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
|
@ -93,7 +93,7 @@ public class RemoveStructuredPropertiesResolver
|
|||||||
.getValue()
|
.getValue()
|
||||||
.data());
|
.data());
|
||||||
|
|
||||||
return StructuredPropertiesMapper.map(context, structuredProperties);
|
return StructuredPropertiesMapper.map(context, structuredProperties, assetUrn);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
String.format("Failed to perform update against input %s", input), e);
|
String.format("Failed to perform update against input %s", input), e);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
||||||
|
|
||||||
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
|
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
|
||||||
import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME;
|
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn;
|
||||||
import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTY_ENTITY_NAME;
|
import static com.linkedin.metadata.Constants.*;
|
||||||
|
|
||||||
import com.linkedin.common.urn.Urn;
|
import com.linkedin.common.urn.Urn;
|
||||||
import com.linkedin.common.urn.UrnUtils;
|
import com.linkedin.common.urn.UrnUtils;
|
||||||
@ -13,18 +13,23 @@ import com.linkedin.datahub.graphql.QueryContext;
|
|||||||
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
|
||||||
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
import com.linkedin.datahub.graphql.exception.AuthorizationException;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
||||||
|
import com.linkedin.datahub.graphql.generated.StructuredPropertySettingsInput;
|
||||||
import com.linkedin.datahub.graphql.generated.UpdateStructuredPropertyInput;
|
import com.linkedin.datahub.graphql.generated.UpdateStructuredPropertyInput;
|
||||||
import com.linkedin.datahub.graphql.types.structuredproperty.StructuredPropertyMapper;
|
import com.linkedin.datahub.graphql.types.structuredproperty.StructuredPropertyMapper;
|
||||||
import com.linkedin.entity.EntityResponse;
|
import com.linkedin.entity.EntityResponse;
|
||||||
import com.linkedin.entity.client.EntityClient;
|
import com.linkedin.entity.client.EntityClient;
|
||||||
import com.linkedin.metadata.aspect.patch.builder.StructuredPropertyDefinitionPatchBuilder;
|
import com.linkedin.metadata.aspect.patch.builder.StructuredPropertyDefinitionPatchBuilder;
|
||||||
|
import com.linkedin.metadata.models.StructuredPropertyUtils;
|
||||||
import com.linkedin.mxe.MetadataChangeProposal;
|
import com.linkedin.mxe.MetadataChangeProposal;
|
||||||
import com.linkedin.structured.PrimitivePropertyValue;
|
import com.linkedin.structured.PrimitivePropertyValue;
|
||||||
import com.linkedin.structured.PropertyCardinality;
|
import com.linkedin.structured.PropertyCardinality;
|
||||||
import com.linkedin.structured.PropertyValue;
|
import com.linkedin.structured.PropertyValue;
|
||||||
import com.linkedin.structured.StructuredPropertyDefinition;
|
import com.linkedin.structured.StructuredPropertyDefinition;
|
||||||
|
import com.linkedin.structured.StructuredPropertySettings;
|
||||||
import graphql.schema.DataFetcher;
|
import graphql.schema.DataFetcher;
|
||||||
import graphql.schema.DataFetchingEnvironment;
|
import graphql.schema.DataFetchingEnvironment;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -57,36 +62,24 @@ public class UpdateStructuredPropertyResolver
|
|||||||
"Unable to update structured property. Please contact your admin.");
|
"Unable to update structured property. Please contact your admin.");
|
||||||
}
|
}
|
||||||
final Urn propertyUrn = UrnUtils.getUrn(input.getUrn());
|
final Urn propertyUrn = UrnUtils.getUrn(input.getUrn());
|
||||||
StructuredPropertyDefinition existingDefinition =
|
final EntityResponse entityResponse =
|
||||||
getExistingStructuredProperty(context, propertyUrn);
|
getExistingStructuredProperty(context, propertyUrn);
|
||||||
StructuredPropertyDefinitionPatchBuilder builder =
|
|
||||||
new StructuredPropertyDefinitionPatchBuilder().urn(propertyUrn);
|
|
||||||
|
|
||||||
if (input.getDisplayName() != null) {
|
List<MetadataChangeProposal> mcps = new ArrayList<>();
|
||||||
builder.setDisplayName(input.getDisplayName());
|
|
||||||
}
|
|
||||||
if (input.getDescription() != null) {
|
|
||||||
builder.setDescription(input.getDescription());
|
|
||||||
}
|
|
||||||
if (input.getImmutable() != null) {
|
|
||||||
builder.setImmutable(input.getImmutable());
|
|
||||||
}
|
|
||||||
if (input.getTypeQualifier() != null) {
|
|
||||||
buildTypeQualifier(input, builder, existingDefinition);
|
|
||||||
}
|
|
||||||
if (input.getNewAllowedValues() != null) {
|
|
||||||
buildAllowedValues(input, builder);
|
|
||||||
}
|
|
||||||
if (input.getSetCardinalityAsMultiple() != null) {
|
|
||||||
builder.setCardinality(PropertyCardinality.MULTIPLE);
|
|
||||||
}
|
|
||||||
if (input.getNewEntityTypes() != null) {
|
|
||||||
input.getNewEntityTypes().forEach(builder::addEntityType);
|
|
||||||
}
|
|
||||||
builder.setLastModified(context.getOperationContext().getAuditStamp());
|
|
||||||
|
|
||||||
MetadataChangeProposal mcp = builder.build();
|
// first update the definition aspect if we need to
|
||||||
_entityClient.ingestProposal(context.getOperationContext(), mcp, false);
|
MetadataChangeProposal definitionMcp =
|
||||||
|
updateDefinition(input, context, propertyUrn, entityResponse);
|
||||||
|
if (definitionMcp != null) {
|
||||||
|
mcps.add(definitionMcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// then update the settings aspect if we need to
|
||||||
|
if (input.getSettings() != null) {
|
||||||
|
mcps.add(updateSettings(context, input.getSettings(), propertyUrn, entityResponse));
|
||||||
|
}
|
||||||
|
|
||||||
|
_entityClient.batchIngestProposals(context.getOperationContext(), mcps, false);
|
||||||
|
|
||||||
EntityResponse response =
|
EntityResponse response =
|
||||||
_entityClient.getV2(
|
_entityClient.getV2(
|
||||||
@ -102,6 +95,120 @@ public class UpdateStructuredPropertyResolver
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasSettingsChanged(
|
||||||
|
StructuredPropertySettings existingSettings, StructuredPropertySettingsInput settingsInput) {
|
||||||
|
if (settingsInput.getIsHidden() != null
|
||||||
|
&& !existingSettings.isIsHidden().equals(settingsInput.getIsHidden())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInSearchFilters() != null
|
||||||
|
&& !existingSettings
|
||||||
|
.isShowInSearchFilters()
|
||||||
|
.equals(settingsInput.getShowInSearchFilters())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInAssetSummary() != null
|
||||||
|
&& !existingSettings.isShowInAssetSummary().equals(settingsInput.getShowInAssetSummary())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowAsAssetBadge() != null
|
||||||
|
&& !existingSettings.isShowAsAssetBadge().equals(settingsInput.getShowAsAssetBadge())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInColumnsTable() != null
|
||||||
|
&& !existingSettings.isShowInColumnsTable().equals(settingsInput.getShowInColumnsTable())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MetadataChangeProposal updateSettings(
|
||||||
|
@Nonnull final QueryContext context,
|
||||||
|
@Nonnull final StructuredPropertySettingsInput settingsInput,
|
||||||
|
@Nonnull final Urn propertyUrn,
|
||||||
|
@Nonnull final EntityResponse entityResponse)
|
||||||
|
throws Exception {
|
||||||
|
StructuredPropertySettings existingSettings =
|
||||||
|
getExistingStructuredPropertySettings(entityResponse);
|
||||||
|
// check if settings has changed to determine if we should update the timestamp
|
||||||
|
boolean hasChanged = hasSettingsChanged(existingSettings, settingsInput);
|
||||||
|
if (hasChanged) {
|
||||||
|
existingSettings.setLastModified(context.getOperationContext().getAuditStamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settingsInput.getIsHidden() != null) {
|
||||||
|
existingSettings.setIsHidden(settingsInput.getIsHidden());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInSearchFilters() != null) {
|
||||||
|
existingSettings.setShowInSearchFilters(settingsInput.getShowInSearchFilters());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInAssetSummary() != null) {
|
||||||
|
existingSettings.setShowInAssetSummary(settingsInput.getShowInAssetSummary());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowAsAssetBadge() != null) {
|
||||||
|
existingSettings.setShowAsAssetBadge(settingsInput.getShowAsAssetBadge());
|
||||||
|
}
|
||||||
|
if (settingsInput.getShowInColumnsTable() != null) {
|
||||||
|
existingSettings.setShowInColumnsTable(settingsInput.getShowInColumnsTable());
|
||||||
|
}
|
||||||
|
|
||||||
|
StructuredPropertyUtils.validatePropertySettings(existingSettings, true);
|
||||||
|
|
||||||
|
return buildMetadataChangeProposalWithUrn(
|
||||||
|
propertyUrn, STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME, existingSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MetadataChangeProposal updateDefinition(
|
||||||
|
@Nonnull final UpdateStructuredPropertyInput input,
|
||||||
|
@Nonnull final QueryContext context,
|
||||||
|
@Nonnull final Urn propertyUrn,
|
||||||
|
@Nonnull final EntityResponse entityResponse)
|
||||||
|
throws Exception {
|
||||||
|
StructuredPropertyDefinition existingDefinition =
|
||||||
|
getExistingStructuredPropertyDefinition(entityResponse);
|
||||||
|
StructuredPropertyDefinitionPatchBuilder builder =
|
||||||
|
new StructuredPropertyDefinitionPatchBuilder().urn(propertyUrn);
|
||||||
|
|
||||||
|
boolean hasUpdatedDefinition = false;
|
||||||
|
|
||||||
|
if (input.getDisplayName() != null) {
|
||||||
|
builder.setDisplayName(input.getDisplayName());
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getDescription() != null) {
|
||||||
|
builder.setDescription(input.getDescription());
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getImmutable() != null) {
|
||||||
|
builder.setImmutable(input.getImmutable());
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getTypeQualifier() != null) {
|
||||||
|
buildTypeQualifier(input, builder, existingDefinition);
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getNewAllowedValues() != null) {
|
||||||
|
buildAllowedValues(input, builder);
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getSetCardinalityAsMultiple() != null
|
||||||
|
&& input.getSetCardinalityAsMultiple().equals(true)) {
|
||||||
|
builder.setCardinality(PropertyCardinality.MULTIPLE);
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
if (input.getNewEntityTypes() != null) {
|
||||||
|
input.getNewEntityTypes().forEach(builder::addEntityType);
|
||||||
|
hasUpdatedDefinition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasUpdatedDefinition) {
|
||||||
|
builder.setLastModified(context.getOperationContext().getAuditStamp());
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void buildTypeQualifier(
|
private void buildTypeQualifier(
|
||||||
@Nonnull final UpdateStructuredPropertyInput input,
|
@Nonnull final UpdateStructuredPropertyInput input,
|
||||||
@Nonnull final StructuredPropertyDefinitionPatchBuilder builder,
|
@Nonnull final StructuredPropertyDefinitionPatchBuilder builder,
|
||||||
@ -141,17 +248,40 @@ public class UpdateStructuredPropertyResolver
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructuredPropertyDefinition getExistingStructuredProperty(
|
private EntityResponse getExistingStructuredProperty(
|
||||||
@Nonnull final QueryContext context, @Nonnull final Urn propertyUrn) throws Exception {
|
@Nonnull final QueryContext context, @Nonnull final Urn propertyUrn) throws Exception {
|
||||||
EntityResponse response =
|
return _entityClient.getV2(
|
||||||
_entityClient.getV2(
|
context.getOperationContext(), STRUCTURED_PROPERTY_ENTITY_NAME, propertyUrn, null);
|
||||||
context.getOperationContext(), STRUCTURED_PROPERTY_ENTITY_NAME, propertyUrn, null);
|
}
|
||||||
|
|
||||||
|
private StructuredPropertyDefinition getExistingStructuredPropertyDefinition(
|
||||||
|
EntityResponse response) throws Exception {
|
||||||
if (response != null
|
if (response != null
|
||||||
&& response.getAspects().containsKey(STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME)) {
|
&& response.getAspects().containsKey(STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME)) {
|
||||||
return new StructuredPropertyDefinition(
|
return new StructuredPropertyDefinition(
|
||||||
response.getAspects().get(STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME).getValue().data());
|
response
|
||||||
|
.getAspects()
|
||||||
|
.get(STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME)
|
||||||
|
.getValue()
|
||||||
|
.data()
|
||||||
|
.copy());
|
||||||
}
|
}
|
||||||
return null;
|
throw new IllegalArgumentException(
|
||||||
|
"Attempting to update a structured property with no definition aspect.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructuredPropertySettings getExistingStructuredPropertySettings(EntityResponse response)
|
||||||
|
throws Exception {
|
||||||
|
if (response != null
|
||||||
|
&& response.getAspects().containsKey(STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME)) {
|
||||||
|
return new StructuredPropertySettings(
|
||||||
|
response
|
||||||
|
.getAspects()
|
||||||
|
.get(STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME)
|
||||||
|
.getValue()
|
||||||
|
.data()
|
||||||
|
.copy());
|
||||||
|
}
|
||||||
|
return new StructuredPropertySettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ public class UpsertStructuredPropertiesResolver
|
|||||||
_entityClient.ingestProposal(
|
_entityClient.ingestProposal(
|
||||||
context.getOperationContext(), structuredPropertiesProposal, false);
|
context.getOperationContext(), structuredPropertiesProposal, false);
|
||||||
|
|
||||||
return StructuredPropertiesMapper.map(context, structuredProperties);
|
return StructuredPropertiesMapper.map(context, structuredProperties, assetUrn);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
String.format("Failed to perform update against input %s", input), e);
|
String.format("Failed to perform update against input %s", input), e);
|
||||||
|
@ -142,7 +142,8 @@ public class ChartMapper implements ModelMapper<EntityResponse, Chart> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((chart, dataMap) ->
|
((chart, dataMap) ->
|
||||||
chart.setStructuredProperties(
|
chart.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -161,7 +161,9 @@ public class ContainerMapper {
|
|||||||
if (envelopedStructuredProps != null) {
|
if (envelopedStructuredProps != null) {
|
||||||
result.setStructuredProperties(
|
result.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(
|
StructuredPropertiesMapper.map(
|
||||||
context, new StructuredProperties(envelopedStructuredProps.getValue().data())));
|
context,
|
||||||
|
new StructuredProperties(envelopedStructuredProps.getValue().data()),
|
||||||
|
entityUrn));
|
||||||
}
|
}
|
||||||
|
|
||||||
final EnvelopedAspect envelopedForms = aspects.get(FORMS_ASPECT_NAME);
|
final EnvelopedAspect envelopedForms = aspects.get(FORMS_ASPECT_NAME);
|
||||||
|
@ -59,7 +59,8 @@ public class CorpGroupMapper implements ModelMapper<EntityResponse, CorpGroup> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -88,7 +88,8 @@ public class CorpUserMapper {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -142,7 +142,8 @@ public class DashboardMapper implements ModelMapper<EntityResponse, Dashboard> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((dashboard, dataMap) ->
|
((dashboard, dataMap) ->
|
||||||
dashboard.setStructuredProperties(
|
dashboard.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -114,7 +114,8 @@ public class DataFlowMapper implements ModelMapper<EntityResponse, DataFlow> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -135,7 +135,8 @@ public class DataJobMapper implements ModelMapper<EntityResponse, DataJob> {
|
|||||||
result.setSubTypes(SubTypesMapper.map(context, new SubTypes(data)));
|
result.setSubTypes(SubTypesMapper.map(context, new SubTypes(data)));
|
||||||
} else if (STRUCTURED_PROPERTIES_ASPECT_NAME.equals(name)) {
|
} else if (STRUCTURED_PROPERTIES_ASPECT_NAME.equals(name)) {
|
||||||
result.setStructuredProperties(
|
result.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(data)));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(data), entityUrn));
|
||||||
} else if (FORMS_ASPECT_NAME.equals(name)) {
|
} else if (FORMS_ASPECT_NAME.equals(name)) {
|
||||||
result.setForms(FormsMapper.map(new Forms(data), entityUrn.toString()));
|
result.setForms(FormsMapper.map(new Forms(data), entityUrn.toString()));
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,8 @@ public class DataProductMapper implements ModelMapper<EntityResponse, DataProduc
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -173,7 +173,8 @@ public class DatasetMapper implements ModelMapper<EntityResponse, Dataset> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((dataset, dataMap) ->
|
((dataset, dataMap) ->
|
||||||
|
@ -71,7 +71,9 @@ public class DomainMapper {
|
|||||||
if (envelopedStructuredProps != null) {
|
if (envelopedStructuredProps != null) {
|
||||||
result.setStructuredProperties(
|
result.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(
|
StructuredPropertiesMapper.map(
|
||||||
context, new StructuredProperties(envelopedStructuredProps.getValue().data())));
|
context,
|
||||||
|
new StructuredProperties(envelopedStructuredProps.getValue().data()),
|
||||||
|
entityUrn));
|
||||||
}
|
}
|
||||||
|
|
||||||
final EnvelopedAspect envelopedForms = aspects.get(FORMS_ASPECT_NAME);
|
final EnvelopedAspect envelopedForms = aspects.get(FORMS_ASPECT_NAME);
|
||||||
|
@ -59,7 +59,8 @@ public class GlossaryNodeMapper implements ModelMapper<EntityResponse, GlossaryN
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -90,7 +90,8 @@ public class GlossaryTermMapper implements ModelMapper<EntityResponse, GlossaryT
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -115,7 +115,8 @@ public class MLFeatureMapper implements ModelMapper<EntityResponse, MLFeature> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((mlFeature, dataMap) ->
|
((mlFeature, dataMap) ->
|
||||||
mlFeature.setStructuredProperties(
|
mlFeature.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -117,7 +117,8 @@ public class MLFeatureTableMapper implements ModelMapper<EntityResponse, MLFeatu
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((mlFeatureTable, dataMap) ->
|
((mlFeatureTable, dataMap) ->
|
||||||
mlFeatureTable.setStructuredProperties(
|
mlFeatureTable.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -112,7 +112,8 @@ public class MLModelGroupMapper implements ModelMapper<EntityResponse, MLModelGr
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((mlModelGroup, dataMap) ->
|
((mlModelGroup, dataMap) ->
|
||||||
mlModelGroup.setStructuredProperties(
|
mlModelGroup.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -174,7 +174,8 @@ public class MLModelMapper implements ModelMapper<EntityResponse, MLModel> {
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((dataset, dataMap) ->
|
((dataset, dataMap) ->
|
||||||
dataset.setStructuredProperties(
|
dataset.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -112,7 +112,8 @@ public class MLPrimaryKeyMapper implements ModelMapper<EntityResponse, MLPrimary
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
entity.setStructuredProperties(
|
entity.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
FORMS_ASPECT_NAME,
|
FORMS_ASPECT_NAME,
|
||||||
((entity, dataMap) ->
|
((entity, dataMap) ->
|
||||||
|
@ -41,7 +41,8 @@ public class SchemaFieldMapper implements ModelMapper<EntityResponse, SchemaFiel
|
|||||||
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
STRUCTURED_PROPERTIES_ASPECT_NAME,
|
||||||
((schemaField, dataMap) ->
|
((schemaField, dataMap) ->
|
||||||
schemaField.setStructuredProperties(
|
schemaField.setStructuredProperties(
|
||||||
StructuredPropertiesMapper.map(context, new StructuredProperties(dataMap)))));
|
StructuredPropertiesMapper.map(
|
||||||
|
context, new StructuredProperties(dataMap), entityUrn))));
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
BUSINESS_ATTRIBUTE_ASPECT,
|
BUSINESS_ATTRIBUTE_ASPECT,
|
||||||
(((schemaField, dataMap) ->
|
(((schemaField, dataMap) ->
|
||||||
|
@ -25,23 +25,29 @@ public class StructuredPropertiesMapper {
|
|||||||
public static final StructuredPropertiesMapper INSTANCE = new StructuredPropertiesMapper();
|
public static final StructuredPropertiesMapper INSTANCE = new StructuredPropertiesMapper();
|
||||||
|
|
||||||
public static com.linkedin.datahub.graphql.generated.StructuredProperties map(
|
public static com.linkedin.datahub.graphql.generated.StructuredProperties map(
|
||||||
@Nullable QueryContext context, @Nonnull final StructuredProperties structuredProperties) {
|
@Nullable QueryContext context,
|
||||||
return INSTANCE.apply(context, structuredProperties);
|
@Nonnull final StructuredProperties structuredProperties,
|
||||||
|
@Nonnull final Urn entityUrn) {
|
||||||
|
return INSTANCE.apply(context, structuredProperties, entityUrn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public com.linkedin.datahub.graphql.generated.StructuredProperties apply(
|
public com.linkedin.datahub.graphql.generated.StructuredProperties apply(
|
||||||
@Nullable QueryContext context, @Nonnull final StructuredProperties structuredProperties) {
|
@Nullable QueryContext context,
|
||||||
|
@Nonnull final StructuredProperties structuredProperties,
|
||||||
|
@Nonnull final Urn entityUrn) {
|
||||||
com.linkedin.datahub.graphql.generated.StructuredProperties result =
|
com.linkedin.datahub.graphql.generated.StructuredProperties result =
|
||||||
new com.linkedin.datahub.graphql.generated.StructuredProperties();
|
new com.linkedin.datahub.graphql.generated.StructuredProperties();
|
||||||
result.setProperties(
|
result.setProperties(
|
||||||
structuredProperties.getProperties().stream()
|
structuredProperties.getProperties().stream()
|
||||||
.map(p -> mapStructuredProperty(context, p))
|
.map(p -> mapStructuredProperty(context, p, entityUrn))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructuredPropertiesEntry mapStructuredProperty(
|
private StructuredPropertiesEntry mapStructuredProperty(
|
||||||
@Nullable QueryContext context, StructuredPropertyValueAssignment valueAssignment) {
|
@Nullable QueryContext context,
|
||||||
|
StructuredPropertyValueAssignment valueAssignment,
|
||||||
|
@Nonnull final Urn entityUrn) {
|
||||||
StructuredPropertiesEntry entry = new StructuredPropertiesEntry();
|
StructuredPropertiesEntry entry = new StructuredPropertiesEntry();
|
||||||
entry.setStructuredProperty(createStructuredPropertyEntity(valueAssignment));
|
entry.setStructuredProperty(createStructuredPropertyEntity(valueAssignment));
|
||||||
final List<PropertyValue> values = new ArrayList<>();
|
final List<PropertyValue> values = new ArrayList<>();
|
||||||
@ -58,6 +64,7 @@ public class StructuredPropertiesMapper {
|
|||||||
});
|
});
|
||||||
entry.setValues(values);
|
entry.setValues(values);
|
||||||
entry.setValueEntities(entities);
|
entry.setValueEntities(entities);
|
||||||
|
entry.setAssociatedUrn(entityUrn.toString());
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import com.linkedin.datahub.graphql.generated.PropertyCardinality;
|
|||||||
import com.linkedin.datahub.graphql.generated.StringValue;
|
import com.linkedin.datahub.graphql.generated.StringValue;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyDefinition;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyDefinition;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
||||||
|
import com.linkedin.datahub.graphql.generated.StructuredPropertySettings;
|
||||||
import com.linkedin.datahub.graphql.generated.TypeQualifier;
|
import com.linkedin.datahub.graphql.generated.TypeQualifier;
|
||||||
import com.linkedin.datahub.graphql.types.common.mappers.util.MappingHelper;
|
import com.linkedin.datahub.graphql.types.common.mappers.util.MappingHelper;
|
||||||
import com.linkedin.datahub.graphql.types.mappers.MapperUtils;
|
import com.linkedin.datahub.graphql.types.mappers.MapperUtils;
|
||||||
@ -55,6 +56,8 @@ public class StructuredPropertyMapper
|
|||||||
MappingHelper<StructuredPropertyEntity> mappingHelper = new MappingHelper<>(aspectMap, result);
|
MappingHelper<StructuredPropertyEntity> mappingHelper = new MappingHelper<>(aspectMap, result);
|
||||||
mappingHelper.mapToResult(
|
mappingHelper.mapToResult(
|
||||||
STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME, (this::mapStructuredPropertyDefinition));
|
STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME, (this::mapStructuredPropertyDefinition));
|
||||||
|
mappingHelper.mapToResult(
|
||||||
|
STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME, (this::mapStructuredPropertySettings));
|
||||||
return mappingHelper.getResult();
|
return mappingHelper.getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +115,21 @@ public class StructuredPropertyMapper
|
|||||||
return allowedValues;
|
return allowedValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void mapStructuredPropertySettings(
|
||||||
|
@Nonnull StructuredPropertyEntity extendedProperty, @Nonnull DataMap dataMap) {
|
||||||
|
com.linkedin.structured.StructuredPropertySettings gmsSettings =
|
||||||
|
new com.linkedin.structured.StructuredPropertySettings(dataMap);
|
||||||
|
StructuredPropertySettings settings = new StructuredPropertySettings();
|
||||||
|
|
||||||
|
settings.setIsHidden(gmsSettings.isIsHidden());
|
||||||
|
settings.setShowInSearchFilters(gmsSettings.isShowInSearchFilters());
|
||||||
|
settings.setShowInAssetSummary(gmsSettings.isShowInAssetSummary());
|
||||||
|
settings.setShowAsAssetBadge(gmsSettings.isShowAsAssetBadge());
|
||||||
|
settings.setShowInColumnsTable(gmsSettings.isShowInColumnsTable());
|
||||||
|
|
||||||
|
extendedProperty.setSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
private DataTypeEntity createDataTypeEntity(final Urn dataTypeUrn) {
|
private DataTypeEntity createDataTypeEntity(final Urn dataTypeUrn) {
|
||||||
final DataTypeEntity dataType = new DataTypeEntity();
|
final DataTypeEntity dataType = new DataTypeEntity();
|
||||||
dataType.setUrn(dataTypeUrn.toString());
|
dataType.setUrn(dataTypeUrn.toString());
|
||||||
|
@ -27,7 +27,8 @@ public class StructuredPropertyType
|
|||||||
implements com.linkedin.datahub.graphql.types.EntityType<StructuredPropertyEntity, String> {
|
implements com.linkedin.datahub.graphql.types.EntityType<StructuredPropertyEntity, String> {
|
||||||
|
|
||||||
public static final Set<String> ASPECTS_TO_FETCH =
|
public static final Set<String> ASPECTS_TO_FETCH =
|
||||||
ImmutableSet.of(STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME);
|
ImmutableSet.of(
|
||||||
|
STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME, STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME);
|
||||||
private final EntityClient _entityClient;
|
private final EntityClient _entityClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,6 +49,11 @@ type StructuredPropertyEntity implements Entity {
|
|||||||
"""
|
"""
|
||||||
definition: StructuredPropertyDefinition!
|
definition: StructuredPropertyDefinition!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Definition of this structured property including its name
|
||||||
|
"""
|
||||||
|
settings: StructuredPropertySettings
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Granular API for querying edges extending from this entity
|
Granular API for querying edges extending from this entity
|
||||||
"""
|
"""
|
||||||
@ -117,6 +122,36 @@ type StructuredPropertyDefinition {
|
|||||||
lastModified: ResolvedAuditStamp
|
lastModified: ResolvedAuditStamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings specific to a structured property entity
|
||||||
|
"""
|
||||||
|
type StructuredPropertySettings {
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be hidden in the main application
|
||||||
|
"""
|
||||||
|
isHidden: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as a search filter
|
||||||
|
"""
|
||||||
|
showInSearchFilters: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed in the asset sidebar
|
||||||
|
"""
|
||||||
|
showInAssetSummary: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as an asset badge on other asset's headers
|
||||||
|
"""
|
||||||
|
showAsAssetBadge: Boolean!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as a column in the schema field table in a Dataset's "Columns" tab.
|
||||||
|
"""
|
||||||
|
showInColumnsTable: Boolean!
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An entry for an allowed value for a structured property
|
An entry for an allowed value for a structured property
|
||||||
"""
|
"""
|
||||||
@ -202,6 +237,11 @@ type StructuredPropertiesEntry {
|
|||||||
The optional entities associated with the values if the values are entity urns
|
The optional entities associated with the values if the values are entity urns
|
||||||
"""
|
"""
|
||||||
valueEntities: [Entity]
|
valueEntities: [Entity]
|
||||||
|
|
||||||
|
"""
|
||||||
|
The urn of the entity this property came from for tracking purposes e.g. when sibling nodes are merged together
|
||||||
|
"""
|
||||||
|
associatedUrn: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -330,8 +370,9 @@ input CreateStructuredPropertyInput {
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
The unique fully qualified name of this structured property, dot delimited.
|
The unique fully qualified name of this structured property, dot delimited.
|
||||||
|
This will be required to match the ID of this structured property.
|
||||||
"""
|
"""
|
||||||
qualifiedName: String!
|
qualifiedName: String
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The optional display name for this property
|
The optional display name for this property
|
||||||
@ -375,6 +416,11 @@ input CreateStructuredPropertyInput {
|
|||||||
For example: ["urn:li:entityType:datahub.dataset"]
|
For example: ["urn:li:entityType:datahub.dataset"]
|
||||||
"""
|
"""
|
||||||
entityTypes: [String!]!
|
entityTypes: [String!]!
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings for this structured property
|
||||||
|
"""
|
||||||
|
settings: StructuredPropertySettingsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -455,6 +501,11 @@ input UpdateStructuredPropertyInput {
|
|||||||
For backwards compatibility, this is append only.
|
For backwards compatibility, this is append only.
|
||||||
"""
|
"""
|
||||||
newEntityTypes: [String!]
|
newEntityTypes: [String!]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings for this structured property
|
||||||
|
"""
|
||||||
|
settings: StructuredPropertySettingsInput
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -477,3 +528,34 @@ input DeleteStructuredPropertyInput {
|
|||||||
"""
|
"""
|
||||||
urn: String!
|
urn: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
Settings for a structured property
|
||||||
|
"""
|
||||||
|
input StructuredPropertySettingsInput {
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be hidden in the main application
|
||||||
|
"""
|
||||||
|
isHidden: Boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as a search filter
|
||||||
|
"""
|
||||||
|
showInSearchFilters: Boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed in the asset sidebar
|
||||||
|
"""
|
||||||
|
showInAssetSummary: Boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as an asset badge on other asset's headers
|
||||||
|
"""
|
||||||
|
showAsAssetBadge: Boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
Whether or not this asset should be displayed as a column in the schema field table in a Dataset's "Columns" tab.
|
||||||
|
"""
|
||||||
|
showInColumnsTable: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import com.linkedin.common.urn.UrnUtils;
|
|||||||
import com.linkedin.datahub.graphql.QueryContext;
|
import com.linkedin.datahub.graphql.QueryContext;
|
||||||
import com.linkedin.datahub.graphql.generated.CreateStructuredPropertyInput;
|
import com.linkedin.datahub.graphql.generated.CreateStructuredPropertyInput;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
||||||
|
import com.linkedin.datahub.graphql.generated.StructuredPropertySettingsInput;
|
||||||
import com.linkedin.entity.EntityResponse;
|
import com.linkedin.entity.EntityResponse;
|
||||||
import com.linkedin.entity.EnvelopedAspectMap;
|
import com.linkedin.entity.EnvelopedAspectMap;
|
||||||
import com.linkedin.entity.client.EntityClient;
|
import com.linkedin.entity.client.EntityClient;
|
||||||
import com.linkedin.metadata.Constants;
|
import com.linkedin.metadata.Constants;
|
||||||
import com.linkedin.mxe.MetadataChangeProposal;
|
|
||||||
import com.linkedin.r2.RemoteInvocationException;
|
import com.linkedin.r2.RemoteInvocationException;
|
||||||
import graphql.schema.DataFetchingEnvironment;
|
import graphql.schema.DataFetchingEnvironment;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -36,7 +36,8 @@ public class CreateStructuredPropertyResolverTest {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new ArrayList<>());
|
new ArrayList<>(),
|
||||||
|
null);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetSuccess() throws Exception {
|
public void testGetSuccess() throws Exception {
|
||||||
@ -56,7 +57,40 @@ public class CreateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that we called ingest
|
// Validate that we called ingest
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(1))
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetMismatchIdAndQualifiedName() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
CreateStructuredPropertyResolver resolver =
|
||||||
|
new CreateStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
CreateStructuredPropertyInput testInput =
|
||||||
|
new CreateStructuredPropertyInput(
|
||||||
|
"mismatched",
|
||||||
|
"io.acryl.test",
|
||||||
|
"Display Name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new ArrayList<>(),
|
||||||
|
null);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(testInput);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||||
|
|
||||||
|
// Validate ingest is not called
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,7 +109,7 @@ public class CreateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that we did NOT call ingest
|
// Validate that we did NOT call ingest
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(0))
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -94,7 +128,83 @@ public class CreateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that ingest was called, but that caused a failure
|
// Validate that ingest was called, but that caused a failure
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(1))
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetInvalidSettingsInput() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
CreateStructuredPropertyResolver resolver =
|
||||||
|
new CreateStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// if isHidden is true, other fields should not be true
|
||||||
|
StructuredPropertySettingsInput settingsInput = new StructuredPropertySettingsInput();
|
||||||
|
settingsInput.setIsHidden(true);
|
||||||
|
settingsInput.setShowAsAssetBadge(true);
|
||||||
|
|
||||||
|
CreateStructuredPropertyInput testInput =
|
||||||
|
new CreateStructuredPropertyInput(
|
||||||
|
null,
|
||||||
|
"io.acryl.test",
|
||||||
|
"Display Name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new ArrayList<>(),
|
||||||
|
settingsInput);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(testInput);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||||
|
|
||||||
|
// Validate ingest is not called
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSuccessWithSettings() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
CreateStructuredPropertyResolver resolver =
|
||||||
|
new CreateStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
StructuredPropertySettingsInput settingsInput = new StructuredPropertySettingsInput();
|
||||||
|
settingsInput.setShowAsAssetBadge(true);
|
||||||
|
|
||||||
|
CreateStructuredPropertyInput testInput =
|
||||||
|
new CreateStructuredPropertyInput(
|
||||||
|
null,
|
||||||
|
"io.acryl.test",
|
||||||
|
"Display Name",
|
||||||
|
"description",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new ArrayList<>(),
|
||||||
|
settingsInput);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(testInput);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
StructuredPropertyEntity prop = resolver.get(mockEnv).get();
|
||||||
|
|
||||||
|
assertEquals(prop.getUrn(), TEST_STRUCTURED_PROPERTY_URN);
|
||||||
|
|
||||||
|
// Validate that we called ingest
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityClient initMockEntityClient(boolean shouldSucceed) throws Exception {
|
private EntityClient initMockEntityClient(boolean shouldSucceed) throws Exception {
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
||||||
|
|
||||||
|
import static com.linkedin.datahub.graphql.TestUtils.getMockAllowContext;
|
||||||
|
import static com.linkedin.datahub.graphql.TestUtils.getMockDenyContext;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.testng.Assert.assertThrows;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import com.linkedin.common.urn.UrnUtils;
|
||||||
|
import com.linkedin.datahub.graphql.QueryContext;
|
||||||
|
import com.linkedin.datahub.graphql.generated.DeleteStructuredPropertyInput;
|
||||||
|
import com.linkedin.entity.client.EntityClient;
|
||||||
|
import com.linkedin.r2.RemoteInvocationException;
|
||||||
|
import graphql.schema.DataFetchingEnvironment;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class DeleteStructuredPropertyResolverTest {
|
||||||
|
private static final String TEST_PROP_URN = "urn:li:structuredProperty:test";
|
||||||
|
|
||||||
|
private static final DeleteStructuredPropertyInput TEST_INPUT =
|
||||||
|
new DeleteStructuredPropertyInput(TEST_PROP_URN);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSuccess() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
DeleteStructuredPropertyResolver resolver =
|
||||||
|
new DeleteStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
Boolean success = resolver.get(mockEnv).get();
|
||||||
|
assertTrue(success);
|
||||||
|
|
||||||
|
// Validate that we called delete
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
|
.deleteEntity(any(), Mockito.eq(UrnUtils.getUrn(TEST_PROP_URN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUnauthorized() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
DeleteStructuredPropertyResolver resolver =
|
||||||
|
new DeleteStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockDenyContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||||
|
|
||||||
|
// Validate that we did NOT call delete
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
|
.deleteEntity(any(), Mockito.eq(UrnUtils.getUrn(TEST_PROP_URN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFailure() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(false);
|
||||||
|
DeleteStructuredPropertyResolver resolver =
|
||||||
|
new DeleteStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||||
|
|
||||||
|
// Validate that deleteEntity was called, but since it's the thing that failed it was called
|
||||||
|
// once still
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
|
.deleteEntity(any(), Mockito.eq(UrnUtils.getUrn(TEST_PROP_URN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityClient initMockEntityClient(boolean shouldSucceed) throws Exception {
|
||||||
|
EntityClient client = Mockito.mock(EntityClient.class);
|
||||||
|
if (!shouldSucceed) {
|
||||||
|
Mockito.doThrow(new RemoteInvocationException()).when(client).deleteEntity(any(), any());
|
||||||
|
}
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
||||||
|
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
import com.linkedin.metadata.models.StructuredPropertyUtils;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class StructuredPropertyUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdMismatchedInput() throws Exception {
|
||||||
|
assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() -> StructuredPropertyUtils.getPropertyId("test1", "test2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdConsistentInput() throws Exception {
|
||||||
|
assertEquals(StructuredPropertyUtils.getPropertyId("test1", "test1"), "test1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdNullQualifiedName() throws Exception {
|
||||||
|
assertEquals(StructuredPropertyUtils.getPropertyId("test1", null), "test1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdNullId() throws Exception {
|
||||||
|
assertEquals(StructuredPropertyUtils.getPropertyId(null, "test1"), "test1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdNullForBoth() throws Exception {
|
||||||
|
try {
|
||||||
|
String id = StructuredPropertyUtils.getPropertyId(null, null);
|
||||||
|
UUID.fromString(id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("ID produced is not a UUID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,20 +2,25 @@ package com.linkedin.datahub.graphql.resolvers.structuredproperties;
|
|||||||
|
|
||||||
import static com.linkedin.datahub.graphql.TestUtils.getMockAllowContext;
|
import static com.linkedin.datahub.graphql.TestUtils.getMockAllowContext;
|
||||||
import static com.linkedin.datahub.graphql.TestUtils.getMockDenyContext;
|
import static com.linkedin.datahub.graphql.TestUtils.getMockDenyContext;
|
||||||
|
import static com.linkedin.metadata.Constants.STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertThrows;
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
|
import com.linkedin.common.UrnArray;
|
||||||
import com.linkedin.common.urn.UrnUtils;
|
import com.linkedin.common.urn.UrnUtils;
|
||||||
import com.linkedin.datahub.graphql.QueryContext;
|
import com.linkedin.datahub.graphql.QueryContext;
|
||||||
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
import com.linkedin.datahub.graphql.generated.StructuredPropertyEntity;
|
||||||
|
import com.linkedin.datahub.graphql.generated.StructuredPropertySettingsInput;
|
||||||
import com.linkedin.datahub.graphql.generated.UpdateStructuredPropertyInput;
|
import com.linkedin.datahub.graphql.generated.UpdateStructuredPropertyInput;
|
||||||
|
import com.linkedin.entity.Aspect;
|
||||||
import com.linkedin.entity.EntityResponse;
|
import com.linkedin.entity.EntityResponse;
|
||||||
|
import com.linkedin.entity.EnvelopedAspect;
|
||||||
import com.linkedin.entity.EnvelopedAspectMap;
|
import com.linkedin.entity.EnvelopedAspectMap;
|
||||||
import com.linkedin.entity.client.EntityClient;
|
import com.linkedin.entity.client.EntityClient;
|
||||||
import com.linkedin.metadata.Constants;
|
import com.linkedin.metadata.Constants;
|
||||||
import com.linkedin.mxe.MetadataChangeProposal;
|
|
||||||
import com.linkedin.r2.RemoteInvocationException;
|
import com.linkedin.r2.RemoteInvocationException;
|
||||||
|
import com.linkedin.structured.StructuredPropertyDefinition;
|
||||||
import graphql.schema.DataFetchingEnvironment;
|
import graphql.schema.DataFetchingEnvironment;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
@ -33,6 +38,7 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
null);
|
null);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -53,7 +59,7 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that we called ingest
|
// Validate that we called ingest
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(1))
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -72,7 +78,7 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that we did NOT call ingest
|
// Validate that we did NOT call ingest
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(0))
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -91,7 +97,80 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
// Validate that ingest was not called since there was a get failure before ingesting
|
// Validate that ingest was not called since there was a get failure before ingesting
|
||||||
Mockito.verify(mockEntityClient, Mockito.times(0))
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
.ingestProposal(any(), any(MetadataChangeProposal.class), Mockito.eq(false));
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetInvalidSettingsInput() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
UpdateStructuredPropertyResolver resolver =
|
||||||
|
new UpdateStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// if isHidden is true, other fields should not be true
|
||||||
|
StructuredPropertySettingsInput settingsInput = new StructuredPropertySettingsInput();
|
||||||
|
settingsInput.setIsHidden(true);
|
||||||
|
settingsInput.setShowInSearchFilters(true);
|
||||||
|
|
||||||
|
final UpdateStructuredPropertyInput testInput =
|
||||||
|
new UpdateStructuredPropertyInput(
|
||||||
|
TEST_STRUCTURED_PROPERTY_URN,
|
||||||
|
"New Display Name",
|
||||||
|
"new description",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
settingsInput);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(testInput);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
|
||||||
|
|
||||||
|
// Validate that ingest was not called since there was a get failure before ingesting
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(0))
|
||||||
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetValidSettingsInput() throws Exception {
|
||||||
|
EntityClient mockEntityClient = initMockEntityClient(true);
|
||||||
|
UpdateStructuredPropertyResolver resolver =
|
||||||
|
new UpdateStructuredPropertyResolver(mockEntityClient);
|
||||||
|
|
||||||
|
// if isHidden is true, other fields should not be true
|
||||||
|
StructuredPropertySettingsInput settingsInput = new StructuredPropertySettingsInput();
|
||||||
|
settingsInput.setIsHidden(true);
|
||||||
|
|
||||||
|
final UpdateStructuredPropertyInput testInput =
|
||||||
|
new UpdateStructuredPropertyInput(
|
||||||
|
TEST_STRUCTURED_PROPERTY_URN,
|
||||||
|
"New Display Name",
|
||||||
|
"new description",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
settingsInput);
|
||||||
|
|
||||||
|
// Execute resolver
|
||||||
|
QueryContext mockContext = getMockAllowContext();
|
||||||
|
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
|
||||||
|
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(testInput);
|
||||||
|
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
|
||||||
|
|
||||||
|
StructuredPropertyEntity prop = resolver.get(mockEnv).get();
|
||||||
|
|
||||||
|
assertEquals(prop.getUrn(), TEST_STRUCTURED_PROPERTY_URN);
|
||||||
|
|
||||||
|
// Validate that we called ingest
|
||||||
|
Mockito.verify(mockEntityClient, Mockito.times(1))
|
||||||
|
.batchIngestProposals(any(), Mockito.anyList(), Mockito.eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityClient initMockEntityClient(boolean shouldSucceed) throws Exception {
|
private EntityClient initMockEntityClient(boolean shouldSucceed) throws Exception {
|
||||||
@ -99,7 +178,11 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
EntityResponse response = new EntityResponse();
|
EntityResponse response = new EntityResponse();
|
||||||
response.setEntityName(Constants.STRUCTURED_PROPERTY_ENTITY_NAME);
|
response.setEntityName(Constants.STRUCTURED_PROPERTY_ENTITY_NAME);
|
||||||
response.setUrn(UrnUtils.getUrn(TEST_STRUCTURED_PROPERTY_URN));
|
response.setUrn(UrnUtils.getUrn(TEST_STRUCTURED_PROPERTY_URN));
|
||||||
response.setAspects(new EnvelopedAspectMap());
|
final EnvelopedAspectMap aspectMap = new EnvelopedAspectMap();
|
||||||
|
aspectMap.put(
|
||||||
|
STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME,
|
||||||
|
new EnvelopedAspect().setValue(new Aspect(createDefinition().data())));
|
||||||
|
response.setAspects(aspectMap);
|
||||||
if (shouldSucceed) {
|
if (shouldSucceed) {
|
||||||
Mockito.when(
|
Mockito.when(
|
||||||
client.getV2(
|
client.getV2(
|
||||||
@ -120,4 +203,13 @@ public class UpdateStructuredPropertyResolverTest {
|
|||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StructuredPropertyDefinition createDefinition() {
|
||||||
|
StructuredPropertyDefinition definition = new StructuredPropertyDefinition();
|
||||||
|
definition.setDisplayName("test");
|
||||||
|
definition.setQualifiedName("test");
|
||||||
|
definition.setValueType(UrnUtils.getUrn("urn:li:dataType:datahub.string"));
|
||||||
|
definition.setEntityTypes(new UrnArray());
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import com.linkedin.metadata.query.filter.Filter;
|
|||||||
import com.linkedin.structured.PrimitivePropertyValue;
|
import com.linkedin.structured.PrimitivePropertyValue;
|
||||||
import com.linkedin.structured.StructuredProperties;
|
import com.linkedin.structured.StructuredProperties;
|
||||||
import com.linkedin.structured.StructuredPropertyDefinition;
|
import com.linkedin.structured.StructuredPropertyDefinition;
|
||||||
|
import com.linkedin.structured.StructuredPropertySettings;
|
||||||
import com.linkedin.structured.StructuredPropertyValueAssignment;
|
import com.linkedin.structured.StructuredPropertyValueAssignment;
|
||||||
import com.linkedin.structured.StructuredPropertyValueAssignmentArray;
|
import com.linkedin.structured.StructuredPropertyValueAssignmentArray;
|
||||||
import com.linkedin.util.Pair;
|
import com.linkedin.util.Pair;
|
||||||
@ -32,6 +33,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -45,6 +47,11 @@ public class StructuredPropertyUtils {
|
|||||||
static final Date MIN_DATE = Date.valueOf("1000-01-01");
|
static final Date MIN_DATE = Date.valueOf("1000-01-01");
|
||||||
static final Date MAX_DATE = Date.valueOf("9999-12-31");
|
static final Date MAX_DATE = Date.valueOf("9999-12-31");
|
||||||
|
|
||||||
|
public static final String INVALID_SETTINGS_MESSAGE =
|
||||||
|
"Cannot have property isHidden = true while other display location settings are also true.";
|
||||||
|
public static final String ONLY_ONE_BADGE =
|
||||||
|
"Cannot have more than one property set with show as badge. Property urns currently set: ";
|
||||||
|
|
||||||
public static LogicalValueType getLogicalValueType(
|
public static LogicalValueType getLogicalValueType(
|
||||||
StructuredPropertyDefinition structuredPropertyDefinition) {
|
StructuredPropertyDefinition structuredPropertyDefinition) {
|
||||||
return getLogicalValueType(structuredPropertyDefinition.getValueType());
|
return getLogicalValueType(structuredPropertyDefinition.getValueType());
|
||||||
@ -355,4 +362,47 @@ public class StructuredPropertyUtils {
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We accept both ID and qualifiedName as inputs when creating a structured property. However,
|
||||||
|
* these two fields should ALWAYS be the same. If they don't provide either, use a UUID for both.
|
||||||
|
* If they provide both, ensure they are the same otherwise throw. Otherwise, use what is provided.
|
||||||
|
*/
|
||||||
|
public static String getPropertyId(
|
||||||
|
@Nullable final String inputId, @Nullable final String inputQualifiedName) {
|
||||||
|
if (inputId != null && inputQualifiedName != null && !inputId.equals(inputQualifiedName)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Qualified name and the ID of a structured property must match");
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
if (inputQualifiedName != null) {
|
||||||
|
id = inputQualifiedName;
|
||||||
|
} else if (inputId != null) {
|
||||||
|
id = inputId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that a structured property settings aspect is valid by ensuring that if isHidden is true,
|
||||||
|
* the other fields concerning display locations are false;
|
||||||
|
*/
|
||||||
|
public static boolean validatePropertySettings(
|
||||||
|
StructuredPropertySettings settings, boolean shouldThrow) {
|
||||||
|
if (settings.isIsHidden()) {
|
||||||
|
if (settings.isShowInSearchFilters()
|
||||||
|
|| settings.isShowInAssetSummary()
|
||||||
|
|| settings.isShowAsAssetBadge()) {
|
||||||
|
if (shouldThrow) {
|
||||||
|
throw new IllegalArgumentException(INVALID_SETTINGS_MESSAGE);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,6 +363,8 @@ public class Constants {
|
|||||||
// Structured Property
|
// Structured Property
|
||||||
public static final String STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME = "propertyDefinition";
|
public static final String STRUCTURED_PROPERTY_DEFINITION_ASPECT_NAME = "propertyDefinition";
|
||||||
public static final String STRUCTURED_PROPERTY_KEY_ASPECT_NAME = "structuredPropertyKey";
|
public static final String STRUCTURED_PROPERTY_KEY_ASPECT_NAME = "structuredPropertyKey";
|
||||||
|
public static final String STRUCTURED_PROPERTY_SETTINGS_ASPECT_NAME =
|
||||||
|
"structuredPropertySettings";
|
||||||
|
|
||||||
// Form
|
// Form
|
||||||
public static final String FORM_INFO_ASPECT_NAME = "formInfo";
|
public static final String FORM_INFO_ASPECT_NAME = "formInfo";
|
||||||
|
@ -118,11 +118,13 @@ class StructuredProperties(ConfigModel):
|
|||||||
@property
|
@property
|
||||||
def fqn(self) -> str:
|
def fqn(self) -> str:
|
||||||
assert self.urn is not None
|
assert self.urn is not None
|
||||||
return (
|
id = Urn.create_from_string(self.urn).get_entity_id()[0]
|
||||||
self.qualified_name
|
if self.qualified_name is not None:
|
||||||
or self.id
|
# ensure that qualified name and ID match
|
||||||
or Urn.from_string(self.urn).get_entity_id()[0]
|
assert (
|
||||||
)
|
self.qualified_name == id
|
||||||
|
), "ID in the urn and the qualified_name must match"
|
||||||
|
return id
|
||||||
|
|
||||||
@validator("urn", pre=True, always=True)
|
@validator("urn", pre=True, always=True)
|
||||||
def urn_must_be_present(cls, v, values):
|
def urn_must_be_present(cls, v, values):
|
||||||
|
@ -89,25 +89,25 @@ record StructuredPropertyDefinition {
|
|||||||
version: optional string
|
version: optional string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created Audit stamp
|
* Created Audit stamp
|
||||||
*/
|
*/
|
||||||
@Searchable = {
|
@Searchable = {
|
||||||
"/time": {
|
"/time": {
|
||||||
"fieldName": "createdTime",
|
"fieldName": "createdTime",
|
||||||
"fieldType": "DATETIME"
|
"fieldType": "DATETIME"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
created: optional AuditStamp
|
created: optional AuditStamp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created Audit stamp
|
* Last Modified Audit stamp
|
||||||
*/
|
*/
|
||||||
@Searchable = {
|
@Searchable = {
|
||||||
"/time": {
|
"/time": {
|
||||||
"fieldName": "lastModified",
|
"fieldName": "lastModified",
|
||||||
"fieldType": "DATETIME"
|
"fieldType": "DATETIME"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastModified: optional AuditStamp
|
lastModified: optional AuditStamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
namespace com.linkedin.structured
|
||||||
|
|
||||||
|
import com.linkedin.common.AuditStamp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings specific to a structured property entity
|
||||||
|
*/
|
||||||
|
@Aspect = {
|
||||||
|
"name": "structuredPropertySettings"
|
||||||
|
}
|
||||||
|
record StructuredPropertySettings {
|
||||||
|
/**
|
||||||
|
* Whether or not this asset should be hidden in the main application
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"fieldType": "BOOLEAN"
|
||||||
|
}
|
||||||
|
isHidden: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this asset should be displayed as a search filter
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"fieldType": "BOOLEAN"
|
||||||
|
}
|
||||||
|
showInSearchFilters: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this asset should be displayed in the asset sidebar
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"fieldType": "BOOLEAN"
|
||||||
|
}
|
||||||
|
showInAssetSummary: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this asset should be displayed as an asset badge on other
|
||||||
|
* asset's headers
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"fieldType": "BOOLEAN"
|
||||||
|
}
|
||||||
|
showAsAssetBadge: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this asset should be displayed as a column in the schema field table
|
||||||
|
* in a Dataset's "Columns" tab.
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"fieldType": "BOOLEAN"
|
||||||
|
}
|
||||||
|
showInColumnsTable: boolean = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last Modified Audit stamp
|
||||||
|
*/
|
||||||
|
@Searchable = {
|
||||||
|
"/time": {
|
||||||
|
"fieldName": "lastModifiedSettings",
|
||||||
|
"fieldType": "DATETIME"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastModified: optional AuditStamp
|
||||||
|
}
|
@ -602,6 +602,7 @@ entities:
|
|||||||
keyAspect: structuredPropertyKey
|
keyAspect: structuredPropertyKey
|
||||||
aspects:
|
aspects:
|
||||||
- propertyDefinition
|
- propertyDefinition
|
||||||
|
- structuredPropertySettings
|
||||||
- institutionalMemory
|
- institutionalMemory
|
||||||
- status
|
- status
|
||||||
- name: form
|
- name: form
|
||||||
|
Loading…
x
Reference in New Issue
Block a user