From 69d5a2f87cc3f8cbf5ac00d3030d712388b70716 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Sat, 21 May 2016 19:51:06 -0700 Subject: [PATCH 01/25] Make find() in MongoStorageAdapter --- src/Adapters/Storage/Mongo/MongoCollection.js | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoCollection.js b/src/Adapters/Storage/Mongo/MongoCollection.js index bf41582b19..e309281884 100644 --- a/src/Adapters/Storage/Mongo/MongoCollection.js +++ b/src/Adapters/Storage/Mongo/MongoCollection.js @@ -1,5 +1,6 @@ let mongodb = require('mongodb'); let Collection = mongodb.Collection; +import * as transform from './MongoTransform'; export default class MongoCollection { _mongoCollection:Collection; @@ -13,25 +14,28 @@ export default class MongoCollection { // none, then build the geoindex. // This could be improved a lot but it's not clear if that's a good // idea. Or even if this behavior is a good idea. + + // Depends on the className and schemaController because mongoObjectToParseObject does. + // TODO: break this dependency find(query, { skip, limit, sort } = {}) { return this._rawFind(query, { skip, limit, sort }) - .catch(error => { - // Check for "no geoindex" error - if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) { - throw error; - } - // Figure out what key needs an index - let key = error.message.match(/field=([A-Za-z_0-9]+) /)[1]; - if (!key) { - throw error; - } + .catch(error => { + // Check for "no geoindex" error + if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) { + throw error; + } + // Figure out what key needs an index + let key = error.message.match(/field=([A-Za-z_0-9]+) /)[1]; + if (!key) { + throw error; + } - var index = {}; - index[key] = '2d'; - return this._mongoCollection.createIndex(index) - // Retry, but just once. - .then(() => this._rawFind(query, { skip, limit, sort })); - }); + var index = {}; + index[key] = '2d'; + return this._mongoCollection.createIndex(index) + // Retry, but just once. + .then(() => this._rawFind(query, { skip, limit, sort })); + }) } _rawFind(query, { skip, limit, sort } = {}) { From 9f149e6db5be402238803ac98142e63f09a75334 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Sat, 21 May 2016 20:57:31 -0700 Subject: [PATCH 02/25] Don't mess with inner object keys called _auth_data_* --- spec/ParseAPI.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index 80fe442c1f..cceb818f9d 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -1121,7 +1121,7 @@ describe('miscellaneous', function() { }) }); - it('does not change inner object key names _auth_data_something', done => { + it('does not change inner object keys named _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 => { From c928dcc118aa35a3c586bd71b3ba237f337b5a7c Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Sat, 21 May 2016 21:20:53 -0700 Subject: [PATCH 03/25] Prevent untransforming inner object keys named _p_* --- spec/ParseAPI.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index cceb818f9d..f8dcc05895 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -1170,4 +1170,6 @@ describe('miscellaneous', function() { done(); }); }); +======= +>>>>>>> Prevent untransforming inner object keys named _p_* }); From 74ee8613d83fde62d7c5890cca1e5fe6eb498ba4 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Sat, 21 May 2016 21:43:21 -0700 Subject: [PATCH 04/25] Fix inner keys named _rperm, _wperm --- spec/ParseAPI.spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index f8dcc05895..cceb818f9d 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -1170,6 +1170,4 @@ describe('miscellaneous', function() { done(); }); }); -======= ->>>>>>> Prevent untransforming inner object keys named _p_* }); From fe8160449cac0eec253715cbfe2b95c58d1d84af Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 11:54:54 -0700 Subject: [PATCH 05/25] Revert changes to find --- src/Adapters/Storage/Mongo/MongoCollection.js | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoCollection.js b/src/Adapters/Storage/Mongo/MongoCollection.js index e309281884..bf41582b19 100644 --- a/src/Adapters/Storage/Mongo/MongoCollection.js +++ b/src/Adapters/Storage/Mongo/MongoCollection.js @@ -1,6 +1,5 @@ let mongodb = require('mongodb'); let Collection = mongodb.Collection; -import * as transform from './MongoTransform'; export default class MongoCollection { _mongoCollection:Collection; @@ -14,28 +13,25 @@ export default class MongoCollection { // none, then build the geoindex. // This could be improved a lot but it's not clear if that's a good // idea. Or even if this behavior is a good idea. - - // Depends on the className and schemaController because mongoObjectToParseObject does. - // TODO: break this dependency find(query, { skip, limit, sort } = {}) { return this._rawFind(query, { skip, limit, sort }) - .catch(error => { - // Check for "no geoindex" error - if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) { - throw error; - } - // Figure out what key needs an index - let key = error.message.match(/field=([A-Za-z_0-9]+) /)[1]; - if (!key) { - throw error; - } + .catch(error => { + // Check for "no geoindex" error + if (error.code != 17007 && !error.message.match(/unable to find index for .geoNear/)) { + throw error; + } + // Figure out what key needs an index + let key = error.message.match(/field=([A-Za-z_0-9]+) /)[1]; + if (!key) { + throw error; + } - var index = {}; - index[key] = '2d'; - return this._mongoCollection.createIndex(index) - // Retry, but just once. - .then(() => this._rawFind(query, { skip, limit, sort })); - }) + var index = {}; + index[key] = '2d'; + return this._mongoCollection.createIndex(index) + // Retry, but just once. + .then(() => this._rawFind(query, { skip, limit, sort })); + }); } _rawFind(query, { skip, limit, sort } = {}) { From 474a893a227434e9dc97309b85cd10c3be54817c Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 15:54:12 -0700 Subject: [PATCH 06/25] Pass the Parse Schema into untransform --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- src/Adapters/Storage/Mongo/MongoTransform.js | 10 +++++----- src/Controllers/DatabaseController.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index b4e1f84eb1..65eca277c6 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -199,10 +199,10 @@ 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) { + find(className, query, { skip, limit, sort }, schemaController, schema) { return this.adaptiveCollection(className) .then(collection => collection.find(query, { skip, limit, sort })) - .then(objects => objects.map(object => transform.mongoObjectToParseObject(schemaController, className, object))); + .then(objects => objects.map(object => transform.mongoObjectToParseObject(schemaController, className, object, schema))); } get transform() { diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 3bb008f78a..7708ed3812 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -755,7 +755,7 @@ const nestedMongoObjectToNestedParseObject = mongoObject => { // 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) => { +const mongoObjectToParseObject = (schemaController, className, mongoObject, schema) => { switch(typeof mongoObject) { case 'string': case 'number': @@ -831,8 +831,8 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => { if (key.indexOf('_p_') == 0) { var newKey = key.substring(3); var expected; - if (schema && schema.getExpectedType) { - expected = schema.getExpectedType(className, newKey); + if (schemaController && schemaController.getExpectedType) { + expected = schemaController.getExpectedType(className, newKey); } if (!expected) { log.info('transform.js', @@ -861,7 +861,7 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => { } else if (key[0] == '_' && key != '__type') { throw ('bad key in untransform: ' + key); } else { - var expectedType = schema.getExpectedType(className, key); + var expectedType = schemaController.getExpectedType(className, key); var value = mongoObject[key]; if (expectedType && expectedType.type === 'File' && FileCoder.isValidDatabaseObject(value)) { restObject[key] = FileCoder.databaseToJSON(value); @@ -876,7 +876,7 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => { } } - return { ...restObject, ...schema.getRelationFields(className) }; + return { ...restObject, ...schemaController.getRelationFields(className) }; default: throw 'unknown js type'; } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 67240a9128..56edb8e02f 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -701,7 +701,7 @@ DatabaseController.prototype.find = function(className, query, { delete mongoOptions.limit; return collection.count(mongoWhere, mongoOptions); } else { - return this.adapter.find(className, mongoWhere, mongoOptions, schemaController) + return this.adapter.find(className, mongoWhere, mongoOptions, schemaController, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 00de555ecb0aa4e1cc95e020c96ae901fdcb39e6 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 16:21:35 -0700 Subject: [PATCH 07/25] remove one use of schemaController --- spec/MongoTransform.spec.js | 8 ++++++-- src/Adapters/Storage/Mongo/MongoTransform.js | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index ca142134f0..7d0aa45ee8 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -132,7 +132,9 @@ describe('mongoObjectToParseObject', () => { it('pointer', (done) => { var input = {_p_userPointer: '_User$123'}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { userPointer: { type: 'Pointer', targetClass: '_User' } }, + }); expect(typeof output.userPointer).toEqual('object'); expect(output.userPointer).toEqual( {__type: 'Pointer', className: '_User', objectId: '123'} @@ -142,7 +144,9 @@ describe('mongoObjectToParseObject', () => { it('null pointer', (done) => { var input = {_p_userPointer: null}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { userPointer: { type: 'Pointer', targetClass: '_User' } }, + }); expect(output.userPointer).toBeUndefined(); done(); }); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 7708ed3812..2af26933c4 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -834,7 +834,7 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche if (schemaController && schemaController.getExpectedType) { expected = schemaController.getExpectedType(className, newKey); } - if (!expected) { + if (!schema.fields[newKey]) { log.info('transform.js', 'Found a pointer column not in the schema, dropping it.', className, newKey); From a55b2b62093960ec77a1b79e94dd845197c33b3e Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 16:24:07 -0700 Subject: [PATCH 08/25] remove another use of schemaController --- src/Adapters/Storage/Mongo/MongoTransform.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 2af26933c4..0e289c0686 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -835,12 +835,10 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche expected = schemaController.getExpectedType(className, newKey); } if (!schema.fields[newKey]) { - log.info('transform.js', - 'Found a pointer column not in the schema, dropping it.', - className, newKey); + log.info('transform.js', 'Found a pointer column not in the schema, dropping it.', className, newKey); break; } - if (expected && expected.type !== 'Pointer') { + if (schema.fields[newKey].type !== 'Pointer') { log.info('transform.js', 'Found a pointer in a non-pointer column, dropping it.', className, key); break; } From d944255e4e6e7138662aea534dea077bd24c4c91 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 16:27:45 -0700 Subject: [PATCH 09/25] remove another use of schemaController --- src/Adapters/Storage/Mongo/MongoTransform.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 0e289c0686..f56a230080 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -846,8 +846,7 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche break; } var objData = mongoObject[key].split('$'); - var newClass = (expected ? expected.targetClass : objData[0]); - if (objData[0] !== newClass) { + if (objData[0] !== schema.fields[newKey].targetClass) { throw 'pointer to incorrect className'; } restObject[newKey] = { From f4b1f7b9513350d3e366cefba2a1f9060910558a Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 16:43:51 -0700 Subject: [PATCH 10/25] Remove all dependencies on schemaController --- spec/MongoTransform.spec.js | 23 +++++++++++++++----- src/Adapters/Storage/Mongo/MongoTransform.js | 9 ++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index 7d0aa45ee8..9a47def9cb 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -153,7 +153,9 @@ describe('mongoObjectToParseObject', () => { it('file', (done) => { var input = {picture: 'pic.jpg'}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { picture: { type: 'File' }}, + }); expect(typeof output.picture).toEqual('object'); expect(output.picture).toEqual({__type: 'File', name: 'pic.jpg'}); done(); @@ -161,7 +163,9 @@ describe('mongoObjectToParseObject', () => { it('geopoint', (done) => { var input = {location: [180, -180]}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { location: { type: 'GeoPoint' }}, + }); expect(typeof output.location).toEqual('object'); expect(output.location).toEqual( {__type: 'GeoPoint', longitude: 180, latitude: -180} @@ -171,7 +175,9 @@ describe('mongoObjectToParseObject', () => { it('nested array', (done) => { var input = {arr: [{_testKey: 'testValue' }]}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { arr: { type: 'Array' } }, + }); expect(Array.isArray(output.arr)).toEqual(true); expect(output.arr).toEqual([{ _testKey: 'testValue'}]); done(); @@ -189,7 +195,9 @@ describe('mongoObjectToParseObject', () => { }, regularKey: "some data", }]} - let output = transform.mongoObjectToParseObject(dummySchema, null, input); + let output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { array: { type: 'Array' }}, + }); expect(dd(output, input)).toEqual(undefined); done(); }); @@ -271,7 +279,12 @@ describe('transform schema key changes', () => { long: mongodb.Long.fromNumber(Number.MAX_SAFE_INTEGER), double: new mongodb.Double(Number.MAX_VALUE) } - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + fields: { + long: { type: 'Number' }, + double: { type: 'Number' }, + }, + }); expect(output.long).toBe(Number.MAX_SAFE_INTEGER); expect(output.double).toBe(Number.MAX_VALUE); done(); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index f56a230080..a5c7f41eaa 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -830,10 +830,6 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche if (key.indexOf('_p_') == 0) { var newKey = key.substring(3); - var expected; - if (schemaController && schemaController.getExpectedType) { - expected = schemaController.getExpectedType(className, newKey); - } if (!schema.fields[newKey]) { log.info('transform.js', 'Found a pointer column not in the schema, dropping it.', className, newKey); break; @@ -858,13 +854,12 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche } else if (key[0] == '_' && key != '__type') { throw ('bad key in untransform: ' + key); } else { - var expectedType = schemaController.getExpectedType(className, key); var value = mongoObject[key]; - if (expectedType && expectedType.type === 'File' && FileCoder.isValidDatabaseObject(value)) { + if (schema.fields[key] && schema.fields[key].type === 'File' && FileCoder.isValidDatabaseObject(value)) { restObject[key] = FileCoder.databaseToJSON(value); break; } - if (expectedType && expectedType.type === 'GeoPoint' && GeoPointCoder.isValidDatabaseObject(value)) { + if (schema.fields[key] && schema.fields[key].type === 'GeoPoint' && GeoPointCoder.isValidDatabaseObject(value)) { restObject[key] = GeoPointCoder.databaseToJSON(value); break; } From e440046be457dedfb7327c745b2f4cbded858755 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 17:01:47 -0700 Subject: [PATCH 11/25] Remove getRelationFields --- spec/MongoTransform.spec.js | 17 +++++++---------- src/Adapters/Storage/Mongo/MongoTransform.js | 11 ++++++++++- src/Controllers/SchemaController.js | 17 ----------------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index 9a47def9cb..d8136483be 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -17,9 +17,6 @@ var dummySchema = { } return; }, - getRelationFields: function() { - return {} - } }; @@ -39,7 +36,7 @@ describe('parseObjectToMongoObjectForCreate', () => { createdAt: "2015-10-06T21:24:50.332Z", updatedAt: "2015-10-06T21:24:50.332Z" }; - var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input); + var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input, { fields: {} }); expect(output._created_at instanceof Date).toBe(true); expect(output._updated_at instanceof Date).toBe(true); done(); @@ -62,14 +59,14 @@ describe('parseObjectToMongoObjectForCreate', () => { //have __op delete in a new object. Figure out what this should actually be testing. notWorking('a delete op', (done) => { var input = {deleteMe: {__op: 'Delete'}}; - var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input); + var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input, { fields: {} }); jequal(output, {}); done(); }); it('basic ACL', (done) => { var input = {ACL: {'0123': {'read': true, 'write': true}}}; - var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input); + var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input, { fields: {} }); // This just checks that it doesn't crash, but it should check format. done(); }); @@ -124,7 +121,7 @@ describe('transformWhere', () => { describe('mongoObjectToParseObject', () => { it('built-in timestamps', (done) => { var input = {createdAt: new Date(), updatedAt: new Date()}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { fields: {} }); expect(typeof output.createdAt).toEqual('string'); expect(typeof output.updatedAt).toEqual('string'); done(); @@ -236,7 +233,7 @@ describe('transform schema key changes', () => { "Kevin": { "write": true } } }; - var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input); + var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input, { fields: {} }); expect(typeof output._rperm).toEqual('object'); expect(typeof output._wperm).toEqual('object'); expect(output.ACL).toBeUndefined(); @@ -253,7 +250,7 @@ describe('transform schema key changes', () => { } }; - var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input); + var output = transform.parseObjectToMongoObjectForCreate(dummySchema, null, input, { fields: {} }); expect(typeof output._acl).toEqual('object'); expect(output._acl["Kevin"].w).toBeTruthy(); expect(output._acl["Kevin"].r).toBeUndefined(); @@ -265,7 +262,7 @@ describe('transform schema key changes', () => { _rperm: ["*"], _wperm: ["Kevin"] }; - var output = transform.mongoObjectToParseObject(dummySchema, null, input); + var output = transform.mongoObjectToParseObject(dummySchema, null, input, { fields: {} }); expect(typeof output.ACL).toEqual('object'); expect(output._rperm).toBeUndefined(); expect(output._wperm).toBeUndefined(); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index a5c7f41eaa..e335f3a02a 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -868,7 +868,16 @@ const mongoObjectToParseObject = (schemaController, className, mongoObject, sche } } - return { ...restObject, ...schemaController.getRelationFields(className) }; + const relationFieldNames = Object.keys(schema.fields).filter(fieldName => schema.fields[fieldName].type === 'Relation'); + let relationFields = {}; + relationFieldNames.forEach(relationFieldName => { + relationFields[relationFieldName] = { + __type: 'Relation', + className: schema.fields[relationFieldName].targetClass, + } + }); + + return { ...restObject, ...relationFields }; default: throw 'unknown js type'; } diff --git a/src/Controllers/SchemaController.js b/src/Controllers/SchemaController.js index b3fdc7bb77..f855021974 100644 --- a/src/Controllers/SchemaController.js +++ b/src/Controllers/SchemaController.js @@ -686,23 +686,6 @@ class SchemaController { hasClass(className) { return this.reloadData().then(() => !!(this.data[className])); } - - getRelationFields(className) { - if (this.data && this.data[className]) { - let classData = this.data[className]; - return Object.keys(classData).filter((field) => { - return classData[field].type === 'Relation'; - }).reduce((memo, field) => { - let type = classData[field]; - memo[field] = { - __type: 'Relation', - className: type.targetClass - }; - return memo; - }, {}); - } - return {}; - } } // Returns a promise for a new Schema. From 7dca7e20b0781bd74525849e1e1eb38c56c7189d Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 17:18:46 -0700 Subject: [PATCH 12/25] Remove schemaController parameter --- spec/MongoTransform.spec.js | 18 +++++++++--------- .../Storage/Mongo/MongoStorageAdapter.js | 2 +- src/Adapters/Storage/Mongo/MongoTransform.js | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index d8136483be..f667a2eee4 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -121,7 +121,7 @@ describe('transformWhere', () => { describe('mongoObjectToParseObject', () => { it('built-in timestamps', (done) => { var input = {createdAt: new Date(), updatedAt: new Date()}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { fields: {} }); + var output = transform.mongoObjectToParseObject(null, input, { fields: {} }); expect(typeof output.createdAt).toEqual('string'); expect(typeof output.updatedAt).toEqual('string'); done(); @@ -129,7 +129,7 @@ describe('mongoObjectToParseObject', () => { it('pointer', (done) => { var input = {_p_userPointer: '_User$123'}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { userPointer: { type: 'Pointer', targetClass: '_User' } }, }); expect(typeof output.userPointer).toEqual('object'); @@ -141,7 +141,7 @@ describe('mongoObjectToParseObject', () => { it('null pointer', (done) => { var input = {_p_userPointer: null}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { userPointer: { type: 'Pointer', targetClass: '_User' } }, }); expect(output.userPointer).toBeUndefined(); @@ -150,7 +150,7 @@ describe('mongoObjectToParseObject', () => { it('file', (done) => { var input = {picture: 'pic.jpg'}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { picture: { type: 'File' }}, }); expect(typeof output.picture).toEqual('object'); @@ -160,7 +160,7 @@ describe('mongoObjectToParseObject', () => { it('geopoint', (done) => { var input = {location: [180, -180]}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { location: { type: 'GeoPoint' }}, }); expect(typeof output.location).toEqual('object'); @@ -172,7 +172,7 @@ describe('mongoObjectToParseObject', () => { it('nested array', (done) => { var input = {arr: [{_testKey: 'testValue' }]}; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { arr: { type: 'Array' } }, }); expect(Array.isArray(output.arr)).toEqual(true); @@ -192,7 +192,7 @@ describe('mongoObjectToParseObject', () => { }, regularKey: "some data", }]} - let output = transform.mongoObjectToParseObject(dummySchema, null, input, { + let output = transform.mongoObjectToParseObject(null, input, { fields: { array: { type: 'Array' }}, }); expect(dd(output, input)).toEqual(undefined); @@ -262,7 +262,7 @@ describe('transform schema key changes', () => { _rperm: ["*"], _wperm: ["Kevin"] }; - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { fields: {} }); + var output = transform.mongoObjectToParseObject(null, input, { fields: {} }); expect(typeof output.ACL).toEqual('object'); expect(output._rperm).toBeUndefined(); expect(output._wperm).toBeUndefined(); @@ -276,7 +276,7 @@ describe('transform schema key changes', () => { long: mongodb.Long.fromNumber(Number.MAX_SAFE_INTEGER), double: new mongodb.Double(Number.MAX_VALUE) } - var output = transform.mongoObjectToParseObject(dummySchema, null, input, { + var output = transform.mongoObjectToParseObject(null, input, { fields: { long: { type: 'Number' }, double: { type: 'Number' }, diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 65eca277c6..0be09a2a7d 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -202,7 +202,7 @@ export class MongoStorageAdapter { find(className, query, { skip, limit, sort }, schemaController, schema) { return this.adaptiveCollection(className) .then(collection => collection.find(query, { skip, limit, sort })) - .then(objects => objects.map(object => transform.mongoObjectToParseObject(schemaController, className, object, schema))); + .then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema))); } get transform() { diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index e335f3a02a..5b7cc1e3d2 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -755,7 +755,7 @@ const nestedMongoObjectToNestedParseObject = mongoObject => { // Converts from a mongo-format object to a REST-format object. // Does not strip out anything based on a lack of authentication. -const mongoObjectToParseObject = (schemaController, className, mongoObject, schema) => { +const mongoObjectToParseObject = (className, mongoObject, schema) => { switch(typeof mongoObject) { case 'string': case 'number': From 405247082052f4dfbd5bdec82233804931774a7a Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 17:29:26 -0700 Subject: [PATCH 13/25] remove schemaController paramater --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 3 +-- src/Controllers/DatabaseController.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 0be09a2a7d..681729b394 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -198,8 +198,7 @@ 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, schema) { + find(className, query, { skip, limit, sort }, schema) { return this.adaptiveCollection(className) .then(collection => collection.find(query, { skip, limit, sort })) .then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema))); diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 56edb8e02f..8b88410b2c 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -701,7 +701,7 @@ DatabaseController.prototype.find = function(className, query, { delete mongoOptions.limit; return collection.count(mongoWhere, mongoOptions); } else { - return this.adapter.find(className, mongoWhere, mongoOptions, schemaController, schema) + return this.adapter.find(className, mongoWhere, mongoOptions, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 1ae1d42c32bb99faa339bd53dbfca8289a5e282e Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 17:39:07 -0700 Subject: [PATCH 14/25] transformWhere in MongoAdapter --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 3 ++- src/Controllers/DatabaseController.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 681729b394..5768262a09 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -199,8 +199,9 @@ export class MongoStorageAdapter { // Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }. find(className, query, { skip, limit, sort }, schema) { + let mongoWhere = this.transform.transformWhere(className, query, schema); return this.adaptiveCollection(className) - .then(collection => collection.find(query, { skip, limit, sort })) + .then(collection => collection.find(mongoWhere, { skip, limit, sort })) .then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema))); } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 8b88410b2c..db2276ff30 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -696,12 +696,12 @@ DatabaseController.prototype.find = function(className, query, { query = addReadACL(query, aclGroup); } validateQuery(query); - let mongoWhere = this.transform.transformWhere(className, query, schema); if (count) { + let mongoWhere = this.transform.transformWhere(className, query, schema); delete mongoOptions.limit; return collection.count(mongoWhere, mongoOptions); } else { - return this.adapter.find(className, mongoWhere, mongoOptions, schema) + return this.adapter.find(className, query, mongoOptions, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 14938bbe7a607e65da052d00e42c1e484cb7a358 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 19:00:58 -0700 Subject: [PATCH 15/25] create + use adapter count instead of collection count --- spec/InstallationsRouter.spec.js | 8 +++----- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 6 ++++++ src/Controllers/DatabaseController.js | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/InstallationsRouter.spec.js b/spec/InstallationsRouter.spec.js index 82416aa42f..2d7224a0d6 100644 --- a/spec/InstallationsRouter.spec.js +++ b/spec/InstallationsRouter.spec.js @@ -123,11 +123,9 @@ describe('InstallationsRouter', () => { var router = new InstallationsRouter(); rest.create(config, auth.nobody(config), '_Installation', androidDeviceRequest) - .then(() => { - return rest.create(config, auth.nobody(config), '_Installation', iosDeviceRequest); - }).then(() => { - return router.handleFind(request); - }).then((res) => { + .then(() => rest.create(config, auth.nobody(config), '_Installation', iosDeviceRequest)) + .then(() => router.handleFind(request)) + .then((res) => { var response = res.response; expect(response.results.length).toEqual(2); expect(response.count).toEqual(2); diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 5768262a09..2bec9895eb 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -205,6 +205,12 @@ export class MongoStorageAdapter { .then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema))); } + // Executs a count. + count(className, query, mongoOptions) { + return this.adaptiveCollection(className) + .then(collection => collection.count(query, mongoOptions)); + } + get transform() { return transform; } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index db2276ff30..c3f92b1f7e 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -699,7 +699,7 @@ DatabaseController.prototype.find = function(className, query, { if (count) { let mongoWhere = this.transform.transformWhere(className, query, schema); delete mongoOptions.limit; - return collection.count(mongoWhere, mongoOptions); + return this.adapter.count(className, mongoWhere, mongoOptions); } else { return this.adapter.find(className, query, mongoOptions, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); From cf0a4b246f5cf3e6fa4c515c557e1d0b43f77fc3 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:04:10 -0700 Subject: [PATCH 16/25] remove adaptive collection call --- src/Controllers/DatabaseController.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index c3f92b1f7e..e547c88395 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -679,8 +679,7 @@ DatabaseController.prototype.find = function(className, query, { return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op)) .then(() => this.reduceRelationKeys(className, query)) .then(() => this.reduceInRelation(className, query, schemaController)) - .then(() => this.adapter.adaptiveCollection(className)) - .then(collection => { + .then(() => { if (!isMaster) { query = this.addPointerPermissions(schemaController, className, op, query, aclGroup); } From c9be5a3aac541dc45196e0003bae818f1a3bb545 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:07:16 -0700 Subject: [PATCH 17/25] Destructure mongo options --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 2bec9895eb..fc3763c597 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -206,9 +206,9 @@ export class MongoStorageAdapter { } // Executs a count. - count(className, query, mongoOptions) { + count(className, query, { limit, skip, sort }) { return this.adaptiveCollection(className) - .then(collection => collection.count(query, mongoOptions)); + .then(collection => collection.count(query, { limit, skip, sort })); } get transform() { From aa072dabfff0bbee4929f3713d349370e3feeb51 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:09:59 -0700 Subject: [PATCH 18/25] Remove limit from count --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index fc3763c597..cf944ecdb3 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -206,9 +206,9 @@ export class MongoStorageAdapter { } // Executs a count. - count(className, query, { limit, skip, sort }) { + count(className, query, { skip, sort }) { return this.adaptiveCollection(className) - .then(collection => collection.count(query, { limit, skip, sort })); + .then(collection => collection.count(query, { skip, sort })); } get transform() { From e444ca8425c6fc85b980f75692aede3637051f28 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:12:03 -0700 Subject: [PATCH 19/25] Can't sort a count --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index cf944ecdb3..2cbe4fed24 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -206,9 +206,9 @@ export class MongoStorageAdapter { } // Executs a count. - count(className, query, { skip, sort }) { + count(className, query, { skip }) { return this.adaptiveCollection(className) - .then(collection => collection.count(query, { skip, sort })); + .then(collection => collection.count(query, { skip })); } get transform() { From 135b0e0254bd7323bc1d27331fadaa86f46cd951 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:15:51 -0700 Subject: [PATCH 20/25] Remove options from count --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- src/Controllers/DatabaseController.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 2cbe4fed24..52573f8b22 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -206,9 +206,9 @@ export class MongoStorageAdapter { } // Executs a count. - count(className, query, { skip }) { + count(className, query) { return this.adaptiveCollection(className) - .then(collection => collection.count(query, { skip })); + .then(collection => collection.count(query)); } get transform() { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index e547c88395..2c6e82eb90 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -697,8 +697,7 @@ DatabaseController.prototype.find = function(className, query, { validateQuery(query); if (count) { let mongoWhere = this.transform.transformWhere(className, query, schema); - delete mongoOptions.limit; - return this.adapter.count(className, mongoWhere, mongoOptions); + return this.adapter.count(className, mongoWhere); } else { return this.adapter.find(className, query, mongoOptions, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); From a763f7c2fc31f887a1336a30e3216344d7fed1d1 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:19:03 -0700 Subject: [PATCH 21/25] move transformWhere into mongo adapter --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 4 ++-- src/Controllers/DatabaseController.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 52573f8b22..cf3a99b10c 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -206,9 +206,9 @@ export class MongoStorageAdapter { } // Executs a count. - count(className, query) { + count(className, query, schema) { return this.adaptiveCollection(className) - .then(collection => collection.count(query)); + .then(collection => collection.count(transform.transformWhere(className, query, schema))); } get transform() { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 2c6e82eb90..4de6a21183 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -696,8 +696,7 @@ DatabaseController.prototype.find = function(className, query, { } validateQuery(query); if (count) { - let mongoWhere = this.transform.transformWhere(className, query, schema); - return this.adapter.count(className, mongoWhere); + return this.adapter.count(className, query, schema); } else { return this.adapter.find(className, query, mongoOptions, schema) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); From d428041a8304b76059994cd2f1983761022683c5 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:22:04 -0700 Subject: [PATCH 22/25] Consistent parameter order --- src/Adapters/Storage/Mongo/MongoStorageAdapter.js | 2 +- src/Controllers/DatabaseController.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index cf3a99b10c..9e0637dc9a 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -198,7 +198,7 @@ export class MongoStorageAdapter { } // Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }. - find(className, query, { skip, limit, sort }, schema) { + find(className, query, schema, { skip, limit, sort }) { let mongoWhere = this.transform.transformWhere(className, query, schema); return this.adaptiveCollection(className) .then(collection => collection.find(mongoWhere, { skip, limit, sort })) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 4de6a21183..582021051b 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -698,7 +698,7 @@ DatabaseController.prototype.find = function(className, query, { if (count) { return this.adapter.count(className, query, schema); } else { - return this.adapter.find(className, query, mongoOptions, schema) + return this.adapter.find(className, query, schema, mongoOptions) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 05ae010b91e04988fe87522115c2158238e85b67 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 20:28:12 -0700 Subject: [PATCH 23/25] Kill mongoOptions --- src/Controllers/DatabaseController.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 582021051b..ae80da3d8a 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -631,13 +631,6 @@ DatabaseController.prototype.find = function(className, query, { sort, count, } = {}) { - let mongoOptions = {}; - if (skip) { - mongoOptions.skip = skip; - } - if (limit) { - mongoOptions.limit = limit; - } let isMaster = acl === undefined; let aclGroup = acl || []; let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find'; @@ -653,8 +646,8 @@ DatabaseController.prototype.find = function(className, query, { throw error; }) .then(schema => { + const transformedSort = {}; if (sort) { - mongoOptions.sort = {}; for (let fieldName in sort) { // Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt, // so duplicate that behaviour here. @@ -673,7 +666,7 @@ DatabaseController.prototype.find = function(className, query, { throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`); } const mongoKey = this.transform.transformKey(className, fieldName, schema); - mongoOptions.sort[mongoKey] = sort[fieldName]; + transformedSort[mongoKey] = sort[fieldName]; } } return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op)) @@ -698,7 +691,7 @@ DatabaseController.prototype.find = function(className, query, { if (count) { return this.adapter.count(className, query, schema); } else { - return this.adapter.find(className, query, schema, mongoOptions) + return this.adapter.find(className, query, schema, { skip, limit, sort: transformedSort }) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 3ed3c7b62ff65b2ae2455a714b231c9cfac13d89 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Mon, 23 May 2016 21:16:03 -0700 Subject: [PATCH 24/25] Move more mongo specific stuff into mongo adapter --- .../Storage/Mongo/MongoStorageAdapter.js | 3 +- src/Controllers/DatabaseController.js | 44 +++++++++---------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js index 9e0637dc9a..c9bb6d6706 100644 --- a/src/Adapters/Storage/Mongo/MongoStorageAdapter.js +++ b/src/Adapters/Storage/Mongo/MongoStorageAdapter.js @@ -200,8 +200,9 @@ export class MongoStorageAdapter { // Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }. find(className, query, schema, { skip, limit, sort }) { let mongoWhere = this.transform.transformWhere(className, query, schema); + let mongoSort = _.mapKeys(sort, (value, fieldName) => transform.transformKey(className, fieldName, schema)); return this.adaptiveCollection(className) - .then(collection => collection.find(mongoWhere, { skip, limit, sort })) + .then(collection => collection.find(mongoWhere, { skip, limit, sort: mongoSort })) .then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema))); } diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index ae80da3d8a..05fab5bbc8 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -628,7 +628,7 @@ DatabaseController.prototype.find = function(className, query, { skip, limit, acl, - sort, + sort = {}, count, } = {}) { let isMaster = acl === undefined; @@ -646,29 +646,25 @@ DatabaseController.prototype.find = function(className, query, { throw error; }) .then(schema => { - const transformedSort = {}; - if (sort) { - for (let fieldName in sort) { - // Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt, - // so duplicate that behaviour here. - if (fieldName === '_created_at') { - fieldName = 'createdAt'; - sort['createdAt'] = sort['_created_at']; - } else if (fieldName === '_updated_at') { - fieldName = 'updatedAt'; - sort['updatedAt'] = sort['_updated_at']; - } - - if (!SchemaController.fieldNameIsValid(fieldName)) { - throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`); - } - if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) { - throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`); - } - const mongoKey = this.transform.transformKey(className, fieldName, schema); - transformedSort[mongoKey] = sort[fieldName]; - } + // Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt, + // so duplicate that behaviour here. If both are specified, the corrent behaviour to match Parse.com is to + // use the one that appears first in the sort list. + if (sort && sort._created_at) { + sort.createdAt = sort._created_at; + delete sort._created_at; } + if (sort && sort._updated_at) { + sort.updatedAt = sort._updated_at; + delete sort._updated_at; + } + Object.keys(sort).forEach(fieldName => { + if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) { + throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`); + } + if (!SchemaController.fieldNameIsValid(fieldName)) { + throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`); + } + }); return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op)) .then(() => this.reduceRelationKeys(className, query)) .then(() => this.reduceInRelation(className, query, schemaController)) @@ -691,7 +687,7 @@ DatabaseController.prototype.find = function(className, query, { if (count) { return this.adapter.count(className, query, schema); } else { - return this.adapter.find(className, query, schema, { skip, limit, sort: transformedSort }) + return this.adapter.find(className, query, schema, { skip, limit, sort }) .then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object))); } }); From 0896f338243cb6895738623c6a5b8832eacc754f Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Tue, 24 May 2016 16:30:43 -0700 Subject: [PATCH 25/25] Remove unnecessary null check --- src/Controllers/DatabaseController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 05fab5bbc8..76fc5589cc 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -649,11 +649,11 @@ DatabaseController.prototype.find = function(className, query, { // Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt, // so duplicate that behaviour here. If both are specified, the corrent behaviour to match Parse.com is to // use the one that appears first in the sort list. - if (sort && sort._created_at) { + if (sort._created_at) { sort.createdAt = sort._created_at; delete sort._created_at; } - if (sort && sort._updated_at) { + if (sort._updated_at) { sort.updatedAt = sort._updated_at; delete sort._updated_at; }