GraphQL Configuration Options (#5782)
* add parse-graph-ql configuration for class schema customisation Not yet tested - essentially an RFC * refactor and add graphql router, controller and config cache * fix(GraphQLController): add missing check isEnabled * chore(GraphQLController): remove awaits from cache put * chore(GraphQLController): remove check for if its enabled * refactor(GraphQLController): only use cache if mounted * chore(GraphQLController): group all validation errors and throw at once * chore(GraphQLSchema): move transformations into controller validation * refactor(GraphQL): improve ctrl validation and fix schema usage of config * refactor(GraphQLSchema): remove code related to additional schema This code has been moved into a separate feature branch. * fix(GraphQLSchema): fix incorrect default return type for class configs * refactor(GraphQLSchema): update staleness check code to account for config * fix(GraphQLServer): fix regressed tests due to internal schema changes This will be followed up with a backwards compatability fix for the `ClassFields` issue to avoid breakages for our users * refactor: rename to ParseGraphQLController for consistency * fix(ParseGraphQLCtrl): numerous fixes for validity checking Also includes some minor code refactoring * chore(GraphQL): minor syntax cleanup * fix(SchemaController): add _GraphQLConfig to volatile classes * refactor(ParseGraphQLServer): return update config value in setGraphQLConfig * testing(ParseGraphQL): add test cases for new graphQLConfig * fix(GraphQLController): fix issue where config with multiple items was not being mapped to the db * fix(postgres): add _GraphQLConfig default schema on load fixes failing postgres tests * GraphQL @mock directive (#5836) * Add mock directive * Include tests for @mock directive * Fix existing tests due to the change from ClassFields to ClassCreateFields * fix(parseClassMutations): safer type transformation based on input type * fix(parseClassMutations): only define necessary input fields * fix(GraphQL): fix incorrect import paths
This commit is contained in:
committed by
Antonio Davi Macedo Coelho de Castro
parent
bbcc20fd60
commit
d3810c2eba
@@ -8,36 +8,57 @@ import * as parseClassQueries from './loaders/parseClassQueries';
|
||||
import * as parseClassMutations from './loaders/parseClassMutations';
|
||||
import * as defaultGraphQLQueries from './loaders/defaultGraphQLQueries';
|
||||
import * as defaultGraphQLMutations from './loaders/defaultGraphQLMutations';
|
||||
import ParseGraphQLController, {
|
||||
ParseGraphQLConfig,
|
||||
} from '../Controllers/ParseGraphQLController';
|
||||
import DatabaseController from '../Controllers/DatabaseController';
|
||||
import { toGraphQLError } from './parseGraphQLUtils';
|
||||
import * as schemaDirectives from './loaders/schemaDirectives';
|
||||
|
||||
class ParseGraphQLSchema {
|
||||
constructor(databaseController, log, graphQLCustomTypeDefs) {
|
||||
databaseController: DatabaseController;
|
||||
parseGraphQLController: ParseGraphQLController;
|
||||
parseGraphQLConfig: ParseGraphQLConfig;
|
||||
graphQLCustomTypeDefs: any;
|
||||
|
||||
constructor(
|
||||
params: {
|
||||
databaseController: DatabaseController,
|
||||
parseGraphQLController: ParseGraphQLController,
|
||||
log: any,
|
||||
} = {}
|
||||
) {
|
||||
this.parseGraphQLController =
|
||||
params.parseGraphQLController ||
|
||||
requiredParameter('You must provide a parseGraphQLController instance!');
|
||||
this.databaseController =
|
||||
databaseController ||
|
||||
params.databaseController ||
|
||||
requiredParameter('You must provide a databaseController instance!');
|
||||
this.log = log || requiredParameter('You must provide a log instance!');
|
||||
this.graphQLCustomTypeDefs = graphQLCustomTypeDefs;
|
||||
this.log =
|
||||
params.log || requiredParameter('You must provide a log instance!');
|
||||
this.graphQLCustomTypeDefs = params.graphQLCustomTypeDefs;
|
||||
}
|
||||
|
||||
async load() {
|
||||
const schemaController = await this.databaseController.loadSchema();
|
||||
const parseClasses = await schemaController.getAllClasses();
|
||||
const { parseGraphQLConfig } = await this._initializeSchemaAndConfig();
|
||||
|
||||
const parseClasses = await this._getClassesForSchema(parseGraphQLConfig);
|
||||
const parseClassesString = JSON.stringify(parseClasses);
|
||||
|
||||
if (this.graphQLSchema) {
|
||||
if (this.parseClasses === parseClasses) {
|
||||
return this.graphQLSchema;
|
||||
}
|
||||
|
||||
if (this.parseClassesString === parseClassesString) {
|
||||
this.parseClasses = parseClasses;
|
||||
return this.graphQLSchema;
|
||||
}
|
||||
if (
|
||||
this.graphQLSchema &&
|
||||
!this._hasSchemaInputChanged({
|
||||
parseClasses,
|
||||
parseClassesString,
|
||||
parseGraphQLConfig,
|
||||
})
|
||||
) {
|
||||
return this.graphQLSchema;
|
||||
}
|
||||
|
||||
this.parseClasses = parseClasses;
|
||||
this.parseClassesString = parseClassesString;
|
||||
this.parseGraphQLConfig = parseGraphQLConfig;
|
||||
this.parseClassTypes = {};
|
||||
this.meType = null;
|
||||
this.graphQLAutoSchema = null;
|
||||
@@ -53,16 +74,15 @@ class ParseGraphQLSchema {
|
||||
|
||||
defaultGraphQLTypes.load(this);
|
||||
|
||||
parseClasses.forEach(parseClass => {
|
||||
parseClassTypes.load(this, parseClass);
|
||||
|
||||
parseClassQueries.load(this, parseClass);
|
||||
|
||||
parseClassMutations.load(this, parseClass);
|
||||
});
|
||||
this._getParseClassesWithConfig(parseClasses, parseGraphQLConfig).forEach(
|
||||
([parseClass, parseClassConfig]) => {
|
||||
parseClassTypes.load(this, parseClass, parseClassConfig);
|
||||
parseClassQueries.load(this, parseClass, parseClassConfig);
|
||||
parseClassMutations.load(this, parseClass, parseClassConfig);
|
||||
}
|
||||
);
|
||||
|
||||
defaultGraphQLQueries.load(this);
|
||||
|
||||
defaultGraphQLMutations.load(this);
|
||||
|
||||
let graphQLQuery = undefined;
|
||||
@@ -160,6 +180,104 @@ class ParseGraphQLSchema {
|
||||
}
|
||||
throw toGraphQLError(error);
|
||||
}
|
||||
|
||||
async _initializeSchemaAndConfig() {
|
||||
const [schemaController, parseGraphQLConfig] = await Promise.all([
|
||||
this.databaseController.loadSchema(),
|
||||
this.parseGraphQLController.getGraphQLConfig(),
|
||||
]);
|
||||
|
||||
this.schemaController = schemaController;
|
||||
|
||||
return {
|
||||
parseGraphQLConfig,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all classes found by the `schemaController`
|
||||
* minus those filtered out by the app's parseGraphQLConfig.
|
||||
*/
|
||||
async _getClassesForSchema(parseGraphQLConfig: ParseGraphQLConfig) {
|
||||
const { enabledForClasses, disabledForClasses } = parseGraphQLConfig;
|
||||
const allClasses = await this.schemaController.getAllClasses();
|
||||
|
||||
if (Array.isArray(enabledForClasses) || Array.isArray(disabledForClasses)) {
|
||||
let includedClasses = allClasses;
|
||||
if (enabledForClasses) {
|
||||
includedClasses = allClasses.filter(clazz => {
|
||||
return enabledForClasses.includes(clazz.className);
|
||||
});
|
||||
}
|
||||
if (disabledForClasses) {
|
||||
// Classes included in `enabledForClasses` that
|
||||
// are also present in `disabledForClasses` will
|
||||
// still be filtered out
|
||||
includedClasses = includedClasses.filter(clazz => {
|
||||
return !disabledForClasses.includes(clazz.className);
|
||||
});
|
||||
}
|
||||
|
||||
this.isUsersClassDisabled = !includedClasses.some(clazz => {
|
||||
return clazz.className === '_User';
|
||||
});
|
||||
|
||||
return includedClasses;
|
||||
} else {
|
||||
return allClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a list of tuples
|
||||
* that provide the parseClass along with
|
||||
* its parseClassConfig where provided.
|
||||
*/
|
||||
_getParseClassesWithConfig(
|
||||
parseClasses,
|
||||
parseGraphQLConfig: ParseGraphQLConfig
|
||||
) {
|
||||
const { classConfigs } = parseGraphQLConfig;
|
||||
return parseClasses.map(parseClass => {
|
||||
let parseClassConfig;
|
||||
if (classConfigs) {
|
||||
parseClassConfig = classConfigs.find(
|
||||
c => c.className === parseClass.className
|
||||
);
|
||||
}
|
||||
return [parseClass, parseClassConfig];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for changes to the parseClasses
|
||||
* objects (i.e. database schema) or to
|
||||
* the parseGraphQLConfig object. If no
|
||||
* changes are found, return true;
|
||||
*/
|
||||
_hasSchemaInputChanged(params: {
|
||||
parseClasses: any,
|
||||
parseClassesString: string,
|
||||
parseGraphQLConfig: ?ParseGraphQLConfig,
|
||||
}): boolean {
|
||||
const { parseClasses, parseClassesString, parseGraphQLConfig } = params;
|
||||
|
||||
if (
|
||||
JSON.stringify(this.parseGraphQLConfig) ===
|
||||
JSON.stringify(parseGraphQLConfig)
|
||||
) {
|
||||
if (this.parseClasses === parseClasses) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.parseClassesString === parseClassesString) {
|
||||
this.parseClasses = parseClasses;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export { ParseGraphQLSchema };
|
||||
|
||||
Reference in New Issue
Block a user