Remove hidden properties from aggregate responses (#4351)
* Remove hidden properties from aggregrate responses * transform results from mongo & postgres * Adjust ordering to comply with tests
This commit is contained in:
committed by
GitHub
parent
37ceae0812
commit
7944e2bd2d
@@ -409,10 +409,11 @@ export class MongoStorageAdapter {
|
||||
distinct(className, schema, query, fieldName) {
|
||||
schema = convertParseSchemaToMongoSchema(schema);
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.distinct(fieldName, transformWhere(className, query, schema)));
|
||||
.then(collection => collection.distinct(fieldName, transformWhere(className, query, schema)))
|
||||
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
|
||||
}
|
||||
|
||||
aggregate(className, pipeline, readPreference) {
|
||||
aggregate(className, schema, pipeline, readPreference) {
|
||||
readPreference = this._parseReadPreference(readPreference);
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.aggregate(pipeline, { readPreference, maxTimeMS: this._maxTimeMS }))
|
||||
@@ -424,7 +425,8 @@ export class MongoStorageAdapter {
|
||||
}
|
||||
});
|
||||
return results;
|
||||
});
|
||||
})
|
||||
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
|
||||
}
|
||||
|
||||
_parseReadPreference(readPreference) {
|
||||
|
||||
@@ -1261,79 +1261,83 @@ export class PostgresStorageAdapter {
|
||||
}
|
||||
return Promise.reject(err);
|
||||
})
|
||||
.then(results => results.map(object => {
|
||||
Object.keys(schema.fields).forEach(fieldName => {
|
||||
if (schema.fields[fieldName].type === 'Pointer' && object[fieldName]) {
|
||||
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass };
|
||||
}
|
||||
if (schema.fields[fieldName].type === 'Relation') {
|
||||
object[fieldName] = {
|
||||
__type: "Relation",
|
||||
className: schema.fields[fieldName].targetClass
|
||||
}
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'GeoPoint') {
|
||||
object[fieldName] = {
|
||||
__type: "GeoPoint",
|
||||
latitude: object[fieldName].y,
|
||||
longitude: object[fieldName].x
|
||||
}
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'Polygon') {
|
||||
let coords = object[fieldName];
|
||||
coords = coords.substr(2, coords.length - 4).split('),(');
|
||||
coords = coords.map((point) => {
|
||||
return [
|
||||
parseFloat(point.split(',')[1]),
|
||||
parseFloat(point.split(',')[0])
|
||||
];
|
||||
});
|
||||
object[fieldName] = {
|
||||
__type: "Polygon",
|
||||
coordinates: coords
|
||||
}
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'File') {
|
||||
object[fieldName] = {
|
||||
__type: 'File',
|
||||
name: object[fieldName]
|
||||
}
|
||||
}
|
||||
.then(results => results.map(object => this.postgresObjectToParseObject(className, object, schema)));
|
||||
}
|
||||
|
||||
// Converts from a postgres-format object to a REST-format object.
|
||||
// Does not strip out anything based on a lack of authentication.
|
||||
postgresObjectToParseObject(className, object, schema) {
|
||||
Object.keys(schema.fields).forEach(fieldName => {
|
||||
if (schema.fields[fieldName].type === 'Pointer' && object[fieldName]) {
|
||||
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass };
|
||||
}
|
||||
if (schema.fields[fieldName].type === 'Relation') {
|
||||
object[fieldName] = {
|
||||
__type: "Relation",
|
||||
className: schema.fields[fieldName].targetClass
|
||||
}
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'GeoPoint') {
|
||||
object[fieldName] = {
|
||||
__type: "GeoPoint",
|
||||
latitude: object[fieldName].y,
|
||||
longitude: object[fieldName].x
|
||||
}
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'Polygon') {
|
||||
let coords = object[fieldName];
|
||||
coords = coords.substr(2, coords.length - 4).split('),(');
|
||||
coords = coords.map((point) => {
|
||||
return [
|
||||
parseFloat(point.split(',')[1]),
|
||||
parseFloat(point.split(',')[0])
|
||||
];
|
||||
});
|
||||
//TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field.
|
||||
if (object.createdAt) {
|
||||
object.createdAt = object.createdAt.toISOString();
|
||||
object[fieldName] = {
|
||||
__type: "Polygon",
|
||||
coordinates: coords
|
||||
}
|
||||
if (object.updatedAt) {
|
||||
object.updatedAt = object.updatedAt.toISOString();
|
||||
}
|
||||
if (object.expiresAt) {
|
||||
object.expiresAt = { __type: 'Date', iso: object.expiresAt.toISOString() };
|
||||
}
|
||||
if (object._email_verify_token_expires_at) {
|
||||
object._email_verify_token_expires_at = { __type: 'Date', iso: object._email_verify_token_expires_at.toISOString() };
|
||||
}
|
||||
if (object._account_lockout_expires_at) {
|
||||
object._account_lockout_expires_at = { __type: 'Date', iso: object._account_lockout_expires_at.toISOString() };
|
||||
}
|
||||
if (object._perishable_token_expires_at) {
|
||||
object._perishable_token_expires_at = { __type: 'Date', iso: object._perishable_token_expires_at.toISOString() };
|
||||
}
|
||||
if (object._password_changed_at) {
|
||||
object._password_changed_at = { __type: 'Date', iso: object._password_changed_at.toISOString() };
|
||||
}
|
||||
if (object[fieldName] && schema.fields[fieldName].type === 'File') {
|
||||
object[fieldName] = {
|
||||
__type: 'File',
|
||||
name: object[fieldName]
|
||||
}
|
||||
}
|
||||
});
|
||||
//TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field.
|
||||
if (object.createdAt) {
|
||||
object.createdAt = object.createdAt.toISOString();
|
||||
}
|
||||
if (object.updatedAt) {
|
||||
object.updatedAt = object.updatedAt.toISOString();
|
||||
}
|
||||
if (object.expiresAt) {
|
||||
object.expiresAt = { __type: 'Date', iso: object.expiresAt.toISOString() };
|
||||
}
|
||||
if (object._email_verify_token_expires_at) {
|
||||
object._email_verify_token_expires_at = { __type: 'Date', iso: object._email_verify_token_expires_at.toISOString() };
|
||||
}
|
||||
if (object._account_lockout_expires_at) {
|
||||
object._account_lockout_expires_at = { __type: 'Date', iso: object._account_lockout_expires_at.toISOString() };
|
||||
}
|
||||
if (object._perishable_token_expires_at) {
|
||||
object._perishable_token_expires_at = { __type: 'Date', iso: object._perishable_token_expires_at.toISOString() };
|
||||
}
|
||||
if (object._password_changed_at) {
|
||||
object._password_changed_at = { __type: 'Date', iso: object._password_changed_at.toISOString() };
|
||||
}
|
||||
|
||||
for (const fieldName in object) {
|
||||
if (object[fieldName] === null) {
|
||||
delete object[fieldName];
|
||||
}
|
||||
if (object[fieldName] instanceof Date) {
|
||||
object[fieldName] = { __type: 'Date', iso: object[fieldName].toISOString() };
|
||||
}
|
||||
}
|
||||
for (const fieldName in object) {
|
||||
if (object[fieldName] === null) {
|
||||
delete object[fieldName];
|
||||
}
|
||||
if (object[fieldName] instanceof Date) {
|
||||
object[fieldName] = { __type: 'Date', iso: object[fieldName].toISOString() };
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}));
|
||||
return object;
|
||||
}
|
||||
|
||||
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
|
||||
@@ -1406,10 +1410,10 @@ export class PostgresStorageAdapter {
|
||||
}
|
||||
const child = fieldName.split('.')[1];
|
||||
return results.map(object => object[column][child]);
|
||||
});
|
||||
}).then(results => results.map(object => this.postgresObjectToParseObject(className, object, schema)));
|
||||
}
|
||||
|
||||
aggregate(className, pipeline) {
|
||||
aggregate(className, schema, pipeline) {
|
||||
debug('aggregate', className, pipeline);
|
||||
const values = [className];
|
||||
let columns = [];
|
||||
@@ -1498,17 +1502,19 @@ export class PostgresStorageAdapter {
|
||||
|
||||
const qs = `SELECT ${columns} FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern} ${groupPattern}`;
|
||||
debug(qs, values);
|
||||
return this._client.any(qs, values).then(results => {
|
||||
if (countField) {
|
||||
results[0][countField] = parseInt(results[0][countField], 10);
|
||||
}
|
||||
results.forEach(result => {
|
||||
if (!result.hasOwnProperty('objectId')) {
|
||||
result.objectId = null;
|
||||
return this._client.any(qs, values)
|
||||
.then(results => results.map(object => this.postgresObjectToParseObject(className, object, schema)))
|
||||
.then(results => {
|
||||
if (countField) {
|
||||
results[0][countField] = parseInt(results[0][countField], 10);
|
||||
}
|
||||
results.forEach(result => {
|
||||
if (!result.hasOwnProperty('objectId')) {
|
||||
result.objectId = null;
|
||||
}
|
||||
});
|
||||
return results;
|
||||
});
|
||||
return results;
|
||||
});
|
||||
}
|
||||
|
||||
performInitialization({ VolatileClassesSchemas }) {
|
||||
|
||||
@@ -875,7 +875,7 @@ DatabaseController.prototype.find = function(className, query, {
|
||||
if (!classExists) {
|
||||
return [];
|
||||
} else {
|
||||
return this.adapter.aggregate(className, pipeline, readPreference);
|
||||
return this.adapter.aggregate(className, schema, pipeline, readPreference);
|
||||
}
|
||||
} else {
|
||||
if (!classExists) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import ClassesRouter from './ClassesRouter';
|
||||
import rest from '../rest';
|
||||
import * as middleware from '../middlewares';
|
||||
import Parse from 'parse/node';
|
||||
import UsersRouter from './UsersRouter';
|
||||
|
||||
const ALLOWED_KEYS = [
|
||||
'where',
|
||||
@@ -65,8 +66,14 @@ export class AggregateRouter extends ClassesRouter {
|
||||
if (typeof body.where === 'string') {
|
||||
body.where = JSON.parse(body.where);
|
||||
}
|
||||
return rest.find(req.config, req.auth, this.className(req), body.where, options, req.info.clientSDK)
|
||||
.then((response) => { return { response }; });
|
||||
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 };
|
||||
});
|
||||
}
|
||||
|
||||
mountRoutes() {
|
||||
|
||||
Reference in New Issue
Block a user