Skip to content

Commit

Permalink
GraphQL: Allow true GraphQL Schema Customization (parse-community#6360)
Browse files Browse the repository at this point in the history
* Allow real GraphQL Schema via ParseServer.start

* wip

* working

* tests ok

* add tests about enum/input use case

* Add async function based merge

* Better naming

* remove useless condition
  • Loading branch information
Moumouls authored Feb 21, 2020
1 parent 291bddb commit cb0edc4
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 127 deletions.
374 changes: 274 additions & 100 deletions spec/ParseGraphQLServer.spec.js

Large diffs are not rendered by default.

59 changes: 50 additions & 9 deletions src/GraphQL/ParseGraphQLSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,19 +197,60 @@ class ParseGraphQLSchema {
if (this.graphQLCustomTypeDefs) {
schemaDirectives.load(this);

this.graphQLSchema = mergeSchemas({
schemas: [
this.graphQLSchemaDirectivesDefinitions,
this.graphQLAutoSchema,
this.graphQLCustomTypeDefs,
],
mergeDirectives: true,
});
if (typeof this.graphQLCustomTypeDefs.getTypeMap === 'function') {
const customGraphQLSchemaTypeMap = this.graphQLCustomTypeDefs.getTypeMap();
Object.values(customGraphQLSchemaTypeMap).forEach(
customGraphQLSchemaType => {
if (
!customGraphQLSchemaType ||
!customGraphQLSchemaType.name ||
customGraphQLSchemaType.name.startsWith('__')
) {
return;
}
const autoGraphQLSchemaType = this.graphQLAutoSchema.getType(
customGraphQLSchemaType.name
);
if (autoGraphQLSchemaType) {
autoGraphQLSchemaType._fields = {
...autoGraphQLSchemaType._fields,
...customGraphQLSchemaType._fields,
};
}
}
);
this.graphQLSchema = mergeSchemas({
schemas: [
this.graphQLSchemaDirectivesDefinitions,
this.graphQLCustomTypeDefs,
this.graphQLAutoSchema,
],
mergeDirectives: true,
});
} else if (typeof this.graphQLCustomTypeDefs === 'function') {
this.graphQLSchema = await this.graphQLCustomTypeDefs({
directivesDefinitionsSchema: this.graphQLSchemaDirectivesDefinitions,
autoSchema: this.graphQLAutoSchema,
mergeSchemas,
});
} else {
this.graphQLSchema = mergeSchemas({
schemas: [
this.graphQLSchemaDirectivesDefinitions,
this.graphQLAutoSchema,
this.graphQLCustomTypeDefs,
],
mergeDirectives: true,
});
}

const graphQLSchemaTypeMap = this.graphQLSchema.getTypeMap();
Object.keys(graphQLSchemaTypeMap).forEach(graphQLSchemaTypeName => {
const graphQLSchemaType = graphQLSchemaTypeMap[graphQLSchemaTypeName];
if (typeof graphQLSchemaType.getFields === 'function') {
if (
typeof graphQLSchemaType.getFields === 'function' &&
this.graphQLCustomTypeDefs.definitions
) {
const graphQLCustomTypeDef = this.graphQLCustomTypeDefs.definitions.find(
definition => definition.name.value === graphQLSchemaTypeName
);
Expand Down
21 changes: 17 additions & 4 deletions src/GraphQL/helpers/objectsQueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { offsetToCursor, cursorToOffset } from 'graphql-relay';
import rest from '../../rest';
import { transformQueryInputToParse } from '../transformers/query';

const needToGetAllKeys = (fields, keys) =>
keys
? !!keys.split(',').find(keyName => !fields[keyName.split('.')[0]])
: true;

const getObject = async (
className,
objectId,
Expand All @@ -12,10 +17,11 @@ const getObject = async (
includeReadPreference,
config,
auth,
info
info,
parseClass
) => {
const options = {};
if (keys) {
if (!needToGetAllKeys(parseClass.fields, keys)) {
options.keys = keys;
}
if (include) {
Expand Down Expand Up @@ -133,7 +139,14 @@ const findObjects = async (
// Silently replace the limit on the query with the max configured
options.limit = config.maxLimit;
}
if (keys) {
if (
!needToGetAllKeys(
parseClasses.find(
({ className: parseClassName }) => className === parseClassName
).fields,
keys
)
) {
options.keys = keys;
}
if (includeAll === true) {
Expand Down Expand Up @@ -313,4 +326,4 @@ const calculateSkipAndLimit = (
};
};

export { getObject, findObjects, calculateSkipAndLimit };
export { getObject, findObjects, calculateSkipAndLimit, needToGetAllKeys };
5 changes: 4 additions & 1 deletion src/GraphQL/loaders/defaultRelaySchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ const load = parseGraphQLSchema => {
undefined,
config,
auth,
info
info,
parseGraphQLSchema.parseClasses.find(
({ className }) => type === className
)
)),
};
} catch (e) {
Expand Down
48 changes: 42 additions & 6 deletions src/GraphQL/loaders/parseClassMutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,12 @@ const load = function(
include,
['id', 'objectId', 'createdAt', 'updatedAt']
);
const needToGetAllKeys = objectsQueries.needToGetAllKeys(
parseClass.fields,
keys
);
let optimizedObject = {};
if (needGet) {
if (needGet && !needToGetAllKeys) {
optimizedObject = await objectsQueries.getObject(
className,
createdObject.objectId,
Expand All @@ -123,7 +127,21 @@ const load = function(
undefined,
config,
auth,
info
info,
parseClass
);
} else if (needToGetAllKeys) {
optimizedObject = await objectsQueries.getObject(
className,
createdObject.objectId,
undefined,
include,
undefined,
undefined,
config,
auth,
info,
parseClass
);
}
return {
Expand Down Expand Up @@ -212,9 +230,12 @@ const load = function(
include,
['id', 'objectId', 'updatedAt']
);

const needToGetAllKeys = objectsQueries.needToGetAllKeys(
parseClass.fields,
keys
);
let optimizedObject = {};
if (needGet) {
if (needGet && !needToGetAllKeys) {
optimizedObject = await objectsQueries.getObject(
className,
id,
Expand All @@ -224,7 +245,21 @@ const load = function(
undefined,
config,
auth,
info
info,
parseClass
);
} else if (needToGetAllKeys) {
optimizedObject = await objectsQueries.getObject(
className,
id,
undefined,
include,
undefined,
undefined,
config,
auth,
info,
parseClass
);
}
return {
Expand Down Expand Up @@ -301,7 +336,8 @@ const load = function(
undefined,
config,
auth,
info
info,
parseClass
);
}
await objectsMutations.deleteObject(
Expand Down
11 changes: 6 additions & 5 deletions src/GraphQL/loaders/parseClassQueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const getParseClassQueryConfig = function(
return (parseClassConfig && parseClassConfig.query) || {};
};

const getQuery = async (className, _source, args, context, queryInfo) => {
const getQuery = async (parseClass, _source, args, context, queryInfo) => {
let { id } = args;
const { options } = args;
const { readPreference, includeReadPreference } = options || {};
Expand All @@ -23,22 +23,23 @@ const getQuery = async (className, _source, args, context, queryInfo) => {

const globalIdObject = fromGlobalId(id);

if (globalIdObject.type === className) {
if (globalIdObject.type === parseClass.className) {
id = globalIdObject.id;
}

const { keys, include } = extractKeysAndInclude(selectedFields);

return await objectsQueries.getObject(
className,
parseClass.className,
id,
keys,
include,
readPreference,
includeReadPreference,
config,
auth,
info
info,
parseClass
);
};

Expand Down Expand Up @@ -79,7 +80,7 @@ const load = function(
),
async resolve(_source, args, context, queryInfo) {
try {
return await getQuery(className, _source, args, context, queryInfo);
return await getQuery(parseClass, _source, args, context, queryInfo);
} catch (e) {
parseGraphQLSchema.handleError(e);
}
Expand Down
2 changes: 1 addition & 1 deletion src/GraphQL/loaders/parseClassTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ const load = (
);
const parseOrder = order && order.join(',');

return await objectsQueries.findObjects(
return objectsQueries.findObjects(
source[field].className,
{
$relatedTo: {
Expand Down
4 changes: 3 additions & 1 deletion src/ParseServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,12 @@ class ParseServer {

if (options.mountGraphQL === true || options.mountPlayground === true) {
let graphQLCustomTypeDefs = undefined;
if (options.graphQLSchema) {
if (typeof options.graphQLSchema === 'string') {
graphQLCustomTypeDefs = parse(
fs.readFileSync(options.graphQLSchema, 'utf8')
);
} else if (typeof options.graphQLSchema === 'object') {
graphQLCustomTypeDefs = options.graphQLSchema;
}

const parseGraphQLServer = new ParseGraphQLServer(this, {
Expand Down

0 comments on commit cb0edc4

Please sign in to comment.