From 83a0d7b6857f1145bb01bb67e834929225e42e29 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Wed, 7 Feb 2018 05:16:54 -0800 Subject: [PATCH] Fix "undefined property '__op'" in postgres update (#4541) * Fix "undefined property '__op'" in postgres update This causes a TypeError which becomes a regular Error, before the update can be issued. (I think) This happens when there is an object schema, and there is also an unrelated field in originalUpdate which is null or undefined. e.g. when 'location' is a mandatory object in postgres, and 'middleName' is an optional string, PostgresStorageAdapter would throw when a query similar to the below was performed: (Object.keys(originalUpdate) would include "middleName" as a value of `k`) query.set('location', {'country': 'US'}) query.set('middleName', undefined); * Fix lint error --- .../Storage/Postgres/PostgresStorageAdapter.js | 11 ++++++++--- src/Routers/UsersRouter.js | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js index 90614751..9b76379c 100644 --- a/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js +++ b/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js @@ -1200,7 +1200,11 @@ export class PostgresStorageAdapter implements StorageAdapter { // Gather keys to increment const keysToIncrement = Object.keys(originalUpdate).filter(k => { // choose top level fields that have a delete operation set - return originalUpdate[k].__op === 'Increment' && k.split('.').length === 2 && k.split(".")[0] === fieldName; + // Note that Object.keys is iterating over the **original** update object + // and that some of the keys of the original update could be null or undefined: + // (See the above check `if (fieldValue === null || typeof fieldValue == "undefined")`) + const value = originalUpdate[k]; + return value && value.__op === 'Increment' && k.split('.').length === 2 && k.split(".")[0] === fieldName; }).map(k => k.split('.')[1]); let incrementPatterns = ''; @@ -1216,8 +1220,9 @@ export class PostgresStorageAdapter implements StorageAdapter { } const keysToDelete = Object.keys(originalUpdate).filter(k => { - // choose top level fields that have a delete operation set - return originalUpdate[k].__op === 'Delete' && k.split('.').length === 2 && k.split(".")[0] === fieldName; + // choose top level fields that have a delete operation set. + const value = originalUpdate[k]; + return value && value.__op === 'Delete' && k.split('.').length === 2 && k.split(".")[0] === fieldName; }).map(k => k.split('.')[1]); const deletePatterns = keysToDelete.reduce((p, c, i) => { diff --git a/src/Routers/UsersRouter.js b/src/Routers/UsersRouter.js index 0863f991..9f671bd3 100644 --- a/src/Routers/UsersRouter.js +++ b/src/Routers/UsersRouter.js @@ -268,7 +268,7 @@ export class UsersRouter extends ClassesRouter { throw new Parse.Error(Parse.Error.EMAIL_NOT_FOUND, `No user found with email ${email}`); } const user = results[0]; - + // remove password field, messes with saving on postgres delete user.password;