Skip to content

Commit

Permalink
Merge pull request #13 from davewalker5/MC-73-Album-Deletion
Browse files Browse the repository at this point in the history
MC-73 Album Deletion
  • Loading branch information
davewalker5 authored Nov 9, 2023
2 parents cb54c28 + e694719 commit 53a308c
Show file tree
Hide file tree
Showing 24 changed files with 219 additions and 49 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ MusicCatalogue.LookupTool --lookup "John Coltrane" "Blue Train"
<img src="diagrams/album-list.png" alt="Album List" width="600">

- As the mouse pointer is moved up and down the table, the current row is highlighted
- Clicking on a row opens the track list for the album shown in that row:
- Clicking on the trash icon prompts for confirmation and, if confirmed, deletes the album shown in that row along with the associated tracks
- Clicking anywhere else on a row opens the track list for the album shown in that row:

<img src="diagrams/track-list.png" alt="Track List" width="600">

Expand Down
Binary file modified diagrams/album-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docker/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/dotnet/core/aspnet:latest
COPY musiccatalogue.api-1.7.0.0 /opt/musiccatalogue.api-1.7.0.0
WORKDIR /opt/musiccatalogue.api-1.7.0.0/bin
COPY musiccatalogue.api-1.8.0.0 /opt/musiccatalogue.api-1.8.0.0
WORKDIR /opt/musiccatalogue.api-1.8.0.0/bin
ENTRYPOINT [ "./MusicCatalogue.Api" ]
4 changes: 2 additions & 2 deletions docker/ui/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM node:20-alpine
COPY musiccatalogue.ui-1.7.0.0 /opt/musiccatalogue.ui-1.7.0.0
WORKDIR /opt/musiccatalogue.ui-1.7.0.0
COPY musiccatalogue.ui-1.8.0.0 /opt/musiccatalogue.ui-1.8.0.0
WORKDIR /opt/musiccatalogue.ui-1.8.0.0
RUN npm install
RUN npm run build
ENTRYPOINT [ "npm", "start" ]
16 changes: 16 additions & 0 deletions src/MusicCatalogue.Api/Controllers/AlbumsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,21 @@ public async Task<ActionResult<IEnumerable<Album>>> GetAlbumsByArtistAsync(int a

return albums;
}

[HttpDelete]
[Route("{id}")]
public async Task<IActionResult> DeleteAlbum(int id)
{
// Check the album exists, first
var album = await _factory.Albums.GetAsync(x => x.Id == id);
if (album == null)
{
return NotFound();
}

// It does, so delete it
await _factory.Albums.DeleteAsync(id);
return Ok();
}
}
}
6 changes: 3 additions & 3 deletions src/MusicCatalogue.Api/MusicCatalogue.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ReleaseVersion>1.7.0.0</ReleaseVersion>
<FileVersion>1.7.0.0</FileVersion>
<ProductVersion>1.7.0</ProductVersion>
<ReleaseVersion>1.8.0.0</ReleaseVersion>
<FileVersion>1.8.0.0</FileVersion>
<ProductVersion>1.8.0</ProductVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/MusicCatalogue.Data/MusicCatalogue.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>MusicCatalogue.Data</PackageId>
<PackageVersion>1.6.0.0</PackageVersion>
<PackageVersion>1.7.0.0</PackageVersion>
<Authors>Dave Walker</Authors>
<Copyright>Copyright (c) Dave Walker 2023</Copyright>
<Owners>Dave Walker</Owners>
Expand All @@ -17,7 +17,7 @@
<PackageProjectUrl>https://github.com/davewalker5/MusicCatalogue</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<ReleaseVersion>1.6.0.0</ReleaseVersion>
<ReleaseVersion>1.7.0.0</ReleaseVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
5 changes: 4 additions & 1 deletion src/MusicCatalogue.Entities/Database/TrackBase.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace MusicCatalogue.Entities.Database
using System.Diagnostics.CodeAnalysis;

namespace MusicCatalogue.Entities.Database
{
[ExcludeFromCodeCoverage]
public abstract class TrackBase
{
public int? Duration { get; set; }
Expand Down
1 change: 1 addition & 0 deletions src/MusicCatalogue.Entities/Interfaces/IAlbumManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public interface IAlbumManager
Task<Album> AddAsync(int artistId, string title, int? released, string? genre, string? coverUrl);
Task<Album> GetAsync(Expression<Func<Album, bool>> predicate);
Task<List<Album>> ListAsync(Expression<Func<Album, bool>> predicate);
Task DeleteAsync(int albumId);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
namespace MusicCatalogue.Entities.Interfaces
using Microsoft.EntityFrameworkCore;

namespace MusicCatalogue.Entities.Interfaces
{
public interface IMusicCatalogueFactory
{
DbContext Context { get; }
IAlbumManager Albums { get; }
IArtistManager Artists { get; }
ITrackManager Tracks { get; }
Expand Down
1 change: 1 addition & 0 deletions src/MusicCatalogue.Entities/Interfaces/ITrackManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public interface ITrackManager
Task<Track> AddAsync(int albumId, string title, int? number, int? duration);
Task<Track> GetAsync(Expression<Func<Track, bool>> predicate);
Task<List<Track>> ListAsync(Expression<Func<Track, bool>> predicate);
Task DeleteAsync(int albumId);
}
}
8 changes: 6 additions & 2 deletions src/MusicCatalogue.Entities/MusicCatalogue.Entities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>MusicCatalogue.Entities</PackageId>
<PackageVersion>1.6.0.0</PackageVersion>
<PackageVersion>1.7.0.0</PackageVersion>
<Authors>Dave Walker</Authors>
<Copyright>Copyright (c) Dave Walker 2023</Copyright>
<Owners>Dave Walker</Owners>
Expand All @@ -17,7 +17,11 @@
<PackageProjectUrl>https://github.com/davewalker5/MusicCatalogue</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<ReleaseVersion>1.6.0.0</ReleaseVersion>
<ReleaseVersion>1.7.0.0</ReleaseVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.11" />
</ItemGroup>

</Project>
44 changes: 35 additions & 9 deletions src/MusicCatalogue.Logic/Database/AlbumManager.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
using Microsoft.EntityFrameworkCore;
using MusicCatalogue.Data;
using MusicCatalogue.Entities.Interfaces;
using MusicCatalogue.Entities.Database;
using MusicCatalogue.Entities.Interfaces;
using MusicCatalogue.Logic.Factory;
using System.Linq.Expressions;

namespace MusicCatalogue.Logic.Database
{
public class AlbumManager : DatabaseManagerBase, IAlbumManager
public class AlbumManager : IAlbumManager
{
internal AlbumManager(MusicCatalogueDbContext context) : base(context)
private readonly MusicCatalogueFactory _factory;
private readonly MusicCatalogueDbContext? _context;

internal AlbumManager(MusicCatalogueFactory factory)
{
_factory = factory;
_context = factory.Context as MusicCatalogueDbContext;
}

/// <summary>
Expand All @@ -32,11 +38,11 @@ public async Task<Album> GetAsync(Expression<Func<Album, bool>> predicate)
/// <param name="predicate"></param>
/// <returns></returns>
public async Task<List<Album>> ListAsync(Expression<Func<Album, bool>> predicate)
=> await _context.Albums
.Where(predicate)
.OrderBy(x => x.Title)
.Include(x => x.Tracks)
.ToListAsync();
=> await _context!.Albums
.Where(predicate)
.OrderBy(x => x.Title)
.Include(x => x.Tracks)
.ToListAsync();

/// <summary>
/// Add an album, if it doesn't already exist
Expand All @@ -62,11 +68,31 @@ public async Task<Album> AddAsync(int artistId, string title, int? released, str
Genre = StringCleaner.RemoveInvalidCharacters(genre),
CoverUrl = StringCleaner.RemoveInvalidCharacters(coverUrl)
};
await _context.Albums.AddAsync(album);
await _context!.Albums.AddAsync(album);
await _context.SaveChangesAsync();
}

return album;
}

/// <summary>
/// Delete the album with the specified Id
/// </summary>
/// <param name="albumId"></param>
/// <returns></returns>
public async Task DeleteAsync(int albumId)
{
// Find the album record and check it exists
Album album = await GetAsync(x => x.Id == albumId);
if (album != null)
{
// Delete the associated tracks
await _factory.Tracks.DeleteAsync(albumId);

// Delete the album record and save changes
_factory.Context.Remove(album);
await _factory.Context.SaveChangesAsync();
}
}
}
}
15 changes: 15 additions & 0 deletions src/MusicCatalogue.Logic/Database/TrackManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,20 @@ public async Task<Track> AddAsync(int albumId, string title, int? number, int? d

return track;
}

/// <summary>
/// Delete the tracks associated with an album, given its ID
/// </summary>
/// <param name="albumId"></param>
/// <returns></returns>
public async Task DeleteAsync(int albumId)
{
List<Track> tracks = await ListAsync(x => x.AlbumId == albumId);
if (tracks.Any())
{
_context.Tracks.RemoveRange(tracks);
await _context.SaveChangesAsync();
}
}
}
}
7 changes: 5 additions & 2 deletions src/MusicCatalogue.Logic/Factory/MusicCatalogueFactory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using MusicCatalogue.Data;
using Microsoft.EntityFrameworkCore;
using MusicCatalogue.Data;
using MusicCatalogue.Entities.Interfaces;
using MusicCatalogue.Logic.Database;
using MusicCatalogue.Logic.DataExchange;
Expand All @@ -18,6 +19,7 @@ public class MusicCatalogueFactory : IMusicCatalogueFactory
private readonly Lazy<IStatisticsManager> _statistics;
private readonly Lazy<IJobStatusManager> _jobStatuses;

public DbContext Context { get; private set; }
public IArtistManager Artists { get { return _artists.Value; } }
public IAlbumManager Albums { get { return _albums.Value; } }
public ITrackManager Tracks { get { return _tracks.Value; } }
Expand All @@ -36,8 +38,9 @@ public class MusicCatalogueFactory : IMusicCatalogueFactory

public MusicCatalogueFactory(MusicCatalogueDbContext context)
{
Context = context;
_artists = new Lazy<IArtistManager>(() => new ArtistManager(context));
_albums = new Lazy<IAlbumManager>(() => new AlbumManager(context));
_albums = new Lazy<IAlbumManager>(() => new AlbumManager(this));
_tracks = new Lazy<ITrackManager>(() => new TrackManager(context));
_jobStatuses = new Lazy<IJobStatusManager>(() => new JobStatusManager(context));
_users = new Lazy<IUserManager>(() => new UserManager(context));
Expand Down
4 changes: 2 additions & 2 deletions src/MusicCatalogue.Logic/MusicCatalogue.Logic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>MusicCatalogue.Logic</PackageId>
<PackageVersion>1.6.0.0</PackageVersion>
<PackageVersion>1.7.0.0</PackageVersion>
<Authors>Dave Walker</Authors>
<Copyright>Copyright (c) Dave Walker 2023</Copyright>
<Owners>Dave Walker</Owners>
Expand All @@ -17,7 +17,7 @@
<PackageProjectUrl>https://github.com/davewalker5/MusicCatalogue</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<ReleaseVersion>1.6.0.0</ReleaseVersion>
<ReleaseVersion>1.7.0.0</ReleaseVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ReleaseVersion>1.6.0.0</ReleaseVersion>
<FileVersion>1.6.0.0</FileVersion>
<ProductVersion>1.6.0</ProductVersion>
<ReleaseVersion>1.7.0.0</ReleaseVersion>
<FileVersion>1.7.0.0</FileVersion>
<ProductVersion>1.7.0</ProductVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
Expand Down
41 changes: 30 additions & 11 deletions src/MusicCatalogue.Tests/AlbumManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,38 @@ public class AlbumManagerTest
private const int Released = 1957;
private const string Genre = "Jazz";
private const string CoverUrl = "https://some.host/blue-train.jpg";
private const string TrackTitle = "Blue Train";
private const int TrackNumber = 1;
private const int TrackDuration = 643200;

private IAlbumManager? _manager = null;
private IMusicCatalogueFactory? _factory;
private int _artistId;
private int _albumId;

[TestInitialize]
public void TestInitialize()
{
MusicCatalogueDbContext context = MusicCatalogueDbContextFactory.CreateInMemoryDbContext();
var factory = new MusicCatalogueFactory(context);
_manager = factory.Albums;
_factory = new MusicCatalogueFactory(context);

// Add an artist to the database
_artistId = Task.Run(() => factory.Artists.AddAsync(ArtistName)).Result.Id;
Task.Run(() => _manager.AddAsync(_artistId, AlbumTitle, Released, Genre, CoverUrl)).Wait();
_artistId = Task.Run(() => _factory.Artists.AddAsync(ArtistName)).Result.Id;
_albumId = Task.Run(() => _factory.Albums.AddAsync(_artistId, AlbumTitle, Released, Genre, CoverUrl)).Result.Id;
Task.Run(() => _factory.Tracks.AddAsync(_albumId, TrackTitle, TrackNumber, TrackDuration)).Wait();
}

[TestMethod]
public async Task AddDuplicateTest()
{
await _manager!.AddAsync(_artistId, AlbumTitle, Released, Genre, CoverUrl);
var albums = await _manager.ListAsync(x => true);
await _factory!.Albums.AddAsync(_artistId, AlbumTitle, Released, Genre, CoverUrl);
var albums = await _factory!.Albums.ListAsync(x => true);
Assert.AreEqual(1, albums.Count);
}

[TestMethod]
public async Task AddAndGetTest()
{
var album = await _manager!.GetAsync(a => a.Title == AlbumTitle);
var album = await _factory!.Albums.GetAsync(a => a.Title == AlbumTitle);
Assert.IsNotNull(album);
Assert.IsTrue(album.Id > 0);
Assert.AreEqual(_artistId, album.ArtistId);
Expand All @@ -52,23 +56,38 @@ public async Task AddAndGetTest()
[TestMethod]
public async Task GetMissingTest()
{
var album = await _manager!.GetAsync(a => a.Title == "Missing");
var album = await _factory!.Albums.GetAsync(a => a.Title == "Missing");
Assert.IsNull(album);
}

[TestMethod]
public async Task ListAllTest()
{
var albums = await _manager!.ListAsync(x => true);
var albums = await _factory!.Albums.ListAsync(x => true);
Assert.AreEqual(1, albums!.Count);
Assert.AreEqual(AlbumTitle, albums.First().Title);
}

[TestMethod]
public async Task ListMissingTest()
{
var albums = await _manager!.ListAsync(e => e.Title == "Missing");
var albums = await _factory!.Albums.ListAsync(e => e.Title == "Missing");
Assert.AreEqual(0, albums!.Count);
}

[TestMethod]
public async Task DeleteTest()
{
var album = await _factory!.Albums.GetAsync(a => a.Title == AlbumTitle);
Assert.IsNotNull(album);
Assert.AreEqual(1, album.Tracks.Count);

await _factory!.Albums.DeleteAsync(_albumId);
album = await _factory.Albums!.GetAsync(a => a.Title == AlbumTitle);
Assert.IsNull(album);

var tracks = await _factory.Tracks.ListAsync(x => x.AlbumId == _albumId);
Assert.IsFalse(tracks.Any());
}
}
}
9 changes: 9 additions & 0 deletions src/MusicCatalogue.Tests/TrackManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,14 @@ public async Task ListMissingTest()
var tracks = await _manager!.ListAsync(e => e.Title == "Missing");
Assert.AreEqual(0, tracks!.Count);
}

[TestMethod]
public async Task DeleteTest()
{
await _manager!.DeleteAsync(_albumId);
var tracks = await _manager!.ListAsync(e => e.AlbumId == _albumId);
Assert.AreEqual(0, tracks!.Count);

}
}
}
Loading

0 comments on commit 53a308c

Please sign in to comment.