kinvey-flex-sdk
Version:
SDK for creating Kinvey Flex Services
228 lines (193 loc) • 6.66 kB
JavaScript
/**
* Copyright (c) 2018 Kinvey Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
const kinveyCompletionHandler = require('./kinveyCompletionHandler');
const kinveyErrors = require('kinvey-datalink-errors');
const notImplementedHandler = require('./notImplementedHandler');
const registeredServiceObjects = new Map();
const dataRegistrationOperators = [
'onInsert',
'onInsertMany',
'onDeleteById',
'onDeleteAll',
'onDeleteByQuery',
'onUpdate',
'onGetById',
'onGetAll',
'onGetByQuery',
'onGetCount',
'onGetCountByQuery'
];
class ServiceObject {
constructor(serviceObjectName) {
this.eventMap = new Map();
this.serviceObjectName = serviceObjectName;
}
register(dataOp, functionToExecute) {
if (dataOp == null || dataRegistrationOperators.indexOf(dataOp) < 0) {
throw new Error('Operation not permitted');
}
this.eventMap.set(dataOp, functionToExecute);
}
unregister(dataOp) {
if (dataOp == null || dataRegistrationOperators.indexOf(dataOp) < 0) {
throw new Error('Operation not permitted');
}
this.eventMap.delete(dataOp);
}
onInsert(functionToExecute) {
this.register('onInsert', functionToExecute);
}
onInsertMany(functionToExecute) {
this.register('onInsertMany', functionToExecute);
}
onDeleteById(functionToExecute) {
this.register('onDeleteById', functionToExecute);
}
onDeleteAll(functionToExecute) {
this.register('onDeleteAll', functionToExecute);
}
onDeleteByQuery(functionToExecute) {
this.register('onDeleteByQuery', functionToExecute);
}
onUpdate(functionToExecute) {
this.register('onUpdate', functionToExecute);
}
onGetById(functionToExecute) {
this.register('onGetById', functionToExecute);
}
onGetAll(functionToExecute) {
this.register('onGetAll', functionToExecute);
}
onGetByQuery(functionToExecute) {
this.register('onGetByQuery', functionToExecute);
}
onGetCount(functionToExecute) {
this.register('onGetCount', functionToExecute);
}
onGetCountByQuery(functionToExecute) {
this.register('onGetCountByQuery', functionToExecute);
}
removeHandler(handler) {
this.unregister(handler);
}
resolve(dataOp) {
const eventToUse = this.eventMap.get(dataOp);
return eventToUse || notImplementedHandler;
}
}
function getServiceObjects() {
return [...registeredServiceObjects.keys()];
}
function serviceObject(serviceObjectName) {
if (!registeredServiceObjects.get(serviceObjectName)) {
registeredServiceObjects.set(serviceObjectName, new ServiceObject(serviceObjectName));
}
return registeredServiceObjects.get(serviceObjectName);
}
function process(task, modules, callback) {
if (task.request == null || task.request.serviceObjectName == null) {
const result = task.response;
result.body = kinveyErrors.generateKinveyError('NotFound', 'ServiceObject name not found');
result.statusCode = result.body.statusCode;
delete result.body.statusCode;
return callback(task);
}
// Handle a bug in KCS - if query is part of the task, put it in the request
if (!task.request.query) {
task.request.query = task.query;
}
const serviceObjectToProcess = serviceObject(task.request.serviceObjectName);
let dataOp = '';
try {
task.request.body = JSON.parse(task.request.body);
} catch (e) {
const body = task.request.body || null;
if (body !== null && typeof body !== 'object') {
const result = task.response;
result.body = kinveyErrors.generateKinveyError('BadRequest', 'Request body contains invalid JSON');
result.statusCode = result.body.statusCode;
delete result.body.statusCode;
return callback(task);
}
}
try {
task.request.query = JSON.parse(task.request.query);
} catch (error) {
const query = task.request.query || null;
if (query !== null && typeof query !== 'object') {
const result = task.response;
result.body = kinveyErrors.generateKinveyError('BadRequest', 'Request query contains invalid JSON');
result.statusCode = result.body.statusCode;
delete result.body.statusCode;
return callback(task);
}
}
if (task.method === 'POST') {
if (Array.isArray(task.request.body)) {
dataOp = 'onInsertMany';
} else {
dataOp = 'onInsert';
}
} else if (task.method === 'PUT') {
dataOp = 'onUpdate';
} else if (task.method === 'GET' && task.endpoint !== '_count') {
const taskRequest = task.request || {};
if (taskRequest.entityId != null) {
dataOp = 'onGetById';
} else if (taskRequest.query != null) {
dataOp = 'onGetByQuery';
} else {
dataOp = 'onGetAll';
}
} else if (task.method === 'GET' && task.endpoint === '_count') {
const taskRequest = task.request || {};
if (taskRequest.query != null) {
dataOp = 'onGetCountByQuery';
} else {
dataOp = 'onGetCount';
}
} else if (task.method === 'DELETE') {
const taskRequest = task.request || {};
if (taskRequest.entityId) {
dataOp = 'onDeleteById';
} else if (taskRequest.query != null) {
dataOp = 'onDeleteByQuery';
} else {
dataOp = 'onDeleteAll';
}
} else {
const result = task.response;
result.body = kinveyErrors.generateKinveyError('BadRequest', 'Cannot determine data operation');
result.statusCode = result.body.statusCode;
delete result.body.statusCode;
return callback(task);
}
const dataCompletionHandler = kinveyCompletionHandler(task, modules, callback);
const operationHandler = serviceObjectToProcess.resolve(dataOp);
return operationHandler(task.request, dataCompletionHandler, modules);
}
function removeServiceObject(serviceObjectToRemove) {
if (serviceObjectToRemove == null) {
throw new Error('Must list ServiceObject name');
}
registeredServiceObjects.delete(serviceObjectToRemove);
}
function clearAll() {
registeredServiceObjects.clear();
}
exports.getServiceObjects = getServiceObjects;
exports.serviceObject = serviceObject;
exports.process = process;
exports.removeServiceObject = removeServiceObject;
exports.clearAll = clearAll;