From 5cabc73dcfa5daf3993942d92e8ba022c6c93939 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Thu, 7 Apr 2016 16:16:09 -0700 Subject: [PATCH 1/5] Fixes #1417 --- spec/transform.spec.js | 32 ++++++++++++++++------ src/transform.js | 61 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/spec/transform.spec.js b/spec/transform.spec.js index 4a47f3598f..d7cf263bbd 100644 --- a/spec/transform.spec.js +++ b/spec/transform.spec.js @@ -1,6 +1,8 @@ // These tests are unit tests designed to only test transform.js. +"use strict"; -var transform = require('../src/transform'); +let transform = require('../src/transform'); +let dd = require('deep-diff'); var dummySchema = { data: {}, @@ -150,14 +152,28 @@ describe('untransformObject', () => { done(); }); - it('nested array', (done) => { - var input = {arr: [{_testKey: 'testValue' }]}; - var output = transform.untransformObject(dummySchema, null, input); - expect(Array.isArray(output.arr)).toEqual(true); - expect(output.arr).toEqual([{ _testKey: 'testValue'}]); - done(); - }); + it('nested array', (done) => { + var input = {arr: [{_testKey: 'testValue' }]}; + var output = transform.untransformObject(dummySchema, null, input); + expect(Array.isArray(output.arr)).toEqual(true); + expect(output.arr).toEqual([{ _testKey: 'testValue'}]); + done(); + }); + it('untransforms objects containing nested special keys', done => { + let input = {array: [{ + _id: "Test ID", + _hashed_password: "I Don't know why you would name a key this, but if you do it should work", + _tombstone: { + _updated_at: "I'm sure people will nest keys like this", + _acl: 7, + _id: {} + }, + }]} + let output = transform.untransformObject(dummySchema, null, input); + expect(dd(output, input)).toEqual(undefined); + done(); + }); }); describe('transformKey', () => { diff --git a/src/transform.js b/src/transform.js index eba2ea16b5..30f525091f 100644 --- a/src/transform.js +++ b/src/transform.js @@ -630,10 +630,9 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals if (mongoObject === null) { return null; } - if (mongoObject instanceof Array) { - return mongoObject.map((o) => { - return untransformObject(schema, className, o, true); + return mongoObject.map(arrayEntry => { + return untransformObject(schema, className, arrayEntry, true); }); } @@ -647,31 +646,84 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals var restObject = untransformACL(mongoObject); for (var key in mongoObject) { + // TODO: This could use some cleanup. Default case handling still needs to happen for some nested keys. switch(key) { case '_id': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['objectId'] = '' + mongoObject[key]; break; case '_hashed_password': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['password'] = mongoObject[key]; break; case '_acl': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_email_verify_token': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_perishable_token': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_tombstone': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } break; case '_session_token': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['sessionToken'] = mongoObject[key]; break; case 'updatedAt': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_updated_at': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['updatedAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'createdAt': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_created_at': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['createdAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'expiresAt': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } case '_expiresAt': + if (isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + break; + } restObject['expiresAt'] = Parse._encode(new Date(mongoObject[key])); break; default: @@ -728,8 +780,7 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals break; } } - restObject[key] = untransformObject(schema, className, - mongoObject[key], true); + restObject[key] = untransformObject(schema, className, mongoObject[key], true); } } From 610313f047bc836d74d229297a8ead2460896aaf Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Thu, 7 Apr 2016 17:24:39 -0700 Subject: [PATCH 2/5] Cleanup --- src/transform.js | 75 +++++++++++++----------------------------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/src/transform.js b/src/transform.js index 30f525091f..fc39976fbd 100644 --- a/src/transform.js +++ b/src/transform.js @@ -1,4 +1,5 @@ import log from './logger'; +import _ from 'lodash'; var mongodb = require('mongodb'); var Parse = require('parse/node').Parse; @@ -149,8 +150,6 @@ export function transformKeyValue(schema, className, restKey, restValue, options throw 'There was a problem transforming an ACL.'; } - - // Handle arrays if (restValue instanceof Array) { if (options.query) { @@ -646,84 +645,50 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals var restObject = untransformACL(mongoObject); for (var key in mongoObject) { - // TODO: This could use some cleanup. Default case handling still needs to happen for some nested keys. + const specialKeys = [ + '_id', + '_hashed_password', + '_acl', + '_email_verify_token', + '_perishable_token', + '_tombstone', + '_session_token', + 'updatedAt', + '_updated_at', + 'createdAt', + '_created_at', + 'expiresAt', + '_expiresAt', + ]; + if (_.includes(specialKeys, key) && isNestedObject) { + restObject[key] = untransformObject(schema, className, mongoObject[key], true); + continue; + } switch(key) { case '_id': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['objectId'] = '' + mongoObject[key]; break; case '_hashed_password': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['password'] = mongoObject[key]; break; case '_acl': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_email_verify_token': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_perishable_token': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_tombstone': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } break; case '_session_token': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['sessionToken'] = mongoObject[key]; break; case 'updatedAt': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_updated_at': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['updatedAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'createdAt': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_created_at': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['createdAt'] = Parse._encode(new Date(mongoObject[key])).iso; break; case 'expiresAt': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } case '_expiresAt': - if (isNestedObject) { - restObject[key] = untransformObject(schema, className, mongoObject[key], true); - break; - } restObject['expiresAt'] = Parse._encode(new Date(mongoObject[key])); break; default: From 810eb8cf44d602ce6757724912c61f2ab3c3581b Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Thu, 7 Apr 2016 17:35:51 -0700 Subject: [PATCH 3/5] Perf improvement --- src/transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transform.js b/src/transform.js index fc39976fbd..c99e51301c 100644 --- a/src/transform.js +++ b/src/transform.js @@ -660,7 +660,7 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals 'expiresAt', '_expiresAt', ]; - if (_.includes(specialKeys, key) && isNestedObject) { + if (isNestedObject && _.includes(specialKeys, key)) { restObject[key] = untransformObject(schema, className, mongoObject[key], true); continue; } From dd98974041bdae1abcd6e41fedc98361f85f7ce2 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Thu, 7 Apr 2016 18:16:52 -0700 Subject: [PATCH 4/5] Hoist constant array --- src/transform.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/transform.js b/src/transform.js index c99e51301c..d3c14a7c8f 100644 --- a/src/transform.js +++ b/src/transform.js @@ -612,6 +612,21 @@ function transformUpdateOperator(operator, flatten) { } } +const specialKeysForUntransform = [ + '_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. @@ -645,22 +660,7 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals var restObject = untransformACL(mongoObject); for (var key in mongoObject) { - const specialKeys = [ - '_id', - '_hashed_password', - '_acl', - '_email_verify_token', - '_perishable_token', - '_tombstone', - '_session_token', - 'updatedAt', - '_updated_at', - 'createdAt', - '_created_at', - 'expiresAt', - '_expiresAt', - ]; - if (isNestedObject && _.includes(specialKeys, key)) { + if (isNestedObject && _.includes(specialKeysForUntransform, key)) { restObject[key] = untransformObject(schema, className, mongoObject[key], true); continue; } From 3959929d5eb176307897e2f435d4a5be9792456a Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Fri, 8 Apr 2016 15:29:55 -0700 Subject: [PATCH 5/5] Improve tests --- spec/transform.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/transform.spec.js b/spec/transform.spec.js index d7cf263bbd..58252b229f 100644 --- a/spec/transform.spec.js +++ b/spec/transform.spec.js @@ -167,8 +167,10 @@ describe('untransformObject', () => { _tombstone: { _updated_at: "I'm sure people will nest keys like this", _acl: 7, - _id: {} + _id: { someString: "str", someNumber: 7}, + regularKey: { moreContents: [1, 2, 3] }, }, + regularKey: "some data", }]} let output = transform.untransformObject(dummySchema, null, input); expect(dd(output, input)).toEqual(undefined);