- Domain layer: Lesson entity, GermanWord value object, repository interfaces - Application layer: CQRS commands, DTOs with mapping - Infrastructure layer: EF Core with SQLite, LessonRepository - Presentation layer: Minimal API endpoints for lessons CRUD Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
65 lines
2 KiB
C#
65 lines
2 KiB
C#
using GermanApp.Application.DTOs;
|
|
using GermanApp.Domain.Entities;
|
|
using GermanApp.Domain.Exceptions;
|
|
using GermanApp.Domain.Interfaces;
|
|
|
|
namespace GermanApp.Application.UseCases.Commands;
|
|
|
|
/// <summary>
|
|
/// Command for creating a new lesson.
|
|
/// This follows the CQRS pattern - commands represent write operations.
|
|
/// </summary>
|
|
public record CreateLessonCommand(CreateLessonDto LessonData) : ICommand<LessonDto>;
|
|
|
|
/// <summary>
|
|
/// Handler for the CreateLessonCommand.
|
|
/// </summary>
|
|
public class CreateLessonCommandHandler : ICommandHandler<CreateLessonCommand, LessonDto>
|
|
{
|
|
private readonly ILessonRepository _lessonRepository;
|
|
|
|
public CreateLessonCommandHandler(ILessonRepository lessonRepository)
|
|
{
|
|
_lessonRepository = lessonRepository;
|
|
}
|
|
|
|
public async Task<LessonDto> Handle(CreateLessonCommand command, CancellationToken cancellationToken)
|
|
{
|
|
// Convert DTO to domain entity
|
|
var lesson = command.LessonData.ToEntity();
|
|
|
|
// Validate business rules (could be extracted to a validator)
|
|
if (lesson.Level < 1 || lesson.Level > 5)
|
|
{
|
|
throw new ValidationException("Level must be between 1 and 5");
|
|
}
|
|
|
|
// Add to repository
|
|
var createdLesson = await _lessonRepository.AddAsync(lesson, cancellationToken);
|
|
|
|
// Return DTO representation
|
|
return createdLesson.ToDto();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generic command interface.
|
|
/// </summary>
|
|
/// <typeparam name="TResult">The result type</typeparam>
|
|
public interface ICommand<out TResult>
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generic command handler interface.
|
|
/// </summary>
|
|
/// <typeparam name="TCommand">The command type</typeparam>
|
|
/// <typeparam name="TResult">The result type</typeparam>
|
|
public interface ICommandHandler<in TCommand, TResult>
|
|
where TCommand : ICommand<TResult>
|
|
{
|
|
Task<TResult> Handle(TCommand command, CancellationToken cancellationToken);
|
|
}
|
|
|
|
// Note: For MediatR integration, you would implement IRequestHandler<TCommand, TResult>
|
|
// instead of the custom interfaces above.
|