Skip to content

Commit

Permalink
Merge pull request #84 from SavelevMatthew/master
Browse files Browse the repository at this point in the history
fix(cache-result-processor): diff should use alias name in partial read
  • Loading branch information
danReynolds authored Aug 6, 2024
2 parents 5e8a1eb + 9ec0bfc commit 29add9e
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
3.3.1 (Dan Reynolds)

Bugfix for aliased queries with variables: https://github.com/NerdWalletOSS/apollo-cache-policies/issues/83
Reporter: https://github.com/SavelevMatthew

3.3.0 (Dan Reynolds)

Add support for specifying the fragment name to use in the `useFragmentWhere` API.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nerdwallet/apollo-cache-policies",
"version": "3.3.0",
"version": "3.3.1",
"description": "An extension to the InMemoryCache from Apollo that adds additional cache policies.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/cache/CacheResultProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class CacheResultProcessor {
// will have it keyed by an alias name if provided so we keep track of the
// result key name in case it needs to be removed from the response due to an evicted TTL
const resultKeyName = resultKeyNameFromField(field);
const subResultStatus = this.processReadSubResult(result, fieldName);
const subResultStatus = this.processReadSubResult(result, resultKeyName);

const typename = entityTypeMap.readEntityById(
makeEntityId(dataId, fieldName)
Expand Down
111 changes: 110 additions & 1 deletion tests/InvalidationPolicyCache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ describe("InvalidationPolicyCache", () => {
}
`;

const employeesWithAliasVariablesAndArrayResponseQuery = gql`
query {
bosses: employees(name: $bossName) {
id
employee_name
employee_salary
employee_age
}
}
`;

const createEmployeeMutation = gql`
query {
createEmployee {
Expand Down Expand Up @@ -176,6 +187,10 @@ describe("InvalidationPolicyCache", () => {
},
};

const employeesWithAliasVariablesAndArrayResponse = {
bosses: [employee3],
};

const employeeMessagesResponse = {
employeeMessages: {
__typename: "EmployeeMessagesResponse",
Expand Down Expand Up @@ -1798,10 +1813,44 @@ describe("InvalidationPolicyCache", () => {
},
});

let queryResult = cache.readQuery({
query: employeesAndBossesWithVariablesQuery,
variables: {
employeeName: "Tester McTest",
bossName: "Tester McBoss"
},
});
expect(queryResult).toEqual({
employees: {
__typename: 'EmployeesResponse',
data: [employee, employee2]
},
bosses: {
__typename: 'EmployeesResponse',
data: [employee3]
}
});
expect(cache.extract(true, false)).toEqual({
[employee.toRef()]: employee,
[employee2.toRef()]: employee2,
[employee3.toRef()]: employee3,
ROOT_QUERY: {
__typename: "Query",
"employees({\"name\":\"Tester McTest\"})": {
__typename: "EmployeesResponse",
data: [{ __ref: employee.toRef() }, { __ref: employee2.toRef() }],
},
"employees({\"name\":\"Tester McBoss\"})": {
__typename: "EmployeesResponse",
data: [{ __ref: employee3.toRef() }],
},
},
});

dateNowSpy.mockRestore();
dateNowSpy = jest.spyOn(Date, "now").mockReturnValue(101);

const queryResult = cache.readQuery({
queryResult = cache.readQuery({
query: employeesAndBossesWithVariablesQuery,
variables: {
employeeName: "Tester McTest",
Expand All @@ -1818,6 +1867,66 @@ describe("InvalidationPolicyCache", () => {
},
});
});

test('should evict an expired array response entity with a field alias', () => {
cache = new InvalidationPolicyCache({
invalidationPolicies: {
timeToLive: 100,
},
});
dateNowSpy = jest.spyOn(Date, "now").mockReturnValue(0);
cache.writeQuery({
query: employeesWithAliasVariablesAndArrayResponseQuery,
data: employeesWithAliasVariablesAndArrayResponse,
variables: {
bossName: "Tester McBoss"
},
});

let queryResult = cache.readQuery({
query: employeesWithAliasVariablesAndArrayResponseQuery,
variables: {
employeeName: "Tester McTest",
bossName: "Tester McBoss"
},
});
expect(queryResult).toEqual({
bosses: [
employee3,
]
});

expect(cache.extract(true, false)).toEqual({
[employee3.toRef()]: employee3,
ROOT_QUERY: {
__typename: "Query",
"employees({\"name\":\"Tester McBoss\"})": [{ __ref: employee3.toRef() }],
},
});

dateNowSpy.mockRestore();
dateNowSpy = jest.spyOn(Date, "now").mockReturnValue(101);

queryResult = cache.readQuery({
query: employeesWithAliasVariablesAndArrayResponseQuery,
variables: {
employeeName: "Tester McTest",
bossName: "Tester McBoss"
},
});

expect(queryResult).toEqual({
bosses: [],
});
expect(cache.extract(true, false)).toEqual({
ROOT_QUERY: {
__typename: "Query",
// The employees field remains in the cache since it's cached value has no __typename field and is not evicted
// itself when read.
"employees({\"name\":\"Tester McBoss\"})": [{ __ref: employee3.toRef() }],
},
});
});
});

describe("with only a type specific timeToLive policy", () => {
Expand Down

0 comments on commit 29add9e

Please # to comment.