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); var publisher = destination.Connect().SubscribeSafe(observer); return new CompositeDisposable(destination, populator, publisher); })); }
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 rightLoader = rightCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { foreach (var change in changes.ToConcreteType()) { switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: //Update with right (and right if it is presents) var right = change.Current; var left = leftCache.Lookup(change.Key); innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); break; case ChangeReason.Remove: //remove from result because a right value is expected innerCache.Remove(change.Key); break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh(change.Key); break; } } }); }); var leftLoader = leftCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { foreach (var change in changes.ToConcreteType()) { TLeft left = change.Current; Optional <TRight> right = rightCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: { if (right.HasValue) { //Update with left and right value innerCache.AddOrUpdate(_resultSelector(change.Key, left, right.Value), change.Key); } else { //There is no right so remove if already in the cache innerCache.Remove(change.Key); } } break; case ChangeReason.Remove: { if (right.HasValue) { //Update with no left value innerCache.AddOrUpdate(_resultSelector(change.Key, Optional <TLeft> .None, right.Value), 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, rightLoader, joinedCache, leftLoader); })); }
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(); var rightCache = _right.Synchronize(locker).ChangeKey(_rightKeySelector).AsObservableCache(); //joined is the final cache var joinedCache = new LockFreeObservableCache <TDestination, TLeftKey>(); var leftLoader = leftCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { foreach (var change in changes.ToConcreteType()) { 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(change.Key); } break; } case ChangeReason.Remove: innerCache.Remove(change.Key); break; case ChangeReason.Refresh: //propagate upstream innerCache.Refresh(change.Key); break; } } }); }); var rightLoader = rightCache.Connect() .Subscribe(changes => { joinedCache.Edit(innerCache => { foreach (var change in changes.ToConcreteType()) { 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); })); }
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: innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); break; case ChangeReason.Remove: if (!right.HasValue) { //remove from result because there is no left and no rights innerCache.Remove(change.Key); } else { //update with no left value innerCache.AddOrUpdate(_resultSelector(change.Key, Optional <TLeft> .None, right), change.Key); } break; case ChangeReason.Evaluate: //propagate upstream innerCache.Evaluate(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: { innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); } break; case ChangeReason.Remove: { if (!left.HasValue) { //remove from result because there is no left and no rights innerCache.Remove(change.Key); } else { //update with no right value innerCache.AddOrUpdate(_resultSelector(change.Key, left, Optional <TRight> .None), change.Key); } } break; case ChangeReason.Evaluate: //propagate upstream innerCache.Evaluate(change.Key); break; } }); }); }); return new CompositeDisposable( joinedCache.Connect().NotEmpty().SubscribeSafe(observer), leftCache, rightCache, leftLoader, joinedCache, rightLoader); })); }