-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Support for Streams and Iterators #2067
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,10 +39,10 @@ | |
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collection; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.OptionalInt; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.CompletionException; | ||
| import java.util.function.Supplier; | ||
|
|
@@ -56,7 +56,9 @@ | |
| import static graphql.execution.FieldValueInfo.CompleteValueType.OBJECT; | ||
| import static graphql.execution.FieldValueInfo.CompleteValueType.SCALAR; | ||
| import static graphql.schema.DataFetchingEnvironmentImpl.newDataFetchingEnvironment; | ||
| import static graphql.schema.GraphQLTypeUtil.isEnum; | ||
| import static graphql.schema.GraphQLTypeUtil.isList; | ||
| import static graphql.schema.GraphQLTypeUtil.isScalar; | ||
| import static java.util.concurrent.CompletableFuture.completedFuture; | ||
|
|
||
| /** | ||
|
|
@@ -421,10 +423,10 @@ protected FieldValueInfo completeValue(ExecutionContext executionContext, Execut | |
| return FieldValueInfo.newFieldValueInfo(NULL).fieldValue(fieldValue).build(); | ||
| } else if (isList(fieldType)) { | ||
| return completeValueForList(executionContext, parameters, result); | ||
| } else if (fieldType instanceof GraphQLScalarType) { | ||
| } else if (isScalar(fieldType)) { | ||
| fieldValue = completeValueForScalar(executionContext, parameters, (GraphQLScalarType) fieldType, result); | ||
| return FieldValueInfo.newFieldValueInfo(SCALAR).fieldValue(fieldValue).build(); | ||
| } else if (fieldType instanceof GraphQLEnumType) { | ||
| } else if (isEnum(fieldType)) { | ||
| fieldValue = completeValueForEnum(executionContext, parameters, (GraphQLEnumType) fieldType, result); | ||
| return FieldValueInfo.newFieldValueInfo(ENUM).fieldValue(fieldValue).build(); | ||
| } | ||
|
|
@@ -494,19 +496,19 @@ protected FieldValueInfo completeValueForList(ExecutionContext executionContext, | |
| */ | ||
| protected FieldValueInfo completeValueForList(ExecutionContext executionContext, ExecutionStrategyParameters parameters, Iterable<Object> iterableValues) { | ||
|
|
||
| Collection<Object> values = FpKit.toCollection(iterableValues); | ||
| OptionalInt size = FpKit.toSize(iterableValues); | ||
| ExecutionStepInfo executionStepInfo = parameters.getExecutionStepInfo(); | ||
|
|
||
| InstrumentationFieldCompleteParameters instrumentationParams = new InstrumentationFieldCompleteParameters(executionContext, parameters, () -> executionStepInfo, values); | ||
| InstrumentationFieldCompleteParameters instrumentationParams = new InstrumentationFieldCompleteParameters(executionContext, parameters, () -> executionStepInfo, iterableValues); | ||
| Instrumentation instrumentation = executionContext.getInstrumentation(); | ||
|
|
||
| InstrumentationContext<ExecutionResult> completeListCtx = instrumentation.beginFieldListComplete( | ||
| instrumentationParams | ||
| ); | ||
|
|
||
| List<FieldValueInfo> fieldValueInfos = new ArrayList<>(values.size()); | ||
| List<FieldValueInfo> fieldValueInfos = new ArrayList<>(size.orElse(1)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the end of the day we are still allocated an array the size of the list - So source of the data can be a stream but we can stay streaming all the way. This is an improvement - as you say it greatly reduces your memory usage (nearly half??) but longer term could we have streams all the way down to the turtles? Thinking aloud here it might be too theoretical - I know there is code out there that assumes ExecutionResult is really a Map of lists and maps and values. Would introducing "streams" in that break things?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yes, I was not able to remove this big list.
This the most big query we have so far.
We are merely introducing streaming between datafetchers and execution strategy: so this is very conservative choice by now. |
||
| int index = 0; | ||
| for (Object item : values) { | ||
| for (Object item : iterableValues) { | ||
| ResultPath indexedPath = parameters.getPath().segment(index); | ||
|
|
||
| ExecutionStepInfo stepInfoForListElement = executionStepInfoFactory.newExecutionStepInfoForListElement(executionStepInfo, index); | ||
|
|
@@ -519,7 +521,7 @@ protected FieldValueInfo completeValueForList(ExecutionContext executionContext, | |
| ExecutionStrategyParameters newParameters = parameters.transform(builder -> | ||
| builder.executionStepInfo(stepInfoForListElement) | ||
| .nonNullFieldValidator(nonNullableFieldValidator) | ||
| .listSize(values.size()) | ||
| .listSize(size.orElse(-1)) // -1 signals that we don't know the size | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a look at I was worried this
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, I think it is backward compatible. Maybe we can introduce a new method that returns |
||
| .localContext(value.getLocalContext()) | ||
| .currentListIndex(finalIndex) | ||
| .path(indexedPath) | ||
|
|
@@ -674,14 +676,15 @@ protected GraphQLObjectType resolveType(ExecutionContext executionContext, Execu | |
|
|
||
|
|
||
| protected Iterable<Object> toIterable(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) { | ||
| if (result.getClass().isArray() || result instanceof Iterable) { | ||
| return toIterable(result); | ||
| if (FpKit.isIterable(result)) { | ||
| return FpKit.toIterable(result); | ||
| } | ||
|
|
||
| handleTypeMismatchProblem(context, parameters, result); | ||
| return null; | ||
| } | ||
|
|
||
|
|
||
| private void handleTypeMismatchProblem(ExecutionContext context, ExecutionStrategyParameters parameters, Object result) { | ||
| TypeMismatchError error = new TypeMismatchError(parameters.getPath(), parameters.getExecutionStepInfo().getUnwrappedNonNullType()); | ||
| logNotSafe.warn("{} got {}", error.getMessage(), result.getClass()); | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a mild breaking change - the input is "Object" but the actual type has changed.
I think this is ok (did we say it WOULD always be a collection??) but I just want to call it out and see others thoughts on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this could be a breaking change.
Arraysare reallocated anymore asList(but I could easily re-introduce this behavior).For Collections we should be fine:
toIterabledoes not change the concrete type.For Streams/Iterators we should be fine as well: nobody is using that right now.