Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
feat: cache category
Browse files Browse the repository at this point in the history
  • Loading branch information
foxminchan committed Jun 6, 2024
1 parent 64b0eb7 commit 6dde099
Show file tree
Hide file tree
Showing 13 changed files with 104 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
using System.Text.Json;
using Ardalis.Result;
using MediatR;
using Microsoft.Extensions.Logging;
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Events;
using RookieShop.Domain.Entities.CategoryAggregator.Primitives;
using RookieShop.Domain.SharedKernel;

namespace RookieShop.Application.Categories.Commands.Create;

public sealed class CreateCategoryHandler(IRepository<Category> repository, ILogger<CreateCategoryHandler> logger)
: ICommandHandler<CreateCategoryCommand, Result<CategoryId>>
public sealed class CreateCategoryHandler(
IRepository<Category> repository,
ILogger<CreateCategoryHandler> logger,
IPublisher publisher) : ICommandHandler<CreateCategoryCommand, Result<CategoryId>>
{
public async Task<Result<CategoryId>> Handle(CreateCategoryCommand request, CancellationToken cancellationToken)
{
Expand All @@ -19,6 +23,10 @@ public async Task<Result<CategoryId>> Handle(CreateCategoryCommand request, Canc

var result = await repository.AddAsync(category, cancellationToken);

await publisher.Publish(
new CreatedCategoryEvent(result.Id, result.Name, result.Description),
cancellationToken);

return result.Id;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Ardalis.GuardClauses;
using Ardalis.Result;
using MediatR;
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Events;
using RookieShop.Domain.SharedKernel;

namespace RookieShop.Application.Categories.Commands.Delete;

public sealed class DeleteCategoryHandler(IRepository<Category> repository)
public sealed class DeleteCategoryHandler(IRepository<Category> repository, IPublisher publisher)
: ICommandHandler<DeleteCategoryCommand, Result>
{
public async Task<Result> Handle(DeleteCategoryCommand request, CancellationToken cancellationToken)
Expand All @@ -16,6 +18,10 @@ public async Task<Result> Handle(DeleteCategoryCommand request, CancellationToke

await repository.DeleteAsync(category, cancellationToken);

await publisher.Publish(
new DeletedCategoryEvent(category.Id),
cancellationToken);

return Result.Success();
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using System.Text.Json;
using Ardalis.GuardClauses;
using Ardalis.Result;
using MediatR;
using Microsoft.Extensions.Logging;
using RookieShop.Application.Categories.DTOs;
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Events;
using RookieShop.Domain.SharedKernel;

namespace RookieShop.Application.Categories.Commands.Update;

public sealed class UpdateCategoryHandler(IRepository<Category> repository, ILogger<UpdateCategoryHandler> logger)
: ICommandHandler<UpdateCategoryCommand, Result<CategoryDto>>
public sealed class UpdateCategoryHandler(
IRepository<Category> repository,
ILogger<UpdateCategoryHandler> logger,
IPublisher publisher) : ICommandHandler<UpdateCategoryCommand, Result<CategoryDto>>
{
public async Task<Result<CategoryDto>> Handle(UpdateCategoryCommand request, CancellationToken cancellationToken)
{
Expand All @@ -24,6 +28,10 @@ public async Task<Result<CategoryDto>> Handle(UpdateCategoryCommand request, Can

await repository.UpdateAsync(category, cancellationToken);

await publisher.Publish(
new UpdatedCategoryEvent(category.Id, category.Name, category.Description),
cancellationToken);

return category.ToCategoryDto();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using MediatR;
using RookieShop.Domain.Entities.CategoryAggregator.Events;
using RookieShop.Infrastructure.Cache.Redis;

namespace RookieShop.Application.Categories.Events;

public sealed class CachedCategoryInvalidationHandler(IRedisService redisService) :
INotificationHandler<CreatedCategoryEvent>,
INotificationHandler<UpdatedCategoryEvent>,
INotificationHandler<DeletedCategoryEvent>
{
private const string CacheKey = nameof(Categories);

public async Task Handle(CreatedCategoryEvent notification, CancellationToken cancellationToken) =>
await InvalidateCache();

public async Task Handle(UpdatedCategoryEvent notification, CancellationToken cancellationToken) =>
await InvalidateCache();

public async Task Handle(DeletedCategoryEvent notification, CancellationToken cancellationToken) =>
await InvalidateCache();

private async Task InvalidateCache() => await redisService.RemoveAsync(CacheKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Specifications;
using RookieShop.Domain.SharedKernel;
using RookieShop.Infrastructure.Cache.Redis;

namespace RookieShop.Application.Categories.Queries.List;

public sealed class ListCategoriesHandler(IReadRepository<Category> repository)
public sealed class ListCategoriesHandler(IReadRepository<Category> repository, IRedisService redisService)
: IQueryHandler<ListCategoriesQuery, PagedResult<IEnumerable<CategoryDto>>>
{
public async Task<PagedResult<IEnumerable<CategoryDto>>> Handle(ListCategoriesQuery request,
CancellationToken cancellationToken)
{
CategoriesFilterSpec spec = new(request.PageIndex, request.PageSize, request.Search);

var categories = await repository.ListAsync(spec, cancellationToken);
var categories = await redisService.GetOrSetAsync(
request.CacheKey,
() => repository.ListAsync(spec, cancellationToken).Result,
request.CacheDuration);

var totalRecords = await repository.CountAsync(cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ardalis.GuardClauses;
using RookieShop.Domain.Entities.CategoryAggregator.Primitives;
using RookieShop.Domain.SeedWork;

namespace RookieShop.Domain.Entities.CategoryAggregator.Events;

public sealed class CreatedCategoryEvent(CategoryId categoryId, string? categoryName, string? description) : EventBase
{
public CategoryId CategoryId { get; set; } = Guard.Against.Default(categoryId);
public string? CategoryName { get; set; } = Guard.Against.NullOrEmpty(categoryName);
public string? Description { get; set; } = description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Ardalis.GuardClauses;
using RookieShop.Domain.Entities.CategoryAggregator.Primitives;
using RookieShop.Domain.SeedWork;

namespace RookieShop.Domain.Entities.CategoryAggregator.Events;

public sealed class DeletedCategoryEvent(CategoryId categoryId) : EventBase
{
public CategoryId CategoryId { get; set; } = Guard.Against.Default(categoryId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Ardalis.GuardClauses;
using RookieShop.Domain.Entities.CategoryAggregator.Primitives;
using RookieShop.Domain.SeedWork;

namespace RookieShop.Domain.Entities.CategoryAggregator.Events;

public sealed class UpdatedCategoryEvent(CategoryId categoryId, string? categoryName, string? description) : EventBase
{
public CategoryId CategoryId { get; set; } = Guard.Against.Default(categoryId);
public string? CategoryName { get; set; } = Guard.Against.NullOrEmpty(categoryName);
public string? Description { get; set; } = description;
}
1 change: 0 additions & 1 deletion src/RookieShop.Persistence/TxBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using RookieShop.Domain.SeedWork;
using RookieShop.Domain.SharedKernel;

namespace RookieShop.Persistence;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using MediatR;
using Microsoft.Extensions.Logging;
using RookieShop.Application.Categories.Commands.Create;
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.SharedKernel;
Expand All @@ -13,8 +14,9 @@ public class CreateCategory
public CreateCategory()
{
Mock<ILogger<CreateCategoryHandler>> loggerMock = new();
Mock<IPublisher> publisherMock = new();
_repositoryMock = new();
_handler = new(_repositoryMock.Object, loggerMock.Object);
_handler = new(_repositoryMock.Object, loggerMock.Object, publisherMock.Object);
}

private static Category CreateCategoryEntity() => new("Category Name", "Category Description");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ardalis.GuardClauses;
using MediatR;
using RookieShop.Application.Categories.Commands.Delete;
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Primitives;
Expand All @@ -13,8 +14,9 @@ public sealed class DeleteCategory

public DeleteCategory()
{
Mock<IPublisher> publisherMock = new();
_repositoryMock = new();
_handler = new(_repositoryMock.Object);
_handler = new(_repositoryMock.Object, publisherMock.Object);
}

private static Category CreateCategoryEntity() => new("Category Name", "Category Description");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using RookieShop.Domain.Entities.CategoryAggregator;
using RookieShop.Domain.Entities.CategoryAggregator.Specifications;
using RookieShop.Domain.SharedKernel;
using RookieShop.Infrastructure.Cache.Redis;

namespace RookieShop.UnitTests.Application.CategoryHandlerTest;

Expand All @@ -13,7 +14,8 @@ public sealed class ListCategory
public ListCategory()
{
_repositoryMock = new();
_handler = new(_repositoryMock.Object);
Mock<IRedisService> redisServiceMock = new();
_handler = new(_repositoryMock.Object, redisServiceMock.Object);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ardalis.GuardClauses;
using MediatR;
using Microsoft.Extensions.Logging;
using RookieShop.Application.Categories.Commands.Update;
using RookieShop.Domain.Entities.CategoryAggregator;
Expand All @@ -15,8 +16,9 @@ public sealed class UpdateCategory
public UpdateCategory()
{
Mock<ILogger<UpdateCategoryHandler>> loggerMock = new();
Mock<IPublisher> publisherMock = new();
_repositoryMock = new();
_handler = new(_repositoryMock.Object, loggerMock.Object);
_handler = new(_repositoryMock.Object, loggerMock.Object, publisherMock.Object);
}

private static Category CreateCategoryEntity() => new("Category Name", "Category Description");
Expand Down

0 comments on commit 6dde099

Please sign in to comment.