GraphQL: Renaming Types/Inputs (#5883)

* Renaming GraphQL Types/Inputs

* Add Native Type to avoid collision

* Use pluralize for renaming

* Fixing tests

* Improve name collision management - tests passsing

* Renaming few more default types

* Rename file input

* Reverting fields types to not collide with the relay spec types
Improver users mutations

* Adding ArrayResult to the reserved list

* Fixing tests

* Add more unit tests to ParseGraphQLSchema

* Test transformClassNameToGraphQL

* Name collision tests
This commit is contained in:
Antoine Cormouls
2019-08-15 23:23:41 +02:00
committed by Antonio Davi Macedo Coelho de Castro
parent cf6e79ee75
commit 59b0221fec
20 changed files with 1505 additions and 864 deletions

View File

@@ -15,6 +15,29 @@ import DatabaseController from '../Controllers/DatabaseController';
import { toGraphQLError } from './parseGraphQLUtils';
import * as schemaDirectives from './loaders/schemaDirectives';
const RESERVED_GRAPHQL_TYPE_NAMES = [
'String',
'Boolean',
'Int',
'Float',
'ID',
'ArrayResult',
'Query',
'Mutation',
'Subscription',
'ObjectsQuery',
'UsersQuery',
'ObjectsMutation',
'FilesMutation',
'UsersMutation',
'FunctionsMutation',
'Viewer',
'SignUpFieldsInput',
'LogInFieldsInput',
];
const RESERVED_GRAPHQL_OBJECT_QUERY_NAMES = ['get', 'find'];
const RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES = ['create', 'update', 'delete'];
class ParseGraphQLSchema {
databaseController: DatabaseController;
parseGraphQLController: ParseGraphQLController;
@@ -60,7 +83,7 @@ class ParseGraphQLSchema {
this.parseClassesString = parseClassesString;
this.parseGraphQLConfig = parseGraphQLConfig;
this.parseClassTypes = {};
this.meType = null;
this.viewerType = null;
this.graphQLAutoSchema = null;
this.graphQLSchema = null;
this.graphQLTypes = [];
@@ -92,7 +115,7 @@ class ParseGraphQLSchema {
description: 'Query is the top level type for queries.',
fields: this.graphQLQueries,
});
this.graphQLTypes.push(graphQLQuery);
this.addGraphQLType(graphQLQuery, true, true);
}
let graphQLMutation = undefined;
@@ -102,7 +125,7 @@ class ParseGraphQLSchema {
description: 'Mutation is the top level type for mutations.',
fields: this.graphQLMutations,
});
this.graphQLTypes.push(graphQLMutation);
this.addGraphQLType(graphQLMutation, true, true);
}
let graphQLSubscription = undefined;
@@ -112,7 +135,7 @@ class ParseGraphQLSchema {
description: 'Subscription is the top level type for subscriptions.',
fields: this.graphQLSubscriptions,
});
this.graphQLTypes.push(graphQLSubscription);
this.addGraphQLType(graphQLSubscription, true, true);
}
this.graphQLAutoSchema = new GraphQLSchema({
@@ -172,6 +195,66 @@ class ParseGraphQLSchema {
return this.graphQLSchema;
}
addGraphQLType(type, throwError = false, ignoreReserved = false) {
if (
(!ignoreReserved && RESERVED_GRAPHQL_TYPE_NAMES.includes(type.name)) ||
this.graphQLTypes.find(existingType => existingType.name === type.name)
) {
const message = `Type ${type.name} could not be added to the auto schema because it collided with an existing type.`;
if (throwError) {
throw new Error(message);
}
this.log.warn(message);
return undefined;
}
this.graphQLTypes.push(type);
return type;
}
addGraphQLObjectQuery(
fieldName,
field,
throwError = false,
ignoreReserved = false
) {
if (
(!ignoreReserved &&
RESERVED_GRAPHQL_OBJECT_QUERY_NAMES.includes(fieldName)) ||
this.graphQLObjectsQueries[fieldName]
) {
const message = `Object query ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
if (throwError) {
throw new Error(message);
}
this.log.warn(message);
return undefined;
}
this.graphQLObjectsQueries[fieldName] = field;
return field;
}
addGraphQLObjectMutation(
fieldName,
field,
throwError = false,
ignoreReserved = false
) {
if (
(!ignoreReserved &&
RESERVED_GRAPHQL_OBJECT_MUTATION_NAMES.includes(fieldName)) ||
this.graphQLObjectsMutations[fieldName]
) {
const message = `Object mutation ${fieldName} could not be added to the auto schema because it collided with an existing field.`;
if (throwError) {
throw new Error(message);
}
this.log.warn(message);
return undefined;
}
this.graphQLObjectsMutations[fieldName] = field;
return field;
}
handleError(error) {
if (error instanceof Parse.Error) {
this.log.error('Parse error: ', error);
@@ -238,7 +321,32 @@ class ParseGraphQLSchema {
parseGraphQLConfig: ParseGraphQLConfig
) {
const { classConfigs } = parseGraphQLConfig;
return parseClasses.map(parseClass => {
// Make sures that the default classes and classes that
// starts with capitalized letter will be generated first.
const sortClasses = (a, b) => {
a = a.className;
b = b.className;
if (a[0] === '_') {
if (b[0] !== '_') {
return -1;
}
}
if (b[0] === '_') {
if (a[0] !== '_') {
return 1;
}
}
if (a === b) {
return 0;
} else if (a < b) {
return -1;
} else {
return 1;
}
};
return parseClasses.sort(sortClasses).map(parseClass => {
let parseClassConfig;
if (classConfigs) {
parseClassConfig = classConfigs.find(