Skip to content

Commit 1854b48

Browse files
committed
Merge branch 'dev' into sh/jest-ts-config
2 parents f796230 + 2f838b8 commit 1854b48

File tree

5 files changed

+315
-1
lines changed

5 files changed

+315
-1
lines changed

package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"*.{js,ts,css,md}": "prettier --write --ignore-unknown"
5050
},
5151
"dependencies": {
52-
"redis": "^4.1.0"
52+
"redis": "^4.1.0",
53+
"graphql": "^16.5.0"
5354
}
5455
}

src/@types/buildTypeWeights.d.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
interface Fields {
2+
[index: string]: number;
3+
}
4+
5+
interface Type {
6+
weight: number;
7+
fields: Fields;
8+
}
9+
10+
interface TypeWeightObject {
11+
[index: string]: Type;
12+
}
13+
14+
interface TypeWeightConfig {
15+
mutation?: number;
16+
query?: number;
17+
object?: number;
18+
scalar?: number;
19+
connection?: number;
20+
}

src/analysis/buildTypeWeights.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { GraphQLSchema } from 'graphql/type/schema';
2+
3+
/**
4+
* The default typeWeightsConfig object is based off of Shopifys implementation of query
5+
* cost analysis. Our function should input a users configuration of type weights or fall
6+
* back on shopifys settings. We can change this later.
7+
*
8+
* This function should
9+
* - itreate through the schema object and create the typeWeightObject as described in the tests
10+
* - validate that the typeWeightsConfig parameter has no negative values (throw an error if it does)
11+
*
12+
* @param schema
13+
* @param typeWeightsConfig
14+
*/
15+
function buildTypeWeightsFromSchema(
16+
schema: GraphQLSchema,
17+
typeWeightsConfig: TypeWeightConfig = {
18+
mutation: 10,
19+
object: 1,
20+
scalar: 0,
21+
connection: 2,
22+
}
23+
): TypeWeightObject {
24+
throw Error(`getTypeWeightsFromSchema is not implemented.`);
25+
}
26+
export default buildTypeWeightsFromSchema;
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
import { buildSchema } from 'graphql';
2+
import { GraphQLSchema } from 'graphql/type/schema';
3+
import buildTypeWeightsFromSchema from '../../src/analysis/buildTypeWeights';
4+
5+
xdescribe('Test buildTypeWeightsFromSchema function', () => {
6+
let schema: GraphQLSchema;
7+
8+
// this is dependant on the default type weight settings for the function
9+
describe('creates the "type weight object" from a graphql schema object with...', () => {
10+
test('a single query type', () => {
11+
schema = buildSchema(`
12+
type Query {
13+
name: String
14+
email: String
15+
}
16+
`);
17+
18+
expect(buildTypeWeightsFromSchema(schema)).toEqual({
19+
Query: {
20+
weight: 1,
21+
fields: {
22+
name: 0,
23+
email: 0,
24+
},
25+
},
26+
});
27+
});
28+
29+
test('multiple types', () => {
30+
schema = buildSchema(`
31+
type User {
32+
name: String
33+
email: String
34+
}
35+
36+
type Movie {
37+
name: String
38+
director: String
39+
}
40+
`);
41+
42+
expect(buildTypeWeightsFromSchema(schema)).toEqual({
43+
User: {
44+
weight: 1,
45+
fields: {
46+
name: 0,
47+
email: 0,
48+
},
49+
},
50+
Movie: {
51+
weight: 1,
52+
fields: {
53+
name: 0,
54+
director: 0,
55+
},
56+
},
57+
});
58+
});
59+
60+
test('nested object types', () => {
61+
schema = buildSchema(`
62+
type Query {
63+
user: User
64+
movie: Movie
65+
}
66+
67+
type User {
68+
name: String
69+
email: String
70+
}
71+
72+
type Movie {
73+
name: String
74+
director: User
75+
}
76+
`);
77+
78+
expect(buildTypeWeightsFromSchema(schema)).toEqual({
79+
Query: {
80+
weight: 1,
81+
fields: {},
82+
},
83+
User: {
84+
weight: 1,
85+
fields: {
86+
name: 0,
87+
email: 0,
88+
},
89+
},
90+
Movie: {
91+
weight: 1,
92+
fields: {
93+
name: 0,
94+
},
95+
},
96+
});
97+
});
98+
99+
test('all scalar types', () => {
100+
schema = buildSchema(`
101+
type Test {
102+
num: Int,
103+
id: ID,
104+
float: Float,
105+
bool: Boolean,
106+
string: String
107+
}
108+
`);
109+
110+
expect(buildTypeWeightsFromSchema(schema)).toEqual({
111+
Test: {
112+
weight: 1,
113+
fields: {
114+
num: 0,
115+
id: 0,
116+
float: 0,
117+
bool: 0,
118+
string: 0,
119+
},
120+
},
121+
});
122+
});
123+
124+
// TODO: Tests should be written to acount for the additional scenarios possible in a schema
125+
// Mutation type
126+
// Subscription type
127+
// List type
128+
// Enem types
129+
// Interface
130+
// Unions
131+
// Input types
132+
});
133+
134+
describe('changes "type weight object" type weights with user configuration of...', () => {
135+
let expectedOutput: TypeWeightObject;
136+
137+
beforeEach(() => {
138+
schema = buildSchema(`
139+
type Query {
140+
user: User
141+
movie: Movie
142+
}
143+
144+
type User {
145+
name: String
146+
email: String
147+
}
148+
149+
type Movie {
150+
name: String
151+
director: User
152+
}
153+
`);
154+
155+
// This expected output is using default type weight settings.
156+
// Each test will override values for feild weights configuration.
157+
expectedOutput = {
158+
Query: {
159+
weight: 1,
160+
fields: {},
161+
},
162+
User: {
163+
weight: 1,
164+
fields: {
165+
name: 0,
166+
email: 0,
167+
},
168+
},
169+
Movie: {
170+
weight: 1,
171+
fields: {
172+
name: 0,
173+
},
174+
},
175+
};
176+
});
177+
178+
// this is only if we choose to have 'query' as its own property (seperate from object types) in the user configuration options
179+
xtest('query parameter', () => {
180+
const typeWeightObject = buildTypeWeightsFromSchema(schema, {
181+
query: 2,
182+
});
183+
expectedOutput.query.weight = 2;
184+
185+
expect(typeWeightObject).toEqual({ expectedOutput });
186+
});
187+
188+
test('object parameter', () => {
189+
const typeWeightObject = buildTypeWeightsFromSchema(schema, {
190+
object: 2,
191+
});
192+
193+
expectedOutput.user.weight = 2;
194+
expectedOutput.movie.weight = 2;
195+
196+
expect(typeWeightObject).toEqual({ expectedOutput });
197+
});
198+
199+
test('scalar parameter', () => {
200+
const typeWeightObject = buildTypeWeightsFromSchema(schema, {
201+
scalar: 2,
202+
});
203+
204+
expectedOutput.user.fields.name = 2;
205+
expectedOutput.user.fields.email = 2;
206+
expectedOutput.movie.fields.name = 2;
207+
208+
expect(typeWeightObject).toEqual({ expectedOutput });
209+
});
210+
211+
// TODO: Tests should be written for the remaining configuration options
212+
// mutations
213+
// connections
214+
// subscriptions
215+
});
216+
217+
describe('throws an error if...', () => {
218+
beforeEach(() => {
219+
schema = buildSchema(`
220+
type Query {
221+
user: User
222+
movie: Movie
223+
}
224+
225+
type User {
226+
name: String
227+
email: String
228+
}
229+
230+
type Movie {
231+
name: String
232+
director: User
233+
}
234+
`);
235+
});
236+
237+
test('user configures the type weights with negative numbers', () => {
238+
// check that the error thrown from the function includes the substring 'negative' to inform the user of negative problem
239+
expect(() => buildTypeWeightsFromSchema(schema, { object: -1 })).toThrowError(
240+
'negative'
241+
);
242+
expect(() => buildTypeWeightsFromSchema(schema, { mutation: -1 })).toThrowError(
243+
'negative'
244+
);
245+
expect(() => buildTypeWeightsFromSchema(schema, { connection: -1 })).toThrowError(
246+
'negative'
247+
);
248+
expect(() => buildTypeWeightsFromSchema(schema, { scalar: -1 })).toThrowError(
249+
'negative'
250+
);
251+
});
252+
});
253+
});

0 commit comments

Comments
 (0)