Skip to content

Commit

Permalink
setting with compatible snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
rbellens committed Oct 6, 2020
1 parent 067883d commit 30c789a
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 2 deletions.
49 changes: 47 additions & 2 deletions lib/src/snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ abstract class Snapshot implements DeepImmutable {
///
/// Unmodified children and grandchildren are recycled. So, also their
/// conversions are reused.
///
/// [value] may either be a JSON-like object or a [Snapshot].
///
/// When the new value equals the old value, this Snapshot will be returned.
/// In case the [value] argument was a compatible (i.e. with same decoder)
/// [Snapshot], the cache of the argument will be merged into this snapshot.
///
/// When [value] is a compatible snapshot, value will be returned with the
/// cache of this snapshot merged.
Snapshot set(dynamic value);

/// Returns a snapshot with updated content at [path].
Expand Down Expand Up @@ -220,9 +229,45 @@ class _SnapshotImpl extends Snapshot {

@override
Snapshot set(newValue) {
if (newValue is Snapshot) {
// TODO recycle cache
if (newValue is _SnapshotImpl && _decoder == newValue._decoder) {
// the new value is a snapshot

if (DeepCollectionEquality().equals(value, newValue.value)) {
// content is identical: return this with cache from newValue

for (var k in newValue._childrenCache.keys) {
if (_childrenCache.containsKey(k)) {
_childrenCache[k] =
_childrenCache[k].set(newValue._childrenCache[k]);
} else {
_childrenCache[k] = newValue._childrenCache[k];
}
}

for (var t in newValue._decodingCache.keys) {
for (var f in newValue._decodingCache[t].keys) {
_decodingCache
.putIfAbsent(t, () => {})
.putIfAbsent(f, () => newValue._decodingCache[t][f]);
}
}
return this;
} else {
// we will return the new value with cache values from old value

for (var k in _childrenCache.keys) {
if (newValue._childrenCache.containsKey(k)) {
newValue._childrenCache[k] =
_childrenCache[k].set(newValue._childrenCache[k]);
} else {
newValue._childrenCache[k] = _childrenCache[k];
}
}

return newValue;
}
}

newValue = newValue is Snapshot ? newValue.as() : newValue;
var isEqual = DeepCollectionEquality().equals(value, newValue);
if (isEqual) return this;
Expand Down
59 changes: 59 additions & 0 deletions test/snapshot_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,65 @@ void main() {

expect(v.child('firstname').as(), 'John');
});

group('Setting with compatible snapshot', () {
var decoder = SnapshotDecoder.from(SnapshotDecoder.defaultDecoder)
..register<Snapshot, Address>((s) => Address(s))
..seal();
var json = {
'firstname': 'Jane',
'lastname': 'Doe',
'address1': {'street': 'Mainstreet', 'number': '1', 'city': 'London'},
'address2': {'street': 'Mainstreet', 'number': '1', 'city': 'London'},
'address3': {'street': 'Mainstreet', 'number': '1', 'city': 'London'},
};
test('Should return this when content unchanged', () {
var person = Snapshot.fromJson(json, decoder: decoder);
var address1Snap = person.child('address1');
var address1 = address1Snap.as<Address>();
var address3Snap = person.child('address3');

var newValue = Snapshot.fromJson(json, decoder: decoder);
newValue.child('address1').as<Address>();
var address2Snap = newValue.child('address2');
var address2 = address2Snap.as<Address>();
var address3 = newValue.child('address3').as<Address>();

var v = person.set(newValue);

expect(v, same(person));
expect(v.child('address1'), same(address1Snap));
expect(v.child('address1').as<Address>(), same(address1));
expect(v.child('address2'), same(address2Snap));
expect(v.child('address2').as<Address>(), same(address2));
expect(v.child('address3'), same(address3Snap));
expect(v.child('address3').as<Address>(), same(address3));
});

test('Should return other when content changed', () {
var person = Snapshot.fromJson(json, decoder: decoder);
var address1Snap = person.child('address1');
var address1 = address1Snap.as<Address>();
var address3Snap = person.child('address3');

var newValue =
Snapshot.fromJson(json..['firstname'] = 'John', decoder: decoder);
newValue.child('address1').as<Address>();
var address2Snap = newValue.child('address2');
var address2 = address2Snap.as<Address>();
var address3 = newValue.child('address3').as<Address>();

var v = person.set(newValue);

expect(v, same(newValue));
expect(v.child('address1'), same(address1Snap));
expect(v.child('address1').as<Address>(), same(address1));
expect(v.child('address2'), same(address2Snap));
expect(v.child('address2').as<Address>(), same(address2));
expect(v.child('address3'), same(address3Snap));
expect(v.child('address3').as<Address>(), same(address3));
});
});
});

group('Snapshot.setPath()', () {
Expand Down

0 comments on commit 30c789a

Please sign in to comment.