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:
committed by
Antonio Davi Macedo Coelho de Castro
parent
cf6e79ee75
commit
59b0221fec
27
package-lock.json
generated
27
package-lock.json
generated
@@ -1214,11 +1214,21 @@
|
||||
"integrity": "sha512-J+YW09/vZRuK2/04SykW31xgMTtA/XTm4mSaLoJ79EW31SWstNUzfti9seu0MdWRafgdmRzUn+qCJ/MqXvQZRg==",
|
||||
"requires": {
|
||||
"@parse/node-gcm": "^1.0.0",
|
||||
"apn": "github:parse-community/node-apn#semver:^v3.0.2-parse",
|
||||
"apn": "github:parse-community/node-apn#3bc4fb20b68d53d3f3b7057cadf5a37ba6a45dc0",
|
||||
"npmlog": "^4.0.2",
|
||||
"parse": "^1.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"apn": {
|
||||
"version": "github:parse-community/node-apn#3bc4fb20b68d53d3f3b7057cadf5a37ba6a45dc0",
|
||||
"from": "github:parse-community/node-apn#3bc4fb20b68d53d3f3b7057cadf5a37ba6a45dc0",
|
||||
"requires": {
|
||||
"debug": "^3.1.0",
|
||||
"jsonwebtoken": "^8.1.0",
|
||||
"node-forge": "^0.7.1",
|
||||
"verror": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"parse": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/parse/-/parse-1.11.1.tgz",
|
||||
@@ -1668,16 +1678,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"apn": {
|
||||
"version": "github:parse-community/node-apn#3bc4fb20b68d53d3f3b7057cadf5a37ba6a45dc0",
|
||||
"from": "github:parse-community/node-apn#semver:^v3.0.2-parse",
|
||||
"requires": {
|
||||
"debug": "^3.1.0",
|
||||
"jsonwebtoken": "^8.1.0",
|
||||
"node-forge": "^0.7.1",
|
||||
"verror": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"apollo-cache": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.3.2.tgz",
|
||||
@@ -9075,6 +9075,11 @@
|
||||
"semver-compare": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"pluralize": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
|
||||
"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="
|
||||
},
|
||||
"posix-character-classes": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"node-rsa": "1.0.5",
|
||||
"parse": "2.6.0",
|
||||
"pg-promise": "9.0.1",
|
||||
"pluralize": "^8.0.0",
|
||||
"redis": "2.8.0",
|
||||
"semver": "6.3.0",
|
||||
"subscriptions-transport-ws": "0.9.16",
|
||||
|
||||
11
spec/ParseGraphQLClassNameTransformer.spec.js
Normal file
11
spec/ParseGraphQLClassNameTransformer.spec.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const {
|
||||
transformClassNameToGraphQL,
|
||||
} = require('../lib/GraphQL/transformers/className');
|
||||
|
||||
describe('transformClassNameToGraphQL', () => {
|
||||
it('should remove starting _ and tansform first letter to upper case', () => {
|
||||
expect(
|
||||
['_User', '_user', 'User', 'user'].map(transformClassNameToGraphQL)
|
||||
).toEqual(['User', 'User', 'User', 'User']);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
const { GraphQLObjectType } = require('graphql');
|
||||
const defaultLogger = require('../lib/logger').default;
|
||||
const { ParseGraphQLSchema } = require('../lib/GraphQL/ParseGraphQLSchema');
|
||||
|
||||
@@ -118,4 +119,428 @@ describe('ParseGraphQLSchema', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addGraphQLType', () => {
|
||||
it('should not load and warn duplicated types', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Type SomeClass could not be added to the auto schema because it collided with an existing type.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const type = new GraphQLObjectType({ name: 'SomeClass' });
|
||||
expect(parseGraphQLSchema.addGraphQLType(type)).toBe(type);
|
||||
expect(parseGraphQLSchema.graphQLTypes).toContain(type);
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLType(
|
||||
new GraphQLObjectType({ name: 'SomeClass' })
|
||||
)
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw error when required', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const type = new GraphQLObjectType({ name: 'SomeClass' });
|
||||
expect(parseGraphQLSchema.addGraphQLType(type, true)).toBe(type);
|
||||
expect(parseGraphQLSchema.graphQLTypes).toContain(type);
|
||||
expect(() =>
|
||||
parseGraphQLSchema.addGraphQLType(
|
||||
new GraphQLObjectType({ name: 'SomeClass' }),
|
||||
true
|
||||
)
|
||||
).toThrowError(
|
||||
'Type SomeClass could not be added to the auto schema because it collided with an existing type.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn reserved name collision', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Type String could not be added to the auto schema because it collided with an existing type.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLType(
|
||||
new GraphQLObjectType({ name: 'String' })
|
||||
)
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should ignore collision when necessary', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const type = new GraphQLObjectType({ name: 'String' });
|
||||
expect(parseGraphQLSchema.addGraphQLType(type, true, true)).toBe(type);
|
||||
expect(parseGraphQLSchema.graphQLTypes).toContain(type);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addGraphQLObjectQuery', () => {
|
||||
it('should not load and warn duplicated queries', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe(
|
||||
field
|
||||
);
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw error when required', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', field)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['someClasses']).toBe(
|
||||
field
|
||||
);
|
||||
expect(() =>
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('someClasses', {}, true)
|
||||
).toThrowError(
|
||||
'Object query someClasses could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn reserved name collision', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object query get could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('get', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should ignore collision when necessary', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
delete parseGraphQLSchema.graphQLObjectsQueries.get;
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectQuery('get', field, true, true)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsQueries['get']).toBe(field);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addGraphQLObjectMutation', () => {
|
||||
it('should not load and warn duplicated mutations', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field)
|
||||
).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.graphQLObjectsMutations['createSomeClass']
|
||||
).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should throw error when required', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', field)
|
||||
).toBe(field);
|
||||
expect(
|
||||
parseGraphQLSchema.graphQLObjectsMutations['createSomeClass']
|
||||
).toBe(field);
|
||||
expect(() =>
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('createSomeClass', {}, true)
|
||||
).toThrowError(
|
||||
'Object mutation createSomeClass could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
});
|
||||
|
||||
it('should warn reserved name collision', async () => {
|
||||
let logged = false;
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: message => {
|
||||
logged = true;
|
||||
expect(message).toEqual(
|
||||
'Object mutation create could not be added to the auto schema because it collided with an existing field.'
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('create', {})
|
||||
).toBeUndefined();
|
||||
expect(logged).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should ignore collision when necessary', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
await parseGraphQLSchema.load();
|
||||
delete parseGraphQLSchema.graphQLObjectsMutations.create;
|
||||
const field = {};
|
||||
expect(
|
||||
parseGraphQLSchema.addGraphQLObjectMutation('create', field, true, true)
|
||||
).toBe(field);
|
||||
expect(parseGraphQLSchema.graphQLObjectsMutations['create']).toBe(field);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_getParseClassesWithConfig', () => {
|
||||
it('should sort classes', () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: {
|
||||
warn: () => {
|
||||
fail('Should not warn');
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
parseGraphQLSchema
|
||||
._getParseClassesWithConfig(
|
||||
[
|
||||
{ className: 'b' },
|
||||
{ className: '_b' },
|
||||
{ className: 'B' },
|
||||
{ className: '_B' },
|
||||
{ className: 'a' },
|
||||
{ className: '_a' },
|
||||
{ className: 'A' },
|
||||
{ className: '_A' },
|
||||
],
|
||||
{
|
||||
classConfigs: [],
|
||||
}
|
||||
)
|
||||
.map(item => item[0])
|
||||
).toEqual([
|
||||
{ className: '_A' },
|
||||
{ className: '_B' },
|
||||
{ className: '_a' },
|
||||
{ className: '_b' },
|
||||
{ className: 'A' },
|
||||
{ className: 'B' },
|
||||
{ className: 'a' },
|
||||
{ className: 'b' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('name collision', () => {
|
||||
it('should not generate duplicate types when colliding to default classes', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: defaultLogger,
|
||||
});
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const types1 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const user = new Parse.Object('User');
|
||||
await user.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const types2 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(types1).not.toBe(types2);
|
||||
expect(types1.map(type => type.name).sort()).toEqual(
|
||||
types2.map(type => type.name).sort()
|
||||
);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(Object.keys(objectMutations1).sort()).toEqual(
|
||||
Object.keys(objectMutations2).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should not generate duplicate types when colliding the same name', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: defaultLogger,
|
||||
});
|
||||
const car1 = new Parse.Object('Car');
|
||||
await car1.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const types1 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const car2 = new Parse.Object('car');
|
||||
await car2.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const types2 = parseGraphQLSchema.graphQLTypes;
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(types1).not.toBe(types2);
|
||||
expect(types1.map(type => type.name).sort()).toEqual(
|
||||
types2.map(type => type.name).sort()
|
||||
);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(Object.keys(objectMutations1).sort()).toEqual(
|
||||
Object.keys(objectMutations2).sort()
|
||||
);
|
||||
});
|
||||
|
||||
it('should not generate duplicate queries when query name collide', async () => {
|
||||
const parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
databaseController,
|
||||
parseGraphQLController,
|
||||
log: defaultLogger,
|
||||
});
|
||||
const car = new Parse.Object('Car');
|
||||
await car.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema1 = await parseGraphQLSchema.load();
|
||||
const objectQueries1 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations1 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
const cars = new Parse.Object('cars');
|
||||
await cars.save();
|
||||
await parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
const schema2 = await parseGraphQLSchema.load();
|
||||
const objectQueries2 = parseGraphQLSchema.graphQLObjectsQueries;
|
||||
const objectMutations2 = parseGraphQLSchema.graphQLObjectsMutations;
|
||||
expect(schema1).not.toBe(schema2);
|
||||
expect(objectQueries1).not.toBe(objectQueries2);
|
||||
expect(Object.keys(objectQueries1).sort()).toEqual(
|
||||
Object.keys(objectQueries2).sort()
|
||||
);
|
||||
expect(objectMutations1).not.toBe(objectMutations2);
|
||||
expect(
|
||||
Object.keys(objectMutations1)
|
||||
.concat('createCars', 'updateCars', 'deleteCars')
|
||||
.sort()
|
||||
).toEqual(Object.keys(objectMutations2).sort());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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(
|
||||
|
||||
@@ -25,25 +25,31 @@ class ParseGraphQLServer {
|
||||
}
|
||||
this.config = config;
|
||||
this.parseGraphQLController = this.parseServer.config.parseGraphQLController;
|
||||
this.log =
|
||||
(this.parseServer.config && this.parseServer.config.loggerController) ||
|
||||
defaultLogger;
|
||||
this.parseGraphQLSchema = new ParseGraphQLSchema({
|
||||
parseGraphQLController: this.parseGraphQLController,
|
||||
databaseController: this.parseServer.config.databaseController,
|
||||
log:
|
||||
(this.parseServer.config && this.parseServer.config.loggerController) ||
|
||||
defaultLogger,
|
||||
log: this.log,
|
||||
graphQLCustomTypeDefs: this.config.graphQLCustomTypeDefs,
|
||||
});
|
||||
}
|
||||
|
||||
async _getGraphQLOptions(req) {
|
||||
return {
|
||||
schema: await this.parseGraphQLSchema.load(),
|
||||
context: {
|
||||
info: req.info,
|
||||
config: req.config,
|
||||
auth: req.auth,
|
||||
},
|
||||
};
|
||||
try {
|
||||
return {
|
||||
schema: await this.parseGraphQLSchema.load(),
|
||||
context: {
|
||||
info: req.info,
|
||||
config: req.config,
|
||||
auth: req.auth,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.log.error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
applyGraphQL(app) {
|
||||
|
||||
@@ -377,24 +377,24 @@ const GEO_POINT_FIELDS = {
|
||||
},
|
||||
};
|
||||
|
||||
const GEO_POINT = new GraphQLInputObjectType({
|
||||
const GEO_POINT_INPUT = new GraphQLInputObjectType({
|
||||
name: 'GeoPointInput',
|
||||
description:
|
||||
'The GeoPointInput type is used in operations that involve inputting fields of type geo point.',
|
||||
fields: GEO_POINT_FIELDS,
|
||||
});
|
||||
|
||||
const GEO_POINT = new GraphQLObjectType({
|
||||
name: 'GeoPoint',
|
||||
description:
|
||||
'The GeoPoint input type is used in operations that involve inputting fields of type geo point.',
|
||||
'The GeoPoint object type is used to return the information about geo point fields.',
|
||||
fields: GEO_POINT_FIELDS,
|
||||
});
|
||||
|
||||
const GEO_POINT_INFO = new GraphQLObjectType({
|
||||
name: 'GeoPointInfo',
|
||||
description:
|
||||
'The GeoPointInfo object type is used to return the information about geo points.',
|
||||
fields: GEO_POINT_FIELDS,
|
||||
});
|
||||
const POLYGON_INPUT = new GraphQLList(new GraphQLNonNull(GEO_POINT_INPUT));
|
||||
|
||||
const POLYGON = new GraphQLList(new GraphQLNonNull(GEO_POINT));
|
||||
|
||||
const POLYGON_INFO = new GraphQLList(new GraphQLNonNull(GEO_POINT_INFO));
|
||||
|
||||
const RELATION_OP = new GraphQLEnumType({
|
||||
name: 'RelationOp',
|
||||
description:
|
||||
@@ -542,10 +542,10 @@ const COUNT_ATT = {
|
||||
type: new GraphQLNonNull(GraphQLInt),
|
||||
};
|
||||
|
||||
const SUBQUERY = new GraphQLInputObjectType({
|
||||
name: 'Subquery',
|
||||
const SUBQUERY_INPUT = new GraphQLInputObjectType({
|
||||
name: 'SubqueryInput',
|
||||
description:
|
||||
'The Subquery input type is used to specific a different query to a different class.',
|
||||
'The SubqueryInput type is used to specific a different query to a different class.',
|
||||
fields: {
|
||||
className: CLASS_NAME_ATT,
|
||||
where: Object.assign({}, WHERE_ATT, {
|
||||
@@ -554,14 +554,14 @@ const SUBQUERY = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const SELECT_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'SelectOperator',
|
||||
const SELECT_INPUT = new GraphQLInputObjectType({
|
||||
name: 'SelectInput',
|
||||
description:
|
||||
'The SelectOperator input type is used to specify a $select operation on a constraint.',
|
||||
'The SelectInput type is used to specify a $select operation on a constraint.',
|
||||
fields: {
|
||||
query: {
|
||||
description: 'This is the subquery to be executed.',
|
||||
type: new GraphQLNonNull(SUBQUERY),
|
||||
type: new GraphQLNonNull(SUBQUERY_INPUT),
|
||||
},
|
||||
key: {
|
||||
description:
|
||||
@@ -571,10 +571,10 @@ const SELECT_OPERATOR = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const SEARCH_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'SearchOperator',
|
||||
const SEARCH_INPUT = new GraphQLInputObjectType({
|
||||
name: 'SearchInput',
|
||||
description:
|
||||
'The SearchOperator input type is used to specifiy a $search operation on a full text search.',
|
||||
'The SearchInput type is used to specifiy a $search operation on a full text search.',
|
||||
fields: {
|
||||
_term: {
|
||||
description: 'This is the term to be searched.',
|
||||
@@ -598,54 +598,54 @@ const SEARCH_OPERATOR = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const TEXT_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'TextOperator',
|
||||
const TEXT_INPUT = new GraphQLInputObjectType({
|
||||
name: 'TextInput',
|
||||
description:
|
||||
'The TextOperator input type is used to specify a $text operation on a constraint.',
|
||||
'The TextInput type is used to specify a $text operation on a constraint.',
|
||||
fields: {
|
||||
_search: {
|
||||
description: 'This is the search to be executed.',
|
||||
type: new GraphQLNonNull(SEARCH_OPERATOR),
|
||||
type: new GraphQLNonNull(SEARCH_INPUT),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const BOX_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'BoxOperator',
|
||||
const BOX_INPUT = new GraphQLInputObjectType({
|
||||
name: 'BoxInput',
|
||||
description:
|
||||
'The BoxOperator input type is used to specifiy a $box operation on a within geo query.',
|
||||
'The BoxInput type is used to specifiy a $box operation on a within geo query.',
|
||||
fields: {
|
||||
bottomLeft: {
|
||||
description: 'This is the bottom left coordinates of the box.',
|
||||
type: new GraphQLNonNull(GEO_POINT),
|
||||
type: new GraphQLNonNull(GEO_POINT_INPUT),
|
||||
},
|
||||
upperRight: {
|
||||
description: 'This is the upper right coordinates of the box.',
|
||||
type: new GraphQLNonNull(GEO_POINT),
|
||||
type: new GraphQLNonNull(GEO_POINT_INPUT),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const WITHIN_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'WithinOperator',
|
||||
const WITHIN_INPUT = new GraphQLInputObjectType({
|
||||
name: 'WithinInput',
|
||||
description:
|
||||
'The WithinOperator input type is used to specify a $within operation on a constraint.',
|
||||
'The WithinInput type is used to specify a $within operation on a constraint.',
|
||||
fields: {
|
||||
_box: {
|
||||
description: 'This is the box to be specified.',
|
||||
type: new GraphQLNonNull(BOX_OPERATOR),
|
||||
type: new GraphQLNonNull(BOX_INPUT),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const CENTER_SPHERE_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'CenterSphereOperator',
|
||||
const CENTER_SPHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'CenterSphereInput',
|
||||
description:
|
||||
'The CenterSphereOperator input type is used to specifiy a $centerSphere operation on a geoWithin query.',
|
||||
'The CenterSphereInput type is used to specifiy a $centerSphere operation on a geoWithin query.',
|
||||
fields: {
|
||||
center: {
|
||||
description: 'This is the center of the sphere.',
|
||||
type: new GraphQLNonNull(GEO_POINT),
|
||||
type: new GraphQLNonNull(GEO_POINT_INPUT),
|
||||
},
|
||||
distance: {
|
||||
description: 'This is the radius of the sphere.',
|
||||
@@ -654,30 +654,30 @@ const CENTER_SPHERE_OPERATOR = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const GEO_WITHIN_OPERATOR = new GraphQLInputObjectType({
|
||||
name: 'GeoWithinOperator',
|
||||
const GEO_WITHIN_INPUT = new GraphQLInputObjectType({
|
||||
name: 'GeoWithinInput',
|
||||
description:
|
||||
'The GeoWithinOperator input type is used to specify a $geoWithin operation on a constraint.',
|
||||
'The GeoWithinInput type is used to specify a $geoWithin operation on a constraint.',
|
||||
fields: {
|
||||
_polygon: {
|
||||
description: 'This is the polygon to be specified.',
|
||||
type: POLYGON,
|
||||
type: POLYGON_INPUT,
|
||||
},
|
||||
_centerSphere: {
|
||||
description: 'This is the sphere to be specified.',
|
||||
type: CENTER_SPHERE_OPERATOR,
|
||||
type: CENTER_SPHERE_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const GEO_INTERSECTS = new GraphQLInputObjectType({
|
||||
name: 'GeoIntersectsOperator',
|
||||
const GEO_INTERSECTS_INPUT = new GraphQLInputObjectType({
|
||||
name: 'GeoIntersectsInput',
|
||||
description:
|
||||
'The GeoIntersectsOperator input type is used to specify a $geoIntersects operation on a constraint.',
|
||||
'The GeoIntersectsInput type is used to specify a $geoIntersects operation on a constraint.',
|
||||
fields: {
|
||||
_point: {
|
||||
description: 'This is the point to be specified.',
|
||||
type: GEO_POINT,
|
||||
type: GEO_POINT_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -739,13 +739,13 @@ const _exists = {
|
||||
const _select = {
|
||||
description:
|
||||
'This is the $select operator to specify a constraint to select the objects where a field equals to a key in the result of a different query.',
|
||||
type: SELECT_OPERATOR,
|
||||
type: SELECT_INPUT,
|
||||
};
|
||||
|
||||
const _dontSelect = {
|
||||
description:
|
||||
'This is the $dontSelect operator to specify a constraint to select the objects where a field do not equal to a key in the result of a different query.',
|
||||
type: SELECT_OPERATOR,
|
||||
type: SELECT_INPUT,
|
||||
};
|
||||
|
||||
const _regex = {
|
||||
@@ -760,10 +760,10 @@ const _options = {
|
||||
type: GraphQLString,
|
||||
};
|
||||
|
||||
const STRING_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'StringConstraint',
|
||||
const STRING_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'StringWhereInput',
|
||||
description:
|
||||
'The StringConstraint input type is used in operations that involve filtering objects by a field of type String.',
|
||||
'The StringWhereInput input type is used in operations that involve filtering objects by a field of type String.',
|
||||
fields: {
|
||||
_eq: _eq(GraphQLString),
|
||||
_ne: _ne(GraphQLString),
|
||||
@@ -781,15 +781,15 @@ const STRING_CONSTRAINT = new GraphQLInputObjectType({
|
||||
_text: {
|
||||
description:
|
||||
'This is the $text operator to specify a full text search constraint.',
|
||||
type: TEXT_OPERATOR,
|
||||
type: TEXT_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const NUMBER_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'NumberConstraint',
|
||||
const NUMBER_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'NumberWhereInput',
|
||||
description:
|
||||
'The NumberConstraint input type is used in operations that involve filtering objects by a field of type Number.',
|
||||
'The NumberWhereInput input type is used in operations that involve filtering objects by a field of type Number.',
|
||||
fields: {
|
||||
_eq: _eq(GraphQLFloat),
|
||||
_ne: _ne(GraphQLFloat),
|
||||
@@ -805,10 +805,10 @@ const NUMBER_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const BOOLEAN_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'BooleanConstraint',
|
||||
const BOOLEAN_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'BooleanWhereInput',
|
||||
description:
|
||||
'The BooleanConstraint input type is used in operations that involve filtering objects by a field of type Boolean.',
|
||||
'The BooleanWhereInput input type is used in operations that involve filtering objects by a field of type Boolean.',
|
||||
fields: {
|
||||
_eq: _eq(GraphQLBoolean),
|
||||
_ne: _ne(GraphQLBoolean),
|
||||
@@ -818,10 +818,10 @@ const BOOLEAN_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const ARRAY_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'ArrayConstraint',
|
||||
const ARRAY_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'ArrayWhereInput',
|
||||
description:
|
||||
'The ArrayConstraint input type is used in operations that involve filtering objects by a field of type Array.',
|
||||
'The ArrayWhereInput input type is used in operations that involve filtering objects by a field of type Array.',
|
||||
fields: {
|
||||
_eq: _eq(ANY),
|
||||
_ne: _ne(ANY),
|
||||
@@ -847,8 +847,8 @@ const ARRAY_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const KEY_VALUE = new GraphQLInputObjectType({
|
||||
name: 'KeyValue',
|
||||
const KEY_VALUE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'KeyValueInput',
|
||||
description: 'An entry from an object, i.e., a pair of key and value.',
|
||||
fields: {
|
||||
_key: {
|
||||
@@ -862,29 +862,29 @@ const KEY_VALUE = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const OBJECT_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'ObjectConstraint',
|
||||
const OBJECT_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'ObjectWhereInput',
|
||||
description:
|
||||
'The ObjectConstraint input type is used in operations that involve filtering result by a field of type Object.',
|
||||
'The ObjectWhereInput input type is used in operations that involve filtering result by a field of type Object.',
|
||||
fields: {
|
||||
_eq: _eq(KEY_VALUE),
|
||||
_ne: _ne(KEY_VALUE),
|
||||
_in: _in(KEY_VALUE),
|
||||
_nin: _nin(KEY_VALUE),
|
||||
_lt: _lt(KEY_VALUE),
|
||||
_lte: _lte(KEY_VALUE),
|
||||
_gt: _gt(KEY_VALUE),
|
||||
_gte: _gte(KEY_VALUE),
|
||||
_eq: _eq(KEY_VALUE_INPUT),
|
||||
_ne: _ne(KEY_VALUE_INPUT),
|
||||
_in: _in(KEY_VALUE_INPUT),
|
||||
_nin: _nin(KEY_VALUE_INPUT),
|
||||
_lt: _lt(KEY_VALUE_INPUT),
|
||||
_lte: _lte(KEY_VALUE_INPUT),
|
||||
_gt: _gt(KEY_VALUE_INPUT),
|
||||
_gte: _gte(KEY_VALUE_INPUT),
|
||||
_exists,
|
||||
_select,
|
||||
_dontSelect,
|
||||
},
|
||||
});
|
||||
|
||||
const DATE_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'DateConstraint',
|
||||
const DATE_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'DateWhereInput',
|
||||
description:
|
||||
'The DateConstraint input type is used in operations that involve filtering objects by a field of type Date.',
|
||||
'The DateWhereInput input type is used in operations that involve filtering objects by a field of type Date.',
|
||||
fields: {
|
||||
_eq: _eq(DATE),
|
||||
_ne: _ne(DATE),
|
||||
@@ -900,10 +900,10 @@ const DATE_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const BYTES_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'BytesConstraint',
|
||||
const BYTES_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'BytesWhereInput',
|
||||
description:
|
||||
'The BytesConstraint input type is used in operations that involve filtering objects by a field of type Bytes.',
|
||||
'The BytesWhereInput input type is used in operations that involve filtering objects by a field of type Bytes.',
|
||||
fields: {
|
||||
_eq: _eq(BYTES),
|
||||
_ne: _ne(BYTES),
|
||||
@@ -919,10 +919,10 @@ const BYTES_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const FILE_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'FileConstraint',
|
||||
const FILE_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'FileWhereInput',
|
||||
description:
|
||||
'The FILE_CONSTRAINT input type is used in operations that involve filtering objects by a field of type File.',
|
||||
'The FileWhereInput input type is used in operations that involve filtering objects by a field of type File.',
|
||||
fields: {
|
||||
_eq: _eq(FILE),
|
||||
_ne: _ne(FILE),
|
||||
@@ -940,16 +940,16 @@ const FILE_CONSTRAINT = new GraphQLInputObjectType({
|
||||
},
|
||||
});
|
||||
|
||||
const GEO_POINT_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'GeoPointConstraint',
|
||||
const GEO_POINT_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'GeoPointWhereInput',
|
||||
description:
|
||||
'The GeoPointConstraint input type is used in operations that involve filtering objects by a field of type GeoPoint.',
|
||||
'The GeoPointWhereInput input type is used in operations that involve filtering objects by a field of type GeoPoint.',
|
||||
fields: {
|
||||
_exists,
|
||||
_nearSphere: {
|
||||
description:
|
||||
'This is the $nearSphere operator to specify a constraint to select the objects where the values of a geo point field is near to another geo point.',
|
||||
type: GEO_POINT,
|
||||
type: GEO_POINT_INPUT,
|
||||
},
|
||||
_maxDistance: {
|
||||
description:
|
||||
@@ -974,26 +974,26 @@ const GEO_POINT_CONSTRAINT = new GraphQLInputObjectType({
|
||||
_within: {
|
||||
description:
|
||||
'This is the $within operator to specify a constraint to select the objects where the values of a geo point field is within a specified box.',
|
||||
type: WITHIN_OPERATOR,
|
||||
type: WITHIN_INPUT,
|
||||
},
|
||||
_geoWithin: {
|
||||
description:
|
||||
'This is the $geoWithin operator to specify a constraint to select the objects where the values of a geo point field is within a specified polygon or sphere.',
|
||||
type: GEO_WITHIN_OPERATOR,
|
||||
type: GEO_WITHIN_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const POLYGON_CONSTRAINT = new GraphQLInputObjectType({
|
||||
name: 'PolygonConstraint',
|
||||
const POLYGON_WHERE_INPUT = new GraphQLInputObjectType({
|
||||
name: 'PolygonWhereInput',
|
||||
description:
|
||||
'The PolygonConstraint input type is used in operations that involve filtering objects by a field of type Polygon.',
|
||||
'The PolygonWhereInput input type is used in operations that involve filtering objects by a field of type Polygon.',
|
||||
fields: {
|
||||
_exists,
|
||||
_geoIntersects: {
|
||||
description:
|
||||
'This is the $geoIntersects operator to specify a constraint to select the objects where the values of a polygon field intersect a specified point.',
|
||||
type: GEO_INTERSECTS,
|
||||
type: GEO_INTERSECTS_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1071,42 +1071,43 @@ const loadArrayResult = (parseGraphQLSchema, parseClasses) => {
|
||||
};
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.graphQLTypes.push(GraphQLUpload);
|
||||
parseGraphQLSchema.graphQLTypes.push(ANY);
|
||||
parseGraphQLSchema.graphQLTypes.push(OBJECT);
|
||||
parseGraphQLSchema.graphQLTypes.push(DATE);
|
||||
parseGraphQLSchema.graphQLTypes.push(BYTES);
|
||||
parseGraphQLSchema.graphQLTypes.push(FILE);
|
||||
parseGraphQLSchema.graphQLTypes.push(FILE_INFO);
|
||||
parseGraphQLSchema.graphQLTypes.push(GEO_POINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(GEO_POINT_INFO);
|
||||
parseGraphQLSchema.graphQLTypes.push(RELATION_OP);
|
||||
parseGraphQLSchema.graphQLTypes.push(CREATE_RESULT);
|
||||
parseGraphQLSchema.graphQLTypes.push(UPDATE_RESULT);
|
||||
parseGraphQLSchema.graphQLTypes.push(CLASS);
|
||||
parseGraphQLSchema.graphQLTypes.push(READ_PREFERENCE);
|
||||
parseGraphQLSchema.graphQLTypes.push(SUBQUERY);
|
||||
parseGraphQLSchema.graphQLTypes.push(SELECT_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(SEARCH_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(TEXT_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(BOX_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(WITHIN_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(CENTER_SPHERE_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(GEO_WITHIN_OPERATOR);
|
||||
parseGraphQLSchema.graphQLTypes.push(GEO_INTERSECTS);
|
||||
parseGraphQLSchema.graphQLTypes.push(STRING_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(NUMBER_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(BOOLEAN_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(ARRAY_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(OBJECT_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(DATE_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(BYTES_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(FILE_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(GEO_POINT_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(POLYGON_CONSTRAINT);
|
||||
parseGraphQLSchema.graphQLTypes.push(FIND_RESULT);
|
||||
parseGraphQLSchema.graphQLTypes.push(SIGN_UP_RESULT);
|
||||
parseGraphQLSchema.graphQLTypes.push(ELEMENT);
|
||||
parseGraphQLSchema.addGraphQLType(GraphQLUpload, true);
|
||||
parseGraphQLSchema.addGraphQLType(ANY, true);
|
||||
parseGraphQLSchema.addGraphQLType(OBJECT, true);
|
||||
parseGraphQLSchema.addGraphQLType(DATE, true);
|
||||
parseGraphQLSchema.addGraphQLType(BYTES, true);
|
||||
parseGraphQLSchema.addGraphQLType(FILE, true);
|
||||
parseGraphQLSchema.addGraphQLType(FILE_INFO, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_POINT_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_POINT, true);
|
||||
parseGraphQLSchema.addGraphQLType(RELATION_OP, true);
|
||||
parseGraphQLSchema.addGraphQLType(CREATE_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(UPDATE_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(CLASS, true);
|
||||
parseGraphQLSchema.addGraphQLType(READ_PREFERENCE, true);
|
||||
parseGraphQLSchema.addGraphQLType(SUBQUERY_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(SELECT_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(SEARCH_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(TEXT_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(BOX_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(WITHIN_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(CENTER_SPHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_WITHIN_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_INTERSECTS_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(STRING_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(NUMBER_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(BOOLEAN_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ARRAY_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(KEY_VALUE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(OBJECT_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(DATE_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(BYTES_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(FILE_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_POINT_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(POLYGON_WHERE_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(FIND_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(SIGN_UP_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ELEMENT, true);
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -1128,10 +1129,10 @@ export {
|
||||
FILE,
|
||||
FILE_INFO,
|
||||
GEO_POINT_FIELDS,
|
||||
GEO_POINT_INPUT,
|
||||
GEO_POINT,
|
||||
GEO_POINT_INFO,
|
||||
POLYGON_INPUT,
|
||||
POLYGON,
|
||||
POLYGON_INFO,
|
||||
RELATION_OP,
|
||||
CLASS_NAME_ATT,
|
||||
FIELDS_ATT,
|
||||
@@ -1157,15 +1158,15 @@ export {
|
||||
SKIP_ATT,
|
||||
LIMIT_ATT,
|
||||
COUNT_ATT,
|
||||
SUBQUERY,
|
||||
SELECT_OPERATOR,
|
||||
SEARCH_OPERATOR,
|
||||
TEXT_OPERATOR,
|
||||
BOX_OPERATOR,
|
||||
WITHIN_OPERATOR,
|
||||
CENTER_SPHERE_OPERATOR,
|
||||
GEO_WITHIN_OPERATOR,
|
||||
GEO_INTERSECTS,
|
||||
SUBQUERY_INPUT,
|
||||
SELECT_INPUT,
|
||||
SEARCH_INPUT,
|
||||
TEXT_INPUT,
|
||||
BOX_INPUT,
|
||||
WITHIN_INPUT,
|
||||
CENTER_SPHERE_INPUT,
|
||||
GEO_WITHIN_INPUT,
|
||||
GEO_INTERSECTS_INPUT,
|
||||
_eq,
|
||||
_ne,
|
||||
_lt,
|
||||
@@ -1179,16 +1180,17 @@ export {
|
||||
_dontSelect,
|
||||
_regex,
|
||||
_options,
|
||||
STRING_CONSTRAINT,
|
||||
NUMBER_CONSTRAINT,
|
||||
BOOLEAN_CONSTRAINT,
|
||||
ARRAY_CONSTRAINT,
|
||||
OBJECT_CONSTRAINT,
|
||||
DATE_CONSTRAINT,
|
||||
BYTES_CONSTRAINT,
|
||||
FILE_CONSTRAINT,
|
||||
GEO_POINT_CONSTRAINT,
|
||||
POLYGON_CONSTRAINT,
|
||||
STRING_WHERE_INPUT,
|
||||
NUMBER_WHERE_INPUT,
|
||||
BOOLEAN_WHERE_INPUT,
|
||||
ARRAY_WHERE_INPUT,
|
||||
KEY_VALUE_INPUT,
|
||||
OBJECT_WHERE_INPUT,
|
||||
DATE_WHERE_INPUT,
|
||||
BYTES_WHERE_INPUT,
|
||||
FILE_WHERE_INPUT,
|
||||
GEO_POINT_WHERE_INPUT,
|
||||
POLYGON_WHERE_INPUT,
|
||||
FIND_RESULT,
|
||||
SIGN_UP_RESULT,
|
||||
ARRAY_RESULT,
|
||||
|
||||
@@ -11,7 +11,7 @@ const load = parseGraphQLSchema => {
|
||||
description:
|
||||
'The create mutation can be used to create and upload a new file.',
|
||||
args: {
|
||||
file: {
|
||||
upload: {
|
||||
description: 'This is the new file to be created and uploaded',
|
||||
type: new GraphQLNonNull(GraphQLUpload),
|
||||
},
|
||||
@@ -19,10 +19,10 @@ const load = parseGraphQLSchema => {
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.FILE_INFO),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { file } = args;
|
||||
const { upload } = args;
|
||||
const { config } = context;
|
||||
|
||||
const { createReadStream, filename, mimetype } = await file;
|
||||
const { createReadStream, filename, mimetype } = await upload;
|
||||
let data = null;
|
||||
if (createReadStream) {
|
||||
const stream = createReadStream();
|
||||
@@ -81,7 +81,7 @@ const load = parseGraphQLSchema => {
|
||||
description: 'FilesMutation is the top level type for files mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(filesMutation);
|
||||
parseGraphQLSchema.addGraphQLType(filesMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.files = {
|
||||
description: 'This is the top level for files mutations.',
|
||||
|
||||
@@ -45,7 +45,7 @@ const load = parseGraphQLSchema => {
|
||||
'FunctionsMutation is the top level type for functions mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(functionsMutation);
|
||||
parseGraphQLSchema.addGraphQLType(functionsMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.functions = {
|
||||
description: 'This is the top level for functions mutations.',
|
||||
|
||||
@@ -1,33 +1,14 @@
|
||||
import { GraphQLNonNull, GraphQLBoolean, GraphQLObjectType } from 'graphql';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import rest from '../../rest';
|
||||
|
||||
const parseMap = {
|
||||
_op: '__op',
|
||||
};
|
||||
|
||||
const transformToParse = fields => {
|
||||
if (!fields || typeof fields !== 'object') {
|
||||
return;
|
||||
}
|
||||
Object.keys(fields).forEach(fieldName => {
|
||||
const fieldValue = fields[fieldName];
|
||||
if (parseMap[fieldName]) {
|
||||
delete fields[fieldName];
|
||||
fields[parseMap[fieldName]] = fieldValue;
|
||||
}
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformToParse(fieldValue);
|
||||
}
|
||||
});
|
||||
};
|
||||
import { transformMutationInputToParse } from '../transformers/mutation';
|
||||
|
||||
const createObject = async (className, fields, config, auth, info) => {
|
||||
if (!fields) {
|
||||
fields = {};
|
||||
}
|
||||
|
||||
transformToParse(fields);
|
||||
transformMutationInputToParse(fields);
|
||||
|
||||
return (await rest.create(config, auth, className, fields, info.clientSDK))
|
||||
.response;
|
||||
@@ -45,7 +26,7 @@ const updateObject = async (
|
||||
fields = {};
|
||||
}
|
||||
|
||||
transformToParse(fields);
|
||||
transformMutationInputToParse(fields);
|
||||
|
||||
return (await rest.update(
|
||||
config,
|
||||
@@ -63,80 +44,95 @@ const deleteObject = async (className, objectId, config, auth, info) => {
|
||||
};
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.graphQLObjectsMutations.create = {
|
||||
description:
|
||||
'The create mutation can be used to create a new object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
fields: defaultGraphQLTypes.FIELDS_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.CREATE_RESULT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, fields } = args;
|
||||
const { config, auth, info } = context;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
'create',
|
||||
{
|
||||
description:
|
||||
'The create mutation can be used to create a new object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
fields: defaultGraphQLTypes.FIELDS_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.CREATE_RESULT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, fields } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return await createObject(className, fields, config, auth, info);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
return await createObject(className, fields, config, auth, info);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.graphQLObjectsMutations.update = {
|
||||
description:
|
||||
'The update mutation can be used to update an object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
fields: defaultGraphQLTypes.FIELDS_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.UPDATE_RESULT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, objectId, fields } = args;
|
||||
const { config, auth, info } = context;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
'update',
|
||||
{
|
||||
description:
|
||||
'The update mutation can be used to update an object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
fields: defaultGraphQLTypes.FIELDS_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.UPDATE_RESULT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, objectId, fields } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return await updateObject(
|
||||
className,
|
||||
objectId,
|
||||
fields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
return await updateObject(
|
||||
className,
|
||||
objectId,
|
||||
fields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.graphQLObjectsMutations.delete = {
|
||||
description:
|
||||
'The delete mutation can be used to delete an object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, objectId } = args;
|
||||
const { config, auth, info } = context;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(
|
||||
'delete',
|
||||
{
|
||||
description:
|
||||
'The delete mutation can be used to delete an object of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const { className, objectId } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return await deleteObject(className, objectId, config, auth, info);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
return await deleteObject(className, objectId, config, auth, info);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
const objectsMutation = new GraphQLObjectType({
|
||||
name: 'ObjectsMutation',
|
||||
description: 'ObjectsMutation is the top level type for objects mutations.',
|
||||
fields: parseGraphQLSchema.graphQLObjectsMutations,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(objectsMutation);
|
||||
parseGraphQLSchema.addGraphQLType(objectsMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.objects = {
|
||||
description: 'This is the top level for objects mutations.',
|
||||
|
||||
@@ -8,6 +8,7 @@ import getFieldNames from 'graphql-list-fields';
|
||||
import Parse from 'parse/node';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import rest from '../../rest';
|
||||
import { transformQueryInputToParse } from '../transformers/query';
|
||||
|
||||
const getObject = async (
|
||||
className,
|
||||
@@ -54,155 +55,6 @@ const getObject = async (
|
||||
return response.results[0];
|
||||
};
|
||||
|
||||
const parseMap = {
|
||||
_or: '$or',
|
||||
_and: '$and',
|
||||
_nor: '$nor',
|
||||
_relatedTo: '$relatedTo',
|
||||
_eq: '$eq',
|
||||
_ne: '$ne',
|
||||
_lt: '$lt',
|
||||
_lte: '$lte',
|
||||
_gt: '$gt',
|
||||
_gte: '$gte',
|
||||
_in: '$in',
|
||||
_nin: '$nin',
|
||||
_exists: '$exists',
|
||||
_select: '$select',
|
||||
_dontSelect: '$dontSelect',
|
||||
_inQuery: '$inQuery',
|
||||
_notInQuery: '$notInQuery',
|
||||
_containedBy: '$containedBy',
|
||||
_all: '$all',
|
||||
_regex: '$regex',
|
||||
_options: '$options',
|
||||
_text: '$text',
|
||||
_search: '$search',
|
||||
_term: '$term',
|
||||
_language: '$language',
|
||||
_caseSensitive: '$caseSensitive',
|
||||
_diacriticSensitive: '$diacriticSensitive',
|
||||
_nearSphere: '$nearSphere',
|
||||
_maxDistance: '$maxDistance',
|
||||
_maxDistanceInRadians: '$maxDistanceInRadians',
|
||||
_maxDistanceInMiles: '$maxDistanceInMiles',
|
||||
_maxDistanceInKilometers: '$maxDistanceInKilometers',
|
||||
_within: '$within',
|
||||
_box: '$box',
|
||||
_geoWithin: '$geoWithin',
|
||||
_polygon: '$polygon',
|
||||
_centerSphere: '$centerSphere',
|
||||
_geoIntersects: '$geoIntersects',
|
||||
_point: '$point',
|
||||
};
|
||||
|
||||
const transformToParse = (constraints, parentFieldName, parentConstraints) => {
|
||||
if (!constraints || typeof constraints !== 'object') {
|
||||
return;
|
||||
}
|
||||
Object.keys(constraints).forEach(fieldName => {
|
||||
let fieldValue = constraints[fieldName];
|
||||
|
||||
/**
|
||||
* If we have a key-value pair, we need to change the way the constraint is structured.
|
||||
*
|
||||
* Example:
|
||||
* From:
|
||||
* {
|
||||
* "someField": {
|
||||
* "_lt": {
|
||||
* "_key":"foo.bar",
|
||||
* "_value": 100
|
||||
* },
|
||||
* "_gt": {
|
||||
* "_key":"foo.bar",
|
||||
* "_value": 10
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* To:
|
||||
* {
|
||||
* "someField.foo.bar": {
|
||||
* "$lt": 100,
|
||||
* "$gt": 10
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
if (
|
||||
fieldValue._key &&
|
||||
fieldValue._value &&
|
||||
parentConstraints &&
|
||||
parentFieldName
|
||||
) {
|
||||
delete parentConstraints[parentFieldName];
|
||||
parentConstraints[`${parentFieldName}.${fieldValue._key}`] = {
|
||||
...parentConstraints[`${parentFieldName}.${fieldValue._key}`],
|
||||
[parseMap[fieldName]]: fieldValue._value,
|
||||
};
|
||||
} else if (parseMap[fieldName]) {
|
||||
delete constraints[fieldName];
|
||||
fieldName = parseMap[fieldName];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
switch (fieldName) {
|
||||
case '$point':
|
||||
case '$nearSphere':
|
||||
if (typeof fieldValue === 'object' && !fieldValue.__type) {
|
||||
fieldValue.__type = 'GeoPoint';
|
||||
}
|
||||
break;
|
||||
case '$box':
|
||||
if (
|
||||
typeof fieldValue === 'object' &&
|
||||
fieldValue.bottomLeft &&
|
||||
fieldValue.upperRight
|
||||
) {
|
||||
fieldValue = [
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.bottomLeft,
|
||||
},
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.upperRight,
|
||||
},
|
||||
];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
break;
|
||||
case '$polygon':
|
||||
if (fieldValue instanceof Array) {
|
||||
fieldValue.forEach(geoPoint => {
|
||||
if (typeof geoPoint === 'object' && !geoPoint.__type) {
|
||||
geoPoint.__type = 'GeoPoint';
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case '$centerSphere':
|
||||
if (
|
||||
typeof fieldValue === 'object' &&
|
||||
fieldValue.center &&
|
||||
fieldValue.distance
|
||||
) {
|
||||
fieldValue = [
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.center,
|
||||
},
|
||||
fieldValue.distance,
|
||||
];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformToParse(fieldValue, fieldName, constraints);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const findObjects = async (
|
||||
className,
|
||||
where,
|
||||
@@ -224,7 +76,7 @@ const findObjects = async (
|
||||
where = {};
|
||||
}
|
||||
|
||||
transformToParse(where);
|
||||
transformQueryInputToParse(where);
|
||||
|
||||
const options = {};
|
||||
|
||||
@@ -282,118 +134,131 @@ const findObjects = async (
|
||||
};
|
||||
|
||||
const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.graphQLObjectsQueries.get = {
|
||||
description:
|
||||
'The get query can be used to get an object of a certain class by its objectId.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
keys: defaultGraphQLTypes.KEYS_ATT,
|
||||
include: defaultGraphQLTypes.INCLUDE_ATT,
|
||||
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
|
||||
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.OBJECT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const {
|
||||
className,
|
||||
objectId,
|
||||
keys,
|
||||
include,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
} = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return await getObject(
|
||||
className,
|
||||
objectId,
|
||||
keys,
|
||||
include,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
parseGraphQLSchema.graphQLObjectsQueries.find = {
|
||||
description:
|
||||
'The find query can be used to find objects of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
where: defaultGraphQLTypes.WHERE_ATT,
|
||||
order: {
|
||||
description:
|
||||
'This is the order in which the objects should be returned',
|
||||
type: GraphQLString,
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(
|
||||
'get',
|
||||
{
|
||||
description:
|
||||
'The get query can be used to get an object of a certain class by its objectId.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
keys: defaultGraphQLTypes.KEYS_ATT,
|
||||
include: defaultGraphQLTypes.INCLUDE_ATT,
|
||||
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
|
||||
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
|
||||
},
|
||||
skip: defaultGraphQLTypes.SKIP_ATT,
|
||||
limit: defaultGraphQLTypes.LIMIT_ATT,
|
||||
keys: defaultGraphQLTypes.KEYS_ATT,
|
||||
include: defaultGraphQLTypes.INCLUDE_ATT,
|
||||
includeAll: {
|
||||
description: 'All pointers will be returned',
|
||||
type: GraphQLBoolean,
|
||||
},
|
||||
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
|
||||
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
|
||||
subqueryReadPreference: defaultGraphQLTypes.SUBQUERY_READ_PREFERENCE_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.FIND_RESULT),
|
||||
async resolve(_source, args, context, queryInfo) {
|
||||
try {
|
||||
const {
|
||||
className,
|
||||
where,
|
||||
order,
|
||||
skip,
|
||||
limit,
|
||||
keys,
|
||||
include,
|
||||
includeAll,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
subqueryReadPreference,
|
||||
} = args;
|
||||
const { config, auth, info } = context;
|
||||
const selectedFields = getFieldNames(queryInfo);
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.OBJECT),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const {
|
||||
className,
|
||||
objectId,
|
||||
keys,
|
||||
include,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
} = args;
|
||||
|
||||
return await findObjects(
|
||||
className,
|
||||
where,
|
||||
order,
|
||||
skip,
|
||||
limit,
|
||||
keys,
|
||||
include,
|
||||
includeAll,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
subqueryReadPreference,
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
selectedFields
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
const { config, auth, info } = context;
|
||||
|
||||
return await getObject(
|
||||
className,
|
||||
objectId,
|
||||
keys,
|
||||
include,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(
|
||||
'find',
|
||||
{
|
||||
description:
|
||||
'The find query can be used to find objects of a certain class.',
|
||||
args: {
|
||||
className: defaultGraphQLTypes.CLASS_NAME_ATT,
|
||||
where: defaultGraphQLTypes.WHERE_ATT,
|
||||
order: {
|
||||
description:
|
||||
'This is the order in which the objects should be returned',
|
||||
type: GraphQLString,
|
||||
},
|
||||
skip: defaultGraphQLTypes.SKIP_ATT,
|
||||
limit: defaultGraphQLTypes.LIMIT_ATT,
|
||||
keys: defaultGraphQLTypes.KEYS_ATT,
|
||||
include: defaultGraphQLTypes.INCLUDE_ATT,
|
||||
includeAll: {
|
||||
description: 'All pointers will be returned',
|
||||
type: GraphQLBoolean,
|
||||
},
|
||||
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
|
||||
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
|
||||
subqueryReadPreference:
|
||||
defaultGraphQLTypes.SUBQUERY_READ_PREFERENCE_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.FIND_RESULT),
|
||||
async resolve(_source, args, context, queryInfo) {
|
||||
try {
|
||||
const {
|
||||
className,
|
||||
where,
|
||||
order,
|
||||
skip,
|
||||
limit,
|
||||
keys,
|
||||
include,
|
||||
includeAll,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
subqueryReadPreference,
|
||||
} = args;
|
||||
|
||||
const { config, auth, info } = context;
|
||||
const selectedFields = getFieldNames(queryInfo);
|
||||
|
||||
return await findObjects(
|
||||
className,
|
||||
where,
|
||||
order,
|
||||
skip,
|
||||
limit,
|
||||
keys,
|
||||
include,
|
||||
includeAll,
|
||||
readPreference,
|
||||
includeReadPreference,
|
||||
subqueryReadPreference,
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
selectedFields
|
||||
);
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
const objectsQuery = new GraphQLObjectType({
|
||||
name: 'ObjectsQuery',
|
||||
description: 'ObjectsQuery is the top level type for objects queries.',
|
||||
fields: parseGraphQLSchema.graphQLObjectsQueries,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(objectsQuery);
|
||||
parseGraphQLSchema.addGraphQLType(objectsQuery, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLQueries.objects = {
|
||||
description: 'This is the top level for objects queries.',
|
||||
|
||||
@@ -5,6 +5,7 @@ import { extractKeysAndInclude } from '../parseGraphQLUtils';
|
||||
import * as objectsMutations from './objectsMutations';
|
||||
import * as objectsQueries from './objectsQueries';
|
||||
import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController';
|
||||
import { transformClassNameToGraphQL } from '../transformers/className';
|
||||
|
||||
const getParseClassMutationConfig = function(
|
||||
parseClassConfig: ?ParseGraphQLClassConfig
|
||||
@@ -39,7 +40,9 @@ const load = function(
|
||||
parseClass,
|
||||
parseClassConfig: ?ParseGraphQLClassConfig
|
||||
) {
|
||||
const { className } = parseClass;
|
||||
const className = parseClass.className;
|
||||
const graphQLClassName = transformClassNameToGraphQL(className);
|
||||
|
||||
const {
|
||||
create: isCreateEnabled = true,
|
||||
update: isUpdateEnabled = true,
|
||||
@@ -52,37 +55,29 @@ const load = function(
|
||||
classGraphQLOutputType,
|
||||
} = parseGraphQLSchema.parseClassTypes[className];
|
||||
|
||||
const createFields = {
|
||||
description: 'These are the fields used to create the object.',
|
||||
type: classGraphQLCreateType,
|
||||
};
|
||||
const updateFields = {
|
||||
description: 'These are the fields used to update the object.',
|
||||
type: classGraphQLUpdateType,
|
||||
};
|
||||
|
||||
const classGraphQLCreateTypeFields = isCreateEnabled
|
||||
? classGraphQLCreateType.getFields()
|
||||
: null;
|
||||
const classGraphQLUpdateTypeFields = isUpdateEnabled
|
||||
? classGraphQLUpdateType.getFields()
|
||||
: null;
|
||||
|
||||
const transformTypes = (inputType: 'create' | 'update', fields) => {
|
||||
if (fields) {
|
||||
const classGraphQLCreateTypeFields =
|
||||
isCreateEnabled && classGraphQLCreateType
|
||||
? classGraphQLCreateType.getFields()
|
||||
: null;
|
||||
const classGraphQLUpdateTypeFields =
|
||||
isUpdateEnabled && classGraphQLUpdateType
|
||||
? classGraphQLUpdateType.getFields()
|
||||
: null;
|
||||
Object.keys(fields).forEach(field => {
|
||||
let inputTypeField;
|
||||
if (inputType === 'create') {
|
||||
if (inputType === 'create' && classGraphQLCreateTypeFields) {
|
||||
inputTypeField = classGraphQLCreateTypeFields[field];
|
||||
} else {
|
||||
} else if (classGraphQLUpdateTypeFields) {
|
||||
inputTypeField = classGraphQLUpdateTypeFields[field];
|
||||
}
|
||||
if (inputTypeField) {
|
||||
switch (inputTypeField.type) {
|
||||
case defaultGraphQLTypes.GEO_POINT:
|
||||
case defaultGraphQLTypes.GEO_POINT_INPUT:
|
||||
fields[field].__type = 'GeoPoint';
|
||||
break;
|
||||
case defaultGraphQLTypes.POLYGON:
|
||||
case defaultGraphQLTypes.POLYGON_INPUT:
|
||||
fields[field] = {
|
||||
__type: 'Polygon',
|
||||
coordinates: fields[field].map(geoPoint => [
|
||||
@@ -98,13 +93,18 @@ const load = function(
|
||||
};
|
||||
|
||||
if (isCreateEnabled) {
|
||||
const createGraphQLMutationName = `create${className}`;
|
||||
parseGraphQLSchema.graphQLObjectsMutations[createGraphQLMutationName] = {
|
||||
description: `The ${createGraphQLMutationName} mutation can be used to create a new object of the ${className} class.`,
|
||||
const createGraphQLMutationName = `create${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(createGraphQLMutationName, {
|
||||
description: `The ${createGraphQLMutationName} mutation can be used to create a new object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
fields: createFields,
|
||||
fields: {
|
||||
description: 'These are the fields used to create the object.',
|
||||
type: classGraphQLCreateType || defaultGraphQLTypes.OBJECT,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(classGraphQLOutputType),
|
||||
type: new GraphQLNonNull(
|
||||
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
||||
),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
let { fields } = args;
|
||||
@@ -150,18 +150,23 @@ const load = function(
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (isUpdateEnabled) {
|
||||
const updateGraphQLMutationName = `update${className}`;
|
||||
parseGraphQLSchema.graphQLObjectsMutations[updateGraphQLMutationName] = {
|
||||
description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${className} class.`,
|
||||
const updateGraphQLMutationName = `update${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(updateGraphQLMutationName, {
|
||||
description: `The ${updateGraphQLMutationName} mutation can be used to update an object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
fields: updateFields,
|
||||
fields: {
|
||||
description: 'These are the fields used to update the object.',
|
||||
type: classGraphQLUpdateType || defaultGraphQLTypes.OBJECT,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(classGraphQLOutputType),
|
||||
type: new GraphQLNonNull(
|
||||
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
||||
),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
const { objectId, fields } = args;
|
||||
@@ -205,17 +210,19 @@ const load = function(
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (isDestroyEnabled) {
|
||||
const deleteGraphQLMutationName = `delete${className}`;
|
||||
parseGraphQLSchema.graphQLObjectsMutations[deleteGraphQLMutationName] = {
|
||||
description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${className} class.`,
|
||||
const deleteGraphQLMutationName = `delete${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLObjectMutation(deleteGraphQLMutationName, {
|
||||
description: `The ${deleteGraphQLMutationName} mutation can be used to delete an object of the ${graphQLClassName} class.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(classGraphQLOutputType),
|
||||
type: new GraphQLNonNull(
|
||||
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
||||
),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
const { objectId } = args;
|
||||
@@ -250,7 +257,7 @@ const load = function(
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import getFieldNames from 'graphql-list-fields';
|
||||
import pluralize from 'pluralize';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import * as objectsQueries from './objectsQueries';
|
||||
import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController';
|
||||
import { transformClassNameToGraphQL } from '../transformers/className';
|
||||
import { extractKeysAndInclude } from '../parseGraphQLUtils';
|
||||
|
||||
const getParseClassQueryConfig = function(
|
||||
@@ -36,7 +38,8 @@ const load = function(
|
||||
parseClass,
|
||||
parseClassConfig: ?ParseGraphQLClassConfig
|
||||
) {
|
||||
const { className } = parseClass;
|
||||
const className = parseClass.className;
|
||||
const graphQLClassName = transformClassNameToGraphQL(className);
|
||||
const {
|
||||
get: isGetEnabled = true,
|
||||
find: isFindEnabled = true,
|
||||
@@ -49,15 +52,18 @@ const load = function(
|
||||
} = parseGraphQLSchema.parseClassTypes[className];
|
||||
|
||||
if (isGetEnabled) {
|
||||
const getGraphQLQueryName = `get${className}`;
|
||||
parseGraphQLSchema.graphQLObjectsQueries[getGraphQLQueryName] = {
|
||||
description: `The ${getGraphQLQueryName} query can be used to get an object of the ${className} class by its id.`,
|
||||
const getGraphQLQueryName =
|
||||
graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1);
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(getGraphQLQueryName, {
|
||||
description: `The ${getGraphQLQueryName} query can be used to get an object of the ${graphQLClassName} class by its id.`,
|
||||
args: {
|
||||
objectId: defaultGraphQLTypes.OBJECT_ID_ATT,
|
||||
readPreference: defaultGraphQLTypes.READ_PREFERENCE_ATT,
|
||||
includeReadPreference: defaultGraphQLTypes.INCLUDE_READ_PREFERENCE_ATT,
|
||||
},
|
||||
type: new GraphQLNonNull(classGraphQLOutputType),
|
||||
type: new GraphQLNonNull(
|
||||
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
||||
),
|
||||
async resolve(_source, args, context, queryInfo) {
|
||||
try {
|
||||
return await getQuery(className, _source, args, context, queryInfo);
|
||||
@@ -65,15 +71,19 @@ const load = function(
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
if (isFindEnabled) {
|
||||
const findGraphQLQueryName = `find${className}`;
|
||||
parseGraphQLSchema.graphQLObjectsQueries[findGraphQLQueryName] = {
|
||||
description: `The ${findGraphQLQueryName} query can be used to find objects of the ${className} class.`,
|
||||
const findGraphQLQueryName = pluralize(
|
||||
graphQLClassName.charAt(0).toLowerCase() + graphQLClassName.slice(1)
|
||||
);
|
||||
parseGraphQLSchema.addGraphQLObjectQuery(findGraphQLQueryName, {
|
||||
description: `The ${findGraphQLQueryName} query can be used to find objects of the ${graphQLClassName} class.`,
|
||||
args: classGraphQLFindArgs,
|
||||
type: new GraphQLNonNull(classGraphQLFindResultType),
|
||||
type: new GraphQLNonNull(
|
||||
classGraphQLFindResultType || defaultGraphQLTypes.FIND_RESULT
|
||||
),
|
||||
async resolve(_source, args, context, queryInfo) {
|
||||
try {
|
||||
const {
|
||||
@@ -116,7 +126,7 @@ const load = function(
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import getFieldNames from 'graphql-list-fields';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import * as objectsQueries from './objectsQueries';
|
||||
import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController';
|
||||
import { transformClassNameToGraphQL } from '../transformers/className';
|
||||
import { extractKeysAndInclude } from '../parseGraphQLUtils';
|
||||
|
||||
const mapInputType = (parseType, targetClass, parseClassTypes) => {
|
||||
@@ -31,13 +32,19 @@ const mapInputType = (parseType, targetClass, parseClassTypes) => {
|
||||
case 'Date':
|
||||
return defaultGraphQLTypes.DATE;
|
||||
case 'Pointer':
|
||||
if (parseClassTypes[targetClass]) {
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLScalarType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLScalarType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
}
|
||||
case 'Relation':
|
||||
if (parseClassTypes[targetClass]) {
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLRelationOpType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLRelationOpType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
@@ -45,9 +52,9 @@ const mapInputType = (parseType, targetClass, parseClassTypes) => {
|
||||
case 'File':
|
||||
return defaultGraphQLTypes.FILE;
|
||||
case 'GeoPoint':
|
||||
return defaultGraphQLTypes.GEO_POINT;
|
||||
return defaultGraphQLTypes.GEO_POINT_INPUT;
|
||||
case 'Polygon':
|
||||
return defaultGraphQLTypes.POLYGON;
|
||||
return defaultGraphQLTypes.POLYGON_INPUT;
|
||||
case 'Bytes':
|
||||
return defaultGraphQLTypes.BYTES;
|
||||
case 'ACL':
|
||||
@@ -72,13 +79,19 @@ const mapOutputType = (parseType, targetClass, parseClassTypes) => {
|
||||
case 'Date':
|
||||
return defaultGraphQLTypes.DATE;
|
||||
case 'Pointer':
|
||||
if (parseClassTypes[targetClass]) {
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLOutputType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLOutputType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
}
|
||||
case 'Relation':
|
||||
if (parseClassTypes[targetClass]) {
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLFindResultType
|
||||
) {
|
||||
return new GraphQLNonNull(
|
||||
parseClassTypes[targetClass].classGraphQLFindResultType
|
||||
);
|
||||
@@ -88,9 +101,9 @@ const mapOutputType = (parseType, targetClass, parseClassTypes) => {
|
||||
case 'File':
|
||||
return defaultGraphQLTypes.FILE_INFO;
|
||||
case 'GeoPoint':
|
||||
return defaultGraphQLTypes.GEO_POINT_INFO;
|
||||
return defaultGraphQLTypes.GEO_POINT;
|
||||
case 'Polygon':
|
||||
return defaultGraphQLTypes.POLYGON_INFO;
|
||||
return defaultGraphQLTypes.POLYGON;
|
||||
case 'Bytes':
|
||||
return defaultGraphQLTypes.BYTES;
|
||||
case 'ACL':
|
||||
@@ -103,33 +116,36 @@ const mapOutputType = (parseType, targetClass, parseClassTypes) => {
|
||||
const mapConstraintType = (parseType, targetClass, parseClassTypes) => {
|
||||
switch (parseType) {
|
||||
case 'String':
|
||||
return defaultGraphQLTypes.STRING_CONSTRAINT;
|
||||
return defaultGraphQLTypes.STRING_WHERE_INPUT;
|
||||
case 'Number':
|
||||
return defaultGraphQLTypes.NUMBER_CONSTRAINT;
|
||||
return defaultGraphQLTypes.NUMBER_WHERE_INPUT;
|
||||
case 'Boolean':
|
||||
return defaultGraphQLTypes.BOOLEAN_CONSTRAINT;
|
||||
return defaultGraphQLTypes.BOOLEAN_WHERE_INPUT;
|
||||
case 'Array':
|
||||
return defaultGraphQLTypes.ARRAY_CONSTRAINT;
|
||||
return defaultGraphQLTypes.ARRAY_WHERE_INPUT;
|
||||
case 'Object':
|
||||
return defaultGraphQLTypes.OBJECT_CONSTRAINT;
|
||||
return defaultGraphQLTypes.OBJECT_WHERE_INPUT;
|
||||
case 'Date':
|
||||
return defaultGraphQLTypes.DATE_CONSTRAINT;
|
||||
return defaultGraphQLTypes.DATE_WHERE_INPUT;
|
||||
case 'Pointer':
|
||||
if (parseClassTypes[targetClass]) {
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLConstraintType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLConstraintType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
}
|
||||
case 'File':
|
||||
return defaultGraphQLTypes.FILE_CONSTRAINT;
|
||||
return defaultGraphQLTypes.FILE_WHERE_INPUT;
|
||||
case 'GeoPoint':
|
||||
return defaultGraphQLTypes.GEO_POINT_CONSTRAINT;
|
||||
return defaultGraphQLTypes.GEO_POINT_WHERE_INPUT;
|
||||
case 'Polygon':
|
||||
return defaultGraphQLTypes.POLYGON_CONSTRAINT;
|
||||
return defaultGraphQLTypes.POLYGON_WHERE_INPUT;
|
||||
case 'Bytes':
|
||||
return defaultGraphQLTypes.BYTES_CONSTRAINT;
|
||||
return defaultGraphQLTypes.BYTES_WHERE_INPUT;
|
||||
case 'ACL':
|
||||
return defaultGraphQLTypes.OBJECT_CONSTRAINT;
|
||||
return defaultGraphQLTypes.OBJECT_WHERE_INPUT;
|
||||
case 'Relation':
|
||||
default:
|
||||
return undefined;
|
||||
@@ -233,7 +249,8 @@ const load = (
|
||||
parseClass,
|
||||
parseClassConfig: ?ParseGraphQLClassConfig
|
||||
) => {
|
||||
const { className } = parseClass;
|
||||
const className = parseClass.className;
|
||||
const graphQLClassName = transformClassNameToGraphQL(className);
|
||||
const {
|
||||
classCreateFields,
|
||||
classUpdateFields,
|
||||
@@ -242,12 +259,12 @@ const load = (
|
||||
classSortFields,
|
||||
} = getInputFieldsAndConstraints(parseClass, parseClassConfig);
|
||||
|
||||
const classGraphQLScalarTypeName = `${className}Pointer`;
|
||||
const classGraphQLScalarTypeName = `${graphQLClassName}Pointer`;
|
||||
const parseScalarValue = value => {
|
||||
if (typeof value === 'string') {
|
||||
return {
|
||||
__type: 'Pointer',
|
||||
className,
|
||||
className: className,
|
||||
objectId: value,
|
||||
};
|
||||
} else if (
|
||||
@@ -256,7 +273,7 @@ const load = (
|
||||
value.className === className &&
|
||||
typeof value.objectId === 'string'
|
||||
) {
|
||||
return value;
|
||||
return { ...value, className };
|
||||
}
|
||||
|
||||
throw new defaultGraphQLTypes.TypeValidationError(
|
||||
@@ -264,9 +281,9 @@ const load = (
|
||||
classGraphQLScalarTypeName
|
||||
);
|
||||
};
|
||||
const classGraphQLScalarType = new GraphQLScalarType({
|
||||
let classGraphQLScalarType = new GraphQLScalarType({
|
||||
name: classGraphQLScalarTypeName,
|
||||
description: `The ${classGraphQLScalarTypeName} is used in operations that involve ${className} pointers.`,
|
||||
description: `The ${classGraphQLScalarTypeName} is used in operations that involve ${graphQLClassName} pointers.`,
|
||||
parseValue: parseScalarValue,
|
||||
serialize(value) {
|
||||
if (typeof value === 'string') {
|
||||
@@ -318,12 +335,14 @@ const load = (
|
||||
);
|
||||
},
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLScalarType);
|
||||
classGraphQLScalarType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLScalarType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLRelationOpTypeName = `${className}RelationOp`;
|
||||
const classGraphQLRelationOpType = new GraphQLInputObjectType({
|
||||
const classGraphQLRelationOpTypeName = `${graphQLClassName}RelationOpInput`;
|
||||
let classGraphQLRelationOpType = new GraphQLInputObjectType({
|
||||
name: classGraphQLRelationOpTypeName,
|
||||
description: `The ${classGraphQLRelationOpTypeName} input type is used in operations that involve relations with the ${className} class.`,
|
||||
description: `The ${classGraphQLRelationOpTypeName} type is used in operations that involve relations with the ${graphQLClassName} class.`,
|
||||
fields: () => ({
|
||||
_op: {
|
||||
description: 'This is the operation to be executed.',
|
||||
@@ -341,12 +360,14 @@ const load = (
|
||||
},
|
||||
}),
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLRelationOpType);
|
||||
classGraphQLRelationOpType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLRelationOpType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLCreateTypeName = `${className}CreateFields`;
|
||||
const classGraphQLCreateType = new GraphQLInputObjectType({
|
||||
const classGraphQLCreateTypeName = `Create${graphQLClassName}FieldsInput`;
|
||||
let classGraphQLCreateType = new GraphQLInputObjectType({
|
||||
name: classGraphQLCreateTypeName,
|
||||
description: `The ${classGraphQLCreateTypeName} input type is used in operations that involve creation of objects in the ${className} class.`,
|
||||
description: `The ${classGraphQLCreateTypeName} input type is used in operations that involve creation of objects in the ${graphQLClassName} class.`,
|
||||
fields: () =>
|
||||
classCreateFields.reduce(
|
||||
(fields, field) => {
|
||||
@@ -372,12 +393,14 @@ const load = (
|
||||
}
|
||||
),
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLCreateType);
|
||||
classGraphQLCreateType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLCreateType
|
||||
);
|
||||
|
||||
const classGraphQLUpdateTypeName = `${className}UpdateFields`;
|
||||
const classGraphQLUpdateType = new GraphQLInputObjectType({
|
||||
const classGraphQLUpdateTypeName = `Update${graphQLClassName}FieldsInput`;
|
||||
let classGraphQLUpdateType = new GraphQLInputObjectType({
|
||||
name: classGraphQLUpdateTypeName,
|
||||
description: `The ${classGraphQLUpdateTypeName} input type is used in operations that involve creation of objects in the ${className} class.`,
|
||||
description: `The ${classGraphQLUpdateTypeName} input type is used in operations that involve creation of objects in the ${graphQLClassName} class.`,
|
||||
fields: () =>
|
||||
classUpdateFields.reduce(
|
||||
(fields, field) => {
|
||||
@@ -403,12 +426,14 @@ const load = (
|
||||
}
|
||||
),
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLUpdateType);
|
||||
classGraphQLUpdateType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLUpdateType
|
||||
);
|
||||
|
||||
const classGraphQLConstraintTypeName = `${className}PointerConstraint`;
|
||||
const classGraphQLConstraintType = new GraphQLInputObjectType({
|
||||
const classGraphQLConstraintTypeName = `${graphQLClassName}PointerWhereInput`;
|
||||
let classGraphQLConstraintType = new GraphQLInputObjectType({
|
||||
name: classGraphQLConstraintTypeName,
|
||||
description: `The ${classGraphQLConstraintTypeName} input type is used in operations that involve filtering objects by a pointer field to ${className} class.`,
|
||||
description: `The ${classGraphQLConstraintTypeName} input type is used in operations that involve filtering objects by a pointer field to ${graphQLClassName} class.`,
|
||||
fields: {
|
||||
_eq: defaultGraphQLTypes._eq(classGraphQLScalarType),
|
||||
_ne: defaultGraphQLTypes._ne(classGraphQLScalarType),
|
||||
@@ -420,21 +445,23 @@ const load = (
|
||||
_inQuery: {
|
||||
description:
|
||||
'This is the $inQuery operator to specify a constraint to select the objects where a field equals to any of the ids in the result of a different query.',
|
||||
type: defaultGraphQLTypes.SUBQUERY,
|
||||
type: defaultGraphQLTypes.SUBQUERY_INPUT,
|
||||
},
|
||||
_notInQuery: {
|
||||
description:
|
||||
'This is the $notInQuery operator to specify a constraint to select the objects where a field do not equal to any of the ids in the result of a different query.',
|
||||
type: defaultGraphQLTypes.SUBQUERY,
|
||||
type: defaultGraphQLTypes.SUBQUERY_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLConstraintType);
|
||||
classGraphQLConstraintType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLConstraintType
|
||||
);
|
||||
|
||||
const classGraphQLConstraintsTypeName = `${className}Constraints`;
|
||||
const classGraphQLConstraintsType = new GraphQLInputObjectType({
|
||||
const classGraphQLConstraintsTypeName = `${graphQLClassName}WhereInput`;
|
||||
let classGraphQLConstraintsType = new GraphQLInputObjectType({
|
||||
name: classGraphQLConstraintsTypeName,
|
||||
description: `The ${classGraphQLConstraintsTypeName} input type is used in operations that involve filtering objects of ${className} class.`,
|
||||
description: `The ${classGraphQLConstraintsTypeName} input type is used in operations that involve filtering objects of ${graphQLClassName} class.`,
|
||||
fields: () => ({
|
||||
...classConstraintFields.reduce((fields, field) => {
|
||||
const type = mapConstraintType(
|
||||
@@ -468,12 +495,14 @@ const load = (
|
||||
},
|
||||
}),
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLConstraintsType);
|
||||
classGraphQLConstraintsType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLConstraintsType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLOrderTypeName = `${className}Order`;
|
||||
const classGraphQLOrderType = new GraphQLEnumType({
|
||||
const classGraphQLOrderTypeName = `${graphQLClassName}Order`;
|
||||
let classGraphQLOrderType = new GraphQLEnumType({
|
||||
name: classGraphQLOrderTypeName,
|
||||
description: `The ${classGraphQLOrderTypeName} input type is used when sorting objects of the ${className} class.`,
|
||||
description: `The ${classGraphQLOrderTypeName} input type is used when sorting objects of the ${graphQLClassName} class.`,
|
||||
values: classSortFields.reduce((sortFields, fieldConfig) => {
|
||||
const { field, asc, desc } = fieldConfig;
|
||||
const updatedSortFields = {
|
||||
@@ -488,7 +517,9 @@ const load = (
|
||||
return updatedSortFields;
|
||||
}, {}),
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLOrderType);
|
||||
classGraphQLOrderType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLOrderType
|
||||
);
|
||||
|
||||
const classGraphQLFindArgs = {
|
||||
where: {
|
||||
@@ -498,7 +529,9 @@ const load = (
|
||||
},
|
||||
order: {
|
||||
description: 'The fields to be used when sorting the data fetched.',
|
||||
type: new GraphQLList(new GraphQLNonNull(classGraphQLOrderType)),
|
||||
type: classGraphQLOrderType
|
||||
? new GraphQLList(new GraphQLNonNull(classGraphQLOrderType))
|
||||
: GraphQLString,
|
||||
},
|
||||
skip: defaultGraphQLTypes.SKIP_ATT,
|
||||
limit: defaultGraphQLTypes.LIMIT_ATT,
|
||||
@@ -507,7 +540,7 @@ const load = (
|
||||
subqueryReadPreference: defaultGraphQLTypes.SUBQUERY_READ_PREFERENCE_ATT,
|
||||
};
|
||||
|
||||
const classGraphQLOutputTypeName = `${className}Class`;
|
||||
const classGraphQLOutputTypeName = `${graphQLClassName}`;
|
||||
const outputFields = () => {
|
||||
return classOutputFields.reduce((fields, field) => {
|
||||
const type = mapOutputType(
|
||||
@@ -548,14 +581,13 @@ const load = (
|
||||
.filter(field => field.includes('.'))
|
||||
.map(field => field.slice(field.indexOf('.') + 1))
|
||||
);
|
||||
|
||||
return await objectsQueries.findObjects(
|
||||
source[field].className,
|
||||
{
|
||||
_relatedTo: {
|
||||
object: {
|
||||
__type: 'Pointer',
|
||||
className,
|
||||
className: className,
|
||||
objectId: source.objectId,
|
||||
},
|
||||
key: field,
|
||||
@@ -634,29 +666,37 @@ const load = (
|
||||
}
|
||||
}, defaultGraphQLTypes.CLASS_FIELDS);
|
||||
};
|
||||
const classGraphQLOutputType = new GraphQLObjectType({
|
||||
let classGraphQLOutputType = new GraphQLObjectType({
|
||||
name: classGraphQLOutputTypeName,
|
||||
description: `The ${classGraphQLOutputTypeName} object type is used in operations that involve outputting objects of ${className} class.`,
|
||||
description: `The ${classGraphQLOutputTypeName} object type is used in operations that involve outputting objects of ${graphQLClassName} class.`,
|
||||
interfaces: [defaultGraphQLTypes.CLASS],
|
||||
fields: outputFields,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLOutputType);
|
||||
classGraphQLOutputType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLOutputType
|
||||
);
|
||||
|
||||
const classGraphQLFindResultTypeName = `${className}FindResult`;
|
||||
const classGraphQLFindResultType = new GraphQLObjectType({
|
||||
const classGraphQLFindResultTypeName = `${graphQLClassName}FindResult`;
|
||||
let classGraphQLFindResultType = new GraphQLObjectType({
|
||||
name: classGraphQLFindResultTypeName,
|
||||
description: `The ${classGraphQLFindResultTypeName} object type is used in the ${className} find query to return the data of the matched objects.`,
|
||||
description: `The ${classGraphQLFindResultTypeName} object type is used in the ${graphQLClassName} find query to return the data of the matched objects.`,
|
||||
fields: {
|
||||
results: {
|
||||
description: 'This is the objects returned by the query',
|
||||
type: new GraphQLNonNull(
|
||||
new GraphQLList(new GraphQLNonNull(classGraphQLOutputType))
|
||||
new GraphQLList(
|
||||
new GraphQLNonNull(
|
||||
classGraphQLOutputType || defaultGraphQLTypes.OBJECT
|
||||
)
|
||||
)
|
||||
),
|
||||
},
|
||||
count: defaultGraphQLTypes.COUNT_ATT,
|
||||
},
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(classGraphQLFindResultType);
|
||||
classGraphQLFindResultType = parseGraphQLSchema.addGraphQLType(
|
||||
classGraphQLFindResultType
|
||||
);
|
||||
|
||||
parseGraphQLSchema.parseClassTypes[className] = {
|
||||
classGraphQLScalarType,
|
||||
@@ -671,22 +711,22 @@ const load = (
|
||||
};
|
||||
|
||||
if (className === '_User') {
|
||||
const meType = new GraphQLObjectType({
|
||||
name: 'Me',
|
||||
description: `The Me object type is used in operations that involve outputting the current user data.`,
|
||||
const viewerType = new GraphQLObjectType({
|
||||
name: 'Viewer',
|
||||
description: `The Viewer object type is used in operations that involve outputting the current user data.`,
|
||||
interfaces: [defaultGraphQLTypes.CLASS],
|
||||
fields: () => ({
|
||||
...outputFields(),
|
||||
sessionToken: defaultGraphQLTypes.SESSION_TOKEN_ATT,
|
||||
}),
|
||||
});
|
||||
parseGraphQLSchema.meType = meType;
|
||||
parseGraphQLSchema.graphQLTypes.push(meType);
|
||||
parseGraphQLSchema.viewerType = viewerType;
|
||||
parseGraphQLSchema.addGraphQLType(viewerType, true, true);
|
||||
|
||||
const userSignUpInputTypeName = '_UserSignUpFields';
|
||||
const userSignUpInputTypeName = 'SignUpFieldsInput';
|
||||
const userSignUpInputType = new GraphQLInputObjectType({
|
||||
name: userSignUpInputTypeName,
|
||||
description: `The ${userSignUpInputTypeName} input type is used in operations that involve inputting objects of ${className} class when signing up.`,
|
||||
description: `The ${userSignUpInputTypeName} input type is used in operations that involve inputting objects of ${graphQLClassName} class when signing up.`,
|
||||
fields: () =>
|
||||
classCreateFields.reduce((fields, field) => {
|
||||
const type = mapInputType(
|
||||
@@ -710,8 +750,9 @@ const load = (
|
||||
}
|
||||
}, {}),
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(userSignUpInputType, true, true);
|
||||
|
||||
const userLogInInputTypeName = '_UserLoginFields';
|
||||
const userLogInInputTypeName = 'LogInFieldsInput';
|
||||
const userLogInInputType = new GraphQLInputObjectType({
|
||||
name: userLogInInputTypeName,
|
||||
description: `The ${userLogInInputTypeName} input type is used to login.`,
|
||||
@@ -726,13 +767,14 @@ const load = (
|
||||
},
|
||||
},
|
||||
});
|
||||
parseGraphQLSchema.addGraphQLType(userLogInInputType, true, true);
|
||||
|
||||
parseGraphQLSchema.parseClassTypes[
|
||||
'_User'
|
||||
className
|
||||
].signUpInputType = userSignUpInputType;
|
||||
parseGraphQLSchema.parseClassTypes[
|
||||
'_User'
|
||||
className
|
||||
].logInInputType = userLogInInputType;
|
||||
parseGraphQLSchema.graphQLTypes.push(userSignUpInputType);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
import UsersRouter from '../../Routers/UsersRouter';
|
||||
import * as objectsMutations from './objectsMutations';
|
||||
import { getUserFromSessionToken } from './usersQueries';
|
||||
@@ -19,10 +19,11 @@ const load = parseGraphQLSchema => {
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].signUpInputType,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.meType),
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context, mutationInfo) {
|
||||
try {
|
||||
const { fields } = args;
|
||||
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const { sessionToken } = await objectsMutations.createObject(
|
||||
@@ -45,16 +46,16 @@ const load = parseGraphQLSchema => {
|
||||
fields.logIn = {
|
||||
description: 'The logIn mutation can be used to log the user in.',
|
||||
args: {
|
||||
input: {
|
||||
fields: {
|
||||
description: 'This is data needed to login',
|
||||
type: parseGraphQLSchema.parseClassTypes['_User'].logInInputType,
|
||||
},
|
||||
},
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.meType),
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, args, context) {
|
||||
try {
|
||||
const {
|
||||
input: { username, password },
|
||||
fields: { username, password },
|
||||
} = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
@@ -76,17 +77,24 @@ const load = parseGraphQLSchema => {
|
||||
|
||||
fields.logOut = {
|
||||
description: 'The logOut mutation can be used to log the user out.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
async resolve(_source, _args, context) {
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, mutationInfo) {
|
||||
try {
|
||||
const { config, auth, info } = context;
|
||||
|
||||
const viewer = await getUserFromSessionToken(
|
||||
config,
|
||||
info,
|
||||
mutationInfo
|
||||
);
|
||||
|
||||
await usersRouter.handleLogOut({
|
||||
config,
|
||||
auth,
|
||||
info,
|
||||
});
|
||||
return true;
|
||||
|
||||
return viewer;
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
@@ -98,7 +106,7 @@ const load = parseGraphQLSchema => {
|
||||
description: 'UsersMutation is the top level type for files mutations.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(usersMutation);
|
||||
parseGraphQLSchema.addGraphQLType(usersMutation, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLMutations.users = {
|
||||
description: 'This is the top level for users mutations.',
|
||||
|
||||
@@ -51,9 +51,10 @@ const load = parseGraphQLSchema => {
|
||||
}
|
||||
const fields = {};
|
||||
|
||||
fields.me = {
|
||||
description: 'The Me query can be used to return the current user data.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.meType),
|
||||
fields.viewer = {
|
||||
description:
|
||||
'The viewer query can be used to return the current user data.',
|
||||
type: new GraphQLNonNull(parseGraphQLSchema.viewerType),
|
||||
async resolve(_source, _args, context, queryInfo) {
|
||||
try {
|
||||
const { config, info } = context;
|
||||
@@ -69,7 +70,7 @@ const load = parseGraphQLSchema => {
|
||||
description: 'UsersQuery is the top level type for users queries.',
|
||||
fields,
|
||||
});
|
||||
parseGraphQLSchema.graphQLTypes.push(usersQuery);
|
||||
parseGraphQLSchema.addGraphQLType(usersQuery, true, true);
|
||||
|
||||
parseGraphQLSchema.graphQLQueries.users = {
|
||||
description: 'This is the top level for users queries.',
|
||||
|
||||
8
src/GraphQL/transformers/className.js
Normal file
8
src/GraphQL/transformers/className.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const transformClassNameToGraphQL = className => {
|
||||
if (className[0] === '_') {
|
||||
className = className.slice(1);
|
||||
}
|
||||
return className[0].toUpperCase() + className.slice(1);
|
||||
};
|
||||
|
||||
export { transformClassNameToGraphQL };
|
||||
21
src/GraphQL/transformers/mutation.js
Normal file
21
src/GraphQL/transformers/mutation.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const parseMap = {
|
||||
_op: '__op',
|
||||
};
|
||||
|
||||
const transformMutationInputToParse = fields => {
|
||||
if (!fields || typeof fields !== 'object') {
|
||||
return;
|
||||
}
|
||||
Object.keys(fields).forEach(fieldName => {
|
||||
const fieldValue = fields[fieldName];
|
||||
if (parseMap[fieldName]) {
|
||||
delete fields[fieldName];
|
||||
fields[parseMap[fieldName]] = fieldValue;
|
||||
}
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformMutationInputToParse(fieldValue);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export { transformMutationInputToParse };
|
||||
154
src/GraphQL/transformers/query.js
Normal file
154
src/GraphQL/transformers/query.js
Normal file
@@ -0,0 +1,154 @@
|
||||
const parseMap = {
|
||||
_or: '$or',
|
||||
_and: '$and',
|
||||
_nor: '$nor',
|
||||
_relatedTo: '$relatedTo',
|
||||
_eq: '$eq',
|
||||
_ne: '$ne',
|
||||
_lt: '$lt',
|
||||
_lte: '$lte',
|
||||
_gt: '$gt',
|
||||
_gte: '$gte',
|
||||
_in: '$in',
|
||||
_nin: '$nin',
|
||||
_exists: '$exists',
|
||||
_select: '$select',
|
||||
_dontSelect: '$dontSelect',
|
||||
_inQuery: '$inQuery',
|
||||
_notInQuery: '$notInQuery',
|
||||
_containedBy: '$containedBy',
|
||||
_all: '$all',
|
||||
_regex: '$regex',
|
||||
_options: '$options',
|
||||
_text: '$text',
|
||||
_search: '$search',
|
||||
_term: '$term',
|
||||
_language: '$language',
|
||||
_caseSensitive: '$caseSensitive',
|
||||
_diacriticSensitive: '$diacriticSensitive',
|
||||
_nearSphere: '$nearSphere',
|
||||
_maxDistance: '$maxDistance',
|
||||
_maxDistanceInRadians: '$maxDistanceInRadians',
|
||||
_maxDistanceInMiles: '$maxDistanceInMiles',
|
||||
_maxDistanceInKilometers: '$maxDistanceInKilometers',
|
||||
_within: '$within',
|
||||
_box: '$box',
|
||||
_geoWithin: '$geoWithin',
|
||||
_polygon: '$polygon',
|
||||
_centerSphere: '$centerSphere',
|
||||
_geoIntersects: '$geoIntersects',
|
||||
_point: '$point',
|
||||
};
|
||||
|
||||
const transformQueryInputToParse = (
|
||||
constraints,
|
||||
parentFieldName,
|
||||
parentConstraints
|
||||
) => {
|
||||
if (!constraints || typeof constraints !== 'object') {
|
||||
return;
|
||||
}
|
||||
Object.keys(constraints).forEach(fieldName => {
|
||||
let fieldValue = constraints[fieldName];
|
||||
|
||||
/**
|
||||
* If we have a key-value pair, we need to change the way the constraint is structured.
|
||||
*
|
||||
* Example:
|
||||
* From:
|
||||
* {
|
||||
* "someField": {
|
||||
* "_lt": {
|
||||
* "_key":"foo.bar",
|
||||
* "_value": 100
|
||||
* },
|
||||
* "_gt": {
|
||||
* "_key":"foo.bar",
|
||||
* "_value": 10
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* To:
|
||||
* {
|
||||
* "someField.foo.bar": {
|
||||
* "$lt": 100,
|
||||
* "$gt": 10
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
if (
|
||||
fieldValue._key &&
|
||||
fieldValue._value &&
|
||||
parentConstraints &&
|
||||
parentFieldName
|
||||
) {
|
||||
delete parentConstraints[parentFieldName];
|
||||
parentConstraints[`${parentFieldName}.${fieldValue._key}`] = {
|
||||
...parentConstraints[`${parentFieldName}.${fieldValue._key}`],
|
||||
[parseMap[fieldName]]: fieldValue._value,
|
||||
};
|
||||
} else if (parseMap[fieldName]) {
|
||||
delete constraints[fieldName];
|
||||
fieldName = parseMap[fieldName];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
switch (fieldName) {
|
||||
case '$point':
|
||||
case '$nearSphere':
|
||||
if (typeof fieldValue === 'object' && !fieldValue.__type) {
|
||||
fieldValue.__type = 'GeoPoint';
|
||||
}
|
||||
break;
|
||||
case '$box':
|
||||
if (
|
||||
typeof fieldValue === 'object' &&
|
||||
fieldValue.bottomLeft &&
|
||||
fieldValue.upperRight
|
||||
) {
|
||||
fieldValue = [
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.bottomLeft,
|
||||
},
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.upperRight,
|
||||
},
|
||||
];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
break;
|
||||
case '$polygon':
|
||||
if (fieldValue instanceof Array) {
|
||||
fieldValue.forEach(geoPoint => {
|
||||
if (typeof geoPoint === 'object' && !geoPoint.__type) {
|
||||
geoPoint.__type = 'GeoPoint';
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case '$centerSphere':
|
||||
if (
|
||||
typeof fieldValue === 'object' &&
|
||||
fieldValue.center &&
|
||||
fieldValue.distance
|
||||
) {
|
||||
fieldValue = [
|
||||
{
|
||||
__type: 'GeoPoint',
|
||||
...fieldValue.center,
|
||||
},
|
||||
fieldValue.distance,
|
||||
];
|
||||
constraints[fieldName] = fieldValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformQueryInputToParse(fieldValue, fieldName, constraints);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export { transformQueryInputToParse };
|
||||
Reference in New Issue
Block a user