Beispiel #1
0
        public static TPropertiesEnum DiffProperties <TPropertiesEnum, TDiffGram>(this ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > self, ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > other)
            where TPropertiesEnum : struct
        {
            TPropertiesEnum changes = self.Value.DiffProperties(other.Value);

            if ((self.Parent == null ^ other.Parent == null) || (self.Parent != null && other.Parent != null && self.Parent.Identity != other.Parent.Identity))
            {
                changes = self.Value.Union(changes, self.Value.ParentProperty);
            }
            else if (self.Value != other.Value && self.Parent != null && other.Parent != null)
            {
                var selfParentOrdered = self.Parent as IRecursiveParentWithOrderedChildren;
                if (selfParentOrdered != null)
                {
                    var selfParentSorted = selfParentOrdered as IRecursiveParentWithSortedChildren;
                    if (selfParentSorted != null)
                    {
                        if (selfParentSorted.Compare(self.Value, other.Value) != 0)
                        {
                            // Calculate where the node was, and where it would go in the old tree.
                            var otherParentSorted = (IRecursiveParentWithSortedChildren)other.Parent;
                            int beforeIndex       = otherParentSorted.IndexOf(other.Value);
                            int afterIndex        = ~otherParentSorted.IndexOf(self.Value);

                            // If the indices are the same, the new one would come "just before" the old one.
                            // If the new index is just 1 greater than the old index, the new one would come "just after" the old one.
                            // In either of these cases, since the old one will be gone in the new tree, the position hasn't changed.
                            if (afterIndex != beforeIndex && afterIndex != beforeIndex + 1)
                            {
                                changes = self.Value.Union(changes, self.Value.PositionUnderParentProperty);
                            }
                        }
                    }
                    else
                    {
                        // Calculate whether items were reordered without leveraging a sorting comparer.
                        var otherParentOrdered = (IRecursiveParentWithOrderedChildren)other.Parent;
                        int beforeIndex        = otherParentOrdered.IndexOf(other.Value);
                        int afterIndex         = selfParentOrdered.IndexOf(self.Value);

                        // TODO: review (and add tests for) cases where items are inserted/removed from the parent,
                        // causing all other items after it to apparently shift in position. We probably don't want
                        // to consider that a change in PositionUnderParent, since the removal or add will take care of it.
                        if (afterIndex != beforeIndex)
                        {
                            changes = self.Value.Union(changes, self.Value.PositionUnderParentProperty);
                        }
                    }
                }
            }

            return(changes);
        }
Beispiel #2
0
 public int GetHashCode(ParentedRecursiveType <TRecursiveParent, TRecursiveType> obj)
 {
     return((int)obj.Value.Identity);
 }
Beispiel #3
0
        public static IReadOnlyList <TDiffGram> ChangesSince <TPropertiesEnum, TDiffGram>(this IRecursiveDiffingType <TPropertiesEnum, TDiffGram> current, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> priorVersion)
            where TPropertiesEnum : struct
            where TDiffGram : struct
        {
            Requires.NotNull(current, "current");
            Requires.NotNull(priorVersion, "priorVersion");

            if (current == priorVersion)
            {
                return(System.Collections.Immutable.ImmutableList.Create <TDiffGram>());
            }

            if (priorVersion.Identity != current.Identity)
            {
                throw new System.ArgumentException("Not another version of the same node.", nameof(priorVersion));
            }

            var currentAsParent        = current as IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >;
            var currentAsRecursiveType = (IRecursiveDiffingType <TPropertiesEnum, TDiffGram>)current;

            var before = new HashSet <ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > >(Comparers.Parented <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());
            var after  = new HashSet <ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > >(Comparers.Parented <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());

            var priorVersionAsParent = priorVersion as IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >;

            if (priorVersionAsParent != null)
            {
                before.UnionWith(priorVersionAsParent.GetSelfAndDescendentsWithParents <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());
            }
            else
            {
                before.Add(priorVersion.WithParent());
            }

            if (currentAsParent != null)
            {
                after.UnionWith(currentAsParent.GetSelfAndDescendentsWithParents <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());
            }
            else
            {
                after.Add(current.WithParent());
            }

            var added   = new HashSet <ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > >(Comparers.Parented <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());
            var removed = new HashSet <ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > >(Comparers.Parented <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());
            var changed = new Dictionary <ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > >(Comparers.Parented <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >());

            var descendentsOfAddOrRemove = new HashSet <IRecursiveType>(Comparers.Identity);

            foreach (var fromBefore in before)
            {
                if (after.Contains(fromBefore))
                {
                    ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> > fromAfter;
                    if (currentAsParent != null)
                    {
                        var parent = currentAsParent.GetParentedNode(fromBefore.Value.Identity);
                        fromAfter = new ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >(
                            (IRecursiveDiffingType <TPropertiesEnum, TDiffGram>)parent.Value,
                            (IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >)parent.Parent);
                    }
                    else
                    {
                        fromAfter = new ParentedRecursiveType <IRecursiveParent <IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >, IRecursiveDiffingType <TPropertiesEnum, TDiffGram> >(
                            fromBefore.Value.Identity == current.Identity ? (IRecursiveDiffingType <TPropertiesEnum, TDiffGram>)current : null);
                    }

                    if (!object.ReferenceEquals(fromBefore.Value, fromAfter.Value) || fromBefore.Parent.Identity != fromAfter.Parent.Identity)
                    {
                        changed.Add(fromBefore, fromAfter);
                    }
                }
                else
                {
                    removed.Add(fromBefore);
                }
            }

            foreach (var fromAfter in after)
            {
                if (!before.Contains(fromAfter))
                {
                    added.Add(fromAfter);
                }
            }

            foreach (var topLevelOperation in added.Concat(removed))
            {
                descendentsOfAddOrRemove.UnionWith(topLevelOperation.Value.GetSelfAndDescendents().Skip(1));
            }

            var history = new List <TDiffGram>();

            history.AddRange(removed.Where(r => !descendentsOfAddOrRemove.Contains(r.Value)).Select(r => currentAsRecursiveType.Remove(r.Value)));

            foreach (var changedNode in changed)
            {
                var oldNode = changedNode.Key;
                var newNode = changedNode.Value;

                var diff = newNode.DiffProperties(oldNode);
                if (!currentAsRecursiveType.Equals(diff, default(TPropertiesEnum)))
                {
                    history.Add(currentAsRecursiveType.Change(oldNode.Value, newNode.Value, diff));
                }
            }

            history.AddRange(added.Where(a => !descendentsOfAddOrRemove.Contains(a.Value)).Select(a => currentAsRecursiveType.Add(a.Value)));

            return(history);
        }
Beispiel #4
0
 public bool Equals(ParentedRecursiveType <TRecursiveParent, TRecursiveType> x, ParentedRecursiveType <TRecursiveParent, TRecursiveType> y)
 {
     return(x.Value.Identity == y.Value.Identity);
 }