Add field aliases to structured GraphQL queries (#116)

Summary:
For pagination, we’ll want to query against multiple entities of the
same type. GraphQL uses aliases to facilitate this. This commit adds
support for aliases to our GraphQL query DSL.

Test Plan:
Inspect snapshot changes, and note that `yarn flow` and `yarn test`
pass.

wchargin-branch: graphql-aliases
This commit is contained in:
William Chargin 2018-03-26 20:54:16 -07:00 committed by GitHub
parent 2f50aa7364
commit e6f401df30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 6 deletions

View File

@ -200,6 +200,7 @@ Array [
],
"selections": Array [
Object {
"alias": null,
"args": Object {
"id": Object {
"data": 12345,
@ -213,6 +214,7 @@ Array [
"name": "thing",
"selections": Array [
Object {
"alias": null,
"args": Object {
"tasty": Object {
"data": true,
@ -235,16 +237,19 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "more",
"selections": Array [
Object {
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "mcguffins",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "quantity",
"selections": Array [],
@ -254,6 +259,7 @@ Array [
"type": "FIELD",
},
Object {
"alias": "goo",
"args": Object {
"state": Object {
"data": "SLIMY",
@ -263,6 +269,7 @@ Array [
"name": "slime",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "availability",
"selections": Array [],
@ -278,6 +285,7 @@ Array [
Object {
"selections": Array [
Object {
"alias": null,
"args": Object {
"attributes": Object {
"data": Object {
@ -325,10 +333,12 @@ Array [
"params": Array [],
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "rateLimit",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "remaining",
"selections": Array [],
@ -344,12 +354,14 @@ Array [
"name": "otherThings",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "__typename",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "quality",
"selections": Array [],
@ -362,7 +374,7 @@ Array [
]
`;
exports[`queries end-to-end-test cases for a query using lots of features should stringify as inline 1`] = `"query QueryWithParameters($qp1: String! $qp2: String!) { thing(id: 12345 name: $qp1) { fruit(type: APPLE tasty: true) ...otherThings } more { ... on Widget { mcguffins { quantity } slime(state: SLIMY) { availability } } ... on Gizmo { cogs(attributes: { teeth: [ 12 14 16 ] shaft: null }) } } } query QueryWithoutParameters { rateLimit { remaining } } fragment otherThings on Thing { __typename quality }"`;
exports[`queries end-to-end-test cases for a query using lots of features should stringify as inline 1`] = `"query QueryWithParameters($qp1: String! $qp2: String!) { thing(id: 12345 name: $qp1) { fruit(type: APPLE tasty: true) ...otherThings } more { ... on Widget { mcguffins { quantity } goo: slime(state: SLIMY) { availability } } ... on Gizmo { cogs(attributes: { teeth: [ 12 14 16 ] shaft: null }) } } } query QueryWithoutParameters { rateLimit { remaining } } fragment otherThings on Thing { __typename quality }"`;
exports[`queries end-to-end-test cases for a query using lots of features should stringify as multiline 1`] = `
"query QueryWithParameters($qp1: String! $qp2: String!) {
@ -375,7 +387,7 @@ exports[`queries end-to-end-test cases for a query using lots of features should
mcguffins {
quantity
}
slime(state: SLIMY) {
goo: slime(state: SLIMY) {
availability
}
}
@ -411,6 +423,7 @@ Array [
],
"selections": Array [
Object {
"alias": null,
"args": Object {
"name": Object {
"data": "repoName",
@ -424,6 +437,7 @@ Array [
"name": "repository",
"selections": Array [
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 100,
@ -433,10 +447,12 @@ Array [
"name": "issues",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -446,34 +462,40 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "title",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "number",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -485,6 +507,7 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 20,
@ -494,10 +517,12 @@ Array [
"name": "comments",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -507,16 +532,19 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -528,12 +556,14 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "url",
"selections": Array [],
@ -552,6 +582,7 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 100,
@ -561,10 +592,12 @@ Array [
"name": "pullRequests",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -574,34 +607,40 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "title",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "number",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -613,6 +652,7 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 20,
@ -622,10 +662,12 @@ Array [
"name": "comments",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -635,16 +677,19 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -656,12 +701,14 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "url",
"selections": Array [],
@ -674,6 +721,7 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 10,
@ -683,10 +731,12 @@ Array [
"name": "reviews",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -696,22 +746,26 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -723,12 +777,14 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "state",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {
"first": Object {
"data": 10,
@ -738,10 +794,12 @@ Array [
"name": "comments",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "pageInfo",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "hasNextPage",
"selections": Array [],
@ -751,22 +809,26 @@ Array [
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "nodes",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "body",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "author",
"selections": Array [
@ -805,12 +867,14 @@ Array [
"name": "whoami",
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "__typename",
"selections": Array [],
"type": "FIELD",
},
Object {
"alias": null,
"args": Object {},
"name": "login",
"selections": Array [],
@ -819,6 +883,7 @@ Array [
Object {
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
@ -831,6 +896,7 @@ Array [
Object {
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],
@ -843,6 +909,7 @@ Array [
Object {
"selections": Array [
Object {
"alias": null,
"args": Object {},
"name": "id",
"selections": Array [],

View File

@ -36,6 +36,7 @@ export type FragmentDefinition = {|
export type Selection = Field | FragmentSpread | InlineFragment;
export type Field = {|
+type: "FIELD",
+alias: ?string,
+name: string,
+args: Arguments,
+selections: Selection[],
@ -100,12 +101,23 @@ export const build = {
field(name: string, args: ?Arguments, selections: ?(Selection[])): Field {
return {
type: "FIELD",
alias: null,
name,
args: args || {},
selections: selections || [],
};
},
alias(newAlias: string, field: Field): Field {
return {
type: "FIELD",
alias: newAlias,
name: field.name,
args: field.args,
selections: field.selections,
};
},
fragmentSpread(fragmentName: string): FragmentSpread {
return {
type: "FRAGMENT_SPREAD",
@ -308,6 +320,13 @@ export const stringify = {
},
field(field: Field, ls: LayoutStrategy): string {
const aliasPart = (() => {
if (field.alias == null) {
return "";
} else {
return `${field.alias}: `;
}
})();
const argsPart = (() => {
if (Object.keys(field.args).length === 0) {
return "";
@ -325,7 +344,7 @@ export const stringify = {
ls.next()
);
return ls.join([
ls.atom(`${field.name}${argsPart} {`),
ls.atom(`${aliasPart}${field.name}${argsPart} {`),
selectionsPart,
ls.atom("}"),
]);

View File

@ -88,9 +88,12 @@ function featurefulQuery(): Body {
b.field("more", {}, [
b.inlineFragment("Widget", [
b.field("mcguffins", {}, [b.field("quantity")]),
b.field("slime", {state: b.enumLiteral("SLIMY")}, [
b.field("availability"),
]),
b.alias(
"goo",
b.field("slime", {state: b.enumLiteral("SLIMY")}, [
b.field("availability"),
])
),
]),
b.inlineFragment("Gizmo", [
b.field("cogs", {