- Add QuizQuestion and QuizOption domain entities with QuestionType enum - Add IQuizQuestionRepository and IQuizOptionRepository interfaces - Add QuizQuestionRepository and QuizOptionRepository EF Core implementations - Add QuizQuestionService with CRUD, quiz submission, and statistics - Add QuizQuestionsController with comprehensive REST API endpoints - Add QuizQuestionDto and related DTOs for API communication - Add EF Core migration (20260612050652_AddQuizQuestionTables) for QuizQuestion and QuizOption - Add seed data with sample quiz questions for Greetings, Numbers, Grammar lessons - Update AppDbContext with DbSets and entity configurations - Update Program.cs with migration retry logic for Docker - Update docker-compose.yml with SeedDatabase configuration - Add unit tests for QuizQuestionService Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
112 lines
3.9 KiB
C#
112 lines
3.9 KiB
C#
using GermanApp.Domain.Entities;
|
|
using GermanApp.Domain.Interfaces;
|
|
using GermanApp.Infrastructure.Data.DbContext;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace GermanApp.Infrastructure.Data.Repositories;
|
|
|
|
/// <summary>
|
|
/// Entity Framework Core implementation of IQuizOptionRepository.
|
|
/// This is part of the Infrastructure layer.
|
|
/// </summary>
|
|
public class QuizOptionRepository : IQuizOptionRepository
|
|
{
|
|
private readonly AppDbContext _context;
|
|
|
|
public QuizOptionRepository(AppDbContext context)
|
|
{
|
|
_context = context;
|
|
}
|
|
|
|
public async Task<QuizOption?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.Include(o => o.QuizQuestion)
|
|
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
|
}
|
|
|
|
public async Task<IReadOnlyList<QuizOption>> GetAllAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.Include(o => o.QuizQuestion)
|
|
.AsNoTracking()
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<QuizOption> AddAsync(QuizOption entity, CancellationToken cancellationToken = default)
|
|
{
|
|
await _context.QuizOptions.AddAsync(entity, cancellationToken);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
return entity;
|
|
}
|
|
|
|
public async Task UpdateAsync(QuizOption entity, CancellationToken cancellationToken = default)
|
|
{
|
|
_context.QuizOptions.Update(entity);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task DeleteAsync(QuizOption entity, CancellationToken cancellationToken = default)
|
|
{
|
|
_context.QuizOptions.Remove(entity);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<bool> ExistsAsync(int id, CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.AnyAsync(o => o.Id == id, cancellationToken);
|
|
}
|
|
|
|
public async Task<IReadOnlyList<QuizOption>> GetByQuestionAsync(int questionId, CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.Include(o => o.QuizQuestion)
|
|
.Where(o => o.QuizQuestionId == questionId)
|
|
.OrderBy(o => o.Order)
|
|
.AsNoTracking()
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<QuizOption?> GetCorrectOptionAsync(int questionId, CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.Include(o => o.QuizQuestion)
|
|
.Where(o => o.QuizQuestionId == questionId && o.IsCorrect)
|
|
.OrderBy(o => o.Order)
|
|
.FirstOrDefaultAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<IReadOnlyList<QuizOption>> GetCorrectOptionsAsync(int questionId, CancellationToken cancellationToken = default)
|
|
{
|
|
return await _context.QuizOptions
|
|
.Include(o => o.QuizQuestion)
|
|
.Where(o => o.QuizQuestionId == questionId && o.IsCorrect)
|
|
.OrderBy(o => o.Order)
|
|
.AsNoTracking()
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task DeleteByQuestionAsync(int questionId, CancellationToken cancellationToken = default)
|
|
{
|
|
var options = await _context.QuizOptions
|
|
.Where(o => o.QuizQuestionId == questionId)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
_context.QuizOptions.RemoveRange(options);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<bool> OrderExistsForQuestionAsync(int questionId, int order, int? excludeId = null, CancellationToken cancellationToken = default)
|
|
{
|
|
var query = _context.QuizOptions
|
|
.Where(o => o.QuizQuestionId == questionId && o.Order == order);
|
|
|
|
if (excludeId.HasValue)
|
|
{
|
|
query = query.Where(o => o.Id != excludeId.Value);
|
|
}
|
|
|
|
return await query.AnyAsync(cancellationToken);
|
|
}
|
|
}
|