Skip to content

Commit

Permalink
Add ToSortedCollection operator for ObservableCache and ObservableList
Browse files Browse the repository at this point in the history
  • Loading branch information
modplug committed Feb 12, 2019
1 parent 9df4204 commit 1ca74e7
Show file tree
Hide file tree
Showing 3 changed files with 2,165 additions and 1,986 deletions.
105 changes: 105 additions & 0 deletions DynamicData.Tests/Cache/ToSortedCollectionFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using DynamicData.Binding;
using DynamicData.Tests.Domain;
using FluentAssertions;
using Microsoft.Reactive.Testing;
using Xunit;

namespace DynamicData.Tests.Cache
{
public class ToSortedCollectionFixture : IDisposable
{
private readonly SourceCache<Person, int> _cache;
private readonly List<Person> _sortedCollection = new List<Person>();
private readonly List<Person> _unsortedCollection = new List<Person>();
private readonly CompositeDisposable _cleanup = new CompositeDisposable();

public ToSortedCollectionFixture()
{
_cache = new SourceCache<Person, int>(p => p.Age);
_cache.AddOrUpdate(Enumerable.Range(1, 10).Select(i => new Person("Name" + i, i)).ToArray());
}

public void Dispose()
{
_cache.Dispose();
_cleanup.Dispose();
}

[Fact]
public void SortAscending()
{
TestScheduler testScheduler = new TestScheduler();

_cleanup.Add(_cache.Connect()
.ObserveOn(testScheduler)
.Sort(SortExpressionComparer<Person>.Ascending(p => p.Age))
.ToCollection()
.Do(persons =>
{
_unsortedCollection.Clear();
_unsortedCollection.AddRange(persons);
})
.Subscribe());

_cleanup.Add(_cache.Connect()
.ObserveOn(testScheduler)
.ToSortedCollection(p => p.Age)
.Do(persons =>
{
_sortedCollection.Clear();
_sortedCollection.AddRange(persons);
})
.Subscribe());

// Insert an item with a lower sort order
_cache.AddOrUpdate(new Person("Name", 0));

testScheduler.AdvanceBy(TimeSpan.FromSeconds(2).Ticks);

_cache.Items.Should().Equal(_unsortedCollection);
_cache.Items.Should().NotEqual(_sortedCollection);
_cache.Items.OrderBy(p => p.Age).Should().Equal(_sortedCollection);
}

[Fact]
public void SortDescending()
{
TestScheduler testScheduler = new TestScheduler();

_cleanup.Add(_cache.Connect()
.ObserveOn(testScheduler)
.Sort(SortExpressionComparer<Person>.Ascending(p => p.Age))
.ToCollection()
.Do(persons =>
{
_unsortedCollection.Clear();
_unsortedCollection.AddRange(persons);
})
.Subscribe());

_cleanup.Add(_cache.Connect()
.ObserveOn(testScheduler)
.ToSortedCollection(p => p.Age, SortDirection.Descending)
.Do(persons =>
{
_sortedCollection.Clear();
_sortedCollection.AddRange(persons);
})
.Subscribe());

// Insert an item with a lower sort order
_cache.AddOrUpdate(new Person("Name", 0));

testScheduler.AdvanceBy(TimeSpan.FromSeconds(2).Ticks);

_cache.Items.Should().Equal(_unsortedCollection);
_cache.Items.Should().NotEqual(_sortedCollection);
_cache.Items.OrderByDescending(p => p.Age).Should().Equal(_sortedCollection);
}
}
}
37 changes: 37 additions & 0 deletions DynamicData/Cache/ObservableCacheEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,43 @@ public static IObservable<IReadOnlyCollection<TObject>> ToCollection<TObject, TK
{
return source.QueryWhenChanged(query => new ReadOnlyCollectionLight<TObject>(query.Items));
}

/// <summary>
/// Converts the changeset into a fully formed sorted collection. Each change in the source results in a new sorted collection
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TSortKey">The sort key</typeparam>
/// <param name="source">The source.</param>
/// <param name="sort">The sort function</param>
/// <param name="sortOrder">The sort order. Defaults to ascending</param>
/// <returns></returns>
public static IObservable<IReadOnlyCollection<TObject>> ToSortedCollection<TObject, TKey, TSortKey>(this IObservable<IChangeSet<TObject, TKey>> source,
Func<TObject, TSortKey> sort, SortDirection sortOrder = SortDirection.Ascending)
{
return source.QueryWhenChanged(query => sortOrder == SortDirection.Ascending
? new ReadOnlyCollectionLight<TObject>(query.Items.OrderBy(sort))
: new ReadOnlyCollectionLight<TObject>(query.Items.OrderByDescending(sort)));
}

/// <summary>
/// Converts the changeset into a fully formed sorted collection. Each change in the source results in a new sorted collection
/// </summary>
/// <typeparam name="TObject">The type of the object.</typeparam>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <param name="source">The source.</param>
/// <param name="comparer">The sort comparer</param>
/// <returns></returns>
public static IObservable<IReadOnlyCollection<TObject>> ToSortedCollection<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source,
IComparer<TObject> comparer)
{
return source.QueryWhenChanged(query =>
{
var items = query.Items.AsList();
items.Sort(comparer);
return new ReadOnlyCollectionLight<TObject>(items);
});
}

#endregion

Expand Down
Loading

0 comments on commit 1ca74e7

Please sign in to comment.