public IObservable <IChangeSet <TObject, TKey> > Run() { return(Observable.Create <IChangeSet <TObject, TKey> >(observer => { var locker = new object(); var destination = new LockFreeObservableCache <TObject, TKey>(); var populator = Observable.Switch(_sources .Do(_ => { lock (locker) destination.Clear(); })) .Synchronize(locker) .PopulateInto(destination); return new CompositeDisposable(destination, populator, destination.Connect().SubscribeSafe(observer)); })); }
public IObservable <IChangeSet <TDestination, TLeftKey> > Run() { return(Observable.Create <IChangeSet <TDestination, TLeftKey> >(observer => { var locker = new object(); //create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); var rightCache = _right.Synchronize(locker).ChangeKey(_rightKeySelector).AsObservableCache(false); //joined is the final cache var joinedCache = new LockFreeObservableCache <TDestination, TLeftKey>(); var leftLoader = leftCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { changes.ForEach(change => { switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: //Update with left (and right if it is presents) var left = change.Current; var right = rightCache.Lookup(change.Key); innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); break; case ChangeReason.Remove: //remove from result because a left value is expected innerCache.Remove(change.Key); break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh(change.Key); break; } }); }); }); var rightLoader = rightCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { changes.ForEach(change => { var right = change.Current; var left = leftCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: { if (left.HasValue) { //Update with left and right value innerCache.AddOrUpdate(_resultSelector(change.Key, left.Value, right), change.Key); } else { //remove if it is already in the cache innerCache.Remove(change.Key); } } break; case ChangeReason.Remove: { if (left.HasValue) { //Update with no right value innerCache.AddOrUpdate( _resultSelector(change.Key, left.Value, Optional <TRight> .None), change.Key); } else { //remove if it is already in the cache innerCache.Remove(change.Key); } } break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh(change.Key); break; } }); }); }); return new CompositeDisposable( joinedCache.Connect().NotEmpty().SubscribeSafe(observer), leftCache, rightCache, leftLoader, joinedCache, rightLoader); })); }
public IObservable <IChangeSet <TDestination, TLeftKey> > Run() { return(Observable.Create <IChangeSet <TDestination, TLeftKey> >(observer => { var locker = new object(); //create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); var rightCache = _right.Synchronize(locker).ChangeKey(_rightKeySelector).AsObservableCache(false); //joined is the final cache var joinedCache = new LockFreeObservableCache <TDestination, TLeftKey>(); var leftLoader = leftCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { changes.ForEach(change => { var left = change.Current; var right = rightCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: { if (right.HasValue) { innerCache.AddOrUpdate(_resultSelector(change.Key, left, right.Value), change.Key); } else { innerCache.Remove((TLeftKey)change.Key); } break; } case ChangeReason.Remove: innerCache.Remove((TLeftKey)change.Key); break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh((TLeftKey)change.Key); break; } }); }); }); var rightLoader = rightCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { changes.ForEach(change => { var right = change.Current; var left = leftCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: { if (left.HasValue) { innerCache.AddOrUpdate(_resultSelector(change.Key, left.Value, right), change.Key); } else { innerCache.Remove(change.Key); } } break; case ChangeReason.Remove: { innerCache.Remove(change.Key);; } break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh(change.Key); break; } }); }); }); return new CompositeDisposable( joinedCache.Connect().NotEmpty().SubscribeSafe(observer), leftCache, rightCache, leftLoader, rightLoader, joinedCache); })); }