public void OnNext(DictionaryModification <TKey, TValue> value) { if (DictionaryModification <TKey, TValue> .Initialised == value) { _dictionary._subject.OnNext(DictionaryNotification.Initialised <TKey, TValue>()); } else { switch (value.Type) { case DictionaryModificationType.Upsert: Upsert(value); break; case DictionaryModificationType.Replace: Replace(value); break; case DictionaryModificationType.Remove: Remove(value); break; case DictionaryModificationType.Clear: Clear(); break; default: throw new ArgumentOutOfRangeException(); } } }
public IDisposable Subscribe(IObserver <DictionaryNotification <TKey, TValue> > observer) { var futureDisposable = new SingleAssignmentDisposable(); var scheduledWorkDisposable = _scheduler.Schedule(() => { if (_isDisposed) { futureDisposable.Disposable = Observable.Throw <DictionaryNotification <TKey, TValue> >( new ObjectDisposedException(this.GetType().Name)).Subscribe(observer); } if (_error != null) { futureDisposable.Disposable = Observable.Throw <DictionaryNotification <TKey, TValue> >(_error).Subscribe(observer); } var existingValues = _state.ToList(); foreach (var existingValue in existingValues) { observer.OnNext(DictionaryNotification.Existing(existingValue.Key, existingValue.Value)); } observer.OnNext(DictionaryNotification.Initialised <TKey, TValue>()); futureDisposable.Disposable = new CompositeDisposable(_subject.Subscribe(observer), Connect()); }); return(new CompositeDisposable(scheduledWorkDisposable, futureDisposable)); }
private void Upsert(DictionaryModification <TKey, TValue> modification) { TValue existingValue; if (_dictionary._state.TryGetValue(modification.Key, out existingValue)) { try { var newValue = _dictionary._updateFunction(modification.Key, existingValue, modification.Value); _dictionary._state[modification.Key] = newValue; _dictionary._subject.OnNext(DictionaryNotification.Updated(modification.Key, newValue, modification.Value, existingValue)); } catch (Exception ex) { _dictionary._error = ex; _dictionary._subject.OnError( new ObservableDictionaryUpdateException("Exception thrown when updating " + modification, ex)); } } else { _dictionary._state[modification.Key] = modification.Value; _dictionary._subject.OnNext(DictionaryNotification.Inserted(modification.Key, modification.Value)); } }
public IDisposable Subscribe(IObserver <DictionaryNotification <TKey, TValue> > observer) { lock (_lock) { if (_isDisposed) { return (Observable.Throw <DictionaryNotification <TKey, TValue> >( new ObjectDisposedException(this.GetType().Name)).Subscribe(observer)); } if (_error != null) { return(Observable.Throw <DictionaryNotification <TKey, TValue> >(_error).Subscribe(observer)); } var existingValues = _state.ToList(); foreach (var existingValue in existingValues) { observer.OnNext(DictionaryNotification.Existing(existingValue.Key, existingValue.Value)); } observer.OnNext(DictionaryNotification.Initialised <TKey, TValue>()); return(new CompositeDisposable(_subject.Subscribe(observer), Connect())); } }
private void Clear() { // todo emit a Removed<> for each item in the DB, rather than just clearing? // todo not atomic without locks. _dictionary._state.Clear(); _dictionary._subject.OnNext(DictionaryNotification.Cleared <TKey, TValue>()); }
private void Upsert(DictionaryModification <TKey, TValue> modification) { TValue existingValue; if (_dictionary._state.TryGetValue(modification.Key, out existingValue)) { try { // TODO Check order is correct here. var newValue = _dictionary._updateFunction.Invoke(modification.Key, existingValue, modification.Value); _dictionary._state[modification.Key] = newValue; _dictionary._subject.OnNext(DictionaryNotification.Updated(modification.Key, newValue, modification.Value, existingValue)); } catch (Exception ex) { // TODO Check that this errors the whole stream. _dictionary._error = ex; _dictionary._subject.OnError( new ObservableDictionaryUpdateException("Exception thrown when updating " + modification, ex)); } } else { _dictionary._state[modification.Key] = modification.Value; _dictionary._subject.OnNext(DictionaryNotification.Inserted(modification.Key, modification.Value)); } }
private void Clear() { foreach (var kvp in _dictionary._state) { _dictionary._subject.OnNext(DictionaryNotification.KeyCleared(kvp.Key, kvp.Value)); } _dictionary._subject.OnNext(DictionaryNotification.DictionaryCleared <TKey, TValue>()); _dictionary._state.Clear(); }
private void Remove(DictionaryModification <TKey, TValue> modification) { TValue removedValue; if (_dictionary._state.TryGetValue(modification.Key, out removedValue)) { _dictionary._state.Remove(modification.Key); _dictionary._subject.OnNext(DictionaryNotification.Removed(modification.Key, removedValue)); } // Design decision: We don't signal 'removed' for a value that didn't exist. }
private void Remove(DictionaryModification <TKey, TValue> modification) { TValue removedValue; if (_dictionary._state.TryGetValue(modification.Key, out removedValue)) { _dictionary._state.Remove(modification.Key); // TODO Should we signal 'removed' for a value that didn't exist..? _dictionary._subject.OnNext(DictionaryNotification.Removed(modification.Key, removedValue)); } }
private void Replace(DictionaryModification <TKey, TValue> modification) { TValue existingValue; if (_dictionary._state.TryGetValue(modification.Key, out existingValue)) { _dictionary._subject.OnNext(DictionaryNotification.Replaced(modification.Key, modification.Value, existingValue)); } else { // TODO Should we do an upsert when the item to be replaced doesn't exist, or signal replaced with a missing value? Upsert(modification); } }
private void Replace(DictionaryModification <TKey, TValue> modification) { TValue existingValue; if (_dictionary._state.TryGetValue(modification.Key, out existingValue)) { _dictionary._state[modification.Key] = modification.Value; _dictionary._subject.OnNext(DictionaryNotification.Replaced(modification.Key, modification.Value, existingValue)); } else { // Design decision: we do an upsert when the item to be replaced doesn't exist, rather than signal replaced with a missing value. Upsert(modification); } }
public IObservable <DictionaryNotification <TKey, TValue> > Get(TKey key) { return(Observable.Create <DictionaryNotification <TKey, TValue> >(observer => { TValue existingValue; if (_state.TryGetValue(key, out existingValue)) { observer.OnNext(DictionaryNotification.Existing(key, existingValue)); } else { observer.OnNext(DictionaryNotification.Missing <TKey, TValue>(key)); } return new CompositeDisposable(_subject .Where(dn => dn.Type == DictionaryNotificationType.KeyCleared || Equals(dn.Key, key)) .Subscribe(observer), Connect()); }) .SubscribeOn(_scheduler)); }
public IObservable <DictionaryNotification <TKey, TValue> > Get(TKey key) { return(Observable.Create <DictionaryNotification <TKey, TValue> >(observer => { lock (_lock) { TValue existingValue; if (_state.TryGetValue(key, out existingValue)) { observer.OnNext(DictionaryNotification.Existing(key, existingValue)); } else { observer.OnNext(DictionaryNotification.Missing <TKey, TValue>(key)); } return new CompositeDisposable(_subject.Subscribe(observer), Connect()); } })); }