mirror: include typenames in extracted data (#897)
Summary: These typenames are often superfluous, but sometimes they are useful. For instance, we might want to fetch the same data for `User`s, `Bot`s, and `Organization`s, but still differentiate which kind of node we fetched from an `Actor` union reference. Similarly, many timeline events may have similar signatures (like, “issue closed” vs. “issue reopened”). Test Plan: Existing unit tests have been updated; run `yarn unit`. wchargin-branch: mirror-extract-typenames
This commit is contained in:
parent
c7ba89b807
commit
9a4c91887b
|
@ -964,24 +964,30 @@ export class Mirror {
|
||||||
* For instance, the result of `extract("issue:1")` might be:
|
* For instance, the result of `extract("issue:1")` might be:
|
||||||
*
|
*
|
||||||
* {
|
* {
|
||||||
|
* __typename: "Issue",
|
||||||
* id: "issue:1172",
|
* id: "issue:1172",
|
||||||
* title: "bug: holding <Space> causes CPU to overheat",
|
* title: "bug: holding <Space> causes CPU to overheat",
|
||||||
* body: "We should fix this immediately.",
|
* body: "We should fix this immediately.",
|
||||||
* author: {
|
* author: {
|
||||||
|
* __typename: "User",
|
||||||
* id: "user:admin",
|
* id: "user:admin",
|
||||||
* login: "admin",
|
* login: "admin",
|
||||||
* },
|
* },
|
||||||
* comments: [
|
* comments: [
|
||||||
* {
|
* {
|
||||||
|
* __typename: "IssueComment",
|
||||||
* body: "I depend on this behavior; please do not change it.",
|
* body: "I depend on this behavior; please do not change it.",
|
||||||
* author: {
|
* author: {
|
||||||
|
* __typename: "User",
|
||||||
* id: "user:longtimeuser4",
|
* id: "user:longtimeuser4",
|
||||||
* login: "longtimeuser4",
|
* login: "longtimeuser4",
|
||||||
* },
|
* },
|
||||||
* },
|
* },
|
||||||
* {
|
* {
|
||||||
|
* __typename: "IssueComment",
|
||||||
* body: "That's horrifying.",
|
* body: "That's horrifying.",
|
||||||
* author: {
|
* author: {
|
||||||
|
* __typename: "User",
|
||||||
* id: "user:admin",
|
* id: "user:admin",
|
||||||
* login: "admin",
|
* login: "admin",
|
||||||
* },
|
* },
|
||||||
|
@ -1090,8 +1096,8 @@ export class Mirror {
|
||||||
// Constructing the result set inherently requires mutation,
|
// Constructing the result set inherently requires mutation,
|
||||||
// because the object graph can have cycles. We start by
|
// because the object graph can have cycles. We start by
|
||||||
// creating a record for each object, with just that object's
|
// creating a record for each object, with just that object's
|
||||||
// primitive data. Then, we link in node references and
|
// primitive data and typename. Then, we link in node references
|
||||||
// connection entries.
|
// and connection entries.
|
||||||
const allObjects: Map<Schema.ObjectId, Object> = new Map();
|
const allObjects: Map<Schema.ObjectId, Object> = new Map();
|
||||||
for (const typename of typenames) {
|
for (const typename of typenames) {
|
||||||
const objectType = this._schemaInfo.objectTypes[typename];
|
const objectType = this._schemaInfo.objectTypes[typename];
|
||||||
|
@ -1125,6 +1131,7 @@ export class Mirror {
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
const object = {};
|
const object = {};
|
||||||
object.id = row.id;
|
object.id = row.id;
|
||||||
|
object.__typename = typename;
|
||||||
for (const key of Object.keys(row)) {
|
for (const key of Object.keys(row)) {
|
||||||
if (key === "id") continue;
|
if (key === "id") continue;
|
||||||
object[key] = JSON.parse(row[key]);
|
object[key] = JSON.parse(row[key]);
|
||||||
|
|
|
@ -1405,16 +1405,19 @@ describe("graphql/mirror", () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
type Caveman = {|
|
type Caveman = {|
|
||||||
|
+__typename: "Caveman",
|
||||||
+id: string,
|
+id: string,
|
||||||
+only: mixed,
|
+only: mixed,
|
||||||
+primitives: mixed,
|
+primitives: mixed,
|
||||||
|};
|
|};
|
||||||
type Feline = {|
|
type Feline = {|
|
||||||
|
+__typename: "Feline",
|
||||||
+id: string,
|
+id: string,
|
||||||
+only: null | Feline,
|
+only: null | Feline,
|
||||||
+lynx: null | Feline,
|
+lynx: null | Feline,
|
||||||
|};
|
|};
|
||||||
type Socket = {|
|
type Socket = {|
|
||||||
|
+__typename: "Socket",
|
||||||
+id: string,
|
+id: string,
|
||||||
+only: $ReadOnlyArray<null | Socket>,
|
+only: $ReadOnlyArray<null | Socket>,
|
||||||
+connections: $ReadOnlyArray<null | Socket>,
|
+connections: $ReadOnlyArray<null | Socket>,
|
||||||
|
@ -1551,6 +1554,7 @@ describe("graphql/mirror", () => {
|
||||||
]);
|
]);
|
||||||
const result: Caveman = (mirror.extract("brog"): any);
|
const result: Caveman = (mirror.extract("brog"): any);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Caveman",
|
||||||
id: "brog",
|
id: "brog",
|
||||||
only: "ugg",
|
only: "ugg",
|
||||||
primitives: "ook",
|
primitives: "ook",
|
||||||
|
@ -1586,12 +1590,15 @@ describe("graphql/mirror", () => {
|
||||||
]);
|
]);
|
||||||
const result = mirror.extract("alpha");
|
const result = mirror.extract("alpha");
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Feline",
|
||||||
id: "alpha",
|
id: "alpha",
|
||||||
only: null,
|
only: null,
|
||||||
lynx: {
|
lynx: {
|
||||||
|
__typename: "Feline",
|
||||||
id: "beta",
|
id: "beta",
|
||||||
only: null,
|
only: null,
|
||||||
lynx: {
|
lynx: {
|
||||||
|
__typename: "Feline",
|
||||||
id: "gamma",
|
id: "gamma",
|
||||||
only: null,
|
only: null,
|
||||||
lynx: null,
|
lynx: null,
|
||||||
|
@ -1634,15 +1641,27 @@ describe("graphql/mirror", () => {
|
||||||
updateConnection("localhost:6060", "connections", []);
|
updateConnection("localhost:6060", "connections", []);
|
||||||
const result = mirror.extract("localhost:8080");
|
const result = mirror.extract("localhost:8080");
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost:8080",
|
id: "localhost:8080",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [
|
connections: [
|
||||||
{
|
{
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost:7070",
|
id: "localhost:7070",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [
|
connections: [
|
||||||
{id: "localhost:6060", only: [], connections: []},
|
{
|
||||||
{id: "localhost:6060", only: [], connections: []},
|
__typename: "Socket",
|
||||||
|
id: "localhost:6060",
|
||||||
|
only: [],
|
||||||
|
connections: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: "Socket",
|
||||||
|
id: "localhost:6060",
|
||||||
|
only: [],
|
||||||
|
connections: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -1656,7 +1675,7 @@ describe("graphql/mirror", () => {
|
||||||
const updateId = mirror._createUpdate(new Date(123));
|
const updateId = mirror._createUpdate(new Date(123));
|
||||||
mirror._updateOwnData(updateId, [{__typename: "Empty", id: "mt"}]);
|
mirror._updateOwnData(updateId, [{__typename: "Empty", id: "mt"}]);
|
||||||
const result = mirror.extract("mt");
|
const result = mirror.extract("mt");
|
||||||
expect(result).toEqual({id: "mt"});
|
expect(result).toEqual({__typename: "Empty", id: "mt"});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("handles boolean primitives", () => {
|
it("handles boolean primitives", () => {
|
||||||
|
@ -1668,6 +1687,7 @@ describe("graphql/mirror", () => {
|
||||||
{__typename: "Caveman", id: "brog", only: false, primitives: true},
|
{__typename: "Caveman", id: "brog", only: false, primitives: true},
|
||||||
]);
|
]);
|
||||||
expect(mirror.extract("brog")).toEqual({
|
expect(mirror.extract("brog")).toEqual({
|
||||||
|
__typename: "Caveman",
|
||||||
id: "brog",
|
id: "brog",
|
||||||
only: false,
|
only: false,
|
||||||
primitives: true,
|
primitives: true,
|
||||||
|
@ -1683,6 +1703,7 @@ describe("graphql/mirror", () => {
|
||||||
{__typename: "Caveman", id: "brog", only: null, primitives: null},
|
{__typename: "Caveman", id: "brog", only: null, primitives: null},
|
||||||
]);
|
]);
|
||||||
expect(mirror.extract("brog")).toEqual({
|
expect(mirror.extract("brog")).toEqual({
|
||||||
|
__typename: "Caveman",
|
||||||
id: "brog",
|
id: "brog",
|
||||||
only: null,
|
only: null,
|
||||||
primitives: null,
|
primitives: null,
|
||||||
|
@ -1698,6 +1719,7 @@ describe("graphql/mirror", () => {
|
||||||
{__typename: "Caveman", id: "brog", only: 123, primitives: 987},
|
{__typename: "Caveman", id: "brog", only: 123, primitives: 987},
|
||||||
]);
|
]);
|
||||||
expect(mirror.extract("brog")).toEqual({
|
expect(mirror.extract("brog")).toEqual({
|
||||||
|
__typename: "Caveman",
|
||||||
id: "brog",
|
id: "brog",
|
||||||
only: 123,
|
only: 123,
|
||||||
primitives: 987,
|
primitives: 987,
|
||||||
|
@ -1733,12 +1755,15 @@ describe("graphql/mirror", () => {
|
||||||
]);
|
]);
|
||||||
const result: Feline = (mirror.extract("alpha"): any);
|
const result: Feline = (mirror.extract("alpha"): any);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Feline",
|
||||||
id: "alpha",
|
id: "alpha",
|
||||||
only: null,
|
only: null,
|
||||||
lynx: {
|
lynx: {
|
||||||
|
__typename: "Feline",
|
||||||
id: "beta",
|
id: "beta",
|
||||||
only: result.lynx,
|
only: result.lynx,
|
||||||
lynx: {
|
lynx: {
|
||||||
|
__typename: "Feline",
|
||||||
id: "gamma",
|
id: "gamma",
|
||||||
only: result.lynx,
|
only: result.lynx,
|
||||||
lynx: null,
|
lynx: null,
|
||||||
|
@ -1784,16 +1809,19 @@ describe("graphql/mirror", () => {
|
||||||
updateConnection("localhost:6060", "connections", ["localhost:7070"]);
|
updateConnection("localhost:6060", "connections", ["localhost:7070"]);
|
||||||
const result: Socket = (mirror.extract("localhost:8080"): any);
|
const result: Socket = (mirror.extract("localhost:8080"): any);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost:8080",
|
id: "localhost:8080",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [
|
connections: [
|
||||||
{
|
{
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost:7070",
|
id: "localhost:7070",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [
|
connections: [
|
||||||
result,
|
result,
|
||||||
result.connections[0],
|
result.connections[0],
|
||||||
{
|
{
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost:6060",
|
id: "localhost:6060",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [result.connections[0]],
|
connections: [result.connections[0]],
|
||||||
|
@ -1838,6 +1866,7 @@ describe("graphql/mirror", () => {
|
||||||
});
|
});
|
||||||
const result: Socket = (mirror.extract("localhost"): any);
|
const result: Socket = (mirror.extract("localhost"): any);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Socket",
|
||||||
id: "localhost",
|
id: "localhost",
|
||||||
only: [],
|
only: [],
|
||||||
connections: [null, result, null, result, result, null],
|
connections: [null, result, null, result, result, null],
|
||||||
|
@ -2071,13 +2100,16 @@ describe("graphql/mirror", () => {
|
||||||
|
|
||||||
const result = mirror.extract("repo:foo/bar");
|
const result = mirror.extract("repo:foo/bar");
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
|
__typename: "Repository",
|
||||||
id: "repo:foo/bar",
|
id: "repo:foo/bar",
|
||||||
url: "url://foo/bar",
|
url: "url://foo/bar",
|
||||||
issues: [
|
issues: [
|
||||||
{
|
{
|
||||||
|
__typename: "Issue",
|
||||||
id: "issue:#1",
|
id: "issue:#1",
|
||||||
url: "url://issue/1",
|
url: "url://issue/1",
|
||||||
author: {
|
author: {
|
||||||
|
__typename: "User",
|
||||||
id: "user:alice",
|
id: "user:alice",
|
||||||
url: "url://alice",
|
url: "url://alice",
|
||||||
login: "alice",
|
login: "alice",
|
||||||
|
@ -2088,6 +2120,7 @@ describe("graphql/mirror", () => {
|
||||||
timeline: [],
|
timeline: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "Issue",
|
||||||
id: "issue:#2",
|
id: "issue:#2",
|
||||||
url: "url://issue/2",
|
url: "url://issue/2",
|
||||||
author: null,
|
author: null,
|
||||||
|
@ -2096,18 +2129,22 @@ describe("graphql/mirror", () => {
|
||||||
"by the time you read this, I will have deleted my account",
|
"by the time you read this, I will have deleted my account",
|
||||||
comments: [
|
comments: [
|
||||||
{
|
{
|
||||||
|
__typename: "IssueComment",
|
||||||
id: "comment:#2.1",
|
id: "comment:#2.1",
|
||||||
body: "cya",
|
body: "cya",
|
||||||
author: {
|
author: {
|
||||||
|
__typename: "User",
|
||||||
id: "user:alice",
|
id: "user:alice",
|
||||||
url: "url://alice",
|
url: "url://alice",
|
||||||
login: "alice",
|
login: "alice",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
__typename: "IssueComment",
|
||||||
id: "comment:#2.2",
|
id: "comment:#2.2",
|
||||||
body: "alas, I did not know them well",
|
body: "alas, I did not know them well",
|
||||||
author: {
|
author: {
|
||||||
|
__typename: "User",
|
||||||
id: "user:bob",
|
id: "user:bob",
|
||||||
url: "url://bob",
|
url: "url://bob",
|
||||||
login: "bob",
|
login: "bob",
|
||||||
|
@ -2116,8 +2153,10 @@ describe("graphql/mirror", () => {
|
||||||
],
|
],
|
||||||
timeline: [
|
timeline: [
|
||||||
{
|
{
|
||||||
|
__typename: "ClosedEvent",
|
||||||
id: "issue:#2!closed#0",
|
id: "issue:#2!closed#0",
|
||||||
actor: {
|
actor: {
|
||||||
|
__typename: "User",
|
||||||
id: "user:alice",
|
id: "user:alice",
|
||||||
url: "url://alice",
|
url: "url://alice",
|
||||||
login: "alice",
|
login: "alice",
|
||||||
|
|
Loading…
Reference in New Issue