- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5
Use deterministic order for type policy keyFields and field policy keyArgs #243
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
Use deterministic order for type policy keyFields and field policy keyArgs #243
Conversation
1c57060    to
    f837f3b      
    Compare
  
    3cc1e5e    to
    cd0be1f      
    Compare
  
    |  | ||
| internal data class TypePolicy( | ||
| val keyFields: Set<String>, | ||
| val keyFields: SortedSet<String>, | 
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.
I think we can just use List. Technically SortedSet makes more sense, but I'd rather avoid the JVM-only type.
Note: the equivalent TypePolicy in com.apollographql.cache.normalized.api also needs to be a List instead of a Set (that's a breaking change but that's all right at the moment).
| addStatement("keyFields = setOf(") | ||
| withIndent { | ||
| typePolicy.keyFields.forEach { keyField -> | ||
| typePolicy.keyFields.sorted().forEach { keyField -> | 
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.
If we use a List I think it'd make more sense to keep the user-defined order set in @typePolicy.
| if (keyArgs.values.isEmpty()) { | ||
| return DefaultCacheResolver.resolveField(context) | ||
| } | ||
| val keyArgsValues = keyArgs.entries.sortedBy { it.key }.map { it.value } | 
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.
I think this works only if the key arguments of a field have the same names as the key fields of the type. So for example:
extend type User @typePolicy(keyFields: "firstName lastName")
extend type Query @fieldPolicy(forField: "user", keyArgs: "firstName lastName"){
  user(firstName: "john", lastName: "smith") {
    firstName
    lastName
  } 
}- The CacheKeyGeneratorwill returnUser:john+smith
- The CacheResolverwill returnUser:john+smith✅
But
extend type User @typePolicy(keyFields: "firstName lastName")
extend type Query @fieldPolicy(forField: "user", keyArgs: "a b"){
  user(b: "john", a: "smith") {
    firstName
    lastName
  } 
}- The CacheKeyGeneratorwill returnUser:john+smith
- The CacheResolverwill returnUser:smith+john❌
In the end I think it would make sense to use the same orders as defined in @typePolicy and @fieldPolicy. But that isn't currently possible because that information is lost in compilation! Instead, for the key args, we use the order in which they are passed to the field. So in the example above we must select user(firstName: "john", lastName: "smith") and not user(lastName: "smith", firstName: "john").
But this soon will be possible, because for the key args, I intend to not use CompiledField but a Map generated in the Cache class. With that we'll have the order information.
| Thanks a lot for opening this. In summary: 
 | 
| 
 Thanks for the review and explanation. If I am understanding it right, did you want me to close out this PR and then open a new one that changes it from a  | 
| 
 I think this can be done in this PR - or a new one if you prefer :) | 
| Thanks again for having opened this. In the end, I needed to change the Sets to Lists in #250 so this one can be closed. | 
When using
@typePolicyand@fieldPolicy, I noticed a few cache misses because thekeyFieldsandkeyArgswere not in the same order. When generating aCacheKeyin theCacheResolver, the generated key wasbar+foo, whereas the type policy generated it asfoo+bar.This PR uses deterministic sorting in both the keyFields of a type policy and keyArgs of a field policy.