Skip to content

Commit 92aacbb

Browse files
committed
add GraphQL.js example
1 parent e41d2b6 commit 92aacbb

File tree

5 files changed

+459
-13
lines changed

5 files changed

+459
-13
lines changed

examples/data.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/**
2+
* This file contains the data that is used in our examples. This file does not
3+
* contain an example itself. For a real example see the other files in the
4+
* examples folder.
5+
*/
6+
7+
/**
8+
* Lookup a user by an id and return that user.
9+
*/
10+
export function getUser(id) {
11+
return userByID.get(id);
12+
}
13+
14+
/**
15+
* A batch function which will take an array of users and return an array of the
16+
* friends for each user.
17+
*
18+
* If a limit is provided then it will configure the maximum number of friends
19+
* that are returned. If no limit is provided then all of the friends are
20+
* returned.
21+
*/
22+
export function getFriendsForUsers(users, limit = Infinity) {
23+
return users.map(user => {
24+
const allFriendIDs = friendsByID.get(user.id) || [];
25+
const friendIDs = allFriendIDs.slice(0, limit + 1);
26+
return friendIDs.map(id => getUser(id));
27+
});
28+
}
29+
30+
/**
31+
* Our raw user data. We have a small set of named users with ids.
32+
*/
33+
const rawUsers = [
34+
{ id: 1, name: 'Shirley Hanson' },
35+
{ id: 2, name: 'Linda Bishop' },
36+
{ id: 3, name: 'Arthur Ford' },
37+
{ id: 4, name: 'Martha Franklin' },
38+
{ id: 5, name: 'Helen Gutierrez' },
39+
{ id: 6, name: 'Mary Gonzalez' },
40+
{ id: 7, name: 'Christina Mcdonald' },
41+
{ id: 8, name: 'Alice Ryan' },
42+
{ id: 9, name: 'Samuel Harrison' },
43+
{ id: 10, name: 'Christopher Ellis' },
44+
{ id: 11, name: 'Matthew Spencer' },
45+
{ id: 12, name: 'Julie Reid' },
46+
{ id: 13, name: 'Elizabeth Freeman' },
47+
{ id: 14, name: 'Jose Vasquez' },
48+
{ id: 15, name: 'Martha Henderson' },
49+
{ id: 16, name: 'Virginia Butler' },
50+
{ id: 17, name: 'Mark Fernandez' },
51+
{ id: 18, name: 'Martin Cole' },
52+
{ id: 19, name: 'Anna Price' },
53+
{ id: 20, name: 'Debra Henderson' },
54+
{ id: 21, name: 'Barbara Carroll' },
55+
{ id: 22, name: 'Jennifer Weaver' },
56+
{ id: 23, name: 'Dennis Hart' },
57+
{ id: 24, name: 'Chris Ryan' },
58+
{ id: 25, name: 'Alan Rivera' },
59+
];
60+
61+
/**
62+
* Convert our user data into a map where we can have efficient searches for
63+
* users by id.
64+
*/
65+
const userByID = new Map(rawUsers.map(user => [user.id, user]));
66+
67+
/**
68+
* Raw friendship data. It is an array of distinct pairs in which no pairs are a
69+
* duplicate.
70+
*
71+
* In other words we do not have the pairs `[1, 2]` and `[2, 1]` as they are not
72+
* distinct. They both have the ids `1` and `2`. We also do not have a pair like
73+
* `[1, 1]` which has duplicate `1`s.
74+
*
75+
* This array and the pairs within are sorted to make it easy to spot incorrect
76+
* pairs.
77+
*/
78+
const rawFriendships = [
79+
[1, 5],
80+
[1, 6],
81+
[1, 10],
82+
[1, 11],
83+
[1, 17],
84+
[1, 19],
85+
[1, 20],
86+
[1, 22],
87+
[1, 25],
88+
[2, 7],
89+
[2, 10],
90+
[2, 21],
91+
[2, 22],
92+
[3, 15],
93+
[3, 18],
94+
[3, 20],
95+
[3, 21],
96+
[3, 22],
97+
[3, 25],
98+
[4, 10],
99+
[4, 14],
100+
[4, 17],
101+
[4, 19],
102+
[4, 21],
103+
[5, 6],
104+
[5, 9],
105+
[5, 11],
106+
[5, 12],
107+
[5, 18],
108+
[6, 7],
109+
[6, 9],
110+
[6, 16],
111+
[6, 17],
112+
[7, 8],
113+
[7, 9],
114+
[7, 11],
115+
[7, 12],
116+
[7, 18],
117+
[7, 19],
118+
[7, 22],
119+
[8, 16],
120+
[8, 22],
121+
[9, 10],
122+
[9, 12],
123+
[9, 14],
124+
[9, 20],
125+
[9, 24],
126+
[9, 25],
127+
[10, 12],
128+
[10, 18],
129+
[11, 13],
130+
[11, 15],
131+
[11, 17],
132+
[11, 18],
133+
[11, 21],
134+
[11, 24],
135+
[12, 20],
136+
[13, 17],
137+
[13, 19],
138+
[13, 21],
139+
[14, 23],
140+
[15, 20],
141+
[15, 22],
142+
[16, 18],
143+
[16, 20],
144+
[16, 24],
145+
[16, 25],
146+
[17, 18],
147+
[17, 20],
148+
[17, 23],
149+
[17, 24],
150+
[18, 22],
151+
[18, 25],
152+
[19, 21],
153+
[19, 23],
154+
[20, 22],
155+
[21, 25],
156+
];
157+
158+
/**
159+
* A map of a user id to the ids that user’s friends.
160+
*/
161+
const friendsByID = new Map();
162+
163+
{
164+
// Populate the `friendsByID` array using the `addFriendOneWay` utility
165+
// function.
166+
rawFriendships.forEach(([id1, id2]) => {
167+
addFriendOneWay(id1, id2);
168+
addFriendOneWay(id2, id1);
169+
});
170+
171+
/**
172+
* A utility function we use to populate the `friendsByID` map. It adds a
173+
* directed friendship. Call this function twice, the second time with
174+
* arguments reversed, for the friendship to go both ways.
175+
*/
176+
function addFriendOneWay(id1, id2) {
177+
if (friendsByID.has(id1)) {
178+
friendsByID.get(id1).push(id2);
179+
} else {
180+
friendsByID.set(id1, [id2]);
181+
}
182+
}
183+
}

examples/graphql.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {
2+
GraphQLObjectType,
3+
GraphQLInt,
4+
GraphQLString,
5+
GraphQLList,
6+
GraphQLNonNull,
7+
GraphQLSchema,
8+
} from 'graphql';
9+
import { createBatchResolver } from '../src/batch';
10+
import { getUser, getFriendsForUsers } from './data';
11+
12+
const UserType = new GraphQLObjectType({
13+
name: 'User',
14+
fields: () => ({
15+
id: { type: GraphQLInt },
16+
name: { type: GraphQLString },
17+
friends: {
18+
type: new GraphQLList(UserType),
19+
args: {
20+
limit: { type: GraphQLInt },
21+
},
22+
resolve: createBatchResolver((users, { limit }) => {
23+
console.log('Resolving friends 👫'); // eslint-disable-line no-console
24+
return getFriendsForUsers(users, limit);
25+
}),
26+
},
27+
}),
28+
});
29+
30+
const QueryType = new GraphQLObjectType({
31+
name: 'Query',
32+
fields: {
33+
user: {
34+
type: UserType,
35+
args: {
36+
id: { type: new GraphQLNonNull(GraphQLInt) },
37+
},
38+
resolve: (source, { id }) => getUser(id),
39+
},
40+
},
41+
});
42+
43+
const Schema = new GraphQLSchema({
44+
query: QueryType,
45+
});
46+
47+
export default Schema;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"scripts": {
3030
"preversion": "npm run ci",
3131
"prepublish": "npm run build",
32-
"format": "prettier 'src/**/*.js' --write --print-width 80 --tab-width 2 --single-quote --trailing-comma all",
32+
"format": "prettier 'src/**/*.js' 'examples/**/*.js' --write --print-width 80 --tab-width 2 --single-quote --trailing-comma all",
3333
"lint": "eslint 'src/**/*.js'",
3434
"test": "jest",
3535
"test-watch": "jest --watch",

src/batch.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,15 @@ class Batcher {
3535
* the batch resolver finishes the `resolve` and `reject` functions will be
3636
* executed.
3737
*
38-
* We group batches together by `info.fieldNodes`.
38+
* We group batches together by the first item in `info.fieldNodes`.
3939
*/
4040
batch(source, args, context, info, resolve, reject) {
41-
const { fieldNodes } = info;
42-
let batch = this._batches.get(fieldNodes);
41+
// We only use the first field node because the array is reconstructed for
42+
// every value. Using only the first node *should not matter*. The nodes
43+
// should not get reused and we should not be missing any information from
44+
// the other fields.
45+
const { fieldNodes: [fieldNode] } = info;
46+
let batch = this._batches.get(fieldNode);
4347

4448
// If no batch currently exists for this array of field nodes then we want
4549
// to create one.
@@ -58,7 +62,7 @@ class Batcher {
5862
sources: [],
5963
callbacks: [],
6064
};
61-
this._batches.set(fieldNodes, batch);
65+
this._batches.set(fieldNode, batch);
6266
}
6367

6468
// Add our source and callbacks to the batch.

0 commit comments

Comments
 (0)