private ISnapshot CreateSnapshot(IChangeSet changeSet) { var parent = changeSet.ParentId.HasValue ? GetSnapshot(changeSet.ParentId.Value) : NullSnapshot.Instance; return snapshotFactory.CreateSnapshot(parent, commandExecutor, changeSet); }
void IMeasurementLoader.Load(IChangeSet updates) { foreach (var loader in loaders) { loader.Load(updates); } }
public static void Process(IChangeSet changes, ListBox listBox) { IDatabase adapter = new ListviewDatabaseAdapter(listBox); listBox.SuspendLayout(); changes.Apply(adapter); listBox.ResumeLayout(); }
public IncrementalCachingSnapshot(ISnapshot parentSnapshot, ICommandExecutor commandExecutor, IChangeSet changeSet) { this.parentSnapshot = parentSnapshot; this.commandExecutor = commandExecutor; foreach (var command in changeSet.Commands) { Load(command); } }
void AddChanges(IChangeSet changes) { ListviewDatabaseAdapter.Process(changes, listBoxEvents); // merge these changes onto the main changeset changes.Apply(events); this.CheckState(); }
public override void AfterCommit(IDocumentSession session, IChangeSet commit) { // See what was just persisted, and possibly carry out post // commit actions var last = commit; last.Updated.Each(x => Debug.WriteLine($"{x} was updated")); last.Deleted.Each(x => Debug.WriteLine($"{x} was deleted")); last.Inserted.Each(x => Debug.WriteLine($"{x} was inserted")); }
public Derivation(ISession session) { this.session = session; this.log = new DerivationLog(this); this.derivedObjects = new HashSet<Object>(); this.preparedObjects = new HashSet<IObject>(); this.changeSet = session.Checkpoint(); this.generation = 0; var user = new Users(session).GetCurrentUser(); }
/// <summary> /// Generates the advisory. /// </summary> /// <param name="svc">The service that holds the data to generate the advisory for.</param> /// <param name="changeSet">The subset of changes to generate the advisory for.</param> /// <returns>The generated advisory.</returns> public IAdvisory GenerateAdvisory( IChangeTrackingService svc, IChangeSet changeSet ) { var result = new List<IAdvisedAction>(); var distinct = this.visitor.Visit( changeSet ); foreach( var kvp in distinct ) { ProposedActions proposedAction = kvp.Value.GetAdvisedAction( kvp.Key ); EntityTrackingStates state = svc.GetEntityState( kvp.Key ); Boolean isTransient = ( state & EntityTrackingStates.IsTransient ) == EntityTrackingStates.IsTransient; switch( proposedAction ) { case ProposedActions.Create | ProposedActions.Update: proposedAction = isTransient ? ProposedActions.Create : ProposedActions.Update; break; case ProposedActions.Delete | ProposedActions.Dispose: proposedAction = isTransient ? ProposedActions.Dispose : ProposedActions.Delete; break; default: throw new NotSupportedException(); } var advisedAction = this.OnCreateAdvisedAction( kvp.Key, proposedAction ); result.Add( advisedAction ); } IEnumerable transientEntities = svc.GetEntities( EntityTrackingStates.IsTransient, true ); foreach( Object te in transientEntities ) { if ( result.Any( a => a.Target == te ) ) { /* * An entity is created as Transient+Persistable, then is added to * a MementoEntityCollection that tracks a change as "item-added" thus * the advisory adds that entity (that is not AutoRemove) as something that * must be created. so if we arrive here and we already have the transient * entity in the advisory we skip it. */ continue; } var advisedAction = this.OnCreateAdvisedAction( te, ProposedActions.Create ); result.Add( advisedAction ); } return new Advisory( result ); }
public IDictionary<object, IChange> Visit( IChangeSet changeSet ) { var distinct = new Dictionary<object, IChange>(); changeSet.ForEach( change => { /* * recuperiamo un riferimento alle entities * che sono oggetto della modifica */ change.GetChangedEntities().ForEach( entity => { if( !distinct.ContainsKey( entity ) ) { /* * se l'entity non è tra quelle che abbiamo * già incontrato la aggiungiamo. */ distinct.Add( entity, change ); } else { /* * Se l'entity è già tra quelle visitate * sostituiamo la IChange associata perchè * la IChange più importante è l'ultima, che è * quella che determina la ProposedActions che * verrà proposta. */ distinct[ entity ] = change; } } ); } ); return distinct; }
public override Task AfterCommitAsync(IDocumentSession session, IChangeSet commit, CancellationToken token) { LastCommit = commit; AfterCommitSession = session; return(Task.CompletedTask); }
public IList <Change <TObject, TKey> > Calculate(IKeyValueCollection <TObject, TKey> currentItems, IKeyValueCollection <TObject, TKey> previousItems, IChangeSet <TObject, TKey> sourceUpdates) { if (currentItems.SortReason == SortReason.ComparerChanged) { //clear collection and rebuild var removed = previousItems.Select((item, index) => new Change <TObject, TKey>(ChangeReason.Remove, item.Key, item.Value, index)); var newitems = currentItems.Select((item, index) => new Change <TObject, TKey>(ChangeReason.Add, item.Key, item.Value, index)); return(new List <Change <TObject, TKey> >(removed.Union(newitems))); } var previousList = previousItems.ToList(); var keyComparer = new KeyComparer <TObject, TKey>(); var removes = previousItems.Except(currentItems, keyComparer).ToList(); var adds = currentItems.Except(previousItems, keyComparer).ToList(); var inbothKeys = previousItems.Intersect(currentItems, keyComparer) .Select(x => x.Key).ToHashSet(); var result = new List <Change <TObject, TKey> >(); foreach (var remove in removes) { int index = previousList.IndexOf(remove); previousList.RemoveAt(index); result.Add(new Change <TObject, TKey>(ChangeReason.Remove, remove.Key, remove.Value, index)); } foreach (var add in adds) { //find new insert position int index = previousList.BinarySearch(add, currentItems.Comparer); int insertIndex = ~index; previousList.Insert(insertIndex, add); result.Add(new Change <TObject, TKey>(ChangeReason.Add, add.Key, add.Value, insertIndex)); } //Adds and removes ahave been accounted for //so check whether anything in the remaining change set have been moved ot updated var remainingItems = sourceUpdates .EmptyIfNull() .Where(u => inbothKeys.Contains(u.Key) && (u.Reason == ChangeReason.Update || u.Reason == ChangeReason.Moved || u.Reason == ChangeReason.Evaluate)) .ToList(); foreach (var change in remainingItems) { if (change.Reason == ChangeReason.Update) { var current = new KeyValuePair <TKey, TObject>(change.Key, change.Current); var previous = new KeyValuePair <TKey, TObject>(change.Key, change.Previous.Value); //remove from the actual index var removeIndex = previousList.IndexOf(previous); previousList.RemoveAt(removeIndex); //insert into the desired index int desiredIndex = previousList.BinarySearch(current, currentItems.Comparer); int insertIndex = ~desiredIndex; previousList.Insert(insertIndex, current); result.Add(new Change <TObject, TKey>(ChangeReason.Update, current.Key, current.Value, previous.Value, insertIndex, removeIndex)); } else if (change.Reason == ChangeReason.Moved) { //TODO: We have the index already, would be more efficient to calculate new position from the original index var current = new KeyValuePair <TKey, TObject>(change.Key, change.Current); var previousindex = previousList.IndexOf(current); int desiredIndex = previousList.BinarySearch(current, currentItems.Comparer); int insertIndex = ~desiredIndex; //this should never be the case, but check anyway if (previousindex == insertIndex) { continue; } previousList.RemoveAt(previousindex); previousList.Insert(insertIndex, current); result.Add(new Change <TObject, TKey>(current.Key, current.Value, insertIndex, previousindex)); } else { //TODO: re-evaluate to check whether item should be moved result.Add(change); } } //Alternative to evaluate is to check order var evaluates = remainingItems.Where(c => c.Reason == ChangeReason.Evaluate) .OrderByDescending(x => new KeyValuePair <TKey, TObject>(x.Key, x.Current), currentItems.Comparer) .ToList(); //calculate moves. Very expensive operation //TODO: Try and make this better foreach (var u in evaluates) { var current = new KeyValuePair <TKey, TObject>(u.Key, u.Current); var old = previousList.IndexOf(current); if (old == -1) { continue; } int newposition = GetInsertPositionLinear(previousList, current, currentItems.Comparer); if (old < newposition) { newposition--; } if (old == newposition) { continue; } previousList.RemoveAt(old); previousList.Insert(newposition, current); result.Add(new Change <TObject, TKey>(u.Key, u.Current, newposition, old)); } return(result); }
public DerivationLog Derive() { var changedObjectIds = new HashSet<ObjectId>(this.changeSet.Associations); changedObjectIds.UnionWith(this.changeSet.Roles); changedObjectIds.UnionWith(this.changeSet.Created); if (this.ForcedDerivations != null) { changedObjectIds.UnionWith(this.ForcedDerivations); } var changedObjects = new HashSet<IObject>(this.Session.Instantiate(changedObjectIds.ToArray())); while (changedObjects.Count > 0) { this.generation++; if (this.StartedGeneration != null) { this.StartedGeneration(this.generation); } this.addedDerivables = new HashSet<IObject>(); var preparationRun = 1; if (this.StartedPreparation != null) { this.StartedPreparation(preparationRun); } this.derivationGraph = new DerivationGraph(this); foreach (var changedObject in changedObjects) { var derivable = this.Session.Instantiate(changedObject) as Object; if (derivable != null) { if (this.Preparing != null) { this.Preparing(derivable); } derivable.OnPreDerive(x => x.WithDerivation(this)); this.preparedObjects.Add(derivable); } } while (this.addedDerivables.Count > 0) { preparationRun++; if (this.StartedPreparation != null) { this.StartedPreparation(preparationRun); } var dependencyObjectsToPrepare = new HashSet<IObject>(this.addedDerivables); dependencyObjectsToPrepare.ExceptWith(this.preparedObjects); this.addedDerivables = new HashSet<IObject>(); foreach (Object dependencyObject in dependencyObjectsToPrepare) { if (this.Preparing != null) { this.Preparing(dependencyObject); } dependencyObject.OnPreDerive(x => x.WithDerivation(this)); this.preparedObjects.Add(dependencyObject); } } if (this.derivationGraph.Count == 0) { break; } this.derivationGraph.Derive(); this.changeSet = this.Session.Checkpoint(); changedObjectIds = new HashSet<ObjectId>(this.changeSet.Associations); changedObjectIds.UnionWith(this.changeSet.Roles); changedObjectIds.UnionWith(this.changeSet.Created); changedObjects = new HashSet<IObject>(this.Session.Instantiate(changedObjectIds.ToArray())); changedObjects.ExceptWith(this.derivedObjects); this.derivationGraph = null; } return this.log; }
private static bool WasItemRemoved(IChangeSet <IRoutableViewModel> changeSet, IRoutableViewModel item) => changeSet .Any( change => change.Reason == ListChangeReason.Clear || (NavigationStackRemovalOperations.Contains(change.Reason) && change.Item.Current == item));
public AggregateEnumerator(IChangeSet <TObject, TKey> source) { _source = source; }
public IGroupChangeSet <TObject, TKey, TGroupKey> Update(IChangeSet <TObject, TKey> updates) { return(HandleUpdates(updates)); }
public ISnapshot CreateSnapshot(ISnapshot parent, ICommandExecutor commandExecutor, IChangeSet changeSet) { return new IncrementalCachingSnapshot(parent, commandExecutor, changeSet); }
public override void AfterCommit(IDocumentSession session, IChangeSet commit) { LastCommit = commit; AfterCommitSession = session; }
public override Task AfterCommitAsync(IDocumentSession session, IChangeSet commit, CancellationToken token) { LastCommit = commit; AfterCommitSession = session; return Task.CompletedTask; }
public void RecordSavedChanges(IDocumentSession session, IChangeSet commit) { var lastCommit = commit; Console.WriteLine( $"Persisted {lastCommit.Updated.Count()} updates, {lastCommit.Inserted.Count()} inserts, and {lastCommit.Deleted.Count()} deletions"); }
public void RecordSavedChanges(IDocumentSession session, IChangeSet commit) { }
public virtual void AfterCommit(IDocumentSession session, IChangeSet commit) { // Nothing }
public virtual Task AfterCommitAsync(IDocumentSession session, IChangeSet commit, CancellationToken token) { // Nothing return Task.CompletedTask; }
private IChangeSet <TObject, TKey> UpdateCombined(IChangeSet <TObject, TKey> updates) { //child caches have been updated before we reached this point. foreach (var update in updates) { TKey key = update.Key; switch (update.Reason) { case ChangeReason.Add: case ChangeReason.Update: { // get the current key. //check whether the item should belong to the cache var cached = _combinedCache.Lookup(key); var contained = cached.HasValue; var match = MatchesConstraint(key); if (match) { if (contained) { if (!ReferenceEquals(update.Current, cached.Value)) { _combinedCache.AddOrUpdate(update.Current, key); } } else { _combinedCache.AddOrUpdate(update.Current, key); } } else { if (contained) { _combinedCache.Remove(key); } } } break; case ChangeReason.Remove: { var cached = _combinedCache.Lookup(key); var contained = cached.HasValue; bool shouldBeIncluded = MatchesConstraint(key); if (shouldBeIncluded) { var firstOne = _sourceCaches.Select(s => s.Lookup(key)) .SelectValues() .First(); if (!cached.HasValue) { _combinedCache.AddOrUpdate(firstOne, key); } else if (!ReferenceEquals(firstOne, cached.Value)) { _combinedCache.AddOrUpdate(firstOne, key); } } else { if (contained) { _combinedCache.Remove(key); } } } break; case ChangeReason.Refresh: { _combinedCache.Refresh(key); } break; } } return(_combinedCache.CaptureChanges()); }
public void Load(IChangeSet updates) { updates.Apply(this); }
private async Task <IChangeSet <TDestination, TKey> > DoTransform(ChangeAwareCache <TransformedItemContainer, TKey> cache, IChangeSet <TSource, TKey> changes) { var transformed = await changes.SelectParallel(Transform, _maximumConcurrency); return(ProcessUpdates(cache, transformed.ToArray())); }
public void RecordSavedChanges(IDocumentSession session, IChangeSet commit) { throw new NotImplementedException(); }
public void Update(IChangeSet <TObject, TKey> changes) { _cache.Clone(changes); }
private void Clone(IChangeSet <TObject, TKey> changes) { Cache.Clone(changes); }
/// <summary> /// Dynamic calculation of moved items which produce a result which can be enumerated through in order /// </summary> /// <returns></returns> public IChangeSet <TObject, TKey> Calculate(IChangeSet <TObject, TKey> changes) { var result = new List <Change <TObject, TKey> >(changes.Count); var refreshes = new List <Change <TObject, TKey> >(changes.Refreshes); foreach (var u in changes) { var current = new KeyValuePair <TKey, TObject>(u.Key, u.Current); switch (u.Reason) { case ChangeReason.Add: { var position = GetInsertPositionBinary(current); _list.Insert(position, current); result.Add(new Change <TObject, TKey>(ChangeReason.Add, u.Key, u.Current, position)); } break; case ChangeReason.Update: { var previous = new KeyValuePair <TKey, TObject>(u.Key, u.Previous.Value); var old = GetCurrentPosition(previous); _list.RemoveAt(old); var newposition = GetInsertPositionBinary(current); _list.Insert(newposition, current); result.Add(new Change <TObject, TKey>(ChangeReason.Update, u.Key, u.Current, u.Previous, newposition, old)); } break; case ChangeReason.Remove: { var position = GetCurrentPosition(current); _list.RemoveAt(position); result.Add(new Change <TObject, TKey>(ChangeReason.Remove, u.Key, u.Current, position)); } break; case ChangeReason.Refresh: { refreshes.Add(u); result.Add(u); } break; } } //for evaluates, check whether the change forces a new position var evaluates = refreshes.OrderByDescending(x => new KeyValuePair <TKey, TObject>(x.Key, x.Current), _comparer) .ToList(); if (evaluates.Count != 0 && _optimisations.HasFlag(SortOptimisations.IgnoreEvaluates)) { //reorder entire sequence and do not calculate moves _list = _list.OrderBy(kv => kv, _comparer).ToList(); } else { //calculate moves. Very expensive operation //TODO: Try and make this better foreach (var u in evaluates) { var current = new KeyValuePair <TKey, TObject>(u.Key, u.Current); var old = _list.IndexOf(current); if (old == -1) { continue; } int newposition = GetInsertPositionLinear(_list, current); if (old < newposition) { newposition--; } if (old == newposition) { continue; } _list.RemoveAt(old); _list.Insert(newposition, current); result.Add(new Change <TObject, TKey>(u.Key, u.Current, newposition, old)); } } return(new ChangeSet <TObject, TKey>(result)); }
private IChangeSet <IGroup <TObject, TGroupKey> > Process(ChangeAwareList <IGroup <TObject, TGroupKey> > result, IDictionary <TGroupKey, Group <TObject, TGroupKey> > groupCollection, IChangeSet <ItemWithGroupKey> changes) { foreach (var grouping in changes.Unified().GroupBy(change => change.Current.Group)) { //lookup group and if created, add to result set var currentGroup = grouping.Key; var lookup = GetCache(groupCollection, currentGroup); var groupCache = lookup.Group; if (lookup.WasCreated) { result.Add(groupCache); } //start a group edit session, so all changes are batched groupCache.Edit( list => { //iterate through the group's items and process foreach (var change in grouping) { switch (change.Reason) { case ListChangeReason.Add: { list.Add(change.Current.Item); break; } case ListChangeReason.Replace: { var previousItem = change.Previous.Value.Item; var previousGroup = change.Previous.Value.Group; //check whether an item changing has resulted in a different group if (previousGroup.Equals(currentGroup)) { //find and replace var index = list.IndexOf(previousItem, ReferenceEqualityComparer <TObject> .Instance); list[index] = change.Current.Item; } else { //add to new group list.Add(change.Current.Item); //remove from old group groupCollection.Lookup(previousGroup) .IfHasValue(g => { g.Edit(oldList => oldList.Remove(previousItem)); if (g.List.Count != 0) { return; } groupCollection.Remove(g.GroupKey); result.Remove(g); }); } break; } case ListChangeReason.Refresh: { //1. Check whether item was in the group and should not be now (or vice versa) var currentItem = change.Current.Item; var previousGroup = change.Current.PrevousGroup.Value; //check whether an item changing has resulted in a different group if (previousGroup.Equals(currentGroup)) { // Propagate refresh eventt var cal = (ChangeAwareList <TObject>)list; cal.Refresh(currentItem); } else { //add to new group list.Add(currentItem); //remove from old group if empty groupCollection.Lookup(previousGroup) .IfHasValue(g => { g.Edit(oldList => oldList.Remove(currentItem)); if (g.List.Count != 0) { return; } groupCollection.Remove(g.GroupKey); result.Remove(g); }); } break; } case ListChangeReason.Remove: { list.Remove(change.Current.Item); break; } case ListChangeReason.Clear: { list.Clear(); break; } } } }); if (groupCache.List.Count == 0) { groupCollection.Remove(groupCache.GroupKey); result.Remove(groupCache); } } return(result.CaptureChanges()); }
private void m_saveRowsButton_Click(object sender, RoutedEventArgs e) { IChangeSet changes = m_session.DataAccess.CreateChangeSet(); // delete all rows first m_session.DataAccess.Brokers.DataTable.DeleteDataRows(changes, m_table.Id, m_session.ModelFactory.CreateAllSelector()); // delete all files first m_session.DataAccess.Brokers.DataTable.DeleteFileInDataTables(changes, m_table.Id, m_session.ModelFactory.CreateAllSelector()); List <IDataTableField> mediaFields = new List <IDataTableField>(); foreach (IDataTableField field in m_table.DataTableDesigns.Items.FirstOrDefault().DataTableFields.Items) { if (field.Type == DataTableFieldType.Media) { mediaFields.Add(field); } } List <string> mediaFileNames = new List <string>(); foreach (IDataRow row in m_rows) { foreach (IDataTableField mediaField in mediaFields) { if (row.Values.ContainsKey(mediaField.Name) && !mediaFileNames.Contains(row.Values[mediaField.Name])) { mediaFileNames.Add(row.Values[mediaField.Name]); } } m_session.DataAccess.Brokers.DataTable.CreateDataRow(changes, m_table.Id, row); } // delete orphaned files foreach (IFileInDataTable fidt in new List <IFileInDataTable>(m_files)) { if (!mediaFileNames.Contains(fidt.Name)) { m_files.Remove(fidt); } } foreach (IFileInDataTable fidt in m_files) { m_session.DataAccess.Brokers.DataTable.CreateFileInDataTable(changes, m_table.Id, fidt); } using (var result = changes.Save()) { if (result.IsSuccess) { m_errors.Text = ""; } else { m_errors.Text = "Failed to update data table: " + result.ToString(); } } }
private IChangeSet <TValue> Process(IChangeSet <ItemWithValue <T, TValue> > updates) { Action <TValue> addAction = value => _valueCounters.Lookup(value) .IfHasValue(count => _valueCounters[value] = count + 1) .Else(() => { _valueCounters[value] = 1; _result.Add(value); }); Action <TValue> removeAction = value => { var counter = _valueCounters.Lookup(value); if (!counter.HasValue) { return; } //decrement counter var newCount = counter.Value - 1; _valueCounters[value] = newCount; if (newCount != 0) { return; } //if there are none, then remove and notify _result.Remove(value); }; foreach (var change in updates) { switch (change.Reason) { case ListChangeReason.Add: { var value = change.Item.Current.Value; addAction(value); break; } case ListChangeReason.AddRange: { change.Range.Select(item => item.Value).ForEach(addAction); break; } // case ListChangeReason.Evaluate: case ListChangeReason.Replace: { var value = change.Item.Current.Value; var previous = change.Item.Previous.Value.Value; if (value.Equals(previous)) { return(_result.CaptureChanges()); } removeAction(previous); addAction(value); break; } case ListChangeReason.Remove: { var previous = change.Item.Current.Value; removeAction(previous); break; } case ListChangeReason.RemoveRange: { change.Range.Select(item => item.Value).ForEach(removeAction); break; } case ListChangeReason.Clear: { _result.Clear(); _valueCounters.Clear(); break; } } } return(_result.CaptureChanges()); }
private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } foreach (var item in changes) { switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count) { transformed.Add(_containerFactory(change.Current, Optional <TDestination> .None, transformed.Count)); } else { var converted = _containerFactory(change.Current, Optional <TDestination> .None, change.CurrentIndex); transformed.Insert(change.CurrentIndex, converted); } break; } case ListChangeReason.AddRange: { var startIndex = item.Range.Index < 0 ? transformed.Count : item.Range.Index; transformed.AddOrInsertRange(item.Range .Select((t, idx) => _containerFactory(t, Optional <TDestination> .None, idx + startIndex)), item.Range.Index); break; } case ListChangeReason.Refresh: { if (_transformOnRefresh) { var change = item.Item; Optional <TDestination> previous = transformed[change.CurrentIndex].Destination; var refreshed = _containerFactory(change.Current, previous, change.CurrentIndex); transformed[change.CurrentIndex] = refreshed; } else { transformed.RefreshAt(item.Item.CurrentIndex); } break; } case ListChangeReason.Replace: { var change = item.Item; Optional <TDestination> previous = transformed[change.PreviousIndex].Destination; if (change.CurrentIndex == change.PreviousIndex) { transformed[change.CurrentIndex] = _containerFactory(change.Current, previous, change.CurrentIndex); } else { transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, _containerFactory(change.Current, Optional <TDestination> .None, change.CurrentIndex)); } break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { transformed.RemoveAt(change.CurrentIndex); } else { var toRemove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, change.Current)); if (toRemove != null) { transformed.Remove(toRemove); } } break; } case ListChangeReason.RemoveRange: { if (item.Range.Index >= 0) { transformed.RemoveRange(item.Range.Index, item.Range.Count); } else { var toRemove = transformed.Where(t => item.Range.Any(current => ReferenceEquals(t.Source, current))); transformed.RemoveMany(toRemove); } break; } case ListChangeReason.Clear: { //i.e. need to store transformed reference so we can correctly clear var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed); transformed.ClearOrRemoveMany(toClear); break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } transformed.Move(change.PreviousIndex, change.CurrentIndex); break; } } } }
private IChangeSet <T> ProcessImpl(ChangeAwareList <T> target, IChangeSet <T> changes) { var refreshes = new List <T>(changes.Refreshes); foreach (var change in changes) { switch (change.Reason) { case ListChangeReason.Add: { var current = change.Item.Current; Insert(target, current); break; } case ListChangeReason.AddRange: { var ordered = change.Range.OrderBy(t => t, _comparer).ToList(); if (target.Count == 0) { target.AddRange(ordered); } else { ordered.ForEach(item => Insert(target, item)); } break; } case ListChangeReason.Remove: { var current = change.Item.Current; Remove(target, current); break; } case ListChangeReason.Refresh: { // add to refresh list so position can be calculated refreshes.Add(change.Item.Current); // add to current list so downstream operators can receive a refresh // notification, so get the latest index and pass the index up the chain var indexed = target.IndexOfOptional(change.Item.Current).ValueOrThrow(() => new SortException($"Cannot find index of {typeof(T).Name} -> {change.Item.Current}. Expected to be in the list")); target.Refresh(indexed.Item, indexed.Index); break; } case ListChangeReason.Replace: { var current = change.Item.Current; // TODO: check whether an item should stay in the same position // i.e. update and move Remove(target, change.Item.Previous.Value); Insert(target, current); break; } case ListChangeReason.RemoveRange: { target.RemoveMany(change.Range); break; } case ListChangeReason.Clear: { target.Clear(); break; } } } // Now deal with refreshes [can be expensive] foreach (var item in refreshes) { var old = target.IndexOf(item); if (old == -1) { continue; } int newPosition = GetInsertPositionLinear(target, item); if (old < newPosition) { newPosition--; } if (old == newPosition) { continue; } target.Move(old, newPosition); } return(target.CaptureChanges()); }
private void UpdateResultList(ChangeAwareCache <TObject, TKey> target, MergeContainer[] sourceLists, IChangeSet <TObject, TKey> changes) { foreach (var change in changes.ToConcreteType()) { ProcessItem(target, sourceLists, change.Current, change.Key); } }
private IChangeSet <TObject, TKey> UpdateCombined(IChangeSet <TObject, TKey> updates) { //child caches have been updated before we reached this point. var updater = new IntermediateUpdater <TObject, TKey>(_combinedCache); foreach (var update in updates) { TKey key = update.Key; switch (update.Reason) { case ChangeReason.Add: case ChangeReason.Update: { // get the current key. //check whether the item should belong to the cache Optional <TObject> cached = updater.Lookup(key); bool contained = cached.HasValue; bool match = MatchesConstraint(key); if (match) { if (contained) { if (!ReferenceEquals(update.Current, cached.Value)) { updater.AddOrUpdate(update.Current, key); } } else { updater.AddOrUpdate(update.Current, key); } } else { if (contained) { updater.Remove(key); } } } break; case ChangeReason.Remove: { var cached = updater.Lookup(key); var contained = cached.HasValue; bool shouldBeIncluded = MatchesConstraint(key); if (shouldBeIncluded) { var firstOne = _sourceCaches.Select(s => s.Lookup(key)) .SelectValues() .First(); if (!cached.HasValue) { updater.AddOrUpdate(firstOne, key); } else if (!ReferenceEquals(firstOne, cached.Value)) { updater.AddOrUpdate(firstOne, key); } } else { if (contained) { updater.Remove(key); } } } break; case ChangeReason.Evaluate: { updater.Evaluate(key); } break; } } return(updater.AsChangeSet()); // } // return up }
private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } transformed.EnsureCapacityFor(changes); foreach (var item in changes) { switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count) { transformed.Add(_containerFactory(change.Current)); } else { transformed.Insert(change.CurrentIndex, _containerFactory(change.Current)); } break; } case ListChangeReason.AddRange: { transformed.AddOrInsertRange(item.Range.Select(_containerFactory), item.Range.Index); break; } case ListChangeReason.Replace: { var change = item.Item; if (change.CurrentIndex == change.PreviousIndex) { transformed[change.CurrentIndex] = _containerFactory(change.Current); } else { transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, _containerFactory(change.Current)); } break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { transformed.RemoveAt(item.Item.CurrentIndex); } else { var toremove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t)); if (toremove != null) { transformed.Remove(toremove); } } break; } case ListChangeReason.RemoveRange: { if (item.Range.Index >= 0) { transformed.RemoveRange(item.Range.Index, item.Range.Count); } else { var toremove = transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray(); transformed.RemoveMany(toremove); } break; } case ListChangeReason.Clear: { //i.e. need to store transformed reference so we can correctly clear var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed); transformed.ClearOrRemoveMany(toClear); break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } var collection = transformed as IExtendedList <TransformedItemContainer>; if (collection != null) { collection.Move(change.PreviousIndex, change.CurrentIndex); } else { var current = transformed[change.PreviousIndex]; transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, current); } break; } } } }
private static IChangeSet <TValue> Process(Dictionary <TValue, int> values, ChangeAwareList <TValue> result, IChangeSet <ItemWithMatch> changes) { void AddAction(TValue value) => values.Lookup(value) .IfHasValue(count => values[value] = count + 1) .Else(() => { values[value] = 1; result.Add(value); }); void RemoveAction(TValue value) { var counter = values.Lookup(value); if (!counter.HasValue) { return; } //decrement counter var newCount = counter.Value - 1; values[value] = newCount; if (newCount != 0) { return; } //if there are none, then remove and notify result.Remove(value); values.Remove(value); } foreach (var change in changes) { switch (change.Reason) { case ListChangeReason.Add: { var value = change.Item.Current.Value; AddAction(value); break; } case ListChangeReason.AddRange: { change.Range.Select(item => item.Value).ForEach(AddAction); break; } case ListChangeReason.Refresh: { var value = change.Item.Current.Value; var previous = change.Item.Current.Previous; if (value.Equals(previous)) { continue; } RemoveAction(previous); AddAction(value); break; } case ListChangeReason.Replace: { var value = change.Item.Current.Value; var previous = change.Item.Previous.Value.Value; if (value.Equals(previous)) { continue; } RemoveAction(previous); AddAction(value); break; } case ListChangeReason.Remove: { var previous = change.Item.Current.Value; RemoveAction(previous); break; } case ListChangeReason.RemoveRange: { change.Range.Select(item => item.Value).ForEach(RemoveAction); break; } case ListChangeReason.Clear: { result.Clear(); values.Clear(); break; } } } return(result.CaptureChanges()); }
public IChangeSet <TObject, TKey> Update(IChangeSet <TObject, TKey> updates) { var withfilter = GetChangesWithFilter(updates); return(ProcessResult(withfilter)); }
public DestinationEnumerator(IChangeSet <ManyContainer, TSourceKey> changes) { _changes = changes; }
protected abstract IEnumerable <UpdateWithFilter> GetChangesWithFilter(IChangeSet <TObject, TKey> updates);
public IEnumerable <Change <T> > Reverse(IChangeSet <T> changes) { foreach (var change in changes) { switch (change.Reason) { case ListChangeReason.Add: { yield return(new Change <T>(ListChangeReason.Add, change.Item.Current, _length - change.Item.CurrentIndex)); _length++; break; } case ListChangeReason.AddRange: { var offset = change.Range.Index == -1 ? 0 : _length - change.Range.Index; yield return(new Change <T>(ListChangeReason.AddRange, change.Range.Reverse(), offset)); _length += change.Range.Count; break; } case ListChangeReason.Replace: { var newIndex = _length - change.Item.CurrentIndex - 1; yield return(new Change <T>(ListChangeReason.Replace, change.Item.Current, change.Item.Previous.Value, newIndex, newIndex)); break; } case ListChangeReason.Remove: { yield return(new Change <T>(ListChangeReason.Remove, change.Item.Current, _length - change.Item.CurrentIndex - 1)); _length--; break; } case ListChangeReason.RemoveRange: { var offset = _length - change.Range.Index - change.Range.Count; yield return(new Change <T>(ListChangeReason.RemoveRange, change.Range.Reverse(), offset)); _length -= change.Range.Count; break; } case ListChangeReason.Moved: { var currentIndex = _length - change.Item.CurrentIndex - 1; var previousIndex = _length - change.Item.PreviousIndex - 1; yield return(new Change <T>(change.Item.Current, currentIndex, previousIndex)); break; } case ListChangeReason.Clear: { yield return(new Change <T>(ListChangeReason.Clear, change.Range.Reverse())); _length = 0; break; } } } }
public DestinationEnumerator(IChangeSet <ManyContainer> changes, IEqualityComparer <TDestination> equalityComparer) { _changes = changes; _equalityComparer = equalityComparer; }
public AddKeyEnumerator([NotNull] IChangeSet <TObject> source, [NotNull] Func <TObject, TKey> keySelector) { _source = source ?? throw new ArgumentNullException(nameof(source)); _keySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector)); }
protected override IEnumerable <UpdateWithFilter> GetChangesWithFilter(IChangeSet <TObject, TKey> updates) { return(updates.Select(u => new UpdateWithFilter(Filter(u.Current), u)).ToArray()); }