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

Commit

Permalink
fix: best seller query issue
Browse files Browse the repository at this point in the history
  • Loading branch information
foxminchan committed Jun 2, 2024
1 parent 6864024 commit 326a87e
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace RookieShop.ApiService.Endpoints.Reports;

public sealed record BestSellerProductsRequest(int Top, DateTime? From, DateTime? To);
public sealed record BestSellerProductsRequest(int Top);
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public sealed class BestSellerProducts(ISender sender)
{
public void MapEndpoint(IEndpointRouteBuilder app) =>
app.MapGet("/reports/best-seller-products",
async (int top, DateTime? from, DateTime? to) => await HandleAsync(new(top, from, to)))
async (int top) => await HandleAsync(new(top)))
.Produces<Ok<List<BestSellerProductsDto>>>()
.WithTags(nameof(Reports))
.WithName("Best Seller Products")
Expand All @@ -22,7 +22,7 @@ public sealed class BestSellerProducts(ISender sender)
public async Task<Ok<List<BestSellerProductsDto>>> HandleAsync(BestSellerProductsRequest request,
CancellationToken cancellationToken = default)
{
BestSellerProductsQuery query = new(request.Top, request.From, request.To);
BestSellerProductsQuery query = new(request.Top);

var result = await sender.Send(query, cancellationToken);

Expand Down
18 changes: 9 additions & 9 deletions src/RookieShop.Application/Reports/DTOs/BestSellerProductsDto.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using RookieShop.Domain.Entities.ProductAggregator.ValueObjects;
namespace RookieShop.Application.Reports.DTOs;

namespace RookieShop.Application.Reports.DTOs;

public sealed record BestSellerProductsDto(
Guid ProductId,
string ProductName,
int TotalSoldQuantity,
ProductPrice Price,
string? ImageUrl);
public sealed class BestSellerProductsDto
{
public Guid ProductId { get; set; }
public string? ProductName { get; set; }
public int TotalSoldQuantity { get; set; }
public string Price { get; set; } = string.Empty;
public string? ImageUrl { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,42 @@
using Dapper;
using RookieShop.Application.Reports.DTOs;
using RookieShop.Domain.SharedKernel;
using RookieShop.Infrastructure.Storage.Azurite;
using RookieShop.Persistence;

namespace RookieShop.Application.Reports.Queries.BestSellerProducts;

public sealed class BestSellerProductsHandler(IDatabaseFactory factory)
public sealed class BestSellerProductsHandler(IDatabaseFactory factory, IAzuriteService azuriteService)
: IQueryHandler<BestSellerProductsQuery, Result<IEnumerable<BestSellerProductsDto>>>
{
public async Task<Result<IEnumerable<BestSellerProductsDto>>> Handle(BestSellerProductsQuery request,
CancellationToken cancellationToken)
{
const string sql = $"""
SELECT
p.id AS {nameof(BestSellerProductsDto.ProductId)},
p.name AS {nameof(BestSellerProductsDto.ProductName)},
p.image_name AS {nameof(BestSellerProductsDto.ImageUrl)},
SUM(od.quantity) AS {nameof(BestSellerProductsDto.TotalSoldQuantity)},
p.price AS {nameof(BestSellerProductsDto.Price)}
p.id AS {nameof(BestSellerProductsDto.ProductId)},
p.name AS {nameof(BestSellerProductsDto.ProductName)},
p.image_name AS {nameof(BestSellerProductsDto.ImageUrl)},
p.price AS {nameof(BestSellerProductsDto.Price)},
COUNT(od.quantity) AS {nameof(BestSellerProductsDto.TotalSoldQuantity)}
FROM products p
JOIN order_details od ON p.id = od.product_id
JOIN orders o ON od.order_id = o.id
WHERE (@From IS NULL OR o.update_date >= @From)
AND (@To IS NULL OR o.update_date <= @To)
AND o.order_status = 1
GROUP BY p.id, p.name, p.image_name, p.price
JOIN order_details od ON p.id = od.product_id
JOIN orders o ON od.order_id = o.id
WHERE o.order_status = 1
GROUP BY p.id, p.name, p.image_name, p.price
ORDER BY {nameof(BestSellerProductsDto.TotalSoldQuantity)} DESC
LIMIT @Top;
LIMIT 5
""";

using var conn = factory.GetOpenConnection();

var result = await conn.QueryAsync<BestSellerProductsDto>(sql, new { request.From, request.To, request.Top });
var data = await conn.QueryAsync<BestSellerProductsDto>(sql, new { request.Top });

var result = data.Select(item =>
{
item.ImageUrl = azuriteService.GetFileUrl(item.ImageUrl);
return item;
}).ToList();

return result.ToList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@

namespace RookieShop.Application.Reports.Queries.BestSellerProducts;

public sealed record BestSellerProductsQuery(int Top, DateTime? From, DateTime? To)
: IQuery<Result<IEnumerable<BestSellerProductsDto>>>;
public sealed record BestSellerProductsQuery(int Top) : IQuery<Result<IEnumerable<BestSellerProductsDto>>>;
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,5 @@ namespace RookieShop.Application.Reports.Queries.BestSellerProducts;

public sealed class BestSellerProductsValidator : AbstractValidator<BestSellerProductsQuery>
{
public BestSellerProductsValidator()
{
RuleFor(x => x.Top)
.NotEmpty()
.GreaterThan(0);

RuleFor(x => x.From)
.LessThan(x => x.To);

RuleFor(x => x.To)
.GreaterThan(x => x.From);
}
public BestSellerProductsValidator() => RuleFor(x => x.Top).NotEmpty().GreaterThan(0);
}

0 comments on commit 326a87e

Please sign in to comment.