feat(response-cache): add extras property to get scope and its metadata from buildResponseCacheKey#2202
Conversation
🦋 Changeset detectedLatest commit: 9e8ea70 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
4f30aba to
a5468bb
Compare
a5468bb to
9e8ea70
Compare
…ta from buildResponseCacheKey
9e8ea70 to
c4de9af
Compare
|
Hi @ardatan, I'm back with a new proposal for this scope functionality with some improvements. |
|
@EmrysMyrddin Could you take a look? |
| new Proxy( | ||
| { | ||
| documentString: getDocumentString(onExecuteParams.args), | ||
| variableValues: onExecuteParams.args.variableValues, | ||
| operationName: onExecuteParams.args.operationName, | ||
| sessionId, | ||
| context: onExecuteParams.args.contextValue, | ||
| extras: undefined as any, | ||
| }, | ||
| { | ||
| get: (obj, prop) => { | ||
| if (prop === 'extras') { | ||
| return getScopeFromQuery(schema, onExecuteParams.args.document.loc.source.body); | ||
| } | ||
| return obj[prop as keyof typeof obj]; | ||
| }, | ||
| }, | ||
| ), |
There was a problem hiding this comment.
I don't remembre how it was implemented before, but is there a reason to use a proxy instead of classic getters?
Like this:
| new Proxy( | |
| { | |
| documentString: getDocumentString(onExecuteParams.args), | |
| variableValues: onExecuteParams.args.variableValues, | |
| operationName: onExecuteParams.args.operationName, | |
| sessionId, | |
| context: onExecuteParams.args.contextValue, | |
| extras: undefined as any, | |
| }, | |
| { | |
| get: (obj, prop) => { | |
| if (prop === 'extras') { | |
| return getScopeFromQuery(schema, onExecuteParams.args.document.loc.source.body); | |
| } | |
| return obj[prop as keyof typeof obj]; | |
| }, | |
| }, | |
| ), | |
| { | |
| documentString: getDocumentString(onExecuteParams.args), | |
| variableValues: onExecuteParams.args.variableValues, | |
| operationName: onExecuteParams.args.operationName, | |
| sessionId, | |
| context: onExecuteParams.args.contextValue, | |
| get extras() { | |
| return getScopeFromQuery(schema, onExecuteParams.args.document.loc.source.body); | |
| }, | |
| }, |
There was a problem hiding this comment.
A recent habit to use proxies for their flexibility, but I can see that a getter in this case would fit better for clarity sake.
| return { scope: 'PUBLIC' as const, metadata: {} }; | ||
| }); | ||
|
|
||
| return fn({ query }); |
There was a problem hiding this comment.
This will disallow memoization isn't it ? Since { query } creates a new object each time the function is called.
There was a problem hiding this comment.
And I'm not sure to understand why schema is not part of the memoize1 key ? Because I fear that on schema update, you will get outadated metadata for the same query.
There was a problem hiding this comment.
Fair points!
I'll include schema using memoize2 function and stringify those objects to fix comparison.
| export let schema: GraphQLSchema; | ||
| let ttlPerSchemaCoordinate: Record<string, CacheControlDirective['maxAge']> = {}; | ||
| let scopePerSchemaCoordinate: Record<string, CacheControlDirective['scope']> = {}; |
There was a problem hiding this comment.
Why do you extract those outside of the plugin? I feel that it will break things, because multiple instances of the same plugin would share those variables.
| export function isPrivate( | ||
| typeName: string, | ||
| data?: Record<string, NonNullable<CacheControlDirective['scope']>>, | ||
| ): boolean { | ||
| if (scopePerSchemaCoordinate[typeName] === 'PRIVATE') { | ||
| return true; | ||
| } | ||
| return data | ||
| ? Object.keys(data).some( | ||
| fieldName => scopePerSchemaCoordinate[`${typeName}.${fieldName}`] === 'PRIVATE', | ||
| ) | ||
| : false; | ||
| } |
There was a problem hiding this comment.
Why do you have to make a duplicate of this function outside of the plugin?
There was a problem hiding this comment.
Mb I merged local code I made last year with the one I use today and simply forgot there was already this function.
I'll keep the exported one since it's needed in get-scope.ts file.
… better scope memoization
|
Hi @EmrysMyrddin, how's it going today ? I made updates to fix the points you brought up :
|
…nd sizePerSchema is accessible
|
It seems square now with :
Tell me if there's still something blocking the merge @EmrysMyrddin. Take care ! |
|
Hi @k-i-k-s, would you mind allowing modification of your PR by maintainers? I've taken a closer look and addressed issues so that we can finally merge this and handle the use case explained in the linked issue. You can take a look at what it looks like here: #2815 If you prefer not to give write access to your PR, I can merge mine instead. |
|
Hi, I don't think I have permission to give write access to the fork, merge your own branch I don't mind, it'll be far easier. |
|
Ok, then don't hesitate to give my PR a try 🙂 No, there isn't any new internal need for the feature, but I'm in the process of merging Envelop and Yoga repository together to ease development. So before this can happen, we need to merge all PRs we don't want to loose. And I didn't want to let this one behind given the effort you put into it 🙂 |
Issue related : #2181
Description
Include a new
extrasproperty to getscope(as aProxyto avoid performance impact when unused) inbuildResponseCacheKey, allowing more granularity over cache control.Type of change
How Has This Been Tested?
I added some unit tests to check that
PRIVATEscope is correctly retrieved from a query, when directive@cacheControl(scope: PRIVATE)is put on query, field and subfield.Checklist:
CONTRIBUTING doc and the
style guidelines of this project