GraphQL: Allow true GraphQL Schema Customization (#6360)
* 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
This commit is contained in:
@@ -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
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -313,4 +326,4 @@ const calculateSkipAndLimit = (
|
||||
};
|
||||
};
|
||||
|
||||
export { getObject, findObjects, calculateSkipAndLimit };
|
||||
export { getObject, findObjects, calculateSkipAndLimit, needToGetAllKeys };
|
||||
|
||||
@@ -30,7 +30,10 @@ const load = parseGraphQLSchema => {
|
||||
undefined,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
info,
|
||||
parseGraphQLSchema.parseClasses.find(
|
||||
({ className }) => type === className
|
||||
)
|
||||
)),
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -301,7 +336,8 @@ const load = function(
|
||||
undefined,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
info,
|
||||
parseClass
|
||||
);
|
||||
}
|
||||
await objectsMutations.deleteObject(
|
||||
|
||||
@@ -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 || {};
|
||||
@@ -23,14 +23,14 @@ 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,
|
||||
@@ -38,7 +38,8 @@ const getQuery = async (className, _source, args, context, queryInfo) => {
|
||||
includeReadPreference,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
info,
|
||||
parseClass
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -436,7 +436,7 @@ const load = (
|
||||
);
|
||||
const parseOrder = order && order.join(',');
|
||||
|
||||
return await objectsQueries.findObjects(
|
||||
return objectsQueries.findObjects(
|
||||
source[field].className,
|
||||
{
|
||||
$relatedTo: {
|
||||
|
||||
Reference in New Issue
Block a user