From f04ddd3a40090d59945ad8fbdccb2aad89fc94cf Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Fri, 9 Apr 2021 06:30:46 -0500 Subject: [PATCH] save collection page size (#157) --- .../PagedMediaCollectionsViewModel.cs | 6 +++ .../Queries/GetPagedCollections.cs | 6 +++ .../Queries/GetPagedCollectionsHandler.cs | 32 ++++++++++++++++ .../Fakes/FakeMediaCollectionRepository.cs | 5 +++ .../IMediaCollectionRepository.cs | 2 + .../Repositories/MediaCollectionRepository.cs | 26 +++++++++++-- ErsatzTV/ErsatzTV.csproj | 1 + ErsatzTV/Pages/Collections.razor | 38 +++++++++++++------ ErsatzTV/Startup.cs | 2 + 9 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 ErsatzTV.Application/MediaCollections/PagedMediaCollectionsViewModel.cs create mode 100644 ErsatzTV.Application/MediaCollections/Queries/GetPagedCollections.cs create mode 100644 ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs diff --git a/ErsatzTV.Application/MediaCollections/PagedMediaCollectionsViewModel.cs b/ErsatzTV.Application/MediaCollections/PagedMediaCollectionsViewModel.cs new file mode 100644 index 000000000..bde112dc0 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/PagedMediaCollectionsViewModel.cs @@ -0,0 +1,6 @@ +using System.Collections.Generic; + +namespace ErsatzTV.Application.MediaCollections +{ + public record PagedMediaCollectionsViewModel(int TotalCount, List Page); +} diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollections.cs b/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollections.cs new file mode 100644 index 000000000..45dded975 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollections.cs @@ -0,0 +1,6 @@ +using MediatR; + +namespace ErsatzTV.Application.MediaCollections.Queries +{ + public record GetPagedCollections(int PageNum, int PageSize) : IRequest; +} diff --git a/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs b/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs new file mode 100644 index 000000000..5433232a8 --- /dev/null +++ b/ErsatzTV.Application/MediaCollections/Queries/GetPagedCollectionsHandler.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using ErsatzTV.Core.Interfaces.Repositories; +using LanguageExt; +using MediatR; +using static ErsatzTV.Application.MediaCollections.Mapper; + +namespace ErsatzTV.Application.MediaCollections.Queries +{ + public class GetPagedCollectionsHandler : IRequestHandler + { + private readonly IMediaCollectionRepository _mediaCollectionRepository; + + public GetPagedCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) => + _mediaCollectionRepository = mediaCollectionRepository; + + public async Task Handle( + GetPagedCollections request, + CancellationToken cancellationToken) + { + int count = await _mediaCollectionRepository.CountAllCollections(); + + List page = await _mediaCollectionRepository + .GetPagedCollections(request.PageNum, request.PageSize) + .Map(list => list.Map(ProjectToViewModel).ToList()); + + return new PagedMediaCollectionsViewModel(count, page); + } + } +} diff --git a/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs b/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs index 6394a55fe..da5dd441c 100644 --- a/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs +++ b/ErsatzTV.Core.Tests/Fakes/FakeMediaCollectionRepository.cs @@ -26,6 +26,11 @@ namespace ErsatzTV.Core.Tests.Fakes throw new NotSupportedException(); public Task> GetAll() => throw new NotSupportedException(); + public Task CountAllCollections() => throw new NotSupportedException(); + + public Task> GetPagedCollections(int pageNumber, int pageSize) => + throw new NotSupportedException(); + public Task>> GetItems(int id) => Some(_data[id].ToList()).AsTask(); Task IMediaCollectionRepository.Update(Collection collection) => throw new NotSupportedException(); public Task Delete(int collectionId) => throw new NotSupportedException(); diff --git a/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs index d7eb97421..bca9db005 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IMediaCollectionRepository.cs @@ -15,6 +15,8 @@ namespace ErsatzTV.Core.Interfaces.Repositories Task> GetCollectionWithItemsUntracked(int id); Task> GetCollectionWithCollectionItemsUntracked(int id); Task> GetAll(); + Task CountAllCollections(); + Task> GetPagedCollections(int pageNumber, int pageSize); Task>> GetItems(int id); Task Update(Collection collection); Task Delete(int collectionId); diff --git a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs index 3b9f5fe21..bc87c7c1d 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs @@ -15,10 +15,15 @@ namespace ErsatzTV.Infrastructure.Data.Repositories { private readonly IDbConnection _dbConnection; private readonly TvContext _dbContext; + private readonly IDbContextFactory _dbContextFactory; - public MediaCollectionRepository(TvContext dbContext, IDbConnection dbConnection) + public MediaCollectionRepository( + TvContext dbContext, + IDbContextFactory dbContextFactory, + IDbConnection dbConnection) { _dbContext = dbContext; + _dbContextFactory = dbContextFactory; _dbConnection = dbConnection; } @@ -29,7 +34,6 @@ namespace ErsatzTV.Infrastructure.Data.Repositories return collection; } - public async Task AddMediaItem(int collectionId, int mediaItemId) { var modified = false; @@ -168,6 +172,22 @@ namespace ErsatzTV.Infrastructure.Data.Repositories public Task> GetAll() => _dbContext.Collections.ToListAsync(); + public Task CountAllCollections() => + _dbConnection.QuerySingleAsync(@"SELECT COUNT (*) FROM Collection"); + + public async Task> GetPagedCollections(int pageNumber, int pageSize) + { + await using TvContext dbContext = _dbContextFactory.CreateDbContext(); + return await dbContext.Collections.FromSqlRaw( + @"SELECT * FROM Collection + ORDER BY Name + LIMIT {0} OFFSET {1}", + pageSize, + (pageNumber - 1) * pageSize) + .AsNoTracking() + .ToListAsync(); + } + public Task>> GetItems(int id) => Get(id).MapT(GetItemsForCollection).Bind(x => x.Sequence()); @@ -227,7 +247,7 @@ namespace ErsatzTV.Infrastructure.Data.Repositories .Filter(m => ids.Contains(m.Id)) .ToListAsync(); } - + private async Task> GetArtistItems(Collection collection) { IEnumerable ids = await _dbConnection.QueryAsync( diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index b0cf0b182..82a7ddc47 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -16,6 +16,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/ErsatzTV/Pages/Collections.razor b/ErsatzTV/Pages/Collections.razor index a4c0d3d7c..86d63bf2a 100644 --- a/ErsatzTV/Pages/Collections.razor +++ b/ErsatzTV/Pages/Collections.razor @@ -1,13 +1,20 @@ @page "/media/collections" +@using Microsoft.Extensions.Caching.Memory +@using Blazored.LocalStorage @using ErsatzTV.Application.MediaCollections @using ErsatzTV.Application.MediaCollections.Commands @using ErsatzTV.Application.MediaCollections.Queries @using ErsatzTV.Application.MediaCards @inject IDialogService Dialog @inject IMediator Mediator +@inject IMemoryCache MemoryCache +@inject ILocalStorageService LocalStorage - + Collections @@ -16,11 +23,7 @@ - - - Name - - + Name @@ -50,12 +53,14 @@ @code { - private List _data; + private MudTable _table; - protected override Task OnParametersSetAsync() => RefreshData(); - - private async Task RefreshData() => - _data = await Mediator.Send(new GetAllCollections()).Map(list => list.OrderBy(vm => vm.Name).ToList()); + protected override async Task OnAfterRenderAsync(bool firstRender) + { + int rowsPerPage = await LocalStorage.GetItemAsync("pages.collections.rows_per_page") ?? 10; + _table.RowsPerPage = rowsPerPage; + await _table.ReloadServerData(); + } private async Task DeleteMediaCollection(MediaCardViewModel vm) { @@ -69,9 +74,18 @@ if (!result.Cancelled) { await Mediator.Send(new DeleteCollection(collection.Id)); - await RefreshData(); + await _table.ReloadServerData(); } } } + + private async Task> ServerReload(TableState state) + { + await LocalStorage.SetItemAsync("pages.collections.rows_per_page", state.PageSize); + + PagedMediaCollectionsViewModel data = await Mediator.Send(new GetPagedCollections(state.Page, state.PageSize)); + return new TableData { TotalItems = data.TotalCount, Items = data.Page }; + } + } \ No newline at end of file diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index 1e7a4497b..41c34c04a 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -3,6 +3,7 @@ using System.Data; using System.IO; using System.Reflection; using System.Threading.Channels; +using Blazored.LocalStorage; using Dapper; using ErsatzTV.Application; using ErsatzTV.Application.Channels.Queries; @@ -90,6 +91,7 @@ namespace ErsatzTV services.AddMudServices(); services.AddCourier(Assembly.GetAssembly(typeof(LibraryScanProgress))); + services.AddBlazoredLocalStorage(); Log.Logger.Information( "ErsatzTV version {Version}",