Skip to content

Commit

Permalink
Add mergeDeep method to State type
Browse files Browse the repository at this point in the history
  • Loading branch information
JaapRood committed May 2, 2018
1 parent 2275208 commit 0e128c4
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,32 @@ const Props = require('./props')

const internals = {}

exports.create = function(identity, factory) {
exports.create = function(identity, factory, schema={}) {
return {
merge: internals.merge.bind(_assign({}, identity, factory))
merge: internals.merge.bind(_assign({}, identity, factory)),
mergeDeep: internals.mergeDeep.bind(_assign({}, identity, factory, schema))
}
}

internals.merge = function(state, data) {
Invariant(this.instanceOf(state), `Instance of ${this.typeName()} is required to merge it with new attributes`)
Invariant(Immutable.Iterable.isIterable(data) || _isPlainObject(data), 'Plain object or Immutable Iterable required as source to merge with the state instance')

return state.merge(internals.mergableInstance.call(this, data));
}

internals.mergeDeep = function(state, data) {
Invariant(this.instanceOf(state), `Instance of ${this.typeName()} is required to merge deep it with new attributes`)
Invariant(Immutable.Iterable.isIterable(data) || _isPlainObject(data), 'Plain object or Immutable Iterable required as source to merge deep with the state instance')

return state.mergeDeep(internals.mergableInstance.call(this, data));
}

internals.mergableInstance = function(data) {
if (!this.instanceOf(data)) {
let dataKeys = Immutable.Seq(Immutable.Iterable.isIterable(data) ? data.keys() : _keys(data))
data = this.factory(data).filter((val, key) => dataKeys.includes(key))
}

return state.merge(data.remove(Props.cid).remove(Props.name));
return data.remove(Props.cid).remove(Props.name)
}
58 changes: 58 additions & 0 deletions test/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,61 @@ Test('state.merge', function(t) {
t.ok(TestState.instanceOf(mergedInstance), 'returns an updated instance of the type of the base')
}, 'accepts a base and source instance with a different state type')
})

Test('state.mergeDeep', function(t) {
t.plan(3 + 4 + 2 + 2)

const rawDefaults = {
c: 1
}

const TestState = State.create('test-state', rawDefaults)
const OtherState = State.create('other-state', rawDefaults)

const baseInstance = TestState.factory({
a: 1,
c: 3,
d: {
e: 5
}
})

const rawSource = {
a: 2,
b: 3,
d: {
f: 6
}
}

const sourceInstance = TestState.factory(rawSource)
const otherInstance = OtherState.factory(rawSource)

t.doesNotThrow(function() {
const mergedInstance = TestState.mergeDeep(baseInstance, rawSource)

t.ok(TestState.instanceOf(mergedInstance), 'returns an updated instance')
t.ok(mergedInstance.equals(baseInstance.mergeDeep(rawSource)), 'updated instance has attributes of source deep merged into instance')
}, 'accepts a State instance and a plain object of new attributes')

t.doesNotThrow(function() {
const mergedInstance = TestState.mergeDeep(baseInstance, sourceInstance)

t.ok(TestState.instanceOf(mergedInstance), 'returns an updated instance')
t.ok(mergedInstance.equals(baseInstance.mergeDeep(rawDefaults, rawSource)), 'updated instance has attributes of source deep merged into base')
t.equals(mergedInstance.get('__cid'), baseInstance.get('__cid'), 'updated instance has client identifer `__cid` from base')
}, 'accepts two State instances, a base and source')

t.doesNotThrow(function() {
const withContext = TestState.mergeDeep(baseInstance, sourceInstance)
const withoutContext = TestState.mergeDeep.call(null, baseInstance, sourceInstance)

t.ok(withContext.equals(withoutContext), 'returns the same when called out of context')
}, 'can be called without context')

t.doesNotThrow(function() {
const mergedInstance = TestState.mergeDeep(baseInstance, otherInstance)

t.ok(TestState.instanceOf(mergedInstance), 'returns an updated instance of the type of the base')
}, 'accepts a base and source instance with a different state type')
})

0 comments on commit 0e128c4

Please sign in to comment.