Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upsert function and accompanying tests #2020

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ export { default as spreadPath } from './spreadPath';
export { default as flattenProp } from './flattenProp';
export { default as flattenPath } from './flattenPath';
export { default as unzipObjWith } from './unzipObjWith';
export { default as upsert } from './upsert';
export { default as zipObjWith } from './zipObjWith';
export { default as isPrototypeOf } from './isPrototypeOf';
// Relation
Expand Down
56 changes: 56 additions & 0 deletions src/upsert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { curry, cond, equals } from 'ramda';

/**
* Adds a value to a map if the map does not already have something at key otherwise updates an existing value at key.
*
* @func upsert
* @memberOf RA
* @category Object
* @since
* @sig k -> (() -> String) -> (() -> String) -> [k, v]
* @param {string} key The key at which to update or insert the value
* @param {Function} update The function to generate the value if key exists
* @param {Function} insert The function to generate the value if key does not exist
* @param {(Array|Object|Map)} collection The collection into which the value is inserted or updated
* @return {(Array|Object|Map)} The collection into which the value has been inserted or updated
* @see
* @example
*
* RA.upsert('key', () => 'new value', () => 'initial value', {});
* //=> {key: 'initial value'}
*/

const emplace = curry((_, key, update, insert, collection) => {
if (collection[key]) {
collection[key] = update();
} else {
collection[key] = insert();
}
return collection;
})

const emplaceMap = curry((_, key, update, insert, collection) => {
if (collection.get(key)) {
collection.set(key, update());
} else {
collection.set(key, insert());
}
return collection;
})

const polymorphicDispatch = cond([
[equals("[object Array]"), emplace],
[equals("[object Object]"), emplace],
[equals("[object Map]"), emplaceMap],
]);

const upsert = curry((key, update, insert, collection) =>
polymorphicDispatch(Object.prototype.toString.call(collection))(
key,
update,
insert,
collection
)
);

export default upsert;
19 changes: 19 additions & 0 deletions test/upsert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { assert } from 'chai';

import * as RA from '../src';

describe('upsert', function () {
console.log(RA.upsert)
it('should work on objects', function () {
assert.deepEqual(RA.upsert('key', () => 'new value', () => 'initial value', {}), {key: 'initial value'});
assert.deepEqual(RA.upsert('key', () => 'new value', () => 'initial value', {key: 'value'}), {key: 'new value'});
});
it('should work on arrays', function () {
assert.deepEqual(RA.upsert(1, () => 'new value', () => 'initial value', []), [, 'initial value']);
assert.deepEqual(RA.upsert(1, () => 'new value', () => 'initial value', ['first value', 'second vaue']), ['first value', 'new value']);
});
it('should work on maps', function () {
assert.deepEqual(RA.upsert('key', () => 'new value', () => 'initial value', new Map()), new Map([['key', 'initial value']]));
assert.deepEqual(RA.upsert('key', () => 'new value', () => 'initial value', new Map([['key', 'initial value']])), new Map([['key', 'new value']]));
});
});