* add parse-graph-ql configuration for class schema customisation Not yet tested - essentially an RFC * refactor and add graphql router, controller and config cache * fix(GraphQLController): add missing check isEnabled * chore(GraphQLController): remove awaits from cache put * chore(GraphQLController): remove check for if its enabled * refactor(GraphQLController): only use cache if mounted * chore(GraphQLController): group all validation errors and throw at once * chore(GraphQLSchema): move transformations into controller validation * refactor(GraphQL): improve ctrl validation and fix schema usage of config * refactor(GraphQLSchema): remove code related to additional schema This code has been moved into a separate feature branch. * fix(GraphQLSchema): fix incorrect default return type for class configs * refactor(GraphQLSchema): update staleness check code to account for config * fix(GraphQLServer): fix regressed tests due to internal schema changes This will be followed up with a backwards compatability fix for the `ClassFields` issue to avoid breakages for our users * refactor: rename to ParseGraphQLController for consistency * fix(ParseGraphQLCtrl): numerous fixes for validity checking Also includes some minor code refactoring * chore(GraphQL): minor syntax cleanup * fix(SchemaController): add _GraphQLConfig to volatile classes * refactor(ParseGraphQLServer): return update config value in setGraphQLConfig * testing(ParseGraphQL): add test cases for new graphQLConfig * fix(GraphQLController): fix issue where config with multiple items was not being mapped to the db * fix(postgres): add _GraphQLConfig default schema on load fixes failing postgres tests * GraphQL @mock directive (#5836) * Add mock directive * Include tests for @mock directive * Fix existing tests due to the change from ClassFields to ClassCreateFields * fix(parseClassMutations): safer type transformation based on input type * fix(parseClassMutations): only define necessary input fields * fix(GraphQL): fix incorrect import paths
281 lines
8.2 KiB
JavaScript
281 lines
8.2 KiB
JavaScript
import authDataManager from '../Adapters/Auth';
|
|
import { ParseServerOptions } from '../Options';
|
|
import { loadAdapter } from '../Adapters/AdapterLoader';
|
|
import defaults from '../defaults';
|
|
import url from 'url';
|
|
// Controllers
|
|
import { LoggerController } from './LoggerController';
|
|
import { FilesController } from './FilesController';
|
|
import { HooksController } from './HooksController';
|
|
import { UserController } from './UserController';
|
|
import { CacheController } from './CacheController';
|
|
import { LiveQueryController } from './LiveQueryController';
|
|
import { AnalyticsController } from './AnalyticsController';
|
|
import { PushController } from './PushController';
|
|
import { PushQueue } from '../Push/PushQueue';
|
|
import { PushWorker } from '../Push/PushWorker';
|
|
import DatabaseController from './DatabaseController';
|
|
import SchemaCache from './SchemaCache';
|
|
|
|
// Adapters
|
|
import { GridFSBucketAdapter } from '../Adapters/Files/GridFSBucketAdapter';
|
|
import { WinstonLoggerAdapter } from '../Adapters/Logger/WinstonLoggerAdapter';
|
|
import { InMemoryCacheAdapter } from '../Adapters/Cache/InMemoryCacheAdapter';
|
|
import { AnalyticsAdapter } from '../Adapters/Analytics/AnalyticsAdapter';
|
|
import MongoStorageAdapter from '../Adapters/Storage/Mongo/MongoStorageAdapter';
|
|
import PostgresStorageAdapter from '../Adapters/Storage/Postgres/PostgresStorageAdapter';
|
|
import ParsePushAdapter from '@parse/push-adapter';
|
|
import ParseGraphQLController from './ParseGraphQLController';
|
|
|
|
export function getControllers(options: ParseServerOptions) {
|
|
const loggerController = getLoggerController(options);
|
|
const filesController = getFilesController(options);
|
|
const userController = getUserController(options);
|
|
const {
|
|
pushController,
|
|
hasPushScheduledSupport,
|
|
hasPushSupport,
|
|
pushControllerQueue,
|
|
pushWorker,
|
|
} = getPushController(options);
|
|
const cacheController = getCacheController(options);
|
|
const analyticsController = getAnalyticsController(options);
|
|
const liveQueryController = getLiveQueryController(options);
|
|
const databaseController = getDatabaseController(options, cacheController);
|
|
const hooksController = getHooksController(options, databaseController);
|
|
const authDataManager = getAuthDataManager(options);
|
|
const parseGraphQLController = getParseGraphQLController(options, {
|
|
databaseController,
|
|
cacheController,
|
|
});
|
|
return {
|
|
loggerController,
|
|
filesController,
|
|
userController,
|
|
pushController,
|
|
hasPushScheduledSupport,
|
|
hasPushSupport,
|
|
pushWorker,
|
|
pushControllerQueue,
|
|
analyticsController,
|
|
cacheController,
|
|
parseGraphQLController,
|
|
liveQueryController,
|
|
databaseController,
|
|
hooksController,
|
|
authDataManager,
|
|
};
|
|
}
|
|
|
|
export function getLoggerController(
|
|
options: ParseServerOptions
|
|
): LoggerController {
|
|
const {
|
|
appId,
|
|
jsonLogs,
|
|
logsFolder,
|
|
verbose,
|
|
logLevel,
|
|
silent,
|
|
loggerAdapter,
|
|
} = options;
|
|
const loggerOptions = { jsonLogs, logsFolder, verbose, logLevel, silent };
|
|
const loggerControllerAdapter = loadAdapter(
|
|
loggerAdapter,
|
|
WinstonLoggerAdapter,
|
|
loggerOptions
|
|
);
|
|
return new LoggerController(loggerControllerAdapter, appId, loggerOptions);
|
|
}
|
|
|
|
export function getFilesController(
|
|
options: ParseServerOptions
|
|
): FilesController {
|
|
const {
|
|
appId,
|
|
databaseURI,
|
|
filesAdapter,
|
|
databaseAdapter,
|
|
preserveFileName,
|
|
} = options;
|
|
if (!filesAdapter && databaseAdapter) {
|
|
throw 'When using an explicit database adapter, you must also use an explicit filesAdapter.';
|
|
}
|
|
const filesControllerAdapter = loadAdapter(filesAdapter, () => {
|
|
return new GridFSBucketAdapter(databaseURI);
|
|
});
|
|
return new FilesController(filesControllerAdapter, appId, {
|
|
preserveFileName,
|
|
});
|
|
}
|
|
|
|
export function getUserController(options: ParseServerOptions): UserController {
|
|
const { appId, emailAdapter, verifyUserEmails } = options;
|
|
const emailControllerAdapter = loadAdapter(emailAdapter);
|
|
return new UserController(emailControllerAdapter, appId, {
|
|
verifyUserEmails,
|
|
});
|
|
}
|
|
|
|
export function getCacheController(
|
|
options: ParseServerOptions
|
|
): CacheController {
|
|
const { appId, cacheAdapter, cacheTTL, cacheMaxSize } = options;
|
|
const cacheControllerAdapter = loadAdapter(
|
|
cacheAdapter,
|
|
InMemoryCacheAdapter,
|
|
{ appId: appId, ttl: cacheTTL, maxSize: cacheMaxSize }
|
|
);
|
|
return new CacheController(cacheControllerAdapter, appId);
|
|
}
|
|
|
|
export function getParseGraphQLController(
|
|
options: ParseServerOptions,
|
|
controllerDeps
|
|
): ParseGraphQLController {
|
|
return new ParseGraphQLController({
|
|
mountGraphQL: options.mountGraphQL,
|
|
...controllerDeps,
|
|
});
|
|
}
|
|
|
|
export function getAnalyticsController(
|
|
options: ParseServerOptions
|
|
): AnalyticsController {
|
|
const { analyticsAdapter } = options;
|
|
const analyticsControllerAdapter = loadAdapter(
|
|
analyticsAdapter,
|
|
AnalyticsAdapter
|
|
);
|
|
return new AnalyticsController(analyticsControllerAdapter);
|
|
}
|
|
|
|
export function getLiveQueryController(
|
|
options: ParseServerOptions
|
|
): LiveQueryController {
|
|
return new LiveQueryController(options.liveQuery);
|
|
}
|
|
|
|
export function getDatabaseController(
|
|
options: ParseServerOptions,
|
|
cacheController: CacheController
|
|
): DatabaseController {
|
|
const {
|
|
databaseURI,
|
|
databaseOptions,
|
|
skipMongoDBServer13732Workaround,
|
|
collectionPrefix,
|
|
schemaCacheTTL,
|
|
enableSingleSchemaCache,
|
|
} = options;
|
|
let { databaseAdapter } = options;
|
|
if (
|
|
(databaseOptions ||
|
|
(databaseURI && databaseURI !== defaults.databaseURI) ||
|
|
collectionPrefix !== defaults.collectionPrefix) &&
|
|
databaseAdapter
|
|
) {
|
|
throw 'You cannot specify both a databaseAdapter and a databaseURI/databaseOptions/collectionPrefix.';
|
|
} else if (!databaseAdapter) {
|
|
databaseAdapter = getDatabaseAdapter(
|
|
databaseURI,
|
|
collectionPrefix,
|
|
databaseOptions
|
|
);
|
|
} else {
|
|
databaseAdapter = loadAdapter(databaseAdapter);
|
|
}
|
|
return new DatabaseController(
|
|
databaseAdapter,
|
|
new SchemaCache(cacheController, schemaCacheTTL, enableSingleSchemaCache),
|
|
skipMongoDBServer13732Workaround
|
|
);
|
|
}
|
|
|
|
export function getHooksController(
|
|
options: ParseServerOptions,
|
|
databaseController: DatabaseController
|
|
): HooksController {
|
|
const { appId, webhookKey } = options;
|
|
return new HooksController(appId, databaseController, webhookKey);
|
|
}
|
|
|
|
interface PushControlling {
|
|
pushController: PushController;
|
|
hasPushScheduledSupport: boolean;
|
|
pushControllerQueue: PushQueue;
|
|
pushWorker: PushWorker;
|
|
}
|
|
|
|
export function getPushController(
|
|
options: ParseServerOptions
|
|
): PushControlling {
|
|
const { scheduledPush, push } = options;
|
|
|
|
const pushOptions = Object.assign({}, push);
|
|
const pushQueueOptions = pushOptions.queueOptions || {};
|
|
if (pushOptions.queueOptions) {
|
|
delete pushOptions.queueOptions;
|
|
}
|
|
|
|
// Pass the push options too as it works with the default
|
|
const pushAdapter = loadAdapter(
|
|
pushOptions && pushOptions.adapter,
|
|
ParsePushAdapter,
|
|
pushOptions
|
|
);
|
|
// We pass the options and the base class for the adatper,
|
|
// Note that passing an instance would work too
|
|
const pushController = new PushController();
|
|
const hasPushSupport = !!(pushAdapter && push);
|
|
const hasPushScheduledSupport = hasPushSupport && scheduledPush === true;
|
|
|
|
const { disablePushWorker } = pushQueueOptions;
|
|
|
|
const pushControllerQueue = new PushQueue(pushQueueOptions);
|
|
let pushWorker;
|
|
if (!disablePushWorker) {
|
|
pushWorker = new PushWorker(pushAdapter, pushQueueOptions);
|
|
}
|
|
return {
|
|
pushController,
|
|
hasPushSupport,
|
|
hasPushScheduledSupport,
|
|
pushControllerQueue,
|
|
pushWorker,
|
|
};
|
|
}
|
|
|
|
export function getAuthDataManager(options: ParseServerOptions) {
|
|
const { auth, enableAnonymousUsers } = options;
|
|
return authDataManager(auth, enableAnonymousUsers);
|
|
}
|
|
|
|
export function getDatabaseAdapter(
|
|
databaseURI,
|
|
collectionPrefix,
|
|
databaseOptions
|
|
) {
|
|
let protocol;
|
|
try {
|
|
const parsedURI = url.parse(databaseURI);
|
|
protocol = parsedURI.protocol ? parsedURI.protocol.toLowerCase() : null;
|
|
} catch (e) {
|
|
/* */
|
|
}
|
|
switch (protocol) {
|
|
case 'postgres:':
|
|
return new PostgresStorageAdapter({
|
|
uri: databaseURI,
|
|
collectionPrefix,
|
|
databaseOptions,
|
|
});
|
|
default:
|
|
return new MongoStorageAdapter({
|
|
uri: databaseURI,
|
|
collectionPrefix,
|
|
mongoOptions: databaseOptions,
|
|
});
|
|
}
|
|
}
|