Skip to content

Commit

Permalink
Merge branch 'master' into release-3.2.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn committed Aug 20, 2020
2 parents ac7717a + d183c22 commit 5023915
Show file tree
Hide file tree
Showing 7 changed files with 952 additions and 636 deletions.
1,462 changes: 842 additions & 620 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@
},
"devDependencies": {
"@babel/parser": "7.11.3",
"@rollup/plugin-node-resolve": "8.4.0",
"@rollup/plugin-node-resolve": "9.0.0",
"@testing-library/react": "9.4.1",
"@types/fast-json-stable-stringify": "2.0.0",
"@types/fetch-mock": "^7.3.2",
"@types/glob": "7.1.3",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/jest": "26.0.8",
"@types/lodash": "4.14.157",
"@types/jest": "26.0.10",
"@types/lodash": "4.14.159",
"@types/node": "14.0.27",
"@types/react": "^16.9.32",
"@types/react-dom": "^16.9.6",
Expand All @@ -102,9 +102,9 @@
"glob": "7.1.6",
"graphql": "15.3.0",
"graphql-tools": "^6.0.12",
"jest": "26.2.2",
"jest": "26.4.0",
"jest-junit": "11.1.0",
"lodash": "4.17.19",
"lodash": "4.17.20",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"recast": "0.19.1",
Expand All @@ -115,7 +115,7 @@
"rollup-plugin-terser": "^7.0.0",
"rxjs": "6.6.2",
"subscriptions-transport-ws": "^0.9.17",
"ts-jest": "26.1.4",
"ts-jest": "26.2.0",
"ts-node": "8.10.2",
"tsc-watch": "3.0.1",
"typescript": "3.9.7",
Expand Down
1 change: 1 addition & 0 deletions src/cache/core/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class MissingFieldError {
public readonly message: string,
public readonly path: (string | number)[],
public readonly query: import('graphql').DocumentNode,
public readonly clientOnly: boolean,
public readonly variables?: Record<string, any>,
) {}
}
Expand Down
20 changes: 12 additions & 8 deletions src/cache/inmemory/__tests__/entityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,14 +1091,16 @@ describe('EntityStore', () => {
new MissingFieldError(
'Can\'t find field \'hobby\' on Author:{"name":"Ted Chiang"} object',
["authorOfBook", "hobby"],
expect.anything(),
expect.anything(),
expect.anything(), // query
false, // clientOnly
expect.anything(), // variables
),
new MissingFieldError(
'Can\'t find field \'publisherOfBook\' on ROOT_QUERY object',
["publisherOfBook"],
expect.anything(),
expect.anything(),
expect.anything(), // query
false, // clientOnly
expect.anything(), // variables
),
],
});
Expand Down Expand Up @@ -1674,8 +1676,9 @@ describe('EntityStore', () => {
new MissingFieldError(
"Dangling reference to missing Author:2 object",
["book", "author"],
expect.anything(),
expect.anything(),
expect.anything(), // query
false, // clientOnly
expect.anything(), // variables
),
];

Expand Down Expand Up @@ -1943,8 +1946,9 @@ describe('EntityStore', () => {
new MissingFieldError(
'Can\'t find field \'title\' on Book:{"isbn":"031648637X"} object',
["book", "title"],
expect.anything(),
expect.anything(),
expect.anything(), // query
false, // clientOnly
expect.anything(), // variables
),
],
});
Expand Down
5 changes: 3 additions & 2 deletions src/cache/inmemory/__tests__/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,8 +1040,9 @@ describe("type policies", function () {
return new MissingFieldError(
`Can't find field 'result' on Job:{"name":"Job #${jobNumber}"} object`,
["jobs", jobNumber - 1, "result"],
expect.anything(),
expect.anything(),
expect.anything(), // query
false, // clientOnly
expect.anything(), // variables
);
}

Expand Down
69 changes: 69 additions & 0 deletions src/cache/inmemory/__tests__/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { StoreObject } from '../types';
import { StoreReader } from '../readFromStore';
import { makeReference, InMemoryCache, Reference, isReference } from '../../../core';
import { Cache } from '../../core/types/Cache';
import { MissingFieldError } from '../../core/types/common';
import { defaultNormalizedCacheFactory } from './helpers';
import { withError } from './diffAgainstStore';

Expand Down Expand Up @@ -556,6 +557,74 @@ describe('reading from the store', () => {
}).toThrowError(/Can't find field 'missingField' on ROOT_QUERY object/);
});

it('distinguishes between missing @client and non-@client fields', () => {
const query = gql`
query {
normal {
present @client
missing
}
clientOnly @client {
present
missing
}
}
`;

const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
normal() {
return { present: "here" };
},
clientOnly() {
return { present: "also here" };
},
},
},
},
});

const { result, complete, missing } = cache.diff({
query,
optimistic: true,
returnPartialData: true,
});

expect(complete).toBe(false);

expect(result).toEqual({
normal: {
present: "here",
},
clientOnly: {
present: "also here",
},
});

expect(missing).toEqual([
new MissingFieldError(
`Can't find field 'missing' on object {
"present": "here"
}`,
["normal", "missing"],
query,
false, // clientOnly
{}, // variables
),
new MissingFieldError(
`Can't find field 'missing' on object {
"present": "also here"
}`,
["clientOnly", "missing"],
query,
true, // clientOnly
{}, // variables
),
]);
});

it('runs a nested query where the reference is null', () => {
const result: any = {
id: 'abcd',
Expand Down
19 changes: 19 additions & 0 deletions src/cache/inmemory/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ interface ReadContext extends ReadMergeModifyContext {
policies: Policies;
fragmentMap: FragmentMap;
path: (string | number)[];
clientOnly: boolean;
};

export type ExecResult<R = any> = {
Expand All @@ -62,6 +63,7 @@ function missingFromInvariant(
err.message,
context.path.slice(),
context.query,
context.clientOnly,
context.variables,
);
}
Expand Down Expand Up @@ -140,6 +142,7 @@ export class StoreReader {
varString: JSON.stringify(variables),
fragmentMap: createFragmentMap(getFragmentDefinitions(query)),
path: [],
clientOnly: false,
},
});

Expand Down Expand Up @@ -260,6 +263,20 @@ export class StoreReader {
const resultName = resultKeyNameFromField(selection);
context.path.push(resultName);

// If this field has an @client directive, then the field and
// everything beneath it is client-only, meaning it will never be
// sent to the server.
const wasClientOnly = context.clientOnly;
// Once we enter a client-only subtree of the query, we can avoid
// repeatedly checking selection.directives.
context.clientOnly = wasClientOnly || !!(
// We don't use the hasDirectives helper here, because it looks
// for directives anywhere inside the AST node, whereas we only
// care about directives directly attached to this field.
selection.directives &&
selection.directives.some(d => d.name.value === "client")
);

if (fieldValue === void 0) {
if (!addTypenameToDocument.added(selection)) {
getMissing().push(
Expand Down Expand Up @@ -312,6 +329,8 @@ export class StoreReader {
objectsToMerge.push({ [resultName]: fieldValue });
}

context.clientOnly = wasClientOnly;

invariant(context.path.pop() === resultName);

} else {
Expand Down

0 comments on commit 5023915

Please sign in to comment.