diff --git a/README.md b/README.md index 0a4d2a4..a94ac32 100644 --- a/README.md +++ b/README.md @@ -394,6 +394,18 @@ var user = { var result = u({ user: u.omit(['authToken', 'SSN']) }, user); expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123' } }); + +### `u.omitted` + +A property updated to this constant will be removed from the final object. +Useful when one wishes to remove and update properties in a single operation. + +```js +var user = { email: 'john@aol.com', username: 'john123', authToken: '1211..' }; + +var result = u({ authToken: u.omitted, active: true }, user); + +expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123', active: true } }); ``` ### `u.omitBy(predicate(, object))` @@ -414,6 +426,7 @@ function isSensitive(value, key) { return key == 'SSN' } var result = u({ user: u.omitBy(isSensitive) }, user); expect(result).to.eql({ user: { email: 'john@aol.com', username: 'john123', authToken: '1211..' } }); + ``` ### `u.reject(predicate(, object))` diff --git a/lib/index.js b/lib/index.js index e2a34db..f2502cd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,7 +7,7 @@ import map from './map' import omit from './omit' import omitBy from './omitBy' import reject from './reject' -import update from './update' +import update, { omitted } from './update' import updateIn from './updateIn' import withDefault from './withDefault' import { _ } from './util/curry' @@ -26,6 +26,7 @@ u.omitBy = omitBy u.reject = reject u.update = update u.updateIn = updateIn +u.omitted = omitted u.withDefault = withDefault module.exports = u diff --git a/lib/update.js b/lib/update.js index 188aa09..fb40cd9 100644 --- a/lib/update.js +++ b/lib/update.js @@ -1,5 +1,11 @@ import isPlainObject from 'lodash/isPlainObject' +import _omitBy from 'lodash/omitBy' + import wrap from './wrap' +import constant from './constant' + +const innerOmitted = { __omitted: true } +export const omitted = constant(innerOmitted) function isEmpty(object) { return !Object.keys(object).length @@ -84,10 +90,15 @@ function update(updates, object, ...args) { } if (Array.isArray(defaultedObject)) { - return updateArray(resolvedUpdates, defaultedObject) + return updateArray(resolvedUpdates, defaultedObject).filter( + value => value !== innerOmitted + ) } - return { ...defaultedObject, ...resolvedUpdates } + return _omitBy( + { ...defaultedObject, ...resolvedUpdates }, + value => value === innerOmitted + ) } export default wrap(update, 2) diff --git a/test/updeep-spec.js b/test/updeep-spec.js index 2bab9fb..ce21320 100644 --- a/test/updeep-spec.js +++ b/test/updeep-spec.js @@ -142,4 +142,33 @@ describe('updeep', () => { const result = u({ created: date }, {}) expect(result).to.eql({ created: date }) }) + + const expectU = (update, orig, expected) => + expect(update(orig)).to.eql(expected) + + describe('u.omitted', () => { + it('omit properties via u.omitted', () => { + expectU(u({ a: u.omitted, b: i => i + 1 }), { a: 1, b: 2 }, { b: 3 }) + }) + + it('omit array and object properties', () => { + expectU( + u({ a: u.omitted, b: 'stuff', c: u.omitted }), + { a: [1, 2, 3], b: 'orig', c: { z: 'bar' } }, + { b: 'stuff' } + ) + }) + + it('deep omit', () => { + expectU( + u({ a: { b: u.omitted, c: 'stuff' } }), + { a: { b: 'foo', z: 'bar' } }, + { a: { z: 'bar', c: 'stuff' } } + ) + }) + + it('omitting an array item filters it out', () => { + expectU(u({ 1: u.omitted }), ['a', 'b', 'c'], ['a', 'c']) + }) + }) })