From 11bff0de6343f50b696176fa9e24363845a88dbb Mon Sep 17 00:00:00 2001 From: moarten Date: Sat, 18 Apr 2026 20:07:24 +0200 Subject: [PATCH] Added endpoints to update verspakketten and add beoordeling. Added some validations and other tweaks --- .../Controllers/VerspakkettenController.cs | 44 +++++ .../Requests/AddBeoordelingRequest.cs | 12 ++ .../Requests/UpdateVerspakketRequest.cs | 12 ++ .../Interfaces/ILutraDbContext.cs | 2 + .../Models/Verspakketten/Verspakket.cs | 6 + .../Verspakketten/AddBeoordeling.Command.cs | 13 ++ .../Verspakketten/AddBeoordeling.Handler.cs | 41 +++++ .../Verspakketten/AddBeoordeling.Response.cs | 9 + .../Verspakketten/AddBeoordeling.cs | 3 + .../Verspakketten/CreateVerspakket.Command.cs | 3 +- .../Verspakketten/GetVerspakket.Handler.cs | 3 + .../Verspakketten/GetVerspakketten.Handler.cs | 3 + .../Verspakketten/UpdateVerspakket.Command.cs | 11 ++ .../Verspakketten/UpdateVerspakket.Handler.cs | 62 +++++++ .../UpdateVerspakket.Response.cs | 9 + .../Verspakketten/UpdateVerspakket.cs | 3 + Lutra/Lutra.Domain/Entities/Verspakket.cs | 1 + Lutra/Lutra.Infrastructure/LutraDbContext.cs | 20 ++- ...dAantalPersonenCheckConstraint.Designer.cs | 157 +++++++++++++++++ ...173428_AddAantalPersonenCheckConstraint.cs | 27 +++ ...ddPrijsInCentenCheckConstraint.Designer.cs | 159 ++++++++++++++++++ ...8174149_AddPrijsInCentenCheckConstraint.cs | 27 +++ .../Migrations/LutraDbContextModelSnapshot.cs | 9 +- 23 files changed, 628 insertions(+), 8 deletions(-) create mode 100644 Lutra/Lutra.API/Requests/AddBeoordelingRequest.cs create mode 100644 Lutra/Lutra.API/Requests/UpdateVerspakketRequest.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Command.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Handler.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Response.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/AddBeoordeling.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Command.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Handler.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Response.cs create mode 100644 Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.cs create mode 100644 Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.Designer.cs create mode 100644 Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.cs create mode 100644 Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.Designer.cs create mode 100644 Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.cs diff --git a/Lutra/Lutra.API/Controllers/VerspakkettenController.cs b/Lutra/Lutra.API/Controllers/VerspakkettenController.cs index 37a2a52..7c5db45 100644 --- a/Lutra/Lutra.API/Controllers/VerspakkettenController.cs +++ b/Lutra/Lutra.API/Controllers/VerspakkettenController.cs @@ -1,4 +1,5 @@ using Cortex.Mediator; +using Lutra.API.Requests; using Lutra.Application.Verspakketten; using Microsoft.AspNetCore.Mvc; @@ -72,5 +73,48 @@ namespace Lutra.API.Controllers return BadRequest(ex.Message); } } + + /// + /// Updates an existing verspakket with the provided values. + /// + /// The verspakket identifier. + /// The updated verspakket values. + /// + /// Returns 204 No Content when the update succeeds. + /// Returns 404 Not Found when the specified verspakket does not exist. + /// + [HttpPut("{id:guid}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task Update(Guid id, [FromBody] UpdateVerspakketRequest request) + { + var command = new UpdateVerspakket.Command(id, request.Naam, request.PrijsInCenten, request.AantalPersonen, request.SupermarktId); + await mediator.SendCommandAsync(command); + return NoContent(); + } + + /// + /// Adds a beoordeling to an existing verspakket. + /// + /// The verspakket ID. + /// The beoordeling values to add. + /// Returns 201 Created with the created beoordeling identifier. + [HttpPost("{id:guid}/beoordelingen")] + [ProducesResponseType(typeof(AddBeoordeling.Response), StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + public async Task> AddBeoordeling(Guid id, [FromBody] AddBeoordelingRequest request) + { + try + { + var command = new AddBeoordeling.Command(id, request.CijferSmaak, request.CijferBereiden, request.Aanbevolen, request.Tekst); + var result = await mediator.SendCommandAsync(command); + + return CreatedAtAction(nameof(GetById), new { id }, result); + } + catch (InvalidOperationException ex) + { + return BadRequest(ex.Message); + } + } } } \ No newline at end of file diff --git a/Lutra/Lutra.API/Requests/AddBeoordelingRequest.cs b/Lutra/Lutra.API/Requests/AddBeoordelingRequest.cs new file mode 100644 index 0000000..ecceb3a --- /dev/null +++ b/Lutra/Lutra.API/Requests/AddBeoordelingRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Lutra.API.Requests; + +/// +/// Represents the data required to add a beoordeling to a verspakket. +/// +public sealed record AddBeoordelingRequest( + [Range(1, 10)] int CijferSmaak, + [Range(1, 10)] int CijferBereiden, + bool Aanbevolen, + [MaxLength(1024)] string? Tekst); \ No newline at end of file diff --git a/Lutra/Lutra.API/Requests/UpdateVerspakketRequest.cs b/Lutra/Lutra.API/Requests/UpdateVerspakketRequest.cs new file mode 100644 index 0000000..375ff52 --- /dev/null +++ b/Lutra/Lutra.API/Requests/UpdateVerspakketRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Lutra.API.Requests; + +/// +/// Represents the data required to update a verspakket. +/// +public sealed record UpdateVerspakketRequest( + [Required, MaxLength(50)] string Naam, + [Range(0, int.MaxValue)] int PrijsInCenten, + [Range(1, 10)] int AantalPersonen, + [Required] Guid SupermarktId); diff --git a/Lutra/Lutra.Application/Interfaces/ILutraDbContext.cs b/Lutra/Lutra.Application/Interfaces/ILutraDbContext.cs index 1e5a811..e9807db 100644 --- a/Lutra/Lutra.Application/Interfaces/ILutraDbContext.cs +++ b/Lutra/Lutra.Application/Interfaces/ILutraDbContext.cs @@ -6,6 +6,8 @@ public interface ILutraDbContext { DbSet Supermarkten { get; } + DbSet Beoordelingen { get; } + DbSet Verspaketten { get; } Task SaveChangesAsync(CancellationToken cancellationToken); diff --git a/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs b/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs index 46a7d78..e07938a 100644 --- a/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs +++ b/Lutra/Lutra.Application/Models/Verspakketten/Verspakket.cs @@ -10,6 +10,12 @@ namespace Lutra.Application.Models.Verspakketten public int? PrijsInCenten { get; init; } + public int AantalPersonen { get; init; } + + public double? AverageCijferSmaak { get; init; } + + public double? AverageCijferBereiden { get; init; } + public Beoordeling[]? Beoordelingen { get; init; } public Supermarkt? Supermarkt { get; init; } diff --git a/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Command.cs b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Command.cs new file mode 100644 index 0000000..d9a235d --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Command.cs @@ -0,0 +1,13 @@ +using Cortex.Mediator.Commands; + +namespace Lutra.Application.Verspakketten; + +public sealed partial class AddBeoordeling +{ + public sealed record Command( + Guid VerspakketId, + int CijferSmaak, + int CijferBereiden, + bool Aanbevolen, + string? Tekst) : ICommand; +} \ No newline at end of file diff --git a/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Handler.cs b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Handler.cs new file mode 100644 index 0000000..c733366 --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Handler.cs @@ -0,0 +1,41 @@ +using Cortex.Mediator.Commands; +using Lutra.Application.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace Lutra.Application.Verspakketten; + +public sealed partial class AddBeoordeling +{ + public sealed class Handler(ILutraDbContext context) : ICommandHandler + { + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var verspakketExists = await context.Verspaketten + .AsNoTracking() + .AnyAsync(v => v.Id == request.VerspakketId && v.DeletedAt == null, cancellationToken); + + if (!verspakketExists) + { + throw new InvalidOperationException($"Verspakket with id '{request.VerspakketId}' was not found."); + } + + var now = DateTime.UtcNow; + var beoordeling = new Domain.Entities.Beoordeling + { + Id = Guid.NewGuid(), + CijferSmaak = request.CijferSmaak, + CijferBereiden = request.CijferBereiden, + Aanbevolen = request.Aanbevolen, + Tekst = request.Tekst, + VerspakketId = request.VerspakketId, + CreatedAt = now, + ModifiedAt = now + }; + + await context.Beoordelingen.AddAsync(beoordeling, cancellationToken); + await context.SaveChangesAsync(cancellationToken); + + return new Response { Id = beoordeling.Id }; + } + } +} \ No newline at end of file diff --git a/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Response.cs b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Response.cs new file mode 100644 index 0000000..c039e06 --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.Response.cs @@ -0,0 +1,9 @@ +namespace Lutra.Application.Verspakketten; + +public sealed partial class AddBeoordeling +{ + public sealed class Response + { + public required Guid Id { get; set; } + } +} \ No newline at end of file diff --git a/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.cs b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.cs new file mode 100644 index 0000000..20e491d --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/AddBeoordeling.cs @@ -0,0 +1,3 @@ +namespace Lutra.Application.Verspakketten; + +public sealed partial class AddBeoordeling { } \ No newline at end of file diff --git a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs index 9a35b7c..3c81545 100644 --- a/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs +++ b/Lutra/Lutra.Application/Verspakketten/CreateVerspakket.Command.cs @@ -1,4 +1,5 @@ using Cortex.Mediator.Commands; +using System.ComponentModel.DataAnnotations; namespace Lutra.Application.Verspakketten; @@ -7,6 +8,6 @@ public sealed partial class CreateVerspakket public sealed record Command( string Naam, int? PrijsInCenten, - int AantalPersonen, + [Range(1, 10)] int AantalPersonen, Guid SupermarktId) : ICommand; } diff --git a/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs b/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs index 2e0b010..8beaa20 100644 --- a/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs +++ b/Lutra/Lutra.Application/Verspakketten/GetVerspakket.Handler.cs @@ -20,6 +20,9 @@ namespace Lutra.Application.Verspakketten Id = v.Id, Naam = v.Naam, PrijsInCenten = v.PrijsInCenten, + AantalPersonen = v.AantalPersonen, + AverageCijferSmaak = v.Beoordelingen.Any() ? v.Beoordelingen.Average(b => (double)b.CijferSmaak) : null, + AverageCijferBereiden = v.Beoordelingen.Any() ? v.Beoordelingen.Average(b => (double)b.CijferBereiden) : null, Beoordelingen = v.Beoordelingen .Select(b => new Beoordeling { diff --git a/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs b/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs index 1f073f9..fae33d9 100644 --- a/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs +++ b/Lutra/Lutra.Application/Verspakketten/GetVerspakketten.Handler.cs @@ -45,6 +45,9 @@ namespace Lutra.Application.Verspakketten Id = v.Id, Naam = v.Naam, PrijsInCenten = v.PrijsInCenten, + AantalPersonen = v.AantalPersonen, + AverageCijferSmaak = v.Beoordelingen.Any() ? v.Beoordelingen.Average(b => (double)b.CijferSmaak) : null, + AverageCijferBereiden = v.Beoordelingen.Any() ? v.Beoordelingen.Average(b => (double)b.CijferBereiden) : null, Beoordelingen = v.Beoordelingen .Select(b => new Beoordeling { diff --git a/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Command.cs b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Command.cs new file mode 100644 index 0000000..08aa023 --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Command.cs @@ -0,0 +1,11 @@ +using Cortex.Mediator.Commands; + +namespace Lutra.Application.Verspakketten; + +public sealed partial class UpdateVerspakket +{ + /// + /// Updates an existing verspakket. + /// + public sealed record Command(Guid Id, string Naam, int PrijsInCenten, int AantalPersonen, Guid SupermarktId) : ICommand; +} diff --git a/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Handler.cs b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Handler.cs new file mode 100644 index 0000000..a6d997d --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Handler.cs @@ -0,0 +1,62 @@ +using Cortex.Mediator.Commands; +using Lutra.Application.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace Lutra.Application.Verspakketten; + +public sealed partial class UpdateVerspakket +{ + /// + /// Handles update requests for verspakketten. + /// + public sealed class Handler(ILutraDbContext context) : ICommandHandler + { + /// + /// Updates an existing verspakket. + /// + /// The update command. + /// The cancellation token. + /// An empty response. + public async Task Handle(Command request, CancellationToken cancellationToken) + { + if (string.IsNullOrWhiteSpace(request.Naam)) + throw new ArgumentException("Naam mag niet leeg zijn.", nameof(request.Naam)); + + if (request.Naam.Length > 50) + throw new ArgumentException("Naam mag maximaal 50 tekens bevatten.", nameof(request.Naam)); + + if (request.PrijsInCenten < 0) + throw new ArgumentException("PrijsInCenten mag niet negatief zijn.", nameof(request.PrijsInCenten)); + + if (request.AantalPersonen is < 1 or > 10) + throw new ArgumentException("AantalPersonen moet tussen 1 en 10 liggen.", nameof(request.AantalPersonen)); + + var verspakket = await context.Verspaketten + .FirstOrDefaultAsync(v => v.Id == request.Id && v.DeletedAt == null, cancellationToken); + + if (verspakket is null) + { + throw new InvalidOperationException($"Verspakket with id '{request.Id}' was not found."); + } + + var supermarktExists = await context.Supermarkten + .AsNoTracking() + .AnyAsync(s => s.Id == request.SupermarktId && s.DeletedAt == null, cancellationToken); + + if (!supermarktExists) + { + throw new InvalidOperationException($"Supermarkt with id '{request.SupermarktId}' was not found."); + } + + verspakket.Naam = request.Naam; + verspakket.PrijsInCenten = request.PrijsInCenten; + verspakket.AantalPersonen = request.AantalPersonen; + verspakket.SupermarktId = request.SupermarktId; + verspakket.ModifiedAt = DateTime.UtcNow; + + await context.SaveChangesAsync(cancellationToken); + + return new Response(); + } + } +} diff --git a/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Response.cs b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Response.cs new file mode 100644 index 0000000..0516519 --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.Response.cs @@ -0,0 +1,9 @@ +namespace Lutra.Application.Verspakketten; + +public sealed partial class UpdateVerspakket +{ + /// + /// Represents the result of an update verspakket operation. + /// + public sealed record Response; +} diff --git a/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.cs b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.cs new file mode 100644 index 0000000..724591a --- /dev/null +++ b/Lutra/Lutra.Application/Verspakketten/UpdateVerspakket.cs @@ -0,0 +1,3 @@ +namespace Lutra.Application.Verspakketten; + +public sealed partial class UpdateVerspakket; diff --git a/Lutra/Lutra.Domain/Entities/Verspakket.cs b/Lutra/Lutra.Domain/Entities/Verspakket.cs index d31a98e..66f018f 100644 --- a/Lutra/Lutra.Domain/Entities/Verspakket.cs +++ b/Lutra/Lutra.Domain/Entities/Verspakket.cs @@ -9,6 +9,7 @@ public class Verspakket : BaseEntity [MaxLength(50)] public required string Naam { get; set; } + [Range(0, int.MaxValue)] public int? PrijsInCenten { get; set; } [Range(1, 10)] diff --git a/Lutra/Lutra.Infrastructure/LutraDbContext.cs b/Lutra/Lutra.Infrastructure/LutraDbContext.cs index 5dba703..403df50 100644 --- a/Lutra/Lutra.Infrastructure/LutraDbContext.cs +++ b/Lutra/Lutra.Infrastructure/LutraDbContext.cs @@ -13,6 +13,8 @@ public class LutraDbContext : DbContext, ILutraDbContext public DbSet Supermarkten => Set(); + public DbSet Beoordelingen => Set(); + public DbSet Verspaketten => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -22,11 +24,19 @@ public class LutraDbContext : DbContext, ILutraDbContext modelBuilder.Entity() .ToTable("Beoordelingen"); - modelBuilder.Entity() - .HasMany(v => v.Beoordelingen) - .WithOne() - .HasForeignKey(b => b.VerspakketId) - .IsRequired(); + modelBuilder.Entity(b => + { + b.HasMany(v => v.Beoordelingen) + .WithOne() + .HasForeignKey(beo => beo.VerspakketId) + .IsRequired(); + + b.ToTable(t => + { + t.HasCheckConstraint("CK_Verspaketten_AantalPersonen", "\"AantalPersonen\" BETWEEN 1 AND 10"); + t.HasCheckConstraint("CK_Verspaketten_PrijsInCenten", "\"PrijsInCenten\" IS NULL OR \"PrijsInCenten\" >= 0"); + }); + }); } public override Task SaveChangesAsync(CancellationToken cancellationToken = default) diff --git a/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.Designer.cs b/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.Designer.cs new file mode 100644 index 0000000..d0b44fe --- /dev/null +++ b/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.Designer.cs @@ -0,0 +1,157 @@ +// +using System; +using Lutra.Infrastructure.Sql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Lutra.Infrastructure.Sql.Migrations +{ + [DbContext(typeof(LutraDbContext))] + [Migration("20260418173428_AddAantalPersonenCheckConstraint")] + partial class AddAantalPersonenCheckConstraint + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Lutra.Domain.Entities.Beoordeling", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aanbevolen") + .HasColumnType("boolean"); + + b.Property("CijferBereiden") + .HasColumnType("integer"); + + b.Property("CijferSmaak") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Tekst") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("VerspakketId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("VerspakketId"); + + b.ToTable("Beoordelingen", (string)null); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Supermarkt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Naam") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("Supermarkten"); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AantalPersonen") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Naam") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PrijsInCenten") + .HasColumnType("integer"); + + b.Property("SupermarktId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SupermarktId"); + + b.ToTable("Verspaketten", t => + { + t.HasCheckConstraint("CK_Verspaketten_AantalPersonen", "\"AantalPersonen\" BETWEEN 1 AND 10"); + }); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Beoordeling", b => + { + b.HasOne("Lutra.Domain.Entities.Verspakket", null) + .WithMany("Beoordelingen") + .HasForeignKey("VerspakketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.HasOne("Lutra.Domain.Entities.Supermarkt", "Supermarkt") + .WithMany() + .HasForeignKey("SupermarktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supermarkt"); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.Navigation("Beoordelingen"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.cs b/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.cs new file mode 100644 index 0000000..5dc2237 --- /dev/null +++ b/Lutra/Lutra.Infrastructure/Migrations/20260418173428_AddAantalPersonenCheckConstraint.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Lutra.Infrastructure.Sql.Migrations +{ + /// + public partial class AddAantalPersonenCheckConstraint : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddCheckConstraint( + name: "CK_Verspaketten_AantalPersonen", + table: "Verspaketten", + sql: "\"AantalPersonen\" BETWEEN 1 AND 10"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropCheckConstraint( + name: "CK_Verspaketten_AantalPersonen", + table: "Verspaketten"); + } + } +} diff --git a/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.Designer.cs b/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.Designer.cs new file mode 100644 index 0000000..8705816 --- /dev/null +++ b/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.Designer.cs @@ -0,0 +1,159 @@ +// +using System; +using Lutra.Infrastructure.Sql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Lutra.Infrastructure.Sql.Migrations +{ + [DbContext(typeof(LutraDbContext))] + [Migration("20260418174149_AddPrijsInCentenCheckConstraint")] + partial class AddPrijsInCentenCheckConstraint + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Lutra.Domain.Entities.Beoordeling", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Aanbevolen") + .HasColumnType("boolean"); + + b.Property("CijferBereiden") + .HasColumnType("integer"); + + b.Property("CijferSmaak") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Tekst") + .HasMaxLength(1024) + .HasColumnType("character varying(1024)"); + + b.Property("VerspakketId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("VerspakketId"); + + b.ToTable("Beoordelingen", (string)null); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Supermarkt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Naam") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.ToTable("Supermarkten"); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AantalPersonen") + .HasColumnType("integer"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ModifiedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Naam") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PrijsInCenten") + .HasColumnType("integer"); + + b.Property("SupermarktId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SupermarktId"); + + b.ToTable("Verspaketten", t => + { + t.HasCheckConstraint("CK_Verspaketten_AantalPersonen", "\"AantalPersonen\" BETWEEN 1 AND 10"); + + t.HasCheckConstraint("CK_Verspaketten_PrijsInCenten", "\"PrijsInCenten\" IS NULL OR \"PrijsInCenten\" >= 0"); + }); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Beoordeling", b => + { + b.HasOne("Lutra.Domain.Entities.Verspakket", null) + .WithMany("Beoordelingen") + .HasForeignKey("VerspakketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.HasOne("Lutra.Domain.Entities.Supermarkt", "Supermarkt") + .WithMany() + .HasForeignKey("SupermarktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supermarkt"); + }); + + modelBuilder.Entity("Lutra.Domain.Entities.Verspakket", b => + { + b.Navigation("Beoordelingen"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.cs b/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.cs new file mode 100644 index 0000000..b0bf25a --- /dev/null +++ b/Lutra/Lutra.Infrastructure/Migrations/20260418174149_AddPrijsInCentenCheckConstraint.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Lutra.Infrastructure.Sql.Migrations +{ + /// + public partial class AddPrijsInCentenCheckConstraint : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddCheckConstraint( + name: "CK_Verspaketten_PrijsInCenten", + table: "Verspaketten", + sql: "\"PrijsInCenten\" IS NULL OR \"PrijsInCenten\" >= 0"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropCheckConstraint( + name: "CK_Verspaketten_PrijsInCenten", + table: "Verspaketten"); + } + } +} diff --git a/Lutra/Lutra.Infrastructure/Migrations/LutraDbContextModelSnapshot.cs b/Lutra/Lutra.Infrastructure/Migrations/LutraDbContextModelSnapshot.cs index 8dd149f..1498258 100644 --- a/Lutra/Lutra.Infrastructure/Migrations/LutraDbContextModelSnapshot.cs +++ b/Lutra/Lutra.Infrastructure/Migrations/LutraDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace Lutra.Infrastructure.Sql.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("ProductVersion", "10.0.6") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -118,7 +118,12 @@ namespace Lutra.Infrastructure.Sql.Migrations b.HasIndex("SupermarktId"); - b.ToTable("Verspaketten"); + b.ToTable("Verspaketten", t => + { + t.HasCheckConstraint("CK_Verspaketten_AantalPersonen", "\"AantalPersonen\" BETWEEN 1 AND 10"); + + t.HasCheckConstraint("CK_Verspaketten_PrijsInCenten", "\"PrijsInCenten\" IS NULL OR \"PrijsInCenten\" >= 0"); + }); }); modelBuilder.Entity("Lutra.Domain.Entities.Beoordeling", b =>