Add brewery location query endpoints

This commit is contained in:
Aaron Po
2026-08-26 23:19:50 -04:00
parent d6306cbcba
commit eebb87811f
14 changed files with 491 additions and 61 deletions

View File

@@ -0,0 +1,21 @@
using Domain.Entities;
using Features.Breweries.Dtos;
using Features.Breweries.Repository;
using MediatR;
namespace Features.Breweries.Queries.GetAllBreweryLocations;
/// <summary>Handles <see cref="GetAllBreweryLocationsQuery" /> by retrieving all located brewery posts.</summary>
public class GetAllBreweryLocationsHandler(IBreweryRepository repository)
: IRequestHandler<GetAllBreweryLocationsQuery, IEnumerable<SimplifiedBreweryDto>>
{
/// <summary>Retrieves every brewery post that has a set location.</summary>
public async Task<IEnumerable<SimplifiedBreweryDto>> Handle(
GetAllBreweryLocationsQuery request,
CancellationToken cancellationToken
)
{
IEnumerable<BreweryPost> breweries = await repository.GetAllLocations();
return breweries.Select(b => b.ToSimplifiedDto());
}
}

View File

@@ -0,0 +1,10 @@
using Features.Breweries.Dtos;
using MediatR;
namespace Features.Breweries.Queries.GetAllBreweryLocations;
/// <summary>
/// Retrieves all brewery posts that have a set location. Bound directly from
/// <c>GET /api/brewery/locations</c>.
/// </summary>
public record GetAllBreweryLocationsQuery : IRequest<IEnumerable<SimplifiedBreweryDto>>;

View File

@@ -0,0 +1,26 @@
using Domain.Entities;
using Features.Breweries.Dtos;
using Features.Breweries.Repository;
using MediatR;
namespace Features.Breweries.Queries.GetBreweryLocationsWithinRange;
/// <summary>
/// Handles <see cref="GetBreweryLocationsWithinRangeQuery" /> by retrieving nearby located brewery posts.
/// </summary>
public class GetBreweryLocationsWithinRangeHandler(IBreweryRepository repository)
: IRequestHandler<GetBreweryLocationsWithinRangeQuery, IEnumerable<SimplifiedBreweryDto>>
{
/// <summary>Retrieves brewery posts within range of the requested coordinates, nearest first.</summary>
public async Task<IEnumerable<SimplifiedBreweryDto>> Handle(
GetBreweryLocationsWithinRangeQuery request,
CancellationToken cancellationToken
)
{
IEnumerable<BreweryPost> breweries = await repository.GetAllLocationsWithinRange(
new CoordinateData(request.Latitude, request.Longitude),
request.RangeInMetres
);
return breweries.Select(b => b.ToSimplifiedDto());
}
}

View File

@@ -0,0 +1,15 @@
using Features.Breweries.Dtos;
using MediatR;
namespace Features.Breweries.Queries.GetBreweryLocationsWithinRange;
/// <summary>
/// Retrieves brewery posts with a set location within <paramref name="RangeInMetres" /> of the given
/// coordinates, nearest first. Bound directly from the query string of
/// <c>GET /api/brewery/locations/nearby</c>.
/// </summary>
/// <param name="Latitude">The origin latitude, in decimal degrees.</param>
/// <param name="Longitude">The origin longitude, in decimal degrees.</param>
/// <param name="RangeInMetres">The maximum distance, in metres, from the origin coordinates.</param>
public record GetBreweryLocationsWithinRangeQuery(double Latitude, double Longitude, double RangeInMetres)
: IRequest<IEnumerable<SimplifiedBreweryDto>>;

View File

@@ -0,0 +1,23 @@
using FluentValidation;
namespace Features.Breweries.Queries.GetBreweryLocationsWithinRange;
/// <summary>Validates <see cref="GetBreweryLocationsWithinRangeQuery" />.</summary>
public class GetBreweryLocationsWithinRangeValidator
: AbstractValidator<GetBreweryLocationsWithinRangeQuery>
{
public GetBreweryLocationsWithinRangeValidator()
{
RuleFor(x => x.Latitude)
.InclusiveBetween(-90, 90)
.WithMessage("Latitude must be between -90 and 90 degrees.");
RuleFor(x => x.Longitude)
.InclusiveBetween(-180, 180)
.WithMessage("Longitude must be between -180 and 180 degrees.");
RuleFor(x => x.RangeInMetres)
.GreaterThan(0)
.WithMessage("RangeInMetres must be greater than zero.");
}
}