-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Singleton property data fetcher #3754
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
Conversation
Test Results 305 files + 1 305 suites +1 45s ⏱️ +5s Results for commit b13b7c8. ± Comparison against base commit f83ba25. This pull request removes 168 and adds 169 tests. Note that renamed tests count towards both.
♻️ This comment has been updated with latest results. |
@@ -189,7 +189,7 @@ public static class Builder { | |||
private final Map<String, DataFetcherFactory<?>> systemDataFetcherMap = new LinkedHashMap<>(); | |||
private final Map<String, TypeResolver> typeResolverMap = new HashMap<>(); | |||
private GraphqlFieldVisibility fieldVisibility = DEFAULT_FIELD_VISIBILITY; | |||
private DataFetcherFactory<?> defaultDataFetcherFactory = env -> PropertyDataFetcher.fetching(env.getFieldDefinition().getName()); | |||
private DataFetcherFactory<?> defaultDataFetcherFactory = PropertyDataFetcher.singletonFactory(); |
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 causes the same instance of the "default" DF to be used
private PropertyDataFetcher() { | ||
this.function = null; | ||
this.propertyName = null; | ||
} |
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.
we no longer need the property name but its kept allow older code to work that might use direct names or functions
newDataFetchingEnvironment().source(dataHolder).fieldType(type).build() | ||
def env(String propertyName, GraphQLOutputType type) { | ||
def fieldDefinition = GraphQLFieldDefinition.newFieldDefinition().name(propertyName).type(type).build() | ||
newDataFetchingEnvironment().source(dataHolder).fieldType(type).fieldDefinition(fieldDefinition).build() |
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.
a valid DataFetchingEnvironment will always have a field definition
…Helper that does NOT put in an entry for defaulted values
…Helper that does NOT put in an entry for defaulted values- DFF tweaked
…a SingletonPropertyDataFetcher class
…efault # Conflicts: # src/main/java/graphql/schema/PropertyDataFetcher.java
@@ -189,7 +189,7 @@ public static class Builder { | |||
private final Map<String, DataFetcherFactory<?>> systemDataFetcherMap = new LinkedHashMap<>(); | |||
private final Map<String, TypeResolver> typeResolverMap = new HashMap<>(); | |||
private GraphqlFieldVisibility fieldVisibility = DEFAULT_FIELD_VISIBILITY; | |||
private DataFetcherFactory<?> defaultDataFetcherFactory = env -> PropertyDataFetcher.fetching(env.getFieldDefinition().getName()); | |||
private DataFetcherFactory<?> defaultDataFetcherFactory = SingletonPropertyDataFetcher.singletonFactory(); |
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.
key change here - no object allocated per field
String fieldName = environment.getFieldDefinition().getName(); | ||
return new PropertyDataFetcher(fieldName); | ||
private DataFetcher<?> dataFetcherOfLastResort() { | ||
return SingletonPropertyDataFetcher.singleton(); |
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 code is not actually used by default - unless GraphqlCodeRegistry had a null default DDF
when: | ||
result = fetcher.get(field, dataHolder, { environment }) | ||
then: | ||
result == "propertyValue" |
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.
extra tests for light weight data fetching
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.
boils down to the same code however in the end
@@ -32,7 +43,7 @@ public static <T> DataFetcherFactory<T> useDataFetcher(DataFetcher<T> dataFetche | |||
* | |||
* @return a new data fetcher that wraps the provided data fetcher | |||
*/ | |||
public static DataFetcher wrapDataFetcher(DataFetcher delegateDataFetcher, BiFunction<DataFetchingEnvironment, Object, Object> mapFunction) { | |||
public static DataFetcher<?> wrapDataFetcher(DataFetcher<?> delegateDataFetcher, BiFunction<DataFetchingEnvironment, Object, Object> mapFunction) { |
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.
small clean up - generics!
…tcher per property per graphql operation (#2079) ### 📝 Description Inspired by graphql-java/graphql-java#3754. Currently, graphql-kotlin, through the [KotlinDataFetcherFactoryProvider](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/KotlinDataFetcherFactoryProvider.kt#L62) creates a [PropertyDataFetcher](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/PropertyDataFetcher.kt) per source's property. This instance is created [every single time ](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/schema/GraphQLCodeRegistry.java#L100)the graphql-java [DataFetcherFactory](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/schema/DataFetcherFactory.java) is invoked, which happens to be on runtime per property per graphql-operation. This PR will introduce a new object class `SingletonPropertyDataFetcher` which will host its own singleton factory that will always return `SingletonPropertyDataFetcher` which will store all `KProperty.Getter<*>`s in a ConcurrentHashMap. Instead of just replacing the SimpleKotlinDataFetcherFactoryProvider, I am creating a new one, to avoid breaking changes, and to allow users to decide what they want, this switch might come with a cost, we are avoiding object allocations, in favor of a singleton that will possibly hold thousands of `KProperty.Getter<*>`s. --------- Co-authored-by: Samuel Vazquez <samvazquez@expediagroup.com>
…tcher per property per graphql operation (#2079) ### 📝 Description Inspired by graphql-java/graphql-java#3754. Currently, graphql-kotlin, through the [KotlinDataFetcherFactoryProvider](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/KotlinDataFetcherFactoryProvider.kt#L62) creates a [PropertyDataFetcher](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/PropertyDataFetcher.kt) per source's property. This instance is created [every single time ](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/schema/GraphQLCodeRegistry.java#L100)the graphql-java [DataFetcherFactory](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/schema/DataFetcherFactory.java) is invoked, which happens to be on runtime per property per graphql-operation. This PR will introduce a new object class `SingletonPropertyDataFetcher` which will host its own singleton factory that will always return `SingletonPropertyDataFetcher` which will store all `KProperty.Getter<*>`s in a ConcurrentHashMap. Instead of just replacing the SimpleKotlinDataFetcherFactoryProvider, I am creating a new one, to avoid breaking changes, and to allow users to decide what they want, this switch might come with a cost, we are avoiding object allocations, in favor of a singleton that will possibly hold thousands of `KProperty.Getter<*>`s. --------- Co-authored-by: Samuel Vazquez <samvazquez@expediagroup.com>
This adds support for a singleton property data fetcher
Before we create a
new PropertyDataFetcher()
for every defaulted field in the schema.This means for large schemas with 1000s of fields, we have a new object per field that ALWAYS fetches values with the name of the field.
This can be static and hence we can save memory by default since MOST fields can use this static fetcher