Move query logic into mongo (#1885)
* Move Parse Server logic into Parse Server and out of MongoAdapter * Move untransforming up one level * Make find() in MongoStorageAdapter * Put nested object untransforming into it's own function * Simplfy nested untransform * Don't mess with inner object keys called _auth_data_* * Prevent untransforming inner object keys named _p_* * Fix inner keys named _rperm, _wperm * Fix bugs with inner objects behaving strange when other fields have same name as key in specific circumstances * remove params from untransform nested object * Revert changes to find
This commit is contained in:
@@ -121,10 +121,10 @@ describe('transformWhere', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('untransformObject', () => {
|
describe('mongoObjectToParseObject', () => {
|
||||||
it('built-in timestamps', (done) => {
|
it('built-in timestamps', (done) => {
|
||||||
var input = {createdAt: new Date(), updatedAt: new Date()};
|
var input = {createdAt: new Date(), updatedAt: new Date()};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(typeof output.createdAt).toEqual('string');
|
expect(typeof output.createdAt).toEqual('string');
|
||||||
expect(typeof output.updatedAt).toEqual('string');
|
expect(typeof output.updatedAt).toEqual('string');
|
||||||
done();
|
done();
|
||||||
@@ -132,7 +132,7 @@ describe('untransformObject', () => {
|
|||||||
|
|
||||||
it('pointer', (done) => {
|
it('pointer', (done) => {
|
||||||
var input = {_p_userPointer: '_User$123'};
|
var input = {_p_userPointer: '_User$123'};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(typeof output.userPointer).toEqual('object');
|
expect(typeof output.userPointer).toEqual('object');
|
||||||
expect(output.userPointer).toEqual(
|
expect(output.userPointer).toEqual(
|
||||||
{__type: 'Pointer', className: '_User', objectId: '123'}
|
{__type: 'Pointer', className: '_User', objectId: '123'}
|
||||||
@@ -142,14 +142,14 @@ describe('untransformObject', () => {
|
|||||||
|
|
||||||
it('null pointer', (done) => {
|
it('null pointer', (done) => {
|
||||||
var input = {_p_userPointer: null};
|
var input = {_p_userPointer: null};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(output.userPointer).toBeUndefined();
|
expect(output.userPointer).toBeUndefined();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('file', (done) => {
|
it('file', (done) => {
|
||||||
var input = {picture: 'pic.jpg'};
|
var input = {picture: 'pic.jpg'};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(typeof output.picture).toEqual('object');
|
expect(typeof output.picture).toEqual('object');
|
||||||
expect(output.picture).toEqual({__type: 'File', name: 'pic.jpg'});
|
expect(output.picture).toEqual({__type: 'File', name: 'pic.jpg'});
|
||||||
done();
|
done();
|
||||||
@@ -157,7 +157,7 @@ describe('untransformObject', () => {
|
|||||||
|
|
||||||
it('geopoint', (done) => {
|
it('geopoint', (done) => {
|
||||||
var input = {location: [180, -180]};
|
var input = {location: [180, -180]};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(typeof output.location).toEqual('object');
|
expect(typeof output.location).toEqual('object');
|
||||||
expect(output.location).toEqual(
|
expect(output.location).toEqual(
|
||||||
{__type: 'GeoPoint', longitude: 180, latitude: -180}
|
{__type: 'GeoPoint', longitude: 180, latitude: -180}
|
||||||
@@ -167,7 +167,7 @@ describe('untransformObject', () => {
|
|||||||
|
|
||||||
it('nested array', (done) => {
|
it('nested array', (done) => {
|
||||||
var input = {arr: [{_testKey: 'testValue' }]};
|
var input = {arr: [{_testKey: 'testValue' }]};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(Array.isArray(output.arr)).toEqual(true);
|
expect(Array.isArray(output.arr)).toEqual(true);
|
||||||
expect(output.arr).toEqual([{ _testKey: 'testValue'}]);
|
expect(output.arr).toEqual([{ _testKey: 'testValue'}]);
|
||||||
done();
|
done();
|
||||||
@@ -185,7 +185,7 @@ describe('untransformObject', () => {
|
|||||||
},
|
},
|
||||||
regularKey: "some data",
|
regularKey: "some data",
|
||||||
}]}
|
}]}
|
||||||
let output = transform.untransformObject(dummySchema, null, input);
|
let output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(dd(output, input)).toEqual(undefined);
|
expect(dd(output, input)).toEqual(undefined);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -253,7 +253,7 @@ describe('transform schema key changes', () => {
|
|||||||
_rperm: ["*"],
|
_rperm: ["*"],
|
||||||
_wperm: ["Kevin"]
|
_wperm: ["Kevin"]
|
||||||
};
|
};
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(typeof output.ACL).toEqual('object');
|
expect(typeof output.ACL).toEqual('object');
|
||||||
expect(output._rperm).toBeUndefined();
|
expect(output._rperm).toBeUndefined();
|
||||||
expect(output._wperm).toBeUndefined();
|
expect(output._wperm).toBeUndefined();
|
||||||
@@ -267,7 +267,7 @@ describe('transform schema key changes', () => {
|
|||||||
long: mongodb.Long.fromNumber(Number.MAX_SAFE_INTEGER),
|
long: mongodb.Long.fromNumber(Number.MAX_SAFE_INTEGER),
|
||||||
double: new mongodb.Double(Number.MAX_VALUE)
|
double: new mongodb.Double(Number.MAX_VALUE)
|
||||||
}
|
}
|
||||||
var output = transform.untransformObject(dummySchema, null, input);
|
var output = transform.mongoObjectToParseObject(dummySchema, null, input);
|
||||||
expect(output.long).toBe(Number.MAX_SAFE_INTEGER);
|
expect(output.long).toBe(Number.MAX_SAFE_INTEGER);
|
||||||
expect(output.double).toBe(Number.MAX_VALUE);
|
expect(output.double).toBe(Number.MAX_VALUE);
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -1120,4 +1120,54 @@ describe('miscellaneous', function() {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not change inner object key names _auth_data_something', done => {
|
||||||
|
new Parse.Object('O').save({ innerObj: {_auth_data_facebook: 7}})
|
||||||
|
.then(object => new Parse.Query('O').get(object.id))
|
||||||
|
.then(object => {
|
||||||
|
expect(object.get('innerObj')).toEqual({_auth_data_facebook: 7});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change inner object key names _p_somethign', done => {
|
||||||
|
new Parse.Object('O').save({ innerObj: {_p_data: 7}})
|
||||||
|
.then(object => new Parse.Query('O').get(object.id))
|
||||||
|
.then(object => {
|
||||||
|
expect(object.get('innerObj')).toEqual({_p_data: 7});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change inner object key names _rperm, _wperm', done => {
|
||||||
|
new Parse.Object('O').save({ innerObj: {_rperm: 7, _wperm: 8}})
|
||||||
|
.then(object => new Parse.Query('O').get(object.id))
|
||||||
|
.then(object => {
|
||||||
|
expect(object.get('innerObj')).toEqual({_rperm: 7, _wperm: 8});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not change inner objects if the key has the same name as a geopoint field on the class, and the value is an array of length 2, or if the key has the same name as a file field on the class, and the value is a string', done => {
|
||||||
|
let file = new Parse.File('myfile.txt', { base64: 'eAo=' });
|
||||||
|
file.save()
|
||||||
|
.then(f => {
|
||||||
|
let obj = new Parse.Object('O');
|
||||||
|
obj.set('fileField', f);
|
||||||
|
obj.set('geoField', new Parse.GeoPoint(0, 0));
|
||||||
|
obj.set('innerObj', {
|
||||||
|
fileField: "data",
|
||||||
|
geoField: [1,2],
|
||||||
|
});
|
||||||
|
return obj.save();
|
||||||
|
})
|
||||||
|
.then(object => object.fetch())
|
||||||
|
.then(object => {
|
||||||
|
expect(object.get('innerObj')).toEqual({
|
||||||
|
fileField: "data",
|
||||||
|
geoField: [1,2],
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -197,6 +197,14 @@ export class MongoStorageAdapter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
||||||
|
// Accepts the schemaController for legacy reasons.
|
||||||
|
find(className, query, { skip, limit, sort }, schemaController) {
|
||||||
|
return this.adaptiveCollection(className)
|
||||||
|
.then(collection => collection.find(query, { skip, limit, sort }))
|
||||||
|
.then(objects => objects.map(object => transform.mongoObjectToParseObject(schemaController, className, object)));
|
||||||
|
}
|
||||||
|
|
||||||
get transform() {
|
get transform() {
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -713,25 +713,7 @@ function transformUpdateOperator({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const specialKeysForUntransform = [
|
const nestedMongoObjectToNestedParseObject = mongoObject => {
|
||||||
'_id',
|
|
||||||
'_hashed_password',
|
|
||||||
'_acl',
|
|
||||||
'_email_verify_token',
|
|
||||||
'_perishable_token',
|
|
||||||
'_tombstone',
|
|
||||||
'_session_token',
|
|
||||||
'updatedAt',
|
|
||||||
'_updated_at',
|
|
||||||
'createdAt',
|
|
||||||
'_created_at',
|
|
||||||
'expiresAt',
|
|
||||||
'_expiresAt',
|
|
||||||
];
|
|
||||||
|
|
||||||
// Converts from a mongo-format object to a REST-format object.
|
|
||||||
// Does not strip out anything based on a lack of authentication.
|
|
||||||
function untransformObject(schema, className, mongoObject, isNestedObject = false) {
|
|
||||||
switch(typeof mongoObject) {
|
switch(typeof mongoObject) {
|
||||||
case 'string':
|
case 'string':
|
||||||
case 'number':
|
case 'number':
|
||||||
@@ -740,15 +722,55 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals
|
|||||||
case 'undefined':
|
case 'undefined':
|
||||||
case 'symbol':
|
case 'symbol':
|
||||||
case 'function':
|
case 'function':
|
||||||
throw 'bad value in untransformObject';
|
throw 'bad value in mongoObjectToParseObject';
|
||||||
case 'object':
|
case 'object':
|
||||||
if (mongoObject === null) {
|
if (mongoObject === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (mongoObject instanceof Array) {
|
if (mongoObject instanceof Array) {
|
||||||
return mongoObject.map(arrayEntry => {
|
return mongoObject.map(nestedMongoObjectToNestedParseObject);
|
||||||
return untransformObject(schema, className, arrayEntry, true);
|
}
|
||||||
});
|
|
||||||
|
if (mongoObject instanceof Date) {
|
||||||
|
return Parse._encode(mongoObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mongoObject instanceof mongodb.Long) {
|
||||||
|
return mongoObject.toNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mongoObject instanceof mongodb.Double) {
|
||||||
|
return mongoObject.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BytesCoder.isValidDatabaseObject(mongoObject)) {
|
||||||
|
return BytesCoder.databaseToJSON(mongoObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.mapValues(mongoObject, nestedMongoObjectToNestedParseObject);
|
||||||
|
default:
|
||||||
|
throw 'unknown js type';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts from a mongo-format object to a REST-format object.
|
||||||
|
// Does not strip out anything based on a lack of authentication.
|
||||||
|
const mongoObjectToParseObject = (schema, className, mongoObject) => {
|
||||||
|
switch(typeof mongoObject) {
|
||||||
|
case 'string':
|
||||||
|
case 'number':
|
||||||
|
case 'boolean':
|
||||||
|
return mongoObject;
|
||||||
|
case 'undefined':
|
||||||
|
case 'symbol':
|
||||||
|
case 'function':
|
||||||
|
throw 'bad value in mongoObjectToParseObject';
|
||||||
|
case 'object':
|
||||||
|
if (mongoObject === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (mongoObject instanceof Array) {
|
||||||
|
return mongoObject.map(nestedMongoObjectToNestedParseObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mongoObject instanceof Date) {
|
if (mongoObject instanceof Date) {
|
||||||
@@ -769,10 +791,6 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals
|
|||||||
|
|
||||||
var restObject = untransformACL(mongoObject);
|
var restObject = untransformACL(mongoObject);
|
||||||
for (var key in mongoObject) {
|
for (var key in mongoObject) {
|
||||||
if (isNestedObject && _.includes(specialKeysForUntransform, key)) {
|
|
||||||
restObject[key] = untransformObject(schema, className, mongoObject[key], true);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch(key) {
|
switch(key) {
|
||||||
case '_id':
|
case '_id':
|
||||||
restObject['objectId'] = '' + mongoObject[key];
|
restObject['objectId'] = '' + mongoObject[key];
|
||||||
@@ -840,7 +858,7 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals
|
|||||||
objectId: objData[1]
|
objectId: objData[1]
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
} else if (!isNestedObject && key[0] == '_' && key != '__type') {
|
} else if (key[0] == '_' && key != '__type') {
|
||||||
throw ('bad key in untransform: ' + key);
|
throw ('bad key in untransform: ' + key);
|
||||||
} else {
|
} else {
|
||||||
var expectedType = schema.getExpectedType(className, key);
|
var expectedType = schema.getExpectedType(className, key);
|
||||||
@@ -854,80 +872,16 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restObject[key] = untransformObject(schema, className, mongoObject[key], true);
|
restObject[key] = nestedMongoObjectToNestedParseObject(mongoObject[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNestedObject) {
|
return { ...restObject, ...schema.getRelationFields(className) };
|
||||||
let relationFields = schema.getRelationFields(className);
|
|
||||||
Object.assign(restObject, relationFields);
|
|
||||||
}
|
|
||||||
return restObject;
|
|
||||||
default:
|
default:
|
||||||
throw 'unknown js type';
|
throw 'unknown js type';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformSelect(selectObject, key ,objects) {
|
|
||||||
var values = [];
|
|
||||||
for (var result of objects) {
|
|
||||||
values.push(result[key]);
|
|
||||||
}
|
|
||||||
delete selectObject['$select'];
|
|
||||||
if (Array.isArray(selectObject['$in'])) {
|
|
||||||
selectObject['$in'] = selectObject['$in'].concat(values);
|
|
||||||
} else {
|
|
||||||
selectObject['$in'] = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformDontSelect(dontSelectObject, key, objects) {
|
|
||||||
var values = [];
|
|
||||||
for (var result of objects) {
|
|
||||||
values.push(result[key]);
|
|
||||||
}
|
|
||||||
delete dontSelectObject['$dontSelect'];
|
|
||||||
if (Array.isArray(dontSelectObject['$nin'])) {
|
|
||||||
dontSelectObject['$nin'] = dontSelectObject['$nin'].concat(values);
|
|
||||||
} else {
|
|
||||||
dontSelectObject['$nin'] = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformInQuery(inQueryObject, className, results) {
|
|
||||||
var values = [];
|
|
||||||
for (var result of results) {
|
|
||||||
values.push({
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: className,
|
|
||||||
objectId: result.objectId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
delete inQueryObject['$inQuery'];
|
|
||||||
if (Array.isArray(inQueryObject['$in'])) {
|
|
||||||
inQueryObject['$in'] = inQueryObject['$in'].concat(values);
|
|
||||||
} else {
|
|
||||||
inQueryObject['$in'] = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformNotInQuery(notInQueryObject, className, results) {
|
|
||||||
var values = [];
|
|
||||||
for (var result of results) {
|
|
||||||
values.push({
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: className,
|
|
||||||
objectId: result.objectId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
delete notInQueryObject['$notInQuery'];
|
|
||||||
if (Array.isArray(notInQueryObject['$nin'])) {
|
|
||||||
notInQueryObject['$nin'] = notInQueryObject['$nin'].concat(values);
|
|
||||||
} else {
|
|
||||||
notInQueryObject['$nin'] = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var DateCoder = {
|
var DateCoder = {
|
||||||
JSONToDatabase(json) {
|
JSONToDatabase(json) {
|
||||||
return new Date(json.iso);
|
return new Date(json.iso);
|
||||||
@@ -1021,9 +975,5 @@ module.exports = {
|
|||||||
parseObjectToMongoObjectForCreate,
|
parseObjectToMongoObjectForCreate,
|
||||||
transformUpdate,
|
transformUpdate,
|
||||||
transformWhere,
|
transformWhere,
|
||||||
transformSelect,
|
mongoObjectToParseObject,
|
||||||
transformDontSelect,
|
|
||||||
transformInQuery,
|
|
||||||
transformNotInQuery,
|
|
||||||
untransformObject
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -146,12 +146,8 @@ DatabaseController.prototype.validateObject = function(className, object, query,
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Like transform.untransformObject but you need to provide a className.
|
|
||||||
// Filters out any data that shouldn't be on this REST-formatted object.
|
// Filters out any data that shouldn't be on this REST-formatted object.
|
||||||
DatabaseController.prototype.untransformObject = function(
|
const filterSensitiveData = (isMaster, aclGroup, className, object) => {
|
||||||
schema, isMaster, aclGroup, className, mongoObject) {
|
|
||||||
var object = this.transform.untransformObject(schema, className, mongoObject);
|
|
||||||
|
|
||||||
if (className !== '_User') {
|
if (className !== '_User') {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
@@ -705,12 +701,8 @@ DatabaseController.prototype.find = function(className, query, {
|
|||||||
delete mongoOptions.limit;
|
delete mongoOptions.limit;
|
||||||
return collection.count(mongoWhere, mongoOptions);
|
return collection.count(mongoWhere, mongoOptions);
|
||||||
} else {
|
} else {
|
||||||
return collection.find(mongoWhere, mongoOptions)
|
return this.adapter.find(className, mongoWhere, mongoOptions, schemaController)
|
||||||
.then(mongoResults => {
|
.then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object)));
|
||||||
return mongoResults.map(result => {
|
|
||||||
return this.untransformObject(schemaController, isMaster, aclGroup, className, result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -188,6 +188,23 @@ RestQuery.prototype.validateClientClassCreation = function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function transformInQuery(inQueryObject, className, results) {
|
||||||
|
var values = [];
|
||||||
|
for (var result of results) {
|
||||||
|
values.push({
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: className,
|
||||||
|
objectId: result.objectId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
delete inQueryObject['$inQuery'];
|
||||||
|
if (Array.isArray(inQueryObject['$in'])) {
|
||||||
|
inQueryObject['$in'] = inQueryObject['$in'].concat(values);
|
||||||
|
} else {
|
||||||
|
inQueryObject['$in'] = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces a $inQuery clause by running the subquery, if there is an
|
// Replaces a $inQuery clause by running the subquery, if there is an
|
||||||
// $inQuery clause.
|
// $inQuery clause.
|
||||||
// The $inQuery clause turns into an $in with values that are just
|
// The $inQuery clause turns into an $in with values that are just
|
||||||
@@ -213,12 +230,29 @@ RestQuery.prototype.replaceInQuery = function() {
|
|||||||
this.config, this.auth, inQueryValue.className,
|
this.config, this.auth, inQueryValue.className,
|
||||||
inQueryValue.where, additionalOptions);
|
inQueryValue.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
this.config.database.transform.transformInQuery(inQueryObject, subquery.className, response.results);
|
transformInQuery(inQueryObject, subquery.className, response.results);
|
||||||
// Recurse to repeat
|
// Recurse to repeat
|
||||||
return this.replaceInQuery();
|
return this.replaceInQuery();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function transformNotInQuery(notInQueryObject, className, results) {
|
||||||
|
var values = [];
|
||||||
|
for (var result of results) {
|
||||||
|
values.push({
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: className,
|
||||||
|
objectId: result.objectId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
delete notInQueryObject['$notInQuery'];
|
||||||
|
if (Array.isArray(notInQueryObject['$nin'])) {
|
||||||
|
notInQueryObject['$nin'] = notInQueryObject['$nin'].concat(values);
|
||||||
|
} else {
|
||||||
|
notInQueryObject['$nin'] = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces a $notInQuery clause by running the subquery, if there is an
|
// Replaces a $notInQuery clause by running the subquery, if there is an
|
||||||
// $notInQuery clause.
|
// $notInQuery clause.
|
||||||
// The $notInQuery clause turns into a $nin with values that are just
|
// The $notInQuery clause turns into a $nin with values that are just
|
||||||
@@ -244,12 +278,25 @@ RestQuery.prototype.replaceNotInQuery = function() {
|
|||||||
this.config, this.auth, notInQueryValue.className,
|
this.config, this.auth, notInQueryValue.className,
|
||||||
notInQueryValue.where, additionalOptions);
|
notInQueryValue.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
this.config.database.transform.transformNotInQuery(notInQueryObject, subquery.className, response.results);
|
transformNotInQuery(notInQueryObject, subquery.className, response.results);
|
||||||
// Recurse to repeat
|
// Recurse to repeat
|
||||||
return this.replaceNotInQuery();
|
return this.replaceNotInQuery();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const transformSelect = (selectObject, key ,objects) => {
|
||||||
|
var values = [];
|
||||||
|
for (var result of objects) {
|
||||||
|
values.push(result[key]);
|
||||||
|
}
|
||||||
|
delete selectObject['$select'];
|
||||||
|
if (Array.isArray(selectObject['$in'])) {
|
||||||
|
selectObject['$in'] = selectObject['$in'].concat(values);
|
||||||
|
} else {
|
||||||
|
selectObject['$in'] = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces a $select clause by running the subquery, if there is a
|
// Replaces a $select clause by running the subquery, if there is a
|
||||||
// $select clause.
|
// $select clause.
|
||||||
// The $select clause turns into an $in with values selected out of
|
// The $select clause turns into an $in with values selected out of
|
||||||
@@ -281,12 +328,25 @@ RestQuery.prototype.replaceSelect = function() {
|
|||||||
this.config, this.auth, selectValue.query.className,
|
this.config, this.auth, selectValue.query.className,
|
||||||
selectValue.query.where, additionalOptions);
|
selectValue.query.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
this.config.database.transform.transformSelect(selectObject, selectValue.key, response.results);
|
transformSelect(selectObject, selectValue.key, response.results);
|
||||||
// Keep replacing $select clauses
|
// Keep replacing $select clauses
|
||||||
return this.replaceSelect();
|
return this.replaceSelect();
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const transformDontSelect = (dontSelectObject, key, objects) => {
|
||||||
|
var values = [];
|
||||||
|
for (var result of objects) {
|
||||||
|
values.push(result[key]);
|
||||||
|
}
|
||||||
|
delete dontSelectObject['$dontSelect'];
|
||||||
|
if (Array.isArray(dontSelectObject['$nin'])) {
|
||||||
|
dontSelectObject['$nin'] = dontSelectObject['$nin'].concat(values);
|
||||||
|
} else {
|
||||||
|
dontSelectObject['$nin'] = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Replaces a $dontSelect clause by running the subquery, if there is a
|
// Replaces a $dontSelect clause by running the subquery, if there is a
|
||||||
// $dontSelect clause.
|
// $dontSelect clause.
|
||||||
// The $dontSelect clause turns into an $nin with values selected out of
|
// The $dontSelect clause turns into an $nin with values selected out of
|
||||||
@@ -316,7 +376,7 @@ RestQuery.prototype.replaceDontSelect = function() {
|
|||||||
this.config, this.auth, dontSelectValue.query.className,
|
this.config, this.auth, dontSelectValue.query.className,
|
||||||
dontSelectValue.query.where, additionalOptions);
|
dontSelectValue.query.where, additionalOptions);
|
||||||
return subquery.execute().then((response) => {
|
return subquery.execute().then((response) => {
|
||||||
this.config.database.transform.transformDontSelect(dontSelectObject, dontSelectValue.key, response.results);
|
transformDontSelect(dontSelectObject, dontSelectValue.key, response.results);
|
||||||
// Keep replacing $dontSelect clauses
|
// Keep replacing $dontSelect clauses
|
||||||
return this.replaceDontSelect();
|
return this.replaceDontSelect();
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user