Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update graphql yoga to v3 #8250

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/definitionsCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const fs = require('fs').promises;
const { exec } = require('child_process');
const core = require('@actions/core');
const { nextTick } = require('process');
const { AbortController } = require("node-abort-controller");
const { AbortController } = require("@whatwg-node/fetch");
(async () => {
const [currentDefinitions, currentDocs] = await Promise.all([
fs.readFile('./src/Options/Definitions.js', 'utf8'),
Expand Down
16,959 changes: 9,194 additions & 7,765 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 2 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,19 @@
"@graphql-tools/merge": "8.3.6",
"@graphql-tools/schema": "9.0.4",
"@graphql-tools/utils": "8.12.0",
"@graphql-yoga/node": "2.6.0",
"@parse/fs-files-adapter": "1.2.2",
"@parse/push-adapter": "4.1.2",
"@whatwg-node/fetch": "0.6.1",
"bcryptjs": "2.4.3",
"body-parser": "1.20.1",
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"commander": "5.1.0",
"cors": "2.8.5",
"deepcopy": "2.1.0",
"express": "4.18.2",
"follow-redirects": "1.15.2",
"graphql": "16.6.0",
"graphql-list-fields": "2.0.2",
"graphql-relay": "0.10.0",
"graphql-tag": "2.12.6",
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"graphql-yoga": "3.3.0",
"intersect": "1.0.1",
"ip-range-check": "0.2.0",
"jsonwebtoken": "8.5.1",
Expand Down Expand Up @@ -84,7 +83,6 @@
"eslint": "8.26.0",
"eslint-plugin-flowtype": "8.0.3",
"flow-bin": "0.119.1",
"form-data": "3.0.0",
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"graphql-tag": "2.12.6",
"husky": "4.3.8",
"jasmine": "3.5.0",
Expand All @@ -97,8 +95,6 @@
"mock-mail-adapter": "file:spec/dependencies/mock-mail-adapter",
"mongodb-runner": "4.8.1",
"mongodb-version-list": "1.0.0",
"node-fetch": "3.2.10",
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"node-abort-controller": "3.0.1",
"nyc": "15.1.0",
"prettier": "2.0.5",
"semantic-release": "17.4.6",
Expand Down
154 changes: 42 additions & 112 deletions spec/ParseGraphQLServer.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const http = require('http');
const express = require('express');
const req = require('../lib/request');
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args));
const FormData = require('form-data');
const { fetch, FormData, File } = require('@whatwg-node/fetch');
const ws = require('ws');
require('./helper');
const { updateCLP } = require('./support/dev');
Expand Down Expand Up @@ -30,6 +29,7 @@ const {
GraphQLInputObjectType,
GraphQLSchema,
GraphQLList,
GraphQLError,
} = require('graphql');
const { ParseServer } = require('../');
const { ParseGraphQLServer } = require('../lib/GraphQL/ParseGraphQLServer');
Expand Down Expand Up @@ -99,54 +99,6 @@ describe('ParseGraphQLServer', () => {
});
});

describe('_getServer', () => {
it('should only return new server on schema changes', async () => {
parseGraphQLServer.server = undefined;
const server1 = await parseGraphQLServer._getServer();
const server2 = await parseGraphQLServer._getServer();
expect(server1).toBe(server2);

// Trigger a schema change
const obj = new Parse.Object('SomeClass');
await obj.save();

const server3 = await parseGraphQLServer._getServer();
const server4 = await parseGraphQLServer._getServer();
expect(server3).not.toBe(server2);
expect(server3).toBe(server4);
});
});

describe('_getGraphQLOptions', () => {
const req = {
info: new Object(),
config: new Object(),
auth: new Object(),
};

it("should return schema and context with req's info, config and auth", async () => {
const options = await parseGraphQLServer._getGraphQLOptions();
expect(options.multipart).toEqual({
fileSize: 20971520,
});
expect(options.schema).toEqual(parseGraphQLServer.parseGraphQLSchema.graphQLSchema);
const contextResponse = options.context({ req });
expect(contextResponse.info).toEqual(req.info);
expect(contextResponse.config).toEqual(req.config);
expect(contextResponse.auth).toEqual(req.auth);
});

it('should load GraphQL schema in every call', async () => {
const originalLoad = parseGraphQLServer.parseGraphQLSchema.load;
let counter = 0;
parseGraphQLServer.parseGraphQLSchema.load = () => ++counter;
expect((await parseGraphQLServer._getGraphQLOptions(req)).schema).toEqual(1);
expect((await parseGraphQLServer._getGraphQLOptions(req)).schema).toEqual(2);
expect((await parseGraphQLServer._getGraphQLOptions(req)).schema).toEqual(3);
parseGraphQLServer.parseGraphQLSchema.load = originalLoad;
});
});

describe('_transformMaxUploadSizeToBytes', () => {
it('should transform to bytes', () => {
expect(parseGraphQLServer._transformMaxUploadSizeToBytes('20mb')).toBe(20971520);
Expand Down Expand Up @@ -532,41 +484,6 @@ describe('ParseGraphQLServer', () => {
expect(healthResponse.data.health).toBeTruthy();
expect(checked).toBeTruthy();
});

it('should handle Parse headers', async () => {
const test = {
context: ({ req: { info, config, auth } }) => {
expect(req.info).toBeDefined();
expect(req.config).toBeDefined();
expect(req.auth).toBeDefined();
return {
info,
config,
auth,
};
},
};
const contextSpy = spyOn(test, 'context');
const originalGetGraphQLOptions = parseGraphQLServer._getGraphQLOptions;
parseGraphQLServer._getGraphQLOptions = async () => {
return {
schema: await parseGraphQLServer.parseGraphQLSchema.load(),
context: test.context,
};
};
const health = (
await apolloClient.query({
query: gql`
query Health {
health
}
`,
})
).data.health;
expect(health).toBeTruthy();
expect(contextSpy).toHaveBeenCalledTimes(1);
parseGraphQLServer._getGraphQLOptions = originalGetGraphQLOptions;
});
});

describe('Playground', () => {
Expand Down Expand Up @@ -1404,22 +1321,28 @@ describe('ParseGraphQLServer', () => {
await parseGraphQLServer.setGraphQLConfig(graphQLConfig);
await resetGraphQLCache();

const { data } = await apolloClient.query({
query: gql`
query UserType {
userType: __type(name: "User") {
fields {
name
let data;
try {
const resp = await apolloClient.query({
query: gql`
query UserType {
userType: __type(name: "User") {
fields {
name
}
}
}
superCarType: __type(name: "SuperCar") {
fields {
name
superCarType: __type(name: "SuperCar") {
fields {
name
}
}
}
}
`,
});
`,
});
data = resp.data;
} catch (e) {
expect(e).toBeFalsy();
}
expect(data.userType).toBeNull();
expect(data.superCarType).toBeTruthy();
});
Expand Down Expand Up @@ -9327,10 +9250,13 @@ describe('ParseGraphQLServer', () => {
})
);
body.append('map', JSON.stringify({ 1: ['variables.input.upload'] }));
body.append('1', 'My File Content', {
filename: 'myFileName.txt',
contentType: 'text/plain',
});
body.append(
'1',
new File(['My File Content'], 'myFileName.txt', {
type: 'text/plain',
}),
'myFileName.txt'
);

let res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
Expand Down Expand Up @@ -9439,10 +9365,11 @@ describe('ParseGraphQLServer', () => {
})
);
body2.append('map', JSON.stringify({ 1: ['variables.fields3.someField.upload'] }));
body2.append('1', 'My File Content', {
filename: 'myFileName.txt',
contentType: 'text/plain',
});
body2.append(
'1',
new File(['My File Content'], 'myFileName.txt', { type: 'text/plain' }),
'myFileName.txt'
);

res = await fetch('http://localhost:13377/graphql', {
method: 'POST',
Expand Down Expand Up @@ -9574,11 +9501,14 @@ describe('ParseGraphQLServer', () => {
body.append('map', JSON.stringify({ 1: ['variables.input.upload'] }));
body.append(
'1',
Buffer.alloc(parseGraphQLServer._transformMaxUploadSizeToBytes('2kb'), 1),
{
filename: 'myFileName.txt',
contentType: 'text/plain',
}
new File(
[Buffer.alloc(parseGraphQLServer._transformMaxUploadSizeToBytes('2kb'), 1)],
'myFileName.txt',
{
type: 'text/plain',
}
),
'myFileName.txt'
);

const res = await fetch('http://localhost:13377/graphql', {
Expand Down Expand Up @@ -10945,7 +10875,7 @@ describe('ParseGraphQLServer', () => {
errorQuery: {
type: new GraphQLNonNull(GraphQLString),
resolve: () => {
throw new Error('A test error');
throw new GraphQLError('A test error');
},
},
customQueryWithAutoTypeReturn: {
Expand Down
84 changes: 11 additions & 73 deletions src/GraphQL/ParseGraphQLSchema.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import Parse from 'parse/node';
import { GraphQLSchema, GraphQLObjectType, DocumentNode, GraphQLNamedType } from 'graphql';
import {
GraphQLSchema,
GraphQLObjectType,
DocumentNode,
GraphQLNamedType,
isSchema,
} from 'graphql';
import { mergeSchemas } from '@graphql-tools/schema';
import { mergeTypeDefs } from '@graphql-tools/merge';
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
import { isDeepStrictEqual } from 'util';
Expand Down Expand Up @@ -203,78 +209,10 @@ class ParseGraphQLSchema {

if (this.graphQLCustomTypeDefs) {
schemaDirectives.load(this);
if (typeof this.graphQLCustomTypeDefs.getTypeMap === 'function') {
// In following code we use underscore attr to keep the direct variable reference
const customGraphQLSchemaTypeMap = this.graphQLCustomTypeDefs._typeMap;
const findAndReplaceLastType = (parent, key) => {
if (parent[key].name) {
if (
this.graphQLAutoSchema._typeMap[parent[key].name] &&
this.graphQLAutoSchema._typeMap[parent[key].name] !== parent[key]
) {
// To avoid unresolved field on overloaded schema
// replace the final type with the auto schema one
parent[key] = this.graphQLAutoSchema._typeMap[parent[key].name];
}
} else {
if (parent[key].ofType) {
findAndReplaceLastType(parent[key], 'ofType');
}
}
};
// Add non shared types from custom schema to auto schema
// note: some non shared types can use some shared types
// so this code need to be ran before the shared types addition
// we use sort to ensure schema consistency over restarts
Object.keys(customGraphQLSchemaTypeMap)
.sort()
.forEach(customGraphQLSchemaTypeKey => {
const customGraphQLSchemaType = customGraphQLSchemaTypeMap[customGraphQLSchemaTypeKey];
if (
!customGraphQLSchemaType ||
!customGraphQLSchemaType.name ||
customGraphQLSchemaType.name.startsWith('__')
) {
return;
}
const autoGraphQLSchemaType = this.graphQLAutoSchema._typeMap[
customGraphQLSchemaType.name
];
if (!autoGraphQLSchemaType) {
this.graphQLAutoSchema._typeMap[
customGraphQLSchemaType.name
] = customGraphQLSchemaType;
}
});
// Handle shared types
// We pass through each type and ensure that all sub field types are replaced
// we use sort to ensure schema consistency over restarts
Object.keys(customGraphQLSchemaTypeMap)
.sort()
.forEach(customGraphQLSchemaTypeKey => {
const customGraphQLSchemaType = customGraphQLSchemaTypeMap[customGraphQLSchemaTypeKey];
if (
!customGraphQLSchemaType ||
!customGraphQLSchemaType.name ||
customGraphQLSchemaType.name.startsWith('__')
) {
return;
}
const autoGraphQLSchemaType = this.graphQLAutoSchema._typeMap[
customGraphQLSchemaType.name
];

if (autoGraphQLSchemaType && typeof customGraphQLSchemaType.getFields === 'function') {
Object.keys(customGraphQLSchemaType._fields)
.sort()
.forEach(fieldKey => {
const field = customGraphQLSchemaType._fields[fieldKey];
findAndReplaceLastType(field, 'type');
autoGraphQLSchemaType._fields[field.name] = field;
});
}
});
this.graphQLSchema = this.graphQLAutoSchema;
if (isSchema(this.graphQLCustomTypeDefs)) {
this.graphQLSchema = mergeSchemas({
schemas: [this.graphQLAutoSchema, this.graphQLCustomTypeDefs],
});
} else if (typeof this.graphQLCustomTypeDefs === 'function') {
this.graphQLSchema = await this.graphQLCustomTypeDefs({
directivesDefinitionsSchema: this.graphQLSchemaDirectivesDefinitions,
Expand Down
Loading