From 5c937d860473e22b390ca67827348f6ce90df1de Mon Sep 17 00:00:00 2001 From: William Chargin Date: Sat, 29 Feb 2020 16:59:39 -0800 Subject: [PATCH] mirror: add typename support to `UpdateResult`s (#1664) Summary: The internal `UpdateResult` structure now lists IDs of objects whose typename has been queried. This list is expected to be empty for now. Test Plan: Unit tests added. wchargin-branch: mirror-typename-updateresult --- src/graphql/mirror.js | 35 +++++++++++++++++++++++++++++------ src/graphql/mirror.test.js | 28 ++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/graphql/mirror.js b/src/graphql/mirror.js index f5d9302..ec32a64 100644 --- a/src/graphql/mirror.js +++ b/src/graphql/mirror.js @@ -735,7 +735,9 @@ export class Mirror { queryResult: UpdateResult ): void { for (const topLevelKey of Object.keys(queryResult)) { - if (topLevelKey.startsWith(_FIELD_PREFIXES.OWN_DATA)) { + if (topLevelKey.startsWith(_FIELD_PREFIXES.TYPENAMES)) { + throw new Error("Typename update results not yet supported"); + } else if (topLevelKey.startsWith(_FIELD_PREFIXES.OWN_DATA)) { const rawValue: OwnDataUpdateResult | NodeConnectionsUpdateResult = queryResult[topLevelKey]; const updateRecord: OwnDataUpdateResult = (rawValue: any); @@ -2092,6 +2094,16 @@ type NestedFieldResult = { +[Schema.Fieldname]: PrimitiveResult | NodeFieldResult, } | null; +/** + * Result describing only the typename of a set of nodes. Used when we + * only have references to nodes via unfaithful fields. + */ +type TypenamesUpdateResult = $ReadOnlyArray<{| + +__typename: Schema.Typename, + +id: Schema.ObjectId, +|}>; +export type _TypenamesUpdateResult = TypenamesUpdateResult; // for tests + /** * Result describing own-data for many nodes of a given type. Whether a * value is a `PrimitiveResult` or a `NodeFieldResult` is determined by @@ -2107,6 +2119,7 @@ type OwnDataUpdateResult = $ReadOnlyArray<{ | NodeFieldResult | NestedFieldResult, }>; +export type _OwnDataUpdateResult = OwnDataUpdateResult; // for tests /** * Result describing new elements for connections on a single node. @@ -2117,12 +2130,13 @@ type NodeConnectionsUpdateResult = { +id: Schema.ObjectId, +[connectionFieldname: Schema.Fieldname]: ConnectionFieldResult, }; +export type _NodeConnectionsUpdateResult = NodeConnectionsUpdateResult; // for tests /** - * Result describing both own-data updates and connection updates. Each - * key's prefix determines what type of results the corresponding value - * represents (see constants below). No field prefix is a prefix of - * another, so this characterization is complete. + * Result describing all kinds of updates. Each key's prefix determines + * what type of results the corresponding value represents (see + * constants below). No field prefix is a prefix of another, so this + * characterization is complete. * * This type would be exact but for facebook/flow#2977, et al. * @@ -2131,10 +2145,19 @@ type NodeConnectionsUpdateResult = { type UpdateResult = { // The prefix of each key determines what type of results the value // represents. See constants below. - +[string]: OwnDataUpdateResult | NodeConnectionsUpdateResult, + +[string]: + | TypenamesUpdateResult + | OwnDataUpdateResult + | NodeConnectionsUpdateResult, }; export const _FIELD_PREFIXES = deepFreeze({ + /** + * A key of an `UpdateResult` has this prefix if and only if the + * corresponding value represents `TypenamesUpdateResult`s. + */ + TYPENAMES: "typenames_", + /** * A key of an `UpdateResult` has this prefix if and only if the * corresponding value represents `OwnDataUpdateResult`s. diff --git a/src/graphql/mirror.test.js b/src/graphql/mirror.test.js index f359934..77aa712 100644 --- a/src/graphql/mirror.test.js +++ b/src/graphql/mirror.test.js @@ -13,6 +13,8 @@ import { _inTransaction, _makeSingleUpdateFunction, Mirror, + type _OwnDataUpdateResult, + type _TypenamesUpdateResult, } from "./mirror"; import stringify from "json-stable-stringify"; @@ -799,6 +801,20 @@ describe("graphql/mirror", () => { }).toThrow('Bad key in query result: "wat_0"'); }); + it("throws if given a key with typename results", () => { + const db = new Database(":memory:"); + const mirror = new Mirror(db, buildGithubSchema()); + const updateId = mirror._createUpdate(new Date(123)); + const result = { + typenames_0: ([ + {id: "issue:#1", __typename: "Issue"}, + ]: _TypenamesUpdateResult), + }; + expect(() => { + mirror._nontransactionallyUpdateData(updateId, result); + }).toThrow("Typename update results not yet supported"); + }); + // We test the happy path lightly, because it just delegates to // other methods, which are themselves tested. This test is // sufficient to effect full coverage. @@ -810,14 +826,14 @@ describe("graphql/mirror", () => { mirror.registerObject({typename: "Issue", id: "issue:#1"}); mirror.registerObject({typename: "Issue", id: "issue:#2"}); const result = { - owndata_0: [ + owndata_0: ([ { __typename: "Repository", id: "repo:foo/bar", url: "url://foo/bar", }, - ], - owndata_1: [ + ]: _OwnDataUpdateResult), + owndata_1: ([ { __typename: "Issue", id: "issue:#1", @@ -846,7 +862,7 @@ describe("graphql/mirror", () => { id: "user:alice", }, }, - ], + ]: _OwnDataUpdateResult), node_0: { id: "repo:foo/bar", issues: { @@ -3797,13 +3813,13 @@ describe("graphql/mirror", () => { const rowid = mirror._logRequest(query, queryParameters, new Date(123)); const response = { - owndata_0: [ + owndata_0: ([ { __typename: "Repository", id: "repo:foo/bar", url: "url://foo/bar", }, - ], + ]: _OwnDataUpdateResult), }; mirror._logResponse(rowid, response, new Date(456));