Skip to content

Commit

Permalink
Merge pull request #3571 from graphql-java/add-field-fetching-method
Browse files Browse the repository at this point in the history
Added field fetching method for Expedia
  • Loading branch information
bbakerman committed May 17, 2024
2 parents 2285351 + 57968f9 commit 11e9788
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 6 deletions.
4 changes: 3 additions & 1 deletion src/main/java/graphql/execution/ExecutionStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import graphql.execution.directives.QueryDirectivesImpl;
import graphql.execution.incremental.DeferredExecutionSupport;
import graphql.execution.instrumentation.ExecuteObjectInstrumentationContext;
import graphql.execution.instrumentation.FieldFetchingInstrumentationContext;
import graphql.execution.instrumentation.Instrumentation;
import graphql.execution.instrumentation.InstrumentationContext;
import graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;
Expand Down Expand Up @@ -487,7 +488,7 @@ Async.CombinedBuilder<FieldValueInfo> getAsyncFieldValueInfo(
Instrumentation instrumentation = executionContext.getInstrumentation();

InstrumentationFieldFetchParameters instrumentationFieldFetchParams = new InstrumentationFieldFetchParameters(executionContext, dataFetchingEnvironment, parameters, dataFetcher instanceof TrivialDataFetcher);
InstrumentationContext<Object> fetchCtx = nonNullCtx(instrumentation.beginFieldFetch(instrumentationFieldFetchParams,
FieldFetchingInstrumentationContext fetchCtx = FieldFetchingInstrumentationContext.nonNullCtx(instrumentation.beginFieldFetching(instrumentationFieldFetchParams,
executionContext.getInstrumentationState())
);

Expand All @@ -496,6 +497,7 @@ Async.CombinedBuilder<FieldValueInfo> getAsyncFieldValueInfo(
Object fetchedObject = invokeDataFetcher(executionContext, parameters, fieldDef, dataFetchingEnvironment, dataFetcher);
executionContext.getDataLoaderDispatcherStrategy().fieldFetched(executionContext, parameters, dataFetcher, fetchedObject);
fetchCtx.onDispatched();
fetchCtx.onFetchedValue(fetchedObject);
if (fetchedObject instanceof CompletableFuture) {
@SuppressWarnings("unchecked")
CompletableFuture<Object> fetchedValue = (CompletableFuture<Object>) fetchedObject;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package graphql.execution.instrumentation;

import com.google.common.collect.ImmutableList;
import graphql.Assert;
import graphql.ExecutionInput;
import graphql.ExecutionResult;
import graphql.ExperimentalApi;
Expand Down Expand Up @@ -159,7 +158,7 @@ public ExecutionStrategyInstrumentationContext beginExecutionStrategy(Instrument
}
BiFunction<Instrumentation, InstrumentationState, ExecuteObjectInstrumentationContext> mapper = (instrumentation, specificState) -> instrumentation.beginExecuteObject(parameters, specificState);
ChainedInstrumentationState chainedInstrumentationState = (ChainedInstrumentationState) state;
if (instrumentations.size() == 1) {
if (instrumentations.size() == 1) {
return mapper.apply(instrumentations.get(0), chainedInstrumentationState.getState(0));
}
return new ChainedExecuteObjectInstrumentationContext(chainedMapAndDropNulls(chainedInstrumentationState, mapper));
Expand All @@ -182,11 +181,26 @@ public InstrumentationContext<ExecutionResult> beginSubscribedFieldEvent(Instrum
return chainedCtx(state, (instrumentation, specificState) -> instrumentation.beginFieldExecution(parameters, specificState));
}

@SuppressWarnings("deprecation")
@Override
public InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
return chainedCtx(state, (instrumentation, specificState) -> instrumentation.beginFieldFetch(parameters, specificState));
}

@Override
public FieldFetchingInstrumentationContext beginFieldFetching(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
if (instrumentations.isEmpty()) {
return FieldFetchingInstrumentationContext.NOOP;
}
BiFunction<Instrumentation, InstrumentationState, FieldFetchingInstrumentationContext> mapper = (instrumentation, specificState) -> instrumentation.beginFieldFetching(parameters, specificState);
ChainedInstrumentationState chainedInstrumentationState = (ChainedInstrumentationState) state;
if (instrumentations.size() == 1) {
return mapper.apply(instrumentations.get(0), chainedInstrumentationState.getState(0));
}
ImmutableList<FieldFetchingInstrumentationContext> objects = chainedMapAndDropNulls(chainedInstrumentationState, mapper);
return new ChainedFieldFetchingInstrumentationContext(objects);
}

@Override
public @Nullable InstrumentationContext<Object> beginFieldCompletion(InstrumentationFieldCompleteParameters parameters, InstrumentationState state) {
return chainedCtx(state, (instrumentation, specificState) -> instrumentation.beginFieldCompletion(parameters, specificState));
Expand Down Expand Up @@ -344,8 +358,33 @@ public void onFieldValuesException() {
}
}

private static class ChainedFieldFetchingInstrumentationContext implements FieldFetchingInstrumentationContext {

private final ImmutableList<FieldFetchingInstrumentationContext> contexts;

ChainedFieldFetchingInstrumentationContext(ImmutableList<FieldFetchingInstrumentationContext> contexts) {
this.contexts = contexts;
}

@Override
public void onDispatched() {
contexts.forEach(FieldFetchingInstrumentationContext::onDispatched);
}

@Override
public void onFetchedValue(Object fetchedValue) {
contexts.forEach(context -> context.onFetchedValue(fetchedValue));
}

@Override
public void onCompleted(Object result, Throwable t) {
contexts.forEach(context -> context.onCompleted(result, t));
}
}

private static class ChainedDeferredExecutionStrategyInstrumentationContext implements InstrumentationContext<Object> {


private final List<InstrumentationContext<Object>> contexts;

ChainedDeferredExecutionStrategyInstrumentationContext(List<InstrumentationContext<Object>> contexts) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package graphql.execution.instrumentation;

import graphql.Internal;
import graphql.PublicSpi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@PublicSpi
public interface FieldFetchingInstrumentationContext extends InstrumentationContext<Object> {

@Internal
FieldFetchingInstrumentationContext NOOP = new FieldFetchingInstrumentationContext() {
@Override
public void onDispatched() {
}

@Override
public void onCompleted(Object result, Throwable t) {
}

@Override
public void onFetchedValue(Object fetchedValue) {
}
};

/**
* This creates a no-op {@link InstrumentationContext} if the one pass in is null
*
* @param nullableContext a {@link InstrumentationContext} that can be null
*
* @return a non null {@link InstrumentationContext} that maybe a no-op
*/
@NotNull
@Internal
static FieldFetchingInstrumentationContext nonNullCtx(FieldFetchingInstrumentationContext nullableContext) {
return nullableContext == null ? NOOP : nullableContext;
}

@Internal
static FieldFetchingInstrumentationContext adapter(@Nullable InstrumentationContext<Object> context) {
if (context == null) {
return null;
}
return new FieldFetchingInstrumentationContext() {
@Override
public void onDispatched() {
context.onDispatched();
}

@Override
public void onCompleted(Object result, Throwable t) {
context.onCompleted(result, t);
}

@Override
public void onFetchedValue(Object fetchedValue) {
}
};
}

/**
* This is called back with value fetched for the field.
*
* @param fetchedValue a value that a field's {@link graphql.schema.DataFetcher} returned
*/
default void onFetchedValue(Object fetchedValue) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,31 @@ default InstrumentationContext<Object> beginFieldExecution(InstrumentationFieldP
* @param state the state created during the call to {@link #createStateAsync(InstrumentationCreateStateParameters)}
*
* @return a nullable {@link InstrumentationContext} object that will be called back when the step ends (assuming it's not null)
*
* @deprecated use {@link #beginFieldFetching(InstrumentationFieldFetchParameters, InstrumentationState)} instead
*/
@Deprecated(since = "2024-04-18")
@Nullable
default InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
return noOp();
}

/**
* This is called just before a field {@link DataFetcher} is invoked. The {@link FieldFetchingInstrumentationContext#onFetchedValue(Object)}
* callback will be invoked once a value is returned by a {@link DataFetcher} but perhaps before
* its value is completed if it's a {@link CompletableFuture} value.
*
* @param parameters the parameters to this step
* @param state the state created during the call to {@link #createStateAsync(InstrumentationCreateStateParameters)}
*
* @return a nullable {@link InstrumentationContext} object that will be called back when the step ends (assuming it's not null)
*/
@Nullable
default FieldFetchingInstrumentationContext beginFieldFetching(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
InstrumentationContext<Object> ctx = beginFieldFetch(parameters, state);
return FieldFetchingInstrumentationContext.adapter(ctx);
}

/**
* This is called just before the complete field is started.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ public InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchP
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldFetch(parameters, specificState));
}

@Override
public FieldFetchingInstrumentationContext beginFieldFetching(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldFetching(parameters, specificState));
}

@Override
public @Nullable InstrumentationContext<Object> beginFieldCompletion(InstrumentationFieldCompleteParameters parameters, InstrumentationState state) {
return runAll(state, (instrumentation, specificState) -> instrumentation.beginFieldCompletion(parameters, specificState));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ public class SimplePerformantInstrumentation implements Instrumentation {
return noOp();
}


@Override
public @Nullable InstrumentationContext<Object> beginFieldCompletion(InstrumentationFieldCompleteParameters parameters, InstrumentationState state) {
return noOp();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ class ModernTestingInstrumentation implements Instrumentation {
}

@Override
InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
FieldFetchingInstrumentationContext beginFieldFetching(InstrumentationFieldFetchParameters parameters, InstrumentationState state) {
assert state == instrumentationState
return new TestingInstrumentContext("fetch-$parameters.field.name", executionList, throwableList, useOnDispatch)
return new TestingFieldFetchingInstrumentationContext("fetch-$parameters.field.name", executionList, throwableList, useOnDispatch)
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package graphql.execution.instrumentation

class TestingFieldFetchingInstrumentationContext extends TestingInstrumentContext<Map<String, Object>> implements FieldFetchingInstrumentationContext {

TestingFieldFetchingInstrumentationContext(Object op, Object executionList, Object throwableList, Boolean useOnDispatch) {
super(op, executionList, throwableList, useOnDispatch)
}
}

0 comments on commit 11e9788

Please sign in to comment.