finish brewery feature set

This commit is contained in:
Aaron Po
2026-06-19 00:48:25 -04:00
parent 254b2afb9f
commit d896f04274
10 changed files with 8040 additions and 7728 deletions

View File

@@ -11,6 +11,7 @@ using Infrastructure.Repository.Sql;
using Infrastructure.Repository.UserAccount;
using Infrastructure.Repository.Breweries;
using Service.Auth;
using Service.Breweries;
using Service.Emails;
using Service.UserManagement.User;
@@ -51,6 +52,7 @@ builder.Services.AddSingleton<
builder.Services.AddScoped<IUserAccountRepository, UserAccountRepository>();
builder.Services.AddScoped<IAuthRepository, AuthRepository>();
builder.Services.AddScoped<IBreweryRepository, BreweryRepository>();
builder.Services.AddScoped<IBreweryService, BreweryService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ILoginService, LoginService>();

View File

@@ -0,0 +1,15 @@
CREATE OR ALTER PROCEDURE dbo.USP_DeleteBrewery
@BreweryPostID UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1
FROM dbo.BreweryPost
WHERE BreweryPostID = @BreweryPostID)
THROW 50404, 'Brewery not found.', 1;
-- BreweryPostLocation and BreweryPostPhoto cascade-delete with their parent BreweryPost.
DELETE FROM dbo.BreweryPost
WHERE BreweryPostID = @BreweryPostID;
END

View File

@@ -0,0 +1,28 @@
CREATE OR ALTER PROCEDURE dbo.USP_GetAllBreweries(
@Limit INT = NULL,
@Offset INT = NULL
)
AS
BEGIN
SET NOCOUNT ON;
SELECT bp.BreweryPostID,
bp.PostedByID,
bp.BreweryName,
bp.Description,
bp.CreatedAt,
bp.UpdatedAt,
bp.Timer,
bpl.BreweryPostLocationID,
bpl.CityID,
bpl.AddressLine1,
bpl.AddressLine2,
bpl.PostalCode,
bpl.Coordinates
FROM dbo.BreweryPost bp
LEFT JOIN dbo.BreweryPostLocation bpl
ON bp.BreweryPostID = bpl.BreweryPostID
ORDER BY bp.CreatedAt DESC
OFFSET ISNULL(@Offset, 0) ROWS
FETCH NEXT ISNULL(@Limit, 2147483647) ROWS ONLY;
END

View File

@@ -0,0 +1,68 @@
CREATE OR ALTER PROCEDURE dbo.USP_UpdateBrewery(
@BreweryPostID UNIQUEIDENTIFIER,
@BreweryName NVARCHAR(256),
@Description NVARCHAR(512),
@BreweryPostLocationID UNIQUEIDENTIFIER = NULL,
@CityID UNIQUEIDENTIFIER = NULL,
@AddressLine1 NVARCHAR(256) = NULL,
@AddressLine2 NVARCHAR(256) = NULL,
@PostalCode NVARCHAR(20) = NULL,
@Coordinates GEOGRAPHY = NULL
)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF @BreweryName IS NULL
THROW 50001, 'Brewery name cannot be null.', 1;
IF @Description IS NULL
THROW 50002, 'Brewery description cannot be null.', 1;
IF NOT EXISTS (SELECT 1
FROM dbo.BreweryPost
WHERE BreweryPostID = @BreweryPostID)
THROW 50404, 'Brewery not found.', 1;
IF @CityID IS NOT NULL AND NOT EXISTS (SELECT 1
FROM dbo.City
WHERE CityID = @CityID)
THROW 50404, 'City not found.', 1;
BEGIN TRANSACTION;
UPDATE dbo.BreweryPost
SET BreweryName = @BreweryName,
Description = @Description,
UpdatedAt = GETDATE()
WHERE BreweryPostID = @BreweryPostID;
IF @CityID IS NULL
BEGIN
-- No location supplied: clear any existing location for this brewery.
DELETE FROM dbo.BreweryPostLocation
WHERE BreweryPostID = @BreweryPostID;
END
ELSE IF EXISTS (SELECT 1
FROM dbo.BreweryPostLocation
WHERE BreweryPostID = @BreweryPostID)
BEGIN
UPDATE dbo.BreweryPostLocation
SET CityID = @CityID,
AddressLine1 = @AddressLine1,
AddressLine2 = @AddressLine2,
PostalCode = @PostalCode,
Coordinates = @Coordinates
WHERE BreweryPostID = @BreweryPostID;
END
ELSE
BEGIN
INSERT INTO dbo.BreweryPostLocation
(BreweryPostLocationID, BreweryPostID, CityID, AddressLine1, AddressLine2, PostalCode, Coordinates)
VALUES (ISNULL(@BreweryPostLocationID, NEWID()), @BreweryPostID, @CityID, @AddressLine1, @AddressLine2,
@PostalCode, @Coordinates);
END
COMMIT TRANSACTION;
END

View File

@@ -38,35 +38,80 @@ public class BreweryRepository(ISqlConnectionFactory connectionFactory)
}
/// <summary>
/// Not yet implemented.
/// Retrieves all brewery posts, optionally paginated, using the <c>USP_GetAllBreweries</c>
/// stored procedure. The <c>@Limit</c> and <c>@Offset</c> parameters are only added when their
/// corresponding argument has a value.
/// </summary>
/// <param name="limit">The maximum number of records to return, or <c>null</c> for no limit.</param>
/// <param name="offset">The number of records to skip, or <c>null</c> for no offset.</param>
/// <returns>Never returns; always throws.</returns>
/// <exception cref="NotImplementedException">Always thrown.</exception>
public Task<IEnumerable<BreweryPost>> GetAllAsync(int? limit, int? offset)
/// <returns>The collection of matching <see cref="BreweryPost"/> records.</returns>
/// <exception cref="Microsoft.Data.SqlClient.SqlException">Thrown when the database command fails.</exception>
public async Task<IEnumerable<BreweryPost>> GetAllAsync(int? limit, int? offset)
{
throw new NotImplementedException();
await using var connection = await CreateConnection();
await using var command = connection.CreateCommand();
command.CommandText = "USP_GetAllBreweries";
command.CommandType = System.Data.CommandType.StoredProcedure;
if (limit.HasValue)
AddParameter(command, "@Limit", limit.Value);
if (offset.HasValue)
AddParameter(command, "@Offset", offset.Value);
await using var reader = await command.ExecuteReaderAsync();
var breweries = new List<BreweryPost>();
while (await reader.ReadAsync())
{
breweries.Add(MapToEntity(reader));
}
return breweries;
}
/// <summary>
/// Not yet implemented.
/// Updates a brewery post's name and description, and upserts or clears its location, using the
/// <c>USP_UpdateBrewery</c> stored procedure. When <paramref name="brewery"/>.<c>Location</c> is
/// <c>null</c>, any existing location for the brewery is removed.
/// </summary>
/// <param name="brewery">The brewery post containing updated values.</param>
/// <exception cref="NotImplementedException">Always thrown.</exception>
public Task UpdateAsync(BreweryPost brewery)
/// <exception cref="Microsoft.Data.SqlClient.SqlException">Thrown when the database command fails.</exception>
public async Task UpdateAsync(BreweryPost brewery)
{
throw new NotImplementedException();
await using var connection = await CreateConnection();
await using var command = connection.CreateCommand();
command.CommandText = "USP_UpdateBrewery";
command.CommandType = System.Data.CommandType.StoredProcedure;
AddParameter(command, "@BreweryPostID", brewery.BreweryPostId);
AddParameter(command, "@BreweryName", brewery.BreweryName);
AddParameter(command, "@Description", brewery.Description);
AddParameter(command, "@BreweryPostLocationID", brewery.Location?.BreweryPostLocationId);
AddParameter(command, "@CityID", brewery.Location?.CityId);
AddParameter(command, "@AddressLine1", brewery.Location?.AddressLine1);
AddParameter(command, "@AddressLine2", brewery.Location?.AddressLine2);
AddParameter(command, "@PostalCode", brewery.Location?.PostalCode);
AddParameter(command, "@Coordinates", brewery.Location?.Coordinates);
await command.ExecuteNonQueryAsync();
}
/// <summary>
/// Not yet implemented.
/// Deletes a brewery post by ID using the <c>USP_DeleteBrewery</c> stored procedure. Its location
/// and photos are removed via cascading foreign keys.
/// </summary>
/// <param name="id">The unique identifier of the brewery post to delete.</param>
/// <exception cref="NotImplementedException">Always thrown.</exception>
public Task DeleteAsync(Guid id)
/// <exception cref="Microsoft.Data.SqlClient.SqlException">Thrown when the database command fails.</exception>
public async Task DeleteAsync(Guid id)
{
throw new NotImplementedException();
await using var connection = await CreateConnection();
await using var command = connection.CreateCommand();
command.CommandText = "USP_DeleteBrewery";
command.CommandType = System.Data.CommandType.StoredProcedure;
AddParameter(command, "@BreweryPostID", id);
await command.ExecuteNonQueryAsync();
}
/// <summary>