Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#75 #76

Merged
merged 4 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions WatchList.Core/Model/Filter/FilterWatchItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections.ObjectModel;
using WatchList.Core.Model.ItemCinema;
using WatchList.Core.Model.ItemCinema.Components;

namespace WatchList.Core.Model.Filter
{
public class FilterWatchItem : IEquatable<FilterWatchItem>
{
public FilterWatchItem()
{
}

public IEnumerable<TypeCinema> FilterTypeField { get; set; }
= new HashSet<TypeCinema>(TypeCinema.List.Where(e => e != TypeCinema.AllType));

public IEnumerable<StatusCinema> FilterStatusField { get; set; }
= new HashSet<StatusCinema>(StatusCinema.List.Where(e => e != StatusCinema.AllStatus));

public ObservableCollection<TypeCinema> TypeItems { get; set; }
= new ObservableCollection<TypeCinema>(TypeCinema.List.Where(e => e != TypeCinema.AllType));

public ObservableCollection<StatusCinema> StatusItems { get; set; }
= new ObservableCollection<StatusCinema>(StatusCinema.List.Where(e => e != StatusCinema.AllStatus));

public IQueryable<WatchItem> Apply(IQueryable<WatchItem> items)
{
items = items.Where(x => FilterTypeField.Contains(x.Type));
items = items.Where(x => FilterStatusField.Contains(x.Status));
return items;
}

public void Clear()
{
FilterTypeField = new HashSet<TypeCinema>(TypeCinema.List.Where(e => e != TypeCinema.AllType));
FilterStatusField = new HashSet<StatusCinema>(StatusCinema.List.Where(e => e != StatusCinema.AllStatus));
}

public override int GetHashCode() => HashCode.Combine(FilterTypeField, FilterStatusField);

public override bool Equals(object? obj) => Equals(obj as FilterWatchItem);

public bool Equals(FilterWatchItem? other)
=> other != null && FilterTypeField == other.FilterTypeField && FilterStatusField == other.FilterStatusField;
}
}
9 changes: 9 additions & 0 deletions WatchList.Core/Model/Sortable/ISortableSmartEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace WatchList.Core.Model.Sortable
{
public interface ISortableSmartEnum<T>
{
IOrderedQueryable<T> OrderBy(IQueryable<T> query, bool asc);

IOrderedQueryable<T> ThenBy(IOrderedQueryable<T> query, bool asc);
}
}
9 changes: 9 additions & 0 deletions WatchList.Core/Model/Sortable/ISortableSmartEnumOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace WatchList.Core.Model.Sortable
{
public interface ISortableSmartEnumOperation<T>
{
static abstract ISortableSmartEnum<T> DefaultValue { get; }

static abstract IReadOnlyCollection<ISortableSmartEnum<T>> List { get; }
}
}
49 changes: 49 additions & 0 deletions WatchList.Core/Model/Sortable/SortFieldWatchItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Linq.Expressions;
using Ardalis.SmartEnum;
using WatchList.Core.Model.ItemCinema;
using WatchList.Core.Model.ItemCinema.Components;

namespace WatchList.Core.Model.Sortable
{
public abstract class SortFieldWatchItem : SmartEnum<SortFieldWatchItem>, ISortableSmartEnum<WatchItem>, ISortableSmartEnumOperation<WatchItem>
{
public static readonly SortFieldWatchItem Title = new SortType<string>("Title", 0, e => e.Title);
public static readonly SortFieldWatchItem Sequel = new SortType<int>("Sequel", 1, e => e.Sequel);
public static readonly SortFieldWatchItem Status = new SortType<StatusCinema>("Status", 2, e => e.Status);
public static readonly SortFieldWatchItem Data = new SortType<DateTime?>("Data", 3, e => e.Date);
public static readonly SortFieldWatchItem Grade = new SortType<int?>("Grade", 4, e => e.Grade);
public static readonly SortFieldWatchItem Type = new SortType<TypeCinema>("Type", 5, e => e.Type);

private SortFieldWatchItem(string name, int value)
: base(name, value)
{
}

static ISortableSmartEnum<WatchItem> ISortableSmartEnumOperation<WatchItem>.DefaultValue => Title;

static IReadOnlyCollection<ISortableSmartEnum<WatchItem>> ISortableSmartEnumOperation<WatchItem>.List => List;

public abstract IOrderedQueryable<WatchItem> OrderBy(IQueryable<WatchItem> query, bool asc);

public abstract IOrderedQueryable<WatchItem> ThenBy(IOrderedQueryable<WatchItem> query, bool asc);

public override string ToString() => Name;

private sealed class SortType<TKey> : SortFieldWatchItem
{
private readonly Expression<Func<WatchItem, TKey>> _expression;

public SortType(string name, int value, Expression<Func<WatchItem, TKey>> expression)
: base(name, value)
{
_expression = expression;
}

public override IOrderedQueryable<WatchItem> OrderBy(IQueryable<WatchItem> query, bool asc)
=> asc ? query.OrderBy(_expression) : query.OrderByDescending(_expression);

public override IOrderedQueryable<WatchItem> ThenBy(IOrderedQueryable<WatchItem> query, bool asc)
=> asc ? query.ThenBy(_expression) : query.ThenByDescending(_expression);
}
}
}
27 changes: 27 additions & 0 deletions WatchList.Core/Model/Sortable/SortWatchItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections.ObjectModel;
using Ardalis.SmartEnum;

namespace WatchList.Core.Model.Sortable
{
public class SortWatchItem<T, TSortField>
where TSortField : SmartEnum<TSortField>, ISortableSmartEnum<T>, ISortableSmartEnumOperation<T>
{
public ISortableSmartEnum<T> SortField { get; set; }

Check warning on line 9 in WatchList.Core/Model/Sortable/SortWatchItem.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'SortField' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 9 in WatchList.Core/Model/Sortable/SortWatchItem.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'SortField' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 9 in WatchList.Core/Model/Sortable/SortWatchItem.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'SortField' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 9 in WatchList.Core/Model/Sortable/SortWatchItem.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'SortField' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

public IEnumerable<ISortableSmartEnum<T>> SortFields { get; set; } = new HashSet<ISortableSmartEnum<T>>() { TSortField.DefaultValue };

public ObservableCollection<ISortableSmartEnum<T>> Items { get; set; } = new ObservableCollection<ISortableSmartEnum<T>>(TSortField.List);

public IQueryable<T> Apply(IQueryable<T> items, bool? ascending = true)
{
var sorter = new Sorter<T>(TSortField.DefaultValue);
return sorter.Apply(items, SortFields, ascending);
}

public void Clear()
=> SortFields = new HashSet<ISortableSmartEnum<T>>()
{
TSortField.DefaultValue,
};
}
}
35 changes: 35 additions & 0 deletions WatchList.Core/Model/Sortable/Sorter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace WatchList.Core.Model.Sortable
{
public sealed class Sorter<T>
{
private readonly ISortableSmartEnum<T> _defaultValue;

public Sorter(ISortableSmartEnum<T> defaultValue)
{
_defaultValue = defaultValue;
}

public IQueryable<T> Apply(IQueryable<T> items, IEnumerable<ISortableSmartEnum<T>> sortFields, bool? ascending = true)
{
if (ascending == null)
{
return items;
}

var asc = ascending.Value;
var actualSortFields = sortFields.ToList();
if (actualSortFields.Count == 0)
{
actualSortFields.Add(_defaultValue);
}

var query = actualSortFields[0].OrderBy(items, asc);
foreach (var item in actualSortFields.Skip(1))
{
query = item.ThenBy(query, asc);
}

return query;
}
}
}
23 changes: 0 additions & 23 deletions WatchList.Core/Model/Sorting/SortField.cs

This file was deleted.

23 changes: 23 additions & 0 deletions WatchList.Core/Model/Sorting/WatchItemSortField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Ardalis.SmartEnum;
using WatchList.Core.Model.ItemCinema;

namespace WatchList.Core.Model.Sorting
{
public class WatchItemSortField : SmartEnum<WatchItemSortField>
{
public static readonly WatchItemSortField Title = new WatchItemSortField("Title", 0, x => x.OrderBy(y => y.Title));
public static readonly WatchItemSortField Sequel = new WatchItemSortField("Sequel", 1, x => x.OrderBy(y => y.Sequel));
public static readonly WatchItemSortField Status = new WatchItemSortField("Status", 2, x => x.OrderBy(y => y.Status));
public static readonly WatchItemSortField Data = new WatchItemSortField("Data", 3, x => x.OrderByDescending(y => y.Date));
public static readonly WatchItemSortField Grade = new WatchItemSortField("Grade", 4, x => x.OrderByDescending(y => y.Grade));
public static readonly WatchItemSortField Type = new WatchItemSortField("Type", 5, x => x.OrderBy(y => y.Type));

private readonly Func<IQueryable<WatchItem>, IOrderedQueryable<WatchItem>> _orderByField;

private WatchItemSortField(string name, int value, Func<IQueryable<WatchItem>, IOrderedQueryable<WatchItem>> orderByField)
: base(name, value)
=> _orderByField = orderByField;

public IOrderedQueryable<WatchItem> Apply(IQueryable<WatchItem> items) => _orderByField(items);
}
}
36 changes: 36 additions & 0 deletions WatchList.Core/PageItem/ItemSearchRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using WatchList.Core.Model.Filter;
using WatchList.Core.Model.ItemCinema;
using WatchList.Core.Model.Sortable;

namespace WatchList.Core.PageItem
{
public class ItemSearchRequest
{
public ItemSearchRequest()
: this(new FilterWatchItem(), new SortWatchItem<WatchItem, SortFieldWatchItem>(), new Page(), true)
{
}

public ItemSearchRequest(FilterWatchItem filter, SortWatchItem<WatchItem, SortFieldWatchItem> sort, Page page, bool isAscending = true)
{
Filter = filter;
Sort = sort;
Page = page;
IsAscending = isAscending;
}

public FilterWatchItem Filter { get; set; }

public SortWatchItem<WatchItem, SortFieldWatchItem> Sort { get; set; }

public Page Page { get; set; }

public bool IsAscending { get; set; } = true;

public bool CompareFilter(FilterItem filter) => Filter.Equals(filter);

public IQueryable<WatchItem> ApplyFilter(IQueryable<WatchItem> items) => Filter.Apply(items);

public IQueryable<WatchItem> ApplyOrderBy(IQueryable<WatchItem> items) => Sort.Apply(items, IsAscending);
}
}
6 changes: 3 additions & 3 deletions WatchList.Core/PageItem/WatchItemSearchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ namespace WatchList.Core.PageItem
public class WatchItemSearchRequest
{
public WatchItemSearchRequest()
: this(new FilterItem(), SortField.Title, new Page())
: this(new FilterItem(), WatchItemSortField.Title, new Page())
{
}

public WatchItemSearchRequest(FilterItem filter, SortField sort, Page page)
public WatchItemSearchRequest(FilterItem filter, WatchItemSortField sort, Page page)
{
Filter = filter;
Sort = sort;
Expand All @@ -20,7 +20,7 @@ public WatchItemSearchRequest(FilterItem filter, SortField sort, Page page)

public FilterItem Filter { get; set; }

public SortField Sort { get; set; }
public WatchItemSortField Sort { get; set; }

public Page Page { get; set; }

Expand Down
7 changes: 7 additions & 0 deletions WatchList.Core/Repository/WatchItemRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ public PagedList<WatchItem> GetPage(WatchItemSearchRequest searchRequest)
return query.GetPagedList(searchRequest.Page);
}

public PagedList<WatchItem> GetPage(ItemSearchRequest searchRequest)
{
var query = searchRequest.ApplyFilter(_db.WatchItem);
query = searchRequest.ApplyOrderBy(query);
return query.GetPagedList(searchRequest.Page);
}

public void Add(WatchItem item)
{
item.Id = _db.ReplaceIdIsNotFree(item);
Expand Down
2 changes: 1 addition & 1 deletion WatchList.Core/Service/DataLoading/DownloadDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

public void Download(WatchItemRepository repository, ILoadRule loadRule)
{
var searchRequest = new WatchItemSearchRequest(new FilterItem(), SortField.Title, new Page(1, NumberOfItemPerPage));
var searchRequest = new WatchItemSearchRequest(new FilterItem(), WatchItemSortField.Title, new Page(1, NumberOfItemPerPage));
var pagedList = repository.GetPage(searchRequest);

while (searchRequest.Page.Number <= pagedList.PageCount)
Expand All @@ -37,7 +37,7 @@

_logger.LogInformation("Load items according to selected rules");
AddItems(watchItemCollection);
UpdateItems(watchItemCollection);

Check warning on line 40 in WatchList.Core/Service/DataLoading/DownloadDataService.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 40 in WatchList.Core/Service/DataLoading/DownloadDataService.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 40 in WatchList.Core/Service/DataLoading/DownloadDataService.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 40 in WatchList.Core/Service/DataLoading/DownloadDataService.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

searchRequest.Page.Number += 1;
pagedList = repository.GetPage(searchRequest);
Expand Down
2 changes: 2 additions & 0 deletions WatchList.Core/Service/WatchItemService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public WatchItemService(WatchItemRepository itemRepository, IMessageBox messageB

public PagedList<WatchItem> GetPage(WatchItemSearchRequest itemSearchRequest) => _repository.GetPage(itemSearchRequest);

public PagedList<WatchItem> GetPage(ItemSearchRequest itemSearchRequest) => _repository.GetPage(itemSearchRequest);

public void Remove(Guid id) => _repository.Remove(id);

public async Task AddAsync(WatchItem item)
Expand Down
28 changes: 0 additions & 28 deletions WatchList.MudBlazors/Model/FilterModel.cs

This file was deleted.

8 changes: 4 additions & 4 deletions WatchList.MudBlazors/Model/SortModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace WatchList.MudBlazors.Model
{
public class SortModel
{
public ObservableCollection<SortField> Items { get; set; } = new ObservableCollection<SortField>(SortField.List);
public ObservableCollection<WatchItemSortField> Items { get; set; } = new ObservableCollection<WatchItemSortField>(WatchItemSortField.List);

public SortField Type { get; set; } = SortField.Title;
public WatchItemSortField Type { get; set; } = WatchItemSortField.Title;

public SortField GetSortItem() => Type;
public WatchItemSortField GetSortItem() => Type;

public void Clear() => Type = SortField.Title;
public void Clear() => Type = WatchItemSortField.Title;
}
}
Loading
Loading