Skip to content

Commit 5c62a34

Browse files
committed
feat: working server but GQL JIT seems to block randomly some tests
1 parent 50e294a commit 5c62a34

File tree

9 files changed

+249
-224
lines changed

9 files changed

+249
-224
lines changed

package-lock.json

Lines changed: 91 additions & 157 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 & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
],
2020
"license": "BSD-3-Clause",
2121
"dependencies": {
22-
"@graphql-tools/links": "8.2.8",
22+
"@envelop/graphql-jit": "^4.2.1",
2323
"@graphql-tools/stitch": "6.2.4",
2424
"@graphql-tools/utils": "6.2.4",
25-
"@graphql-yoga/node": "2.4.0",
25+
"@graphql-yoga/node": "2.5.0-canary-205d67f.0",
2626
"@parse/fs-files-adapter": "1.2.2",
2727
"@parse/push-adapter": "4.1.2",
2828
"bcryptjs": "2.4.3",

spec/ParseGraphQLServer.spec.js

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ describe('ParseGraphQLServer', () => {
8585

8686
it('should initialize parseGraphQLSchema with a log controller', async () => {
8787
const loggerAdapter = {
88-
log: () => { },
89-
error: () => { },
88+
log: () => {},
89+
error: () => {},
9090
};
9191
const parseServer = await global.reconfigureServer({
9292
loggerAdapter,
@@ -98,6 +98,21 @@ describe('ParseGraphQLServer', () => {
9898
});
9999
});
100100

101+
describe('_getServer', () => {
102+
it('should only return new server on schema changes', async () => {
103+
parseGraphQLServer.server = undefined;
104+
const server1 = await parseGraphQLServer._getServer();
105+
const server2 = await parseGraphQLServer._getServer();
106+
expect(server1).toBe(server2);
107+
108+
parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
109+
const server3 = await parseGraphQLServer._getServer();
110+
const server4 = await parseGraphQLServer._getServer();
111+
expect(server3).not.toBe(server2);
112+
expect(server3).toBe(server4);
113+
});
114+
});
115+
101116
describe('_getGraphQLOptions', () => {
102117
const req = {
103118
info: new Object(),
@@ -107,6 +122,9 @@ describe('ParseGraphQLServer', () => {
107122

108123
it("should return schema and context with req's info, config and auth", async () => {
109124
const options = await parseGraphQLServer._getGraphQLOptions();
125+
expect(options.multipart).toEqual({
126+
fileSize: 20971520,
127+
});
110128
expect(options.schema).toEqual(parseGraphQLServer.parseGraphQLSchema.graphQLSchema);
111129
const contextResponse = options.context({ req });
112130
expect(contextResponse.info).toEqual(req.info);
@@ -441,8 +459,8 @@ describe('ParseGraphQLServer', () => {
441459
},
442460
},
443461
});
444-
spyOn(console, 'warn').and.callFake(() => { });
445-
spyOn(console, 'error').and.callFake(() => { });
462+
spyOn(console, 'warn').and.callFake(() => {});
463+
spyOn(console, 'error').and.callFake(() => {});
446464
});
447465

448466
afterEach(async () => {
@@ -821,7 +839,7 @@ describe('ParseGraphQLServer', () => {
821839
});
822840

823841
it('should have clientMutationId in call function input', async () => {
824-
Parse.Cloud.define('hello', () => { });
842+
Parse.Cloud.define('hello', () => {});
825843

826844
const callFunctionInputFields = (
827845
await apolloClient.query({
@@ -843,7 +861,7 @@ describe('ParseGraphQLServer', () => {
843861
});
844862

845863
it('should have clientMutationId in call function payload', async () => {
846-
Parse.Cloud.define('hello', () => { });
864+
Parse.Cloud.define('hello', () => {});
847865

848866
const callFunctionPayloadFields = (
849867
await apolloClient.query({
@@ -3301,7 +3319,6 @@ describe('ParseGraphQLServer', () => {
33013319
});
33023320
fail('should fail');
33033321
} catch (e) {
3304-
console.log(e);
33053322
expect(e.graphQLErrors[0].extensions.code).toEqual(Parse.Error.OPERATION_FORBIDDEN);
33063323
expect(e.graphQLErrors[0].message).toEqual('unauthorized: master key is required');
33073324
}
@@ -6512,7 +6529,7 @@ describe('ParseGraphQLServer', () => {
65126529
);
65136530
expect(
65146531
(await deleteObject(object4.className, object4.id)).data.delete[
6515-
object4.className.charAt(0).toLowerCase() + object4.className.slice(1)
6532+
object4.className.charAt(0).toLowerCase() + object4.className.slice(1)
65166533
]
65176534
).toEqual({ objectId: object4.id, __typename: 'PublicClass' });
65186535
await expectAsync(object4.fetch({ useMasterKey: true })).toBeRejectedWith(
@@ -6799,7 +6816,7 @@ describe('ParseGraphQLServer', () => {
67996816

68006817
expect(queryResult.data.customers.edges.length).toEqual(1);
68016818
} catch (e) {
6802-
console.log(JSON.stringify(e));
6819+
console.error(JSON.stringify(e));
68036820
}
68046821
});
68056822
});
@@ -7242,9 +7259,9 @@ describe('ParseGraphQLServer', () => {
72427259
it('should send reset password', async () => {
72437260
const clientMutationId = uuidv4();
72447261
const emailAdapter = {
7245-
sendVerificationEmail: () => { },
7262+
sendVerificationEmail: () => {},
72467263
sendPasswordResetEmail: () => Promise.resolve(),
7247-
sendMail: () => { },
7264+
sendMail: () => {},
72487265
};
72497266
parseServer = await global.reconfigureServer({
72507267
appName: 'test',
@@ -7282,11 +7299,11 @@ describe('ParseGraphQLServer', () => {
72827299
const clientMutationId = uuidv4();
72837300
let resetPasswordToken;
72847301
const emailAdapter = {
7285-
sendVerificationEmail: () => { },
7302+
sendVerificationEmail: () => {},
72867303
sendPasswordResetEmail: ({ link }) => {
72877304
resetPasswordToken = link.split('token=')[1].split('&')[0];
72887305
},
7289-
sendMail: () => { },
7306+
sendMail: () => {},
72907307
};
72917308
parseServer = await global.reconfigureServer({
72927309
appName: 'test',
@@ -7351,9 +7368,9 @@ describe('ParseGraphQLServer', () => {
73517368
it('should send verification email again', async () => {
73527369
const clientMutationId = uuidv4();
73537370
const emailAdapter = {
7354-
sendVerificationEmail: () => { },
7371+
sendVerificationEmail: () => {},
73557372
sendPasswordResetEmail: () => Promise.resolve(),
7356-
sendMail: () => { },
7373+
sendMail: () => {},
73577374
};
73587375
parseServer = await global.reconfigureServer({
73597376
appName: 'test',
@@ -9109,7 +9126,7 @@ describe('ParseGraphQLServer', () => {
91099126
expect(result6[0].node.name).toEqual('imACountry3');
91109127
});
91119128

9112-
fit('should support files', async () => {
9129+
it('should support files', async () => {
91139130
try {
91149131
parseServer = await global.reconfigureServer({
91159132
publicServerURL: 'http://localhost:13377/parse',
@@ -9152,7 +9169,6 @@ describe('ParseGraphQLServer', () => {
91529169

91539170
const result = JSON.parse(await res.text());
91549171

9155-
console.log(result.errors)
91569172
expect(result.data.createFile.fileInfo.name).toEqual(
91579173
jasmine.stringMatching(/_myFileName.txt$/)
91589174
);
@@ -9358,6 +9374,51 @@ describe('ParseGraphQLServer', () => {
93589374
}
93599375
});
93609376

9377+
it('should not upload if file is too large', async () => {
9378+
parseGraphQLServer.parseServer.config.maxUploadSize = '1kb';
9379+
9380+
const body = new FormData();
9381+
body.append(
9382+
'operations',
9383+
JSON.stringify({
9384+
query: `
9385+
mutation CreateFile($input: CreateFileInput!) {
9386+
createFile(input: $input) {
9387+
fileInfo {
9388+
name
9389+
url
9390+
}
9391+
}
9392+
}
9393+
`,
9394+
variables: {
9395+
input: {
9396+
upload: null,
9397+
},
9398+
},
9399+
})
9400+
);
9401+
body.append('map', JSON.stringify({ 1: ['variables.input.upload'] }));
9402+
body.append(
9403+
'1',
9404+
Buffer.alloc(parseGraphQLServer._transformMaxUploadSizeToBytes('2kb'), 1),
9405+
{
9406+
filename: 'myFileName.txt',
9407+
contentType: 'text/plain',
9408+
}
9409+
);
9410+
9411+
const res = await fetch('http://localhost:13377/graphql', {
9412+
method: 'POST',
9413+
headers,
9414+
body,
9415+
});
9416+
9417+
expect(res.status).toEqual(200);
9418+
const result = JSON.parse(await res.text());
9419+
expect(result.errors).toBeDefined();
9420+
});
9421+
93619422
it('should support object values', async () => {
93629423
try {
93639424
const someObjectFieldValue = {
@@ -10549,25 +10610,25 @@ describe('ParseGraphQLServer', () => {
1054910610
},
1055010611
});
1055110612
const SomeClassType = new GraphQLObjectType({
10552-
name: 'SomeClass',
10553-
fields: {
10554-
nameUpperCase: {
10555-
type: new GraphQLNonNull(GraphQLString),
10556-
resolve: p => p.name.toUpperCase(),
10557-
},
10558-
type: { type: TypeEnum },
10559-
language: {
10560-
type: new GraphQLEnumType({
10561-
name: 'LanguageEnum',
10562-
values: {
10563-
fr: { value: 'fr' },
10564-
en: { value: 'en' },
10565-
},
10566-
}),
10567-
resolve: () => 'fr',
10613+
name: 'SomeClass',
10614+
fields: {
10615+
nameUpperCase: {
10616+
type: new GraphQLNonNull(GraphQLString),
10617+
resolve: p => p.name.toUpperCase(),
10618+
},
10619+
type: { type: TypeEnum },
10620+
language: {
10621+
type: new GraphQLEnumType({
10622+
name: 'LanguageEnum',
10623+
values: {
10624+
fr: { value: 'fr' },
10625+
en: { value: 'en' },
10626+
},
10627+
}),
10628+
resolve: () => 'fr',
10629+
},
1056810630
},
10569-
},
10570-
}),
10631+
}),
1057110632
parseGraphQLServer = new ParseGraphQLServer(parseServer, {
1057210633
graphQLPath: '/graphql',
1057310634
graphQLCustomTypeDefs: new GraphQLSchema({

src/GraphQL/ParseGraphQLSchema.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,14 @@ class ParseGraphQLSchema {
8989
this.graphQLCustomTypeDefs = params.graphQLCustomTypeDefs;
9090
this.appId = params.appId || requiredParameter('You must provide the appId!');
9191
this.schemaCache = SchemaCache;
92+
this.logCache = {};
9293
}
9394

9495
async load() {
9596
const { parseGraphQLConfig } = await this._initializeSchemaAndConfig();
9697
const parseClasses = await this._getClassesForSchema(parseGraphQLConfig);
9798
const functionNames = await this._getFunctionNames();
98-
const functionNamesString = JSON.stringify(functionNames);
99+
const functionNamesString = functionNames.join();
99100

100101
if (
101102
!this._hasSchemaInputChanged({
@@ -327,6 +328,14 @@ class ParseGraphQLSchema {
327328
return this.graphQLSchema;
328329
}
329330

331+
_logOnce(severity, message) {
332+
if (this.logCache[message]) {
333+
return;
334+
}
335+
this.log[severity](message);
336+
this.logCache[message] = true;
337+
}
338+
330339
addGraphQLType(type, throwError = false, ignoreReserved = false, ignoreConnection = false) {
331340
if (
332341
(!ignoreReserved && RESERVED_GRAPHQL_TYPE_NAMES.includes(type.name)) ||
@@ -337,7 +346,7 @@ class ParseGraphQLSchema {
337346
if (throwError) {
338347
throw new Error(message);
339348
}
340-
this.log.warn(message);
349+
if (this.warnCache) this.log.warn(message);
341350
return undefined;
342351
}
343352
this.graphQLTypes.push(type);
@@ -353,7 +362,7 @@ class ParseGraphQLSchema {
353362
if (throwError) {
354363
throw new Error(message);
355364
}
356-
this.log.warn(message);
365+
this._logOnce('warn', message);
357366
return undefined;
358367
}
359368
this.graphQLQueries[fieldName] = field;
@@ -369,7 +378,7 @@ class ParseGraphQLSchema {
369378
if (throwError) {
370379
throw new Error(message);
371380
}
372-
this.log.warn(message);
381+
this._logOnce('warn', message);
373382
return undefined;
374383
}
375384
this.graphQLMutations[fieldName] = field;
@@ -478,7 +487,8 @@ class ParseGraphQLSchema {
478487
if (/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(functionName)) {
479488
return true;
480489
} else {
481-
this.log.warn(
490+
this._logOnce(
491+
'warn',
482492
`Function ${functionName} could not be added to the auto schema because GraphQL names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/.`
483493
);
484494
return false;

src/GraphQL/ParseGraphQLServer.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import corsMiddleware from 'cors';
2-
import bodyParser from 'body-parser';
32
import { createServer, renderGraphiQL } from '@graphql-yoga/node';
3+
import { useGraphQlJit } from '@envelop/graphql-jit';
44
import { execute, subscribe } from 'graphql';
55
import { SubscriptionServer } from 'subscriptions-transport-ws';
66
import { handleParseErrors, handleParseHeaders } from '../middlewares';
@@ -39,13 +39,30 @@ class ParseGraphQLServer {
3939
config,
4040
auth,
4141
}),
42+
plugins: [useGraphQlJit()],
43+
multipart: {
44+
fileSize: this._transformMaxUploadSizeToBytes(
45+
this.parseServer.config.maxUploadSize || '20mb'
46+
),
47+
},
4248
};
4349
} catch (e) {
4450
this.log.error(e.stack || (typeof e.toString === 'function' && e.toString()) || e);
4551
throw e;
4652
}
4753
}
4854

55+
async _getServer() {
56+
const schemaRef = this.parseGraphQLSchema.graphQLSchema;
57+
const newSchemaRef = await this.parseGraphQLSchema.load();
58+
if (schemaRef === newSchemaRef && this._server) {
59+
return this._server;
60+
}
61+
const options = await this._getGraphQLOptions();
62+
this._server = createServer(options);
63+
return this._server;
64+
}
65+
4966
_transformMaxUploadSizeToBytes(maxUploadSize) {
5067
const unitMap = {
5168
kb: 1,
@@ -71,8 +88,7 @@ class ParseGraphQLServer {
7188
app.use(this.config.graphQLPath, handleParseHeaders);
7289
app.use(this.config.graphQLPath, handleParseErrors);
7390
app.use(this.config.graphQLPath, async (req, res) => {
74-
const options = await this._getGraphQLOptions();
75-
const server = createServer(options);
91+
const server = await this._getServer();
7692
return server(req, res);
7793
});
7894
}
@@ -83,7 +99,7 @@ class ParseGraphQLServer {
8399
}
84100
app.get(
85101
this.config.playgroundPath ||
86-
requiredParameter('You must provide a config.playgroundPath to applyPlayground!'),
102+
requiredParameter('You must provide a config.playgroundPath to applyPlayground!'),
87103
(_req, res) => {
88104
res.setHeader('Content-Type', 'text/html');
89105
res.write(

src/GraphQL/helpers/objectsQueries.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const getObject = async (
5858
options.keys = keys;
5959
}
6060
} catch (e) {
61-
console.log(e);
61+
console.error(e);
6262
}
6363
if (include) {
6464
options.include = include;

0 commit comments

Comments
 (0)