Improve callCloudCode mutation to receive a CloudCodeFunction enum instead of a String (#6029)

* Add listing test

* Improvements

* Fixinf package.json

* Fix package.json

* Fix tests
This commit is contained in:
Antonio Davi Macedo Coelho de Castro
2019-09-09 15:07:22 -07:00
committed by GitHub
parent 33d2b16476
commit a754b883b2
6 changed files with 245 additions and 54 deletions

View File

@@ -15,6 +15,7 @@ import DatabaseController from '../Controllers/DatabaseController';
import { toGraphQLError } from './parseGraphQLUtils';
import * as schemaDirectives from './loaders/schemaDirectives';
import * as schemaTypes from './loaders/schemaTypes';
import { getFunctionNames } from '../triggers';
const RESERVED_GRAPHQL_TYPE_NAMES = [
'String',
@@ -29,6 +30,7 @@ const RESERVED_GRAPHQL_TYPE_NAMES = [
'Viewer',
'SignUpFieldsInput',
'LogInFieldsInput',
'CloudCodeFunction',
];
const RESERVED_GRAPHQL_QUERY_NAMES = ['health', 'viewer', 'class', 'classes'];
const RESERVED_GRAPHQL_MUTATION_NAMES = [
@@ -53,6 +55,7 @@ class ParseGraphQLSchema {
databaseController: DatabaseController,
parseGraphQLController: ParseGraphQLController,
log: any,
appId: string,
} = {}
) {
this.parseGraphQLController =
@@ -64,13 +67,16 @@ class ParseGraphQLSchema {
this.log =
params.log || requiredParameter('You must provide a log instance!');
this.graphQLCustomTypeDefs = params.graphQLCustomTypeDefs;
this.appId =
params.appId || requiredParameter('You must provide the appId!');
}
async load() {
const { parseGraphQLConfig } = await this._initializeSchemaAndConfig();
const parseClasses = await this._getClassesForSchema(parseGraphQLConfig);
const parseClassesString = JSON.stringify(parseClasses);
const functionNames = await this._getFunctionNames();
const functionNamesString = JSON.stringify(functionNames);
if (
this.graphQLSchema &&
@@ -78,6 +84,7 @@ class ParseGraphQLSchema {
parseClasses,
parseClassesString,
parseGraphQLConfig,
functionNamesString,
})
) {
return this.graphQLSchema;
@@ -86,6 +93,8 @@ class ParseGraphQLSchema {
this.parseClasses = parseClasses;
this.parseClassesString = parseClassesString;
this.parseGraphQLConfig = parseGraphQLConfig;
this.functionNames = functionNames;
this.functionNamesString = functionNamesString;
this.parseClassTypes = {};
this.viewerType = null;
this.graphQLAutoSchema = null;
@@ -360,6 +369,19 @@ class ParseGraphQLSchema {
});
}
async _getFunctionNames() {
return await getFunctionNames(this.appId).filter(functionName => {
if (/^[_a-zA-Z][_a-zA-Z0-9]*$/.test(functionName)) {
return true;
} else {
this.log.warn(
`Function ${functionName} could not be added to the auto schema because GraphQL names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/.`
);
return false;
}
});
}
/**
* Checks for changes to the parseClasses
* objects (i.e. database schema) or to
@@ -370,12 +392,19 @@ class ParseGraphQLSchema {
parseClasses: any,
parseClassesString: string,
parseGraphQLConfig: ?ParseGraphQLConfig,
functionNamesString: string,
}): boolean {
const { parseClasses, parseClassesString, parseGraphQLConfig } = params;
const {
parseClasses,
parseClassesString,
parseGraphQLConfig,
functionNamesString,
} = params;
if (
JSON.stringify(this.parseGraphQLConfig) ===
JSON.stringify(parseGraphQLConfig)
JSON.stringify(parseGraphQLConfig) &&
this.functionNamesString === functionNamesString
) {
if (this.parseClasses === parseClasses) {
return false;

View File

@@ -33,6 +33,7 @@ class ParseGraphQLServer {
databaseController: this.parseServer.config.databaseController,
log: this.log,
graphQLCustomTypeDefs: this.config.graphQLCustomTypeDefs,
appId: this.parseServer.config.appId,
});
}

View File

@@ -1,46 +1,65 @@
import { GraphQLNonNull, GraphQLString } from 'graphql';
import { GraphQLNonNull, GraphQLEnumType } from 'graphql';
import { FunctionsRouter } from '../../Routers/FunctionsRouter';
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
const load = parseGraphQLSchema => {
parseGraphQLSchema.addGraphQLMutation(
'callCloudCode',
{
description:
'The call mutation can be used to invoke a cloud code function.',
args: {
functionName: {
description: 'This is the name of the function to be called.',
type: new GraphQLNonNull(GraphQLString),
},
params: {
description: 'These are the params to be passed to the function.',
type: defaultGraphQLTypes.OBJECT,
},
},
type: defaultGraphQLTypes.ANY,
async resolve(_source, args, context) {
try {
const { functionName, params } = args;
const { config, auth, info } = context;
if (parseGraphQLSchema.functionNames.length > 0) {
const cloudCodeFunctionEnum = parseGraphQLSchema.addGraphQLType(
new GraphQLEnumType({
name: 'CloudCodeFunction',
description:
'The CloudCodeFunction enum type contains a list of all available cloud code functions.',
values: parseGraphQLSchema.functionNames.reduce(
(values, functionName) => ({
...values,
[functionName]: { value: functionName },
}),
{}
),
}),
true,
true
);
return (await FunctionsRouter.handleCloudFunction({
params: {
functionName,
},
config,
auth,
info,
body: params,
})).response.result;
} catch (e) {
parseGraphQLSchema.handleError(e);
}
parseGraphQLSchema.addGraphQLMutation(
'callCloudCode',
{
description:
'The call mutation can be used to invoke a cloud code function.',
args: {
functionName: {
description: 'This is the function to be called.',
type: new GraphQLNonNull(cloudCodeFunctionEnum),
},
params: {
description: 'These are the params to be passed to the function.',
type: defaultGraphQLTypes.OBJECT,
},
},
type: defaultGraphQLTypes.ANY,
async resolve(_source, args, context) {
try {
const { functionName, params } = args;
const { config, auth, info } = context;
return (await FunctionsRouter.handleCloudFunction({
params: {
functionName,
},
config,
auth,
info,
body: params,
})).response.result;
} catch (e) {
parseGraphQLSchema.handleError(e);
}
},
},
},
true,
true
);
true,
true
);
}
};
export { load };