From 44ab4f5864f6a40cd41ff46cff3b7a8dc01658e8 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Mon, 9 Oct 2017 18:27:19 -0700 Subject: [PATCH] Allow intermediate null value in getIn path. Fixes #1361 Closes #1362 --- __tests__/getIn.ts | 47 ++++++++++++++++++++++++++----------------- src/CollectionImpl.js | 4 ++++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/__tests__/getIn.ts b/__tests__/getIn.ts index ffb64401ef..86784a51ff 100644 --- a/__tests__/getIn.ts +++ b/__tests__/getIn.ts @@ -34,31 +34,34 @@ describe('getIn', () => { ).toThrow('Invalid keyPath: expected Ordered Collection or Array: abc'); }); - it('deep get throws if non-readable path', () => { + function withWarnings(fn) { const realWarn = console.warn; const warnings: Array = []; console.warn = w => warnings.push(w); - try { - const deep = Map({ key: { regular: "jsobj" }, list: List([ Map({num: 10}) ]) }); - deep.getIn(["key", "foo", "item"]); - expect(warnings.length).toBe(1); - expect(warnings[0]).toBe( - 'Invalid keyPath: Value at ["key"] does not have a .get() method: [object Object]' + - '\nThis warning will throw in a future version', - ); - - warnings.length = 0; - deep.getIn(["list", 0, "num", "badKey"]); - expect(warnings.length).toBe(1); - expect(warnings[0]).toBe( - 'Invalid keyPath: Value at ["list",0,"num"] does not have a .get() method: 10' + - '\nThis warning will throw in a future version', - ); + fn(warnings); } finally { console.warn = realWarn; } - }); + } + + it('deep get throws if non-readable path', withWarnings(warnings => { + const deep = Map({ key: { regular: "jsobj" }, list: List([ Map({num: 10}) ]) }); + deep.getIn(["key", "foo", "item"]); + expect(warnings.length).toBe(1); + expect(warnings[0]).toBe( + 'Invalid keyPath: Value at ["key"] does not have a .get() method: [object Object]' + + '\nThis warning will throw in a future version', + ); + + warnings.length = 0; + deep.getIn(["list", 0, "num", "badKey"]); + expect(warnings.length).toBe(1); + expect(warnings[0]).toBe( + 'Invalid keyPath: Value at ["list",0,"num"] does not have a .get() method: 10' + + '\nThis warning will throw in a future version', + ); + })); it('deep get returns not found if path does not match', () => { const m = fromJS({a: {b: {c: 10}}}); @@ -76,4 +79,12 @@ describe('getIn', () => { expect(m.getIn(['a', 'b', 'd'], 123)).toEqual(undefined); }); + it('deep get returns not found if path encounters null or undefined', withWarnings(warnings => { + const m = fromJS({a: {b: {c: null, d: undefined}}}); + expect(m.getIn(['a', 'b', 'c', 'x'])).toEqual(undefined); + expect(m.getIn(['a', 'b', 'd', 'x'])).toEqual(undefined); + expect(m.getIn(['a', 'b', 'c', 'x'], 123)).toEqual(123); + expect(m.getIn(['a', 'b', 'd', 'x'], 123)).toEqual(123); + expect(warnings.length).toBe(0); + })); }); diff --git a/src/CollectionImpl.js b/src/CollectionImpl.js index e7f3eefa1d..3a4e102c66 100644 --- a/src/CollectionImpl.js +++ b/src/CollectionImpl.js @@ -848,6 +848,10 @@ function getIn(value, notSetValue, searchKeyPath, reportBadKeyPath) { const keyPath = coerceKeyPath(searchKeyPath); let i = 0; while (i !== keyPath.length) { + // Intermediate null/undefined value along path + if (value == null) { + return notSetValue; + } if (!value || !value.get) { if (reportBadKeyPath) { warn(