using Dapper; using Npgsql; namespace SDG_Backend_Barracuda.Models; public record Deck { public int Id { get; init; } public string Name { get; init; } = string.Empty; public int CardListId { get; init; } public IEnumerable? GameList { get; init; } public Deck() { } public Deck(int id, string name, int cardListId, IEnumerable? gameList = null) { Id = id; Name = name; CardListId = cardListId; GameList = gameList; } } public record DeckInformation(string Name, int CardListId, IEnumerable? GameIds = null); public interface IDeckModel : IDatabaseModel { } public class DeckModel(NpgsqlDataSource dataSource) : IDeckModel, IEndpointRouteHandler { public static void MapEndpoints(IEndpointRouteBuilder router) { var deckEndpoint = router.MapGroup("/deck"); // Create deckEndpoint.MapPost("/", async (DeckInformation input, IDeckModel model) => { var newDeck = await model.Create(input); return Results.Created($"/deck/{newDeck.Id}", newDeck); }); // Get all deckEndpoint.MapGet("/", async (IDeckModel model) => Results.Ok(await model.GetAll())); // Get one deckEndpoint.MapGet("/{id}", async (int id, IDeckModel model) => await model.GetById(id) is { } d ? Results.Ok(d) : Results.NotFound()); // Update deckEndpoint.MapPut("/{id}", async (int id, DeckInformation input, IDeckModel model) => await model.Update(id, input) is { } d ? Results.Ok(d) : Results.NotFound()); // Delete deckEndpoint.MapDelete("/{id}", async (int id, IDeckModel model) => await model.Delete(id) ? Results.NoContent() : Results.NotFound()); } public async Task> GetAll() { await using var connection = await dataSource.OpenConnectionAsync(); var sql = """SELECT * FROM "Deck";"""; var decks = await connection.QueryAsync(sql); var result = new List(); foreach (var deck in decks) { result.Add(await GetById(deck.Id) ?? deck); } return result; } public async Task GetById(int id) { await using var connection = await dataSource.OpenConnectionAsync(); var deckSql = """SELECT * FROM "Deck" WHERE "Id" = @Id;"""; var deck = await connection.QueryFirstOrDefaultAsync(deckSql, new { Id = id }); if (deck == null) return null; var gamesSql = """ SELECT g.* FROM "Game" g JOIN "DeckGame" dg ON g."Id" = dg."GameId" WHERE dg."DeckId" = @Id; """; var games = await connection.QueryAsync(gamesSql, new { Id = id }); return deck with { GameList = games }; } public async Task Create(DeckInformation input) { await using var connection = await dataSource.OpenConnectionAsync(); var sql = """ INSERT INTO "Deck" ("Name", "CardListId") VALUES (@Name, @CardListId) RETURNING "Id", "Name", "CardListId"; """; var newDeck = await connection.QuerySingleAsync(sql, new { input.Name, input.CardListId }); if (input.GameIds != null) { foreach (var gameId in input.GameIds) { await connection.ExecuteAsync( """INSERT INTO "DeckGame" ("DeckId", "GameId") VALUES (@DeckId, @GameId)""", new { DeckId = newDeck.Id, GameId = gameId }); } } return (await GetById(newDeck.Id))!; } public async Task Update(int id, DeckInformation input) { await using var connection = await dataSource.OpenConnectionAsync(); var sql = """ UPDATE "Deck" SET "Name" = @Name, "CardListId" = @CardListId WHERE "Id" = @Id RETURNING "Id", "Name", "CardListId"; """; var updatedDeck = await connection.QueryFirstOrDefaultAsync(sql, new { Id = id, input.Name, input.CardListId }); if (updatedDeck == null) return null; await connection.ExecuteAsync("""DELETE FROM "DeckGame" WHERE "DeckId" = @Id""", new { Id = id }); if (input.GameIds != null) { foreach (var gameId in input.GameIds) { await connection.ExecuteAsync( """INSERT INTO "DeckGame" ("DeckId", "GameId") VALUES (@Id, @GameId)""", new { Id = id, GameId = gameId }); } } return await GetById(id); } public async Task Delete(int id) { await using var connection = await dataSource.OpenConnectionAsync(); var rowsAffected = await connection.ExecuteAsync("""DELETE FROM "Deck" WHERE "Id" = @Id""", new { Id = id }); return rowsAffected > 0; } }