Endpoint to add a verspakket
This commit is contained in:
@@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace Lutra.API.Controllers
|
namespace Lutra.API.Controllers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides read-only access to verspakket resources.
|
/// Provides access to verspakket resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/verspakketten")]
|
[Route("api/verspakketten")]
|
||||||
@@ -50,5 +50,27 @@ namespace Lutra.API.Controllers
|
|||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new verspakket.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">The verspakket values to create.</param>
|
||||||
|
/// <returns>Returns 201 Created with the created verspakket identifier.</returns>
|
||||||
|
[HttpPost]
|
||||||
|
[ProducesResponseType(typeof(CreateVerspakket.Response), StatusCodes.Status201Created)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
public async Task<ActionResult<CreateVerspakket.Response>> Post([FromBody] CreateVerspakket.Command command)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await mediator.SendCommandAsync<CreateVerspakket.Command, CreateVerspakket.Response>(command);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
return BadRequest(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
@@ -12,13 +12,13 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Cortex.Mediator" Version="3.1.2" />
|
<PackageReference Include="Cortex.Mediator" Version="3.1.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.5" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.5">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.6">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
|
||||||
<PackageReference Include="Scalar.AspNetCore" Version="2.13.20" />
|
<PackageReference Include="Scalar.AspNetCore" Version="2.14.0" />
|
||||||
<ProjectReference Include="..\Lutra.Infrastructure\Lutra.Infrastructure.Sql.csproj" />
|
<ProjectReference Include="..\Lutra.Infrastructure\Lutra.Infrastructure.Sql.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Cortex.Mediator" Version="3.1.2" />
|
<PackageReference Include="Cortex.Mediator" Version="3.1.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
{
|
{
|
||||||
public record Supermarkt
|
public record Supermarkt
|
||||||
{
|
{
|
||||||
|
public required Guid Id { get; init; }
|
||||||
|
|
||||||
public required string Naam { get; init; }
|
public required string Naam { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
public class Beoordeling
|
public class Beoordeling
|
||||||
{
|
{
|
||||||
public required int CijferSmaak { get; init; }
|
public required int CijferSmaak { get; init; }
|
||||||
|
|
||||||
public required int CijferBereiden { get; init; }
|
public required int CijferBereiden { get; init; }
|
||||||
|
|
||||||
public required bool Aanbevolen { get; init; }
|
public required bool Aanbevolen { get; init; }
|
||||||
|
|
||||||
public string? Tekst { get; init; }
|
public string? Tekst { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,14 @@ namespace Lutra.Application.Models.Verspakketten
|
|||||||
{
|
{
|
||||||
public record Verspakket
|
public record Verspakket
|
||||||
{
|
{
|
||||||
|
public required Guid Id { get; init; }
|
||||||
|
|
||||||
public required string Naam { get; init; }
|
public required string Naam { get; init; }
|
||||||
|
|
||||||
public int? PrijsInCenten { get; init; }
|
public int? PrijsInCenten { get; init; }
|
||||||
|
|
||||||
public Beoordeling[]? Beoordelingen { get; init; }
|
public Beoordeling[]? Beoordelingen { get; init; }
|
||||||
|
|
||||||
public Supermarkt? Supermarkt { get; init; }
|
public Supermarkt? Supermarkt { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,15 @@ namespace Lutra.Application.Supermarkten
|
|||||||
{
|
{
|
||||||
var supermarkten = await context.Supermarkten
|
var supermarkten = await context.Supermarkten
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
|
.Where(w => w.DeletedAt == null)
|
||||||
.OrderBy(s => s.Naam)
|
.OrderBy(s => s.Naam)
|
||||||
.Skip(request.Skip)
|
.Skip(request.Skip)
|
||||||
.Take(request.Take)
|
.Take(request.Take)
|
||||||
.Select(s => new Supermarkt { Naam = s.Naam })
|
.Select(s => new Supermarkt
|
||||||
|
{
|
||||||
|
Id = s.Id,
|
||||||
|
Naam = s.Naam
|
||||||
|
})
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
return new Response { Supermarkten = supermarkten };
|
return new Response { Supermarkten = supermarkten };
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Cortex.Mediator.Commands;
|
||||||
|
|
||||||
|
namespace Lutra.Application.Verspakketten;
|
||||||
|
|
||||||
|
public sealed partial class CreateVerspakket
|
||||||
|
{
|
||||||
|
public sealed record Command(
|
||||||
|
string Naam,
|
||||||
|
int? PrijsInCenten,
|
||||||
|
int AantalPersonen,
|
||||||
|
Guid SupermarktId) : ICommand<Response>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Cortex.Mediator.Commands;
|
||||||
|
using Lutra.Application.Interfaces;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Lutra.Application.Verspakketten;
|
||||||
|
|
||||||
|
public sealed partial class CreateVerspakket
|
||||||
|
{
|
||||||
|
public sealed class Handler(ILutraDbContext context) : ICommandHandler<Command, Response>
|
||||||
|
{
|
||||||
|
public async Task<Response> Handle(Command request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var supermarktExists = await context.Supermarkten
|
||||||
|
.AsNoTracking()
|
||||||
|
.AnyAsync(s => s.Id == request.SupermarktId, cancellationToken);
|
||||||
|
|
||||||
|
if (!supermarktExists)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Supermarkt with id '{request.SupermarktId}' was not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var verspakket = new Domain.Entities.Verspakket
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Naam = request.Naam,
|
||||||
|
PrijsInCenten = request.PrijsInCenten,
|
||||||
|
AantalPersonen = request.AantalPersonen,
|
||||||
|
SupermarktId = request.SupermarktId,
|
||||||
|
CreatedAt = now,
|
||||||
|
ModifiedAt = now
|
||||||
|
};
|
||||||
|
|
||||||
|
await context.Verspaketten.AddAsync(verspakket, cancellationToken);
|
||||||
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
return new Response { Id = verspakket.Id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Lutra.Application.Verspakketten;
|
||||||
|
|
||||||
|
public sealed partial class CreateVerspakket
|
||||||
|
{
|
||||||
|
public sealed class Response
|
||||||
|
{
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Lutra.Application.Verspakketten;
|
||||||
|
|
||||||
|
public sealed partial class CreateVerspakket { }
|
||||||
@@ -17,6 +17,7 @@ namespace Lutra.Application.Verspakketten
|
|||||||
.Where(v => v.Id == request.Id)
|
.Where(v => v.Id == request.Id)
|
||||||
.Select(v => new Verspakket
|
.Select(v => new Verspakket
|
||||||
{
|
{
|
||||||
|
Id = v.Id,
|
||||||
Naam = v.Naam,
|
Naam = v.Naam,
|
||||||
PrijsInCenten = v.PrijsInCenten,
|
PrijsInCenten = v.PrijsInCenten,
|
||||||
Beoordelingen = v.Beoordelingen
|
Beoordelingen = v.Beoordelingen
|
||||||
@@ -30,6 +31,7 @@ namespace Lutra.Application.Verspakketten
|
|||||||
.ToArray(),
|
.ToArray(),
|
||||||
Supermarkt = new Supermarkt
|
Supermarkt = new Supermarkt
|
||||||
{
|
{
|
||||||
|
Id = v.Supermarkt.Id,
|
||||||
Naam = v.Supermarkt.Naam
|
Naam = v.Supermarkt.Naam
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ namespace Lutra.Application.Verspakketten
|
|||||||
{
|
{
|
||||||
public async Task<Response> Handle(Query request, CancellationToken cancellationToken)
|
public async Task<Response> Handle(Query request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var query = context.Verspaketten.AsNoTracking();
|
var query = context.Verspaketten
|
||||||
|
.Where(w => w.DeletedAt == null)
|
||||||
|
.AsNoTracking();
|
||||||
|
|
||||||
// Apply sort before pagination so the database handles ordering efficiently.
|
// Apply sort before pagination so the database handles ordering efficiently.
|
||||||
IOrderedQueryable<Domain.Entities.Verspakket> sorted = request.SortField switch
|
IOrderedQueryable<Domain.Entities.Verspakket> sorted = request.SortField switch
|
||||||
@@ -40,6 +42,7 @@ namespace Lutra.Application.Verspakketten
|
|||||||
.Take(request.Take)
|
.Take(request.Take)
|
||||||
.Select(v => new Verspakket
|
.Select(v => new Verspakket
|
||||||
{
|
{
|
||||||
|
Id = v.Id,
|
||||||
Naam = v.Naam,
|
Naam = v.Naam,
|
||||||
PrijsInCenten = v.PrijsInCenten,
|
PrijsInCenten = v.PrijsInCenten,
|
||||||
Beoordelingen = v.Beoordelingen
|
Beoordelingen = v.Beoordelingen
|
||||||
@@ -53,6 +56,7 @@ namespace Lutra.Application.Verspakketten
|
|||||||
.ToArray(),
|
.ToArray(),
|
||||||
Supermarkt = new Supermarkt
|
Supermarkt = new Supermarkt
|
||||||
{
|
{
|
||||||
|
Id = v.Supermarkt.Id,
|
||||||
Naam = v.Supermarkt.Naam
|
Naam = v.Supermarkt.Naam
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,6 +9,4 @@ public abstract class BaseEntity
|
|||||||
public DateTime ModifiedAt { get; set; }
|
public DateTime ModifiedAt { get; set; }
|
||||||
|
|
||||||
public DateTime? DeletedAt { get; set; }
|
public DateTime? DeletedAt { get; set; }
|
||||||
|
|
||||||
public bool IsDeleted => DeletedAt.HasValue;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public class Verspakket : BaseEntity
|
|||||||
|
|
||||||
public required Guid SupermarktId { get; set; }
|
public required Guid SupermarktId { get; set; }
|
||||||
|
|
||||||
public required virtual Supermarkt Supermarkt { get; set; }
|
public virtual Supermarkt Supermarkt { get; set; } = null!;
|
||||||
|
|
||||||
public IReadOnlyCollection<Beoordeling> Beoordelingen => _beoordelingen.AsReadOnly();
|
public IReadOnlyCollection<Beoordeling> Beoordelingen => _beoordelingen.AsReadOnly();
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.5" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.6" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.5">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.6">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.6" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user