From 8cae5ead5cdc4b17e502ab4ed978b4f25afe920a Mon Sep 17 00:00:00 2001 From: NoahFournier <63198198+NoahFournier@users.noreply.github.com> Date: Mon, 23 May 2022 16:37:07 +0100 Subject: [PATCH 01/18] feat(graphql): add MutableType.batchUpdate method --- .../linkedin/datahub/graphql/types/MutableType.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index 6b5a349e73d476..3e7317792dcd4e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -24,4 +24,14 @@ public interface MutableType { * @param context the {@link QueryContext} corresponding to the request. */ T update(@Nonnull final String urn, @Nonnull final I input, @Nonnull final QueryContext context) throws Exception; + + /** + * Update many entities + * + * @param input input type + * @param context the {@link QueryContext} corresponding to the request. + */ + default T batchUpdate(@Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { + return null; + } } From c40c6726caf33d50a258baa682c80a251e704535 Mon Sep 17 00:00:00 2001 From: NoahFournier <63198198+NoahFournier@users.noreply.github.com> Date: Mon, 23 May 2022 16:41:19 +0100 Subject: [PATCH 02/18] feat(graphql): add MutableTypeBatchResolver.java --- .../mutate/MutableTypeBatchResolver.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java new file mode 100644 index 00000000000000..e3bda8d9c776fa --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java @@ -0,0 +1,51 @@ +package com.linkedin.datahub.graphql.resolvers.mutate; + +import com.codahale.metrics.Timer; +import com.linkedin.datahub.graphql.exception.AuthorizationException; +import com.linkedin.datahub.graphql.types.MutableType; +import com.linkedin.metadata.utils.metrics.MetricUtils; +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.*; + + +/** + * Generic GraphQL resolver responsible for performing updates against particular types. + * + * @param the generated GraphQL POJO corresponding to the input type. + * @param the generated GraphQL POJO corresponding to the return type. + */ +public class MutableTypeBatchResolver implements DataFetcher> { + + private static final Logger _logger = LoggerFactory.getLogger(MutableTypeResolverBatch.class.getName()); + + private final MutableType _mutableType; + + public MutableTypeResolverBatch(final MutableType mutableType) { + _mutableType = mutableType; + } + + @Override + public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + final I[] inputs = bindArgument(environment.getArgument("inputs"), _mutableType.arrayInputClass()); + + return CompletableFuture.supplyAsync(() -> { + Timer.Context timer = MetricUtils.timer(this.getClass(), "batchMutate").time(); + + try { + return _mutableType.batchUpdate(inputs, environment.getContext()); + } catch (AuthorizationException e) { + throw e; + } catch (Exception e) { + _logger.error("Failed to perform batchUpdate", e); + throw new IllegalArgumentException(e); + } finally { + timer.stop(); + } + }); + } +} From 6cbdda860f6373f0deb5fe3a8a2ab3df6e52b849 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Tue, 24 May 2022 11:33:12 +0100 Subject: [PATCH 03/18] feat(graphql): add MutableType.arrayInputClass method --- .../java/com/linkedin/datahub/graphql/types/MutableType.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index 3e7317792dcd4e..aa3e28d1850b92 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -15,6 +15,10 @@ public interface MutableType { */ Class inputClass(); + default Class arrayInputClass() throws UnsupportedOperationException { + throw new UnsupportedOperationException(this.getClass().getName() + " does not implement arrayInputClass method"); + } + /** * Update an entity by urn From 6076b0c5ed70f4271e522f8ef46bd7ed4c6ae631 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Tue, 24 May 2022 11:35:37 +0100 Subject: [PATCH 04/18] fix(graphql): correct typos --- .../graphql/resolvers/mutate/MutableTypeBatchResolver.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java index e3bda8d9c776fa..879d7070d61d31 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java @@ -21,11 +21,11 @@ */ public class MutableTypeBatchResolver implements DataFetcher> { - private static final Logger _logger = LoggerFactory.getLogger(MutableTypeResolverBatch.class.getName()); + private static final Logger _logger = LoggerFactory.getLogger(MutableTypeBatchResolver.class.getName()); - private final MutableType _mutableType; + private final MutableType _mutableType; - public MutableTypeResolverBatch(final MutableType mutableType) { + public MutableTypeBatchResolver(final MutableType mutableType) { _mutableType = mutableType; } From 87f17afc081b009fda203e4697309a8e236b32d7 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Tue, 24 May 2022 11:37:41 +0100 Subject: [PATCH 05/18] fix(graphql): throw exception when batchUpdate is called without being implemented --- .../java/com/linkedin/datahub/graphql/types/MutableType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index aa3e28d1850b92..b30f593f50741a 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -36,6 +36,6 @@ default Class arrayInputClass() throws UnsupportedOperationException { * @param context the {@link QueryContext} corresponding to the request. */ default T batchUpdate(@Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { - return null; + throw new UnsupportedOperationException(this.getClass().getName() + " does nto implement batchUpdate method"); } } From 88c046ba51e8d0621069b88d1211d1354c6455d7 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Wed, 25 May 2022 10:00:41 +0100 Subject: [PATCH 06/18] fix(graphql): fix typo --- .../java/com/linkedin/datahub/graphql/types/MutableType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index b30f593f50741a..b7e2e473d1f8e9 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -36,6 +36,6 @@ default Class arrayInputClass() throws UnsupportedOperationException { * @param context the {@link QueryContext} corresponding to the request. */ default T batchUpdate(@Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { - throw new UnsupportedOperationException(this.getClass().getName() + " does nto implement batchUpdate method"); + throw new UnsupportedOperationException(this.getClass().getName() + " does not implement batchUpdate method"); } } From ad65a42c9f157b97908d67cf2a420ee2f596c3e6 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Wed, 25 May 2022 10:26:12 +0100 Subject: [PATCH 07/18] feat(graphql): implement arrayInputClass for mutable types --- .../com/linkedin/datahub/graphql/types/chart/ChartType.java | 3 +++ .../datahub/graphql/types/corpgroup/CorpGroupType.java | 3 +++ .../linkedin/datahub/graphql/types/corpuser/CorpUserType.java | 3 +++ .../datahub/graphql/types/dashboard/DashboardType.java | 3 +++ .../linkedin/datahub/graphql/types/dataflow/DataFlowType.java | 3 +++ .../linkedin/datahub/graphql/types/datajob/DataJobType.java | 3 +++ .../linkedin/datahub/graphql/types/dataset/DatasetType.java | 3 +++ .../linkedin/datahub/graphql/types/notebook/NotebookType.java | 3 +++ .../java/com/linkedin/datahub/graphql/types/tag/TagType.java | 3 +++ 9 files changed, 27 insertions(+) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java index 53f04b193adc84..8d60cfa492e756 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java @@ -86,6 +86,9 @@ public Class inputClass() { return ChartUpdateInput.class; } + @Override + public Class arrayInputClass() { return ChartUpdateInput[].class; } + @Override public EntityType type() { return EntityType.CHART; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java index e0feb3c903c76c..3f687e25f933d0 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java @@ -61,6 +61,9 @@ public Class inputClass() { return CorpGroupUpdateInput.class; } + @Override + public Class arrayInputClass() { return CorpGroupUpdateInput[].class; } + @Override public EntityType type() { return EntityType.CORP_GROUP; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java index 06c5245d4b6573..3ee89512a76a15 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java @@ -121,6 +121,9 @@ public Class inputClass() { return CorpUserUpdateInput.class; } + @Override + public Class arrayInputClass() { return CorpUserUpdateInput[].class; } + @Override public CorpUser update(@Nonnull String urn, @Nonnull CorpUserUpdateInput input, @Nonnull QueryContext context) throws Exception { if (isAuthorizedToUpdate(urn, input, context)) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java index 4ee1c8e28808ac..691308a952d6c6 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java @@ -87,6 +87,9 @@ public Class inputClass() { return DashboardUpdateInput.class; } + @Override + public Class arrayInputClass() { return DashboardUpdateInput[].class; } + @Override public EntityType type() { return EntityType.DASHBOARD; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java index 57e03f16061c88..88846ae535670e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java @@ -99,6 +99,9 @@ public Class inputClass() { return DataFlowUpdateInput.class; } + @Override + public Class arrayInputClass() { return DataFlowUpdateInput[].class; } + @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java index 8a5d74faf93497..83a6e232308f0e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java @@ -100,6 +100,9 @@ public Class inputClass() { return DataJobUpdateInput.class; } + @Override + public Class arrayInputClass() { return DataJobUpdateInput[].class; } + @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index ca123bb43c063e..b1539578ad4700 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -98,6 +98,9 @@ public Class inputClass() { return DatasetUpdateInput.class; } + @Override + public Class arrayInputClass() { return DatasetUpdateInput[].class; } + @Override public EntityType type() { return EntityType.DATASET; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java index ba715d990e8b0c..327a3b1edfce47 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java @@ -163,6 +163,9 @@ public Class inputClass() { return NotebookUpdateInput.class; } + @Override + public Class arrayInputClass() { return NotebookUpdateInput[].class; } + @Override public Notebook update(@Nonnull String urn, @Nonnull NotebookUpdateInput input, @Nonnull QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java index 41ae275f4242bf..4cd95c57b07698 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java @@ -76,6 +76,9 @@ public Class inputClass() { return TagUpdateInput.class; } + @Override + public Class arrayInputClass() { return TagUpdateInput[].class; } + @Override public List> batchLoad(final List urns, final QueryContext context) { From 4ac9b6f683013d03f5d0368d4763fdb4dd9119d7 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Wed, 25 May 2022 14:37:03 +0100 Subject: [PATCH 08/18] test(graphql): add failure tests for MutableTypeBatchResolver --- .../mutate/MutableTypeBatchResolverTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java new file mode 100644 index 00000000000000..5b353d75f38951 --- /dev/null +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java @@ -0,0 +1,53 @@ +package com.linkedin.datahub.graphql.resolvers.mutate; + +import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.exception.AuthorizationException; +import com.linkedin.datahub.graphql.generated.DatasetUpdateInput; +import com.linkedin.datahub.graphql.types.MutableType; +import com.linkedin.datahub.graphql.types.dataset.DatasetType; +import com.linkedin.entity.client.EntityClient; +import com.linkedin.entity.client.RestliEntityClient; +import graphql.schema.DataFetchingEnvironment; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +import java.util.concurrent.CompletionException; + +import static com.linkedin.datahub.graphql.TestUtils.*; +import static org.testng.Assert.*; + +public class MutableTypeBatchResolverTest { + + private static final DatasetUpdateInput[] TEST_INPUTS = new DatasetUpdateInput[]{ + new DatasetUpdateInput(), new DatasetUpdateInput() + }; + + @Test + public void testGetUnsupportedOperation() throws Exception { + EntityClient mockClient = Mockito.mock(RestliEntityClient.class); + MutableType mutableType = new DatasetType(mockClient); + + MutableTypeBatchResolver resolver = new MutableTypeBatchResolver(mutableType); + + DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class); + Mockito.when(mockEnv.getArgument(Mockito.eq("inputs"))).thenReturn(TEST_INPUTS); + QueryContext mockContext = getMockAllowContext(); + Mockito.when(mockEnv.getContext()).thenReturn(mockContext); + + assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); + } + + @Test + public void testGetFailureUnauthorized() throws Exception { + EntityClient mockClient = Mockito.mock(RestliEntityClient.class); + MutableType mutableType = new DatasetType(mockClient); + + MutableTypeBatchResolver resolver = new MutableTypeBatchResolver(mutableType); + + DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class); + QueryContext mockContext = getMockDenyContext(); + Mockito.when(mockEnv.getContext()).thenReturn(mockContext); + + assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); + } +} From 759a9b052723f2ef53d8bf91abe2dfa9cd50e256 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 8 Jul 2022 14:41:58 +0100 Subject: [PATCH 09/18] feat(graphql): add batchUpdate support for Datasets --- .../datahub/graphql/GmsGraphQLEngine.java | 4 +- .../mutate/MutableTypeBatchResolver.java | 13 +++++-- .../datahub/graphql/types/MutableType.java | 4 +- .../graphql/types/dataset/DatasetType.java | 39 ++++++++++++++++--- .../src/main/resources/entity.graphql | 5 +++ 5 files changed, 54 insertions(+), 11 deletions(-) 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 3eefd597583d4f..526077c3be4335 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 @@ -135,15 +135,16 @@ import com.linkedin.datahub.graphql.resolvers.mutate.AddTagsResolver; import com.linkedin.datahub.graphql.resolvers.mutate.AddTermResolver; import com.linkedin.datahub.graphql.resolvers.mutate.AddTermsResolver; +import com.linkedin.datahub.graphql.resolvers.mutate.MutableTypeBatchResolver; import com.linkedin.datahub.graphql.resolvers.mutate.MutableTypeResolver; import com.linkedin.datahub.graphql.resolvers.mutate.RemoveLinkResolver; import com.linkedin.datahub.graphql.resolvers.mutate.RemoveOwnerResolver; import com.linkedin.datahub.graphql.resolvers.mutate.RemoveTagResolver; import com.linkedin.datahub.graphql.resolvers.mutate.RemoveTermResolver; import com.linkedin.datahub.graphql.resolvers.mutate.UpdateDescriptionResolver; -import com.linkedin.datahub.graphql.resolvers.operation.ReportOperationResolver; import com.linkedin.datahub.graphql.resolvers.mutate.UpdateNameResolver; import com.linkedin.datahub.graphql.resolvers.mutate.UpdateParentNodeResolver; +import com.linkedin.datahub.graphql.resolvers.operation.ReportOperationResolver; import com.linkedin.datahub.graphql.resolvers.policy.DeletePolicyResolver; import com.linkedin.datahub.graphql.resolvers.policy.GetGrantedPrivilegesResolver; import com.linkedin.datahub.graphql.resolvers.policy.ListPoliciesResolver; @@ -675,6 +676,7 @@ private String getUrnField(DataFetchingEnvironment env) { private void configureMutationResolvers(final RuntimeWiring.Builder builder) { builder.type("Mutation", typeWiring -> typeWiring .dataFetcher("updateDataset", new MutableTypeResolver<>(datasetType)) + .dataFetcher("updateDatasets", new MutableTypeBatchResolver<>(datasetType)) .dataFetcher("createTag", new CreateTagResolver(this.entityClient)) .dataFetcher("updateTag", new MutableTypeResolver<>(tagType)) .dataFetcher("setTagColor", new SetTagColorResolver(entityClient, entityService)) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java index 879d7070d61d31..d4f6981d31cd84 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java @@ -6,6 +6,8 @@ import com.linkedin.metadata.utils.metrics.MetricUtils; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; + +import java.util.List; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +21,7 @@ * @param the generated GraphQL POJO corresponding to the input type. * @param the generated GraphQL POJO corresponding to the return type. */ -public class MutableTypeBatchResolver implements DataFetcher> { +public class MutableTypeBatchResolver implements DataFetcher>> { private static final Logger _logger = LoggerFactory.getLogger(MutableTypeBatchResolver.class.getName()); @@ -30,14 +32,19 @@ public MutableTypeBatchResolver(final MutableType mutableType) { } @Override - public CompletableFuture get(DataFetchingEnvironment environment) throws Exception { + public CompletableFuture> get(DataFetchingEnvironment environment) throws Exception { + final String[] urns = bindArgument(environment.getArgument("urns"), String[].class); final I[] inputs = bindArgument(environment.getArgument("inputs"), _mutableType.arrayInputClass()); + if (urns.length != inputs.length) { + throw new IllegalArgumentException("Batch updates must contain as many URNs as inputs."); + } + return CompletableFuture.supplyAsync(() -> { Timer.Context timer = MetricUtils.timer(this.getClass(), "batchMutate").time(); try { - return _mutableType.batchUpdate(inputs, environment.getContext()); + return _mutableType.batchUpdate(urns, inputs, environment.getContext()); } catch (AuthorizationException e) { throw e; } catch (Exception e) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index b7e2e473d1f8e9..885b3249e5972d 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -1,7 +1,9 @@ package com.linkedin.datahub.graphql.types; import com.linkedin.datahub.graphql.QueryContext; + import javax.annotation.Nonnull; +import java.util.List; /** * Graph type that can be updated. @@ -35,7 +37,7 @@ default Class arrayInputClass() throws UnsupportedOperationException { * @param input input type * @param context the {@link QueryContext} corresponding to the request. */ - default T batchUpdate(@Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { + default List batchUpdate(@Nonnull final String[] urns, @Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { throw new UnsupportedOperationException(this.getClass().getName() + " does not implement batchUpdate method"); } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index 8745cc3ee5a820..807c16125f42fb 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -11,14 +11,14 @@ import com.linkedin.datahub.graphql.authorization.ConjunctivePrivilegeGroup; import com.linkedin.datahub.graphql.authorization.DisjunctivePrivilegeGroup; import com.linkedin.datahub.graphql.exception.AuthorizationException; +import com.linkedin.datahub.graphql.generated.DatasetUpdateInput; +import com.linkedin.datahub.graphql.generated.Dataset; +import com.linkedin.datahub.graphql.generated.FacetFilterInput; +import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.AutoCompleteResults; -import com.linkedin.datahub.graphql.generated.BrowsePath; import com.linkedin.datahub.graphql.generated.BrowseResults; -import com.linkedin.datahub.graphql.generated.Dataset; -import com.linkedin.datahub.graphql.generated.DatasetUpdateInput; +import com.linkedin.datahub.graphql.generated.BrowsePath; import com.linkedin.datahub.graphql.generated.Entity; -import com.linkedin.datahub.graphql.generated.EntityType; -import com.linkedin.datahub.graphql.generated.FacetFilterInput; import com.linkedin.datahub.graphql.generated.SearchResults; import com.linkedin.datahub.graphql.resolvers.ResolverUtils; import com.linkedin.datahub.graphql.types.BrowsableEntityType; @@ -39,8 +39,11 @@ import com.linkedin.metadata.search.SearchResult; import com.linkedin.mxe.MetadataChangeProposal; import com.linkedin.r2.RemoteInvocationException; +import graphql.com.google.common.collect.Streams; import graphql.execution.DataFetcherResult; + import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -100,7 +103,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return DatasetUpdateInput[].class; } + public Class arrayInputClass() { + return DatasetUpdateInput[].class; + } @Override public EntityType type() { @@ -187,6 +192,28 @@ public List browsePaths(@Nonnull String urn, @Nonnull final QueryCon return BrowsePathsMapper.map(result); } + @Override + public List batchUpdate(@Nonnull String[] urns, @Nonnull DatasetUpdateInput[] inputs, @Nonnull QueryContext context) throws Exception { + final CorpuserUrn actor = CorpuserUrn.createFromString(context.getAuthentication().getActor().toUrnStr()); + + final Collection proposals = Streams.zip(Arrays.stream(urns), Arrays.stream(inputs), (urn, input) -> { + if (isAuthorized(urn, input, context)) { + Collection datasetProposals = DatasetUpdateInputMapper.map(input, actor); + datasetProposals.forEach(proposal -> proposal.setEntityUrn(UrnUtils.getUrn(urn))); + return datasetProposals; + } + throw new AuthorizationException("Unauthorized to perform this action. Please contact your Datahub administator."); + }).flatMap(Collection::stream).collect(Collectors.toList()); + + try { + _entityClient.batchIngestProposals(proposals, context.getAuthentication()); + } catch (RemoteInvocationException e) { + throw new RuntimeException(String.format("Failed to write entity with urn %s", urns), e); + } + + return batchLoad(Arrays.asList(urns), context).stream().map(DataFetcherResult::getData).collect(Collectors.toList()); + } + @Override public Dataset update(@Nonnull String urn, @Nonnull DatasetUpdateInput input, @Nonnull QueryContext context) throws Exception { if (isAuthorized(urn, input, context)) { diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index b0c7a9bd7b1282..a13da99709d655 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -185,6 +185,11 @@ type Mutation { """ updateDataset(urn: String!, input: DatasetUpdateInput!): Dataset + """ + Update the metadata about a batch of Datasets + """ + updateDatasets(urns: [String!]!, inputs: [DatasetUpdateInput!]!): [Dataset] + """ Update the metadata about a particular Chart """ From 7ba0d9741b5acbe7caeb1480ae6f5f9b5c99d95b Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 8 Jul 2022 14:42:23 +0100 Subject: [PATCH 10/18] fix(graphql): fix graphql checktyle violations --- .../com/linkedin/datahub/graphql/types/chart/ChartType.java | 4 +++- .../datahub/graphql/types/corpgroup/CorpGroupType.java | 4 +++- .../datahub/graphql/types/corpuser/CorpUserType.java | 4 +++- .../datahub/graphql/types/dashboard/DashboardType.java | 4 +++- .../datahub/graphql/types/dataflow/DataFlowType.java | 5 +++-- .../linkedin/datahub/graphql/types/datajob/DataJobType.java | 4 +++- .../datahub/graphql/types/notebook/NotebookType.java | 4 +++- .../java/com/linkedin/datahub/graphql/types/tag/TagType.java | 4 +++- 8 files changed, 24 insertions(+), 9 deletions(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java index 8d60cfa492e756..f2eeda6d820bc9 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java @@ -87,7 +87,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return ChartUpdateInput[].class; } + public Class arrayInputClass() { + return ChartUpdateInput[].class; + } @Override public EntityType type() { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java index 3f687e25f933d0..2e93eb31ad2b6c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java @@ -62,7 +62,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return CorpGroupUpdateInput[].class; } + public Class arrayInputClass() { + return CorpGroupUpdateInput[].class; + } @Override public EntityType type() { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java index 3ee89512a76a15..ba8101c2e3c7ae 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java @@ -122,7 +122,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return CorpUserUpdateInput[].class; } + public Class arrayInputClass() { + return CorpUserUpdateInput[].class; + } @Override public CorpUser update(@Nonnull String urn, @Nonnull CorpUserUpdateInput input, @Nonnull QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java index 691308a952d6c6..f7000bb58b1bdc 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java @@ -88,7 +88,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return DashboardUpdateInput[].class; } + public Class arrayInputClass() { + return DashboardUpdateInput[].class; + } @Override public EntityType type() { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java index 88846ae535670e..da9c7a528e175a 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java @@ -100,8 +100,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return DataFlowUpdateInput[].class; } - + public Class arrayInputClass() { + return DataFlowUpdateInput[].class; + } @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java index 83a6e232308f0e..2715d6799b2b84 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java @@ -101,7 +101,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return DataJobUpdateInput[].class; } + public Class arrayInputClass() { + return DataJobUpdateInput[].class; + } @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java index 327a3b1edfce47..44d85516ce8972 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java @@ -164,7 +164,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return NotebookUpdateInput[].class; } + public Class arrayInputClass() { + return NotebookUpdateInput[].class; + } @Override public Notebook update(@Nonnull String urn, @Nonnull NotebookUpdateInput input, @Nonnull QueryContext context) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java index 4cd95c57b07698..8a92e97ccaf97b 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java @@ -77,7 +77,9 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { return TagUpdateInput[].class; } + public Class arrayInputClass() { + return TagUpdateInput[].class; + } @Override public List> batchLoad(final List urns, final QueryContext context) { From 9f5845f89bf7d7d732c5874b91b457266fa3b249 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 8 Jul 2022 14:59:42 +0100 Subject: [PATCH 11/18] fix(graphql): fix typo --- .../com/linkedin/datahub/graphql/types/dataset/DatasetType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index 807c16125f42fb..e5e3a6540b5d96 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -202,7 +202,7 @@ public List batchUpdate(@Nonnull String[] urns, @Nonnull DatasetUpdateI datasetProposals.forEach(proposal -> proposal.setEntityUrn(UrnUtils.getUrn(urn))); return datasetProposals; } - throw new AuthorizationException("Unauthorized to perform this action. Please contact your Datahub administator."); + throw new AuthorizationException("Unauthorized to perform this action. Please contact your Datahub administrator."); }).flatMap(Collection::stream).collect(Collectors.toList()); try { From db7cc510ea7c6591bd5f5e9d0407a9c8455d6c51 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Thu, 28 Jul 2022 15:41:25 +0100 Subject: [PATCH 12/18] Add BatchDatasetUpdateInput and BatchMutableType --- .../mutate/MutableTypeBatchResolver.java | 19 +++++--------- .../datahub/graphql/types/MutableType.java | 18 +------------ .../graphql/types/chart/ChartType.java | 5 ---- .../types/corpgroup/CorpGroupType.java | 6 ----- .../graphql/types/corpuser/CorpUserType.java | 5 ---- .../types/dashboard/DashboardType.java | 5 ---- .../graphql/types/dataflow/DataFlowType.java | 4 --- .../graphql/types/datajob/DataJobType.java | 5 ---- .../graphql/types/dataset/DatasetType.java | 26 ++++++++++--------- .../graphql/types/notebook/NotebookType.java | 5 ---- .../datahub/graphql/types/tag/TagType.java | 5 ---- .../src/main/resources/entity.graphql | 11 +++++++- .../mutate/MutableTypeBatchResolverTest.java | 25 ++---------------- 13 files changed, 34 insertions(+), 105 deletions(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java index d4f6981d31cd84..30bd940a7dfed4 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolver.java @@ -2,7 +2,7 @@ import com.codahale.metrics.Timer; import com.linkedin.datahub.graphql.exception.AuthorizationException; -import com.linkedin.datahub.graphql.types.MutableType; +import com.linkedin.datahub.graphql.types.BatchMutableType; import com.linkedin.metadata.utils.metrics.MetricUtils; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; @@ -21,30 +21,25 @@ * @param the generated GraphQL POJO corresponding to the input type. * @param the generated GraphQL POJO corresponding to the return type. */ -public class MutableTypeBatchResolver implements DataFetcher>> { +public class MutableTypeBatchResolver implements DataFetcher>> { private static final Logger _logger = LoggerFactory.getLogger(MutableTypeBatchResolver.class.getName()); - private final MutableType _mutableType; + private final BatchMutableType _batchMutableType; - public MutableTypeBatchResolver(final MutableType mutableType) { - _mutableType = mutableType; + public MutableTypeBatchResolver(final BatchMutableType batchMutableType) { + _batchMutableType = batchMutableType; } @Override public CompletableFuture> get(DataFetchingEnvironment environment) throws Exception { - final String[] urns = bindArgument(environment.getArgument("urns"), String[].class); - final I[] inputs = bindArgument(environment.getArgument("inputs"), _mutableType.arrayInputClass()); - - if (urns.length != inputs.length) { - throw new IllegalArgumentException("Batch updates must contain as many URNs as inputs."); - } + final B[] input = bindArgument(environment.getArgument("input"), _batchMutableType.batchInputClass()); return CompletableFuture.supplyAsync(() -> { Timer.Context timer = MetricUtils.timer(this.getClass(), "batchMutate").time(); try { - return _mutableType.batchUpdate(urns, inputs, environment.getContext()); + return _batchMutableType.batchUpdate(input, environment.getContext()); } catch (AuthorizationException e) { throw e; } catch (Exception e) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java index 885b3249e5972d..94f1200d3a7833 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/MutableType.java @@ -3,7 +3,6 @@ import com.linkedin.datahub.graphql.QueryContext; import javax.annotation.Nonnull; -import java.util.List; /** * Graph type that can be updated. @@ -11,16 +10,11 @@ * @param : The input type corresponding to the write. */ public interface MutableType { - /** * Returns generated GraphQL class associated with the input type */ - Class inputClass(); - - default Class arrayInputClass() throws UnsupportedOperationException { - throw new UnsupportedOperationException(this.getClass().getName() + " does not implement arrayInputClass method"); - } + Class inputClass(); /** * Update an entity by urn @@ -30,14 +24,4 @@ default Class arrayInputClass() throws UnsupportedOperationException { * @param context the {@link QueryContext} corresponding to the request. */ T update(@Nonnull final String urn, @Nonnull final I input, @Nonnull final QueryContext context) throws Exception; - - /** - * Update many entities - * - * @param input input type - * @param context the {@link QueryContext} corresponding to the request. - */ - default List batchUpdate(@Nonnull final String[] urns, @Nonnull final I[] input, @Nonnull final QueryContext context) throws Exception { - throw new UnsupportedOperationException(this.getClass().getName() + " does not implement batchUpdate method"); - } } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java index f2eeda6d820bc9..53f04b193adc84 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/chart/ChartType.java @@ -86,11 +86,6 @@ public Class inputClass() { return ChartUpdateInput.class; } - @Override - public Class arrayInputClass() { - return ChartUpdateInput[].class; - } - @Override public EntityType type() { return EntityType.CHART; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java index 2e93eb31ad2b6c..5163d35343c9a8 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java @@ -60,12 +60,6 @@ public Class objectClass() { public Class inputClass() { return CorpGroupUpdateInput.class; } - - @Override - public Class arrayInputClass() { - return CorpGroupUpdateInput[].class; - } - @Override public EntityType type() { return EntityType.CORP_GROUP; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java index ba8101c2e3c7ae..06c5245d4b6573 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpuser/CorpUserType.java @@ -121,11 +121,6 @@ public Class inputClass() { return CorpUserUpdateInput.class; } - @Override - public Class arrayInputClass() { - return CorpUserUpdateInput[].class; - } - @Override public CorpUser update(@Nonnull String urn, @Nonnull CorpUserUpdateInput input, @Nonnull QueryContext context) throws Exception { if (isAuthorizedToUpdate(urn, input, context)) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java index f7000bb58b1bdc..4ee1c8e28808ac 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dashboard/DashboardType.java @@ -87,11 +87,6 @@ public Class inputClass() { return DashboardUpdateInput.class; } - @Override - public Class arrayInputClass() { - return DashboardUpdateInput[].class; - } - @Override public EntityType type() { return EntityType.DASHBOARD; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java index da9c7a528e175a..57e03f16061c88 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataflow/DataFlowType.java @@ -99,10 +99,6 @@ public Class inputClass() { return DataFlowUpdateInput.class; } - @Override - public Class arrayInputClass() { - return DataFlowUpdateInput[].class; - } @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java index 2715d6799b2b84..8a5d74faf93497 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/datajob/DataJobType.java @@ -100,11 +100,6 @@ public Class inputClass() { return DataJobUpdateInput.class; } - @Override - public Class arrayInputClass() { - return DataJobUpdateInput[].class; - } - @Override public List> batchLoad(final List urnStrs, @Nonnull final QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index e5e3a6540b5d96..873155b5b18fee 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -20,9 +20,10 @@ import com.linkedin.datahub.graphql.generated.BrowsePath; import com.linkedin.datahub.graphql.generated.Entity; import com.linkedin.datahub.graphql.generated.SearchResults; +import com.linkedin.datahub.graphql.generated.BatchDatasetUpdateInput; import com.linkedin.datahub.graphql.resolvers.ResolverUtils; +import com.linkedin.datahub.graphql.types.BatchMutableType; import com.linkedin.datahub.graphql.types.BrowsableEntityType; -import com.linkedin.datahub.graphql.types.MutableType; import com.linkedin.datahub.graphql.types.SearchableEntityType; import com.linkedin.datahub.graphql.types.dataset.mappers.DatasetMapper; import com.linkedin.datahub.graphql.types.dataset.mappers.DatasetUpdateInputMapper; @@ -39,7 +40,6 @@ import com.linkedin.metadata.search.SearchResult; import com.linkedin.mxe.MetadataChangeProposal; import com.linkedin.r2.RemoteInvocationException; -import graphql.com.google.common.collect.Streams; import graphql.execution.DataFetcherResult; import java.util.ArrayList; @@ -59,7 +59,7 @@ public class DatasetType implements SearchableEntityType, BrowsableEntityType, - MutableType { + BatchMutableType { private static final Set ASPECTS_TO_RESOLVE = ImmutableSet.of( DATASET_KEY_ASPECT_NAME, @@ -103,8 +103,8 @@ public Class inputClass() { } @Override - public Class arrayInputClass() { - return DatasetUpdateInput[].class; + public Class batchInputClass() { + return BatchDatasetUpdateInput[].class; } @Override @@ -193,25 +193,27 @@ public List browsePaths(@Nonnull String urn, @Nonnull final QueryCon } @Override - public List batchUpdate(@Nonnull String[] urns, @Nonnull DatasetUpdateInput[] inputs, @Nonnull QueryContext context) throws Exception { + public List batchUpdate(@Nonnull BatchDatasetUpdateInput[] input, @Nonnull QueryContext context) throws Exception { final CorpuserUrn actor = CorpuserUrn.createFromString(context.getAuthentication().getActor().toUrnStr()); - final Collection proposals = Streams.zip(Arrays.stream(urns), Arrays.stream(inputs), (urn, input) -> { - if (isAuthorized(urn, input, context)) { - Collection datasetProposals = DatasetUpdateInputMapper.map(input, actor); - datasetProposals.forEach(proposal -> proposal.setEntityUrn(UrnUtils.getUrn(urn))); + final Collection proposals = Arrays.stream(input).map(updateInput -> { + if (isAuthorized(updateInput.getUrn(), updateInput.getUpdate(), context)) { + Collection datasetProposals = DatasetUpdateInputMapper.map(updateInput.getUpdate(), actor); + datasetProposals.forEach(proposal -> proposal.setEntityUrn(UrnUtils.getUrn(updateInput.getUrn()))); return datasetProposals; } - throw new AuthorizationException("Unauthorized to perform this action. Please contact your Datahub administrator."); + throw new AuthorizationException("Unauthorized to perform this action. Please contact your DataHub administrator."); }).flatMap(Collection::stream).collect(Collectors.toList()); + final List urns = Arrays.stream(input).map(BatchDatasetUpdateInput::getUrn).collect(Collectors.toList()); + try { _entityClient.batchIngestProposals(proposals, context.getAuthentication()); } catch (RemoteInvocationException e) { throw new RuntimeException(String.format("Failed to write entity with urn %s", urns), e); } - return batchLoad(Arrays.asList(urns), context).stream().map(DataFetcherResult::getData).collect(Collectors.toList()); + return batchLoad(urns, context).stream().map(DataFetcherResult::getData).collect(Collectors.toList()); } @Override diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java index 44d85516ce8972..ba715d990e8b0c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/notebook/NotebookType.java @@ -163,11 +163,6 @@ public Class inputClass() { return NotebookUpdateInput.class; } - @Override - public Class arrayInputClass() { - return NotebookUpdateInput[].class; - } - @Override public Notebook update(@Nonnull String urn, @Nonnull NotebookUpdateInput input, @Nonnull QueryContext context) throws Exception { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java index 8a92e97ccaf97b..41ae275f4242bf 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/tag/TagType.java @@ -76,11 +76,6 @@ public Class inputClass() { return TagUpdateInput.class; } - @Override - public Class arrayInputClass() { - return TagUpdateInput[].class; - } - @Override public List> batchLoad(final List urns, final QueryContext context) { diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index 51b8715ab79c97..b279f905387613 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -188,7 +188,7 @@ type Mutation { """ Update the metadata about a batch of Datasets """ - updateDatasets(urns: [String!]!, inputs: [DatasetUpdateInput!]!): [Dataset] + updateDatasets(input: [BatchDatasetUpdateInput!]!): [Dataset] """ Update the metadata about a particular Chart @@ -3562,6 +3562,15 @@ input DatasetUpdateInput { editableProperties: DatasetEditablePropertiesUpdate } +""" +Arguments provided to batch update Dataset entities +""" +input BatchDatasetUpdateInput { + urn: String! + update: DatasetUpdateInput! +} + + """ Update to editable schema metadata of the dataset """ diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java index 5b353d75f38951..53c6edbe3b78f3 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java @@ -1,9 +1,7 @@ package com.linkedin.datahub.graphql.resolvers.mutate; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.exception.AuthorizationException; -import com.linkedin.datahub.graphql.generated.DatasetUpdateInput; -import com.linkedin.datahub.graphql.types.MutableType; +import com.linkedin.datahub.graphql.types.BatchMutableType; import com.linkedin.datahub.graphql.types.dataset.DatasetType; import com.linkedin.entity.client.EntityClient; import com.linkedin.entity.client.RestliEntityClient; @@ -18,29 +16,10 @@ public class MutableTypeBatchResolverTest { - private static final DatasetUpdateInput[] TEST_INPUTS = new DatasetUpdateInput[]{ - new DatasetUpdateInput(), new DatasetUpdateInput() - }; - - @Test - public void testGetUnsupportedOperation() throws Exception { - EntityClient mockClient = Mockito.mock(RestliEntityClient.class); - MutableType mutableType = new DatasetType(mockClient); - - MutableTypeBatchResolver resolver = new MutableTypeBatchResolver(mutableType); - - DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class); - Mockito.when(mockEnv.getArgument(Mockito.eq("inputs"))).thenReturn(TEST_INPUTS); - QueryContext mockContext = getMockAllowContext(); - Mockito.when(mockEnv.getContext()).thenReturn(mockContext); - - assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join()); - } - @Test public void testGetFailureUnauthorized() throws Exception { EntityClient mockClient = Mockito.mock(RestliEntityClient.class); - MutableType mutableType = new DatasetType(mockClient); + BatchMutableType mutableType = new DatasetType(mockClient); MutableTypeBatchResolver resolver = new MutableTypeBatchResolver(mutableType); From 20de27d7614a9c3881a79eb30a8f57d90111e253 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Thu, 28 Jul 2022 15:43:24 +0100 Subject: [PATCH 13/18] fix(graphql): Add BatchMutableType --- .../datahub/graphql/types/BatchMutableType.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/BatchMutableType.java diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/BatchMutableType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/BatchMutableType.java new file mode 100644 index 00000000000000..3bd8719a37abc4 --- /dev/null +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/BatchMutableType.java @@ -0,0 +1,16 @@ +package com.linkedin.datahub.graphql.types; + +import com.linkedin.datahub.graphql.QueryContext; + +import javax.annotation.Nonnull; +import java.util.List; + +public interface BatchMutableType extends MutableType { + default Class batchInputClass() throws UnsupportedOperationException { + throw new UnsupportedOperationException(this.getClass().getName() + " does not implement batchInputClass method"); + } + + default List batchUpdate(@Nonnull final B[] updateInput, QueryContext context) throws Exception { + throw new UnsupportedOperationException(this.getClass().getName() + " does not implement batchUpdate method"); + } +} From 38f995abb1dc0dca6fb5e1b5aa87482565d859e2 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Thu, 28 Jul 2022 15:45:13 +0100 Subject: [PATCH 14/18] fix(graphql): Revert whitespace change --- .../linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java index 5163d35343c9a8..e0feb3c903c76c 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/corpgroup/CorpGroupType.java @@ -60,6 +60,7 @@ public Class objectClass() { public Class inputClass() { return CorpGroupUpdateInput.class; } + @Override public EntityType type() { return EntityType.CORP_GROUP; From 98ce1d9c2f8f531a6b30f100dec3825a2c442c5e Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 29 Jul 2022 11:26:29 +0100 Subject: [PATCH 15/18] docs(graphql): Add field descriptions for BatchDatasetUpdateInput --- datahub-graphql-core/src/main/resources/entity.graphql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index b279f905387613..a7feec59ec17f9 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -3566,7 +3566,15 @@ input DatasetUpdateInput { Arguments provided to batch update Dataset entities """ input BatchDatasetUpdateInput { + + """ + Primary key of the Dataset to which the update will be applied + """ urn: String! + + """ + Arguments provided to update the Dataset + """ update: DatasetUpdateInput! } From 04562fc1f44255fccb2b60b7a1fceb520323dc7b Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 29 Jul 2022 11:28:43 +0100 Subject: [PATCH 16/18] fix(graphql): Use more generic Urn class instead of CorpuserUrn --- .../com/linkedin/datahub/graphql/types/dataset/DatasetType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index 873155b5b18fee..87b96f91aeda6e 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -194,7 +194,7 @@ public List browsePaths(@Nonnull String urn, @Nonnull final QueryCon @Override public List batchUpdate(@Nonnull BatchDatasetUpdateInput[] input, @Nonnull QueryContext context) throws Exception { - final CorpuserUrn actor = CorpuserUrn.createFromString(context.getAuthentication().getActor().toUrnStr()); + final Urn actor = Urn.createFromString(context.getAuthentication().getActor().toUrnStr()); final Collection proposals = Arrays.stream(input).map(updateInput -> { if (isAuthorized(updateInput.getUrn(), updateInput.getUpdate(), context)) { From 33a1957ce7b5d5977e0ca18fc8a8cb9c84f35665 Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Fri, 29 Jul 2022 18:00:31 +0100 Subject: [PATCH 17/18] test(graphql): Add MutableTypeBatchResolverTest success case --- .../mutate/MutableTypeBatchResolverTest.java | 143 +++++++++++++++++- 1 file changed, 141 insertions(+), 2 deletions(-) diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java index 53c6edbe3b78f3..e570d7403d5f2a 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java @@ -1,14 +1,34 @@ package com.linkedin.datahub.graphql.resolvers.mutate; +import com.datahub.authentication.Actor; +import com.datahub.authentication.ActorType; +import com.datahub.authentication.Authentication; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.linkedin.common.Deprecation; +import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; +import com.linkedin.datahub.graphql.generated.*; import com.linkedin.datahub.graphql.types.BatchMutableType; import com.linkedin.datahub.graphql.types.dataset.DatasetType; +import com.linkedin.entity.EntityResponse; +import com.linkedin.entity.EnvelopedAspect; +import com.linkedin.entity.EnvelopedAspectMap; import com.linkedin.entity.client.EntityClient; import com.linkedin.entity.client.RestliEntityClient; +import com.linkedin.metadata.Constants; +import com.linkedin.mxe.MetadataChangeProposal; import graphql.schema.DataFetchingEnvironment; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.testng.annotations.Test; +import com.linkedin.entity.Aspect; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; import java.util.concurrent.CompletionException; import static com.linkedin.datahub.graphql.TestUtils.*; @@ -16,12 +36,131 @@ public class MutableTypeBatchResolverTest { + private static final String TEST_DATASET_1_URN = "urn:li:dataset:id-1"; + private static final String TEST_DATASET_2_URN = "urn:li:dataset:id-2"; + private static final boolean TEST_DATASET_1_IS_DEPRECATED = true; + private static final boolean TEST_DATASET_2_IS_DEPRECATED = false; + private static final String TEST_DATASET_1_DEPRECATION_NOTE = "Test Deprecation Note"; + private static final String TEST_DATASET_2_DEPRECATION_NOTE = ""; + private static final Deprecation TEST_DATASET_1_DEPRECATION; + + static { + try { + TEST_DATASET_1_DEPRECATION = new Deprecation() + .setDeprecated(TEST_DATASET_1_IS_DEPRECATED) + .setNote(TEST_DATASET_1_DEPRECATION_NOTE) + .setActor(Urn.createFromString("urn:li:corpuser:datahub")); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private static final Deprecation TEST_DATASET_2_DEPRECATION; + + static { + try { + TEST_DATASET_2_DEPRECATION = new Deprecation() + .setDeprecated(TEST_DATASET_2_IS_DEPRECATED) + .setNote(TEST_DATASET_2_DEPRECATION_NOTE) + .setActor(Urn.createFromString("urn:li:corpuser:datahub")); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + @Test + public void testGetSuccess() throws Exception { + EntityClient mockClient = Mockito.mock(RestliEntityClient.class); + BatchMutableType batchMutableType = new DatasetType(mockClient); + + MutableTypeBatchResolver resolver = new MutableTypeBatchResolver<>(batchMutableType); + + List mockInputs = Arrays.asList( + new BatchDatasetUpdateInput.Builder() + .setUrn(TEST_DATASET_1_URN) + .setUpdate( + new DatasetUpdateInput.Builder() + .setDeprecation( + new DatasetDeprecationUpdate.Builder() + .setDeprecated(TEST_DATASET_1_IS_DEPRECATED) + .setNote(TEST_DATASET_1_DEPRECATION_NOTE) + .build() + ) + .build() + ) + .build(), + new BatchDatasetUpdateInput.Builder() + .setUrn(TEST_DATASET_2_URN) + .setUpdate( + new DatasetUpdateInput.Builder() + .setDeprecation( + new DatasetDeprecationUpdate.Builder() + .setDeprecated(TEST_DATASET_2_IS_DEPRECATED) + .setNote(TEST_DATASET_2_DEPRECATION_NOTE) + .build() + ) + .build() + ) + .build() + ); + + DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class); + Mockito.when(mockEnv.getArgument("input")).thenReturn(mockInputs); + QueryContext mockContext = getMockAllowContext(); + Mockito.when(mockEnv.getContext()).thenReturn(mockContext); + Authentication mockAuth = Mockito.mock(Authentication.class); + Mockito.when(mockContext.getAuthentication()).thenReturn(mockAuth); + Mockito.when(mockAuth.getActor()).thenReturn(new Actor(ActorType.USER, "datahub")); + + Urn datasetUrn1 = Urn.createFromString(TEST_DATASET_1_URN); + Urn datasetUrn2 = Urn.createFromString(TEST_DATASET_2_URN); + + Mockito.when(mockClient.batchGetV2(Mockito.eq(Constants.DATASET_ENTITY_NAME), + Mockito.eq(new HashSet<>(ImmutableSet.of(datasetUrn1, datasetUrn2))), + Mockito.any(), + Mockito.any(Authentication.class))) + .thenReturn(ImmutableMap.of( + datasetUrn1, + new EntityResponse() + .setEntityName(Constants.DATASET_ENTITY_NAME) + .setUrn(datasetUrn1) + .setAspects(new EnvelopedAspectMap(ImmutableMap.of( + Constants.DATASET_DEPRECATION_ASPECT_NAME, + new EnvelopedAspect().setValue(new Aspect(TEST_DATASET_1_DEPRECATION.data())) + ))), + datasetUrn2, + new EntityResponse() + .setEntityName(Constants.DATASET_ENTITY_NAME) + .setUrn(datasetUrn2) + .setAspects(new EnvelopedAspectMap(ImmutableMap.of( + Constants.DATASET_DEPRECATION_ASPECT_NAME, + new EnvelopedAspect().setValue(new Aspect(TEST_DATASET_2_DEPRECATION.data())) + ))) + )); + + List result = resolver.get(mockEnv).join(); + + ArgumentCaptor> changeProposalCaptor = ArgumentCaptor.forClass((Class) Collection.class); + Mockito.verify(mockClient, Mockito.times(1)).batchIngestProposals(changeProposalCaptor.capture(), Mockito.any()); + Mockito.verify(mockClient, Mockito.times(1)).batchGetV2( + Mockito.eq(Constants.DATASET_ENTITY_NAME), + Mockito.eq(ImmutableSet.of(datasetUrn1, datasetUrn2)), + // Dataset aspects to fetch are private, but aren't important for this test + Mockito.any(), + Mockito.any(Authentication.class) + ); + Collection changeProposals = changeProposalCaptor.getValue(); + + assertEquals(changeProposals.size(), 2); + assertEquals(result.size(), 2); + } + @Test public void testGetFailureUnauthorized() throws Exception { EntityClient mockClient = Mockito.mock(RestliEntityClient.class); - BatchMutableType mutableType = new DatasetType(mockClient); + BatchMutableType batchMutableType = new DatasetType(mockClient); - MutableTypeBatchResolver resolver = new MutableTypeBatchResolver(mutableType); + MutableTypeBatchResolver resolver = new MutableTypeBatchResolver<>(batchMutableType); DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class); QueryContext mockContext = getMockDenyContext(); From ba8b8b14e2b96fef2bfed285b8aae04181fa0a3b Mon Sep 17 00:00:00 2001 From: Noah Fournier Date: Tue, 2 Aug 2022 17:43:29 +0100 Subject: [PATCH 18/18] style(graphql): Fix test checkstyle --- .../resolvers/mutate/MutableTypeBatchResolverTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java index e570d7403d5f2a..04ed7720333151 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/mutate/MutableTypeBatchResolverTest.java @@ -8,7 +8,10 @@ import com.linkedin.common.Deprecation; import com.linkedin.common.urn.Urn; import com.linkedin.datahub.graphql.QueryContext; -import com.linkedin.datahub.graphql.generated.*; +import com.linkedin.datahub.graphql.generated.BatchDatasetUpdateInput; +import com.linkedin.datahub.graphql.generated.Dataset; +import com.linkedin.datahub.graphql.generated.DatasetDeprecationUpdate; +import com.linkedin.datahub.graphql.generated.DatasetUpdateInput; import com.linkedin.datahub.graphql.types.BatchMutableType; import com.linkedin.datahub.graphql.types.dataset.DatasetType; import com.linkedin.entity.EntityResponse;