2017-11-12 13:00:22 -06:00
|
|
|
import ClassesRouter from './ClassesRouter';
|
|
|
|
|
import rest from '../rest';
|
|
|
|
|
import * as middleware from '../middlewares';
|
|
|
|
|
import Parse from 'parse/node';
|
2017-11-22 23:07:45 -08:00
|
|
|
import UsersRouter from './UsersRouter';
|
2017-11-12 13:00:22 -06:00
|
|
|
|
2018-06-23 11:28:17 -05:00
|
|
|
const BASE_KEYS = ['where', 'distinct'];
|
|
|
|
|
|
|
|
|
|
const PIPELINE_KEYS = [
|
|
|
|
|
'addFields',
|
|
|
|
|
'bucket',
|
|
|
|
|
'bucketAuto',
|
|
|
|
|
'collStats',
|
|
|
|
|
'count',
|
|
|
|
|
'currentOp',
|
|
|
|
|
'facet',
|
|
|
|
|
'geoNear',
|
|
|
|
|
'graphLookup',
|
|
|
|
|
'group',
|
|
|
|
|
'indexStats',
|
|
|
|
|
'limit',
|
|
|
|
|
'listLocalSessions',
|
|
|
|
|
'listSessions',
|
|
|
|
|
'lookup',
|
2017-11-12 13:00:22 -06:00
|
|
|
'match',
|
2018-06-23 11:28:17 -05:00
|
|
|
'out',
|
|
|
|
|
'project',
|
2017-11-12 13:00:22 -06:00
|
|
|
'redact',
|
2018-06-23 11:28:17 -05:00
|
|
|
'replaceRoot',
|
2017-11-12 13:00:22 -06:00
|
|
|
'sample',
|
2018-06-23 11:28:17 -05:00
|
|
|
'skip',
|
2017-11-12 13:00:22 -06:00
|
|
|
'sort',
|
|
|
|
|
'sortByCount',
|
2018-06-23 11:28:17 -05:00
|
|
|
'unwind',
|
2017-11-12 13:00:22 -06:00
|
|
|
];
|
|
|
|
|
|
2018-06-23 11:28:17 -05:00
|
|
|
const ALLOWED_KEYS = [...BASE_KEYS, ...PIPELINE_KEYS];
|
|
|
|
|
|
2017-11-12 13:00:22 -06:00
|
|
|
export class AggregateRouter extends ClassesRouter {
|
|
|
|
|
|
|
|
|
|
handleFind(req) {
|
|
|
|
|
const body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
|
|
|
|
|
const options = {};
|
2018-06-23 11:28:17 -05:00
|
|
|
let pipeline = [];
|
2017-11-12 13:00:22 -06:00
|
|
|
|
2018-06-23 11:28:17 -05:00
|
|
|
if (Array.isArray(body)) {
|
|
|
|
|
pipeline = body.map((stage) => {
|
|
|
|
|
const stageName = Object.keys(stage)[0];
|
|
|
|
|
return this.transformStage(stageName, stage);
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
const stages = [];
|
|
|
|
|
for (const stageName in body) {
|
|
|
|
|
stages.push(this.transformStage(stageName, body));
|
2017-11-12 13:00:22 -06:00
|
|
|
}
|
2018-06-23 11:28:17 -05:00
|
|
|
pipeline = stages;
|
2017-11-12 13:00:22 -06:00
|
|
|
}
|
|
|
|
|
if (body.distinct) {
|
|
|
|
|
options.distinct = String(body.distinct);
|
|
|
|
|
}
|
|
|
|
|
options.pipeline = pipeline;
|
|
|
|
|
if (typeof body.where === 'string') {
|
|
|
|
|
body.where = JSON.parse(body.where);
|
|
|
|
|
}
|
2017-11-22 23:07:45 -08:00
|
|
|
return rest.find(req.config, req.auth, this.className(req), body.where, options, req.info.clientSDK).then((response) => {
|
|
|
|
|
for(const result of response.results) {
|
|
|
|
|
if(typeof result === 'object') {
|
|
|
|
|
UsersRouter.removeHiddenProperties(result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return { response };
|
|
|
|
|
});
|
2017-11-12 13:00:22 -06:00
|
|
|
}
|
|
|
|
|
|
2018-06-23 11:28:17 -05:00
|
|
|
transformStage(stageName, stage) {
|
|
|
|
|
if (ALLOWED_KEYS.indexOf(stageName) === -1) {
|
|
|
|
|
throw new Parse.Error(
|
|
|
|
|
Parse.Error.INVALID_QUERY,
|
|
|
|
|
`Invalid parameter for query: ${stageName}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (stageName === 'group') {
|
|
|
|
|
if (stage[stageName].hasOwnProperty('_id')) {
|
|
|
|
|
throw new Parse.Error(
|
|
|
|
|
Parse.Error.INVALID_QUERY,
|
|
|
|
|
`Invalid parameter for query: group. Please use objectId instead of _id`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if (!stage[stageName].hasOwnProperty('objectId')) {
|
|
|
|
|
throw new Parse.Error(
|
|
|
|
|
Parse.Error.INVALID_QUERY,
|
|
|
|
|
`Invalid parameter for query: group. objectId is required`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
stage[stageName]._id = stage[stageName].objectId;
|
|
|
|
|
delete stage[stageName].objectId;
|
|
|
|
|
}
|
|
|
|
|
return { [`$${stageName}`]: stage[stageName] };
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-12 13:00:22 -06:00
|
|
|
mountRoutes() {
|
|
|
|
|
this.route('GET','/aggregate/:className', middleware.promiseEnforceMasterKeyAccess, req => { return this.handleFind(req); });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default AggregateRouter;
|