Skip to content

Commit

Permalink
feat: Add "mergeAll" and "mergeBy". Update "merge" to allow curried call
Browse files Browse the repository at this point in the history
  • Loading branch information
andreidmt committed Sep 1, 2020
1 parent 1e1928d commit 8d4978a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export { isMatch } from "./is-match/is-match"
// Object
export { pick } from "./pick/pick"
export { pluck } from "./pluck/pluck"
export { merge } from "./merge/merge"
export { merge, mergeAll, mergeBy } from "./merge/merge"
export { keys } from "./keys/keys"
export { zipToObj } from "./zip-to-obj/zip-to-obj"

Expand Down
58 changes: 41 additions & 17 deletions src/merge/merge.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
import { is } from "../is/is"

const _merge = (fn, source) => {
let result = {}

for (let i = 0, length = source.length; i < length; i++) {
const sourceEntries = Object.entries(source[i])

if (is(fn)) {
result = fn(result, source[i])
} else {
for (
let j = 0, sourceEntriesLength = sourceEntries.length;
j < sourceEntriesLength;
j++
) {
const [key, value] = sourceEntries[j]

result[key] = value
}
}
}

return result
}

/**
* Combine from left to right, 2 or more objects into a new single one.
* Properties will be shallow copied. Those with the same name will be
Expand All @@ -14,26 +40,24 @@
* merge({a: "lorem"}, {b: "ipsum", c: 41}, {c: 42, b: undefined})
* // => { a: "lorem", b: "ipsum", c: 42 }
*/
const merge = (...sources) => {
const result = {}

for (let i = 0, length = sources.length; i < length; i++) {
const sourceEntries = Object.entries(sources[i])
export const merge = (...params) => {
// @signature (obj1) => (obj2)
if (params.length <= 1) {
return obj2 => _merge(null, [params[0], obj2])
}

for (
let j = 0, sourceEntriesLength = sourceEntries.length;
j < sourceEntriesLength;
j++
) {
const [key, value] = sourceEntries[j]
// @signature (obj1, obj2)
return _merge(null, ...params)
}

if (value !== undefined) {
result[key] = value
}
}
export const mergeBy = (...params) => {
// @signature (fn) => (source)
if (params.length <= 1) {
return source => _merge(params[0], source)
}

return result
// @signature (fn, source)
return _merge(...params)
}

export { merge }
export const mergeAll = source => _merge(null, source)
31 changes: 20 additions & 11 deletions src/merge/merge.test.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
import test from "tape"
import { merge } from ".."
import { merge, mergeAll, mergeBy } from ".."

test("merge", t => {
test("merge, mergeAll", t => {
const obj1 = { a: undefined }
const obj2 = { a: "lorem", b: "ipsum", c: 41 }
const obj3 = { c: 42, b: undefined }
const result = merge(obj1, obj2, obj3)

const resultAgain = merge(result, obj1, obj2, obj3)
t.deepEqual(
mergeBy((a, b) => ({ ...a, ...b }), [obj1, obj2, obj3]),
{ a: "lorem", b: undefined, c: 42 },
"mergeBy 3 objects - uncurried"
)

t.deepEqual(
result,
{ a: "lorem", b: "ipsum", c: 42 },
"3 objects should be merged into one"
mergeBy((a, b) => ({ ...a, ...b }))([obj1, obj2, obj3]),
{ a: "lorem", b: undefined, c: 42 },
"mergeBy 3 objects - curried"
)

t.deepEqual(result, resultAgain, "Idempotence")
t.deepEqual(
mergeAll([obj1, obj2, obj3]),
{ a: "lorem", b: undefined, c: 42 },
"mergeAll 3 objects - uncurried"
)

t.notEqual(result, obj1, "Imutability - first object")
t.notEqual(result, obj2, "Imutability - second object")
t.notEqual(result, obj3, "Imutability - third object")
t.deepEqual(
merge(obj1)(obj2),
{ a: "lorem", b: "ipsum", c: 41 },
"merge 2 objects - curried"
)

t.end()
})

0 comments on commit 8d4978a

Please sign in to comment.