using LehrerApp.Core.Interfaces; using LehrerApp.Core.Models; namespace LehrerApp.Data.Repositories; public class StudentRepository(LiteDbContext db) : IStudentRepository { public Student? GetById(Guid id) => db.Students.FindById(id); public List GetAll(bool includeInactive = false) => (includeInactive ? db.Students.FindAll() : db.Students.Find(s => s.IsActive)) .OrderBy(s => s.LastName).ToList(); public List GetByGroup(Guid groupId) { var ids = db.Memberships .Find(e => e.GroupId == groupId) .Select(e => e.StudentId).ToHashSet(); return db.Students.Find(s => ids.Contains(s.Id)).OrderBy(s => s.LastName).ToList(); } public void Save(Student s) { s.UpdatedAt = DateTime.UtcNow; db.Students.Upsert(s); } public void Delete(Guid id) => db.Students.Delete(id); } public class GroupRepository(LiteDbContext db) : IGroupRepository { public LearningGroup? GetById(Guid id) => db.Groups.FindById(id); public List GetAll(bool includeInactive = false) => (includeInactive ? db.Groups.FindAll() : db.Groups.Find(g => g.IsActive)) .OrderBy(g => g.SchoolYear).ThenBy(g => g.Name).ToList(); public List GetBySchoolYear(string schoolYear, bool includeInactive = false) => (includeInactive ? db.Groups.Find(g => g.SchoolYear == schoolYear) : db.Groups.Find(g => g.SchoolYear == schoolYear && g.IsActive)) .OrderBy(g => g.Name).ToList(); public void Save(LearningGroup g) { if (g.SubjectId is Guid subjectId && db.Subjects.FindById(subjectId) is null) throw new InvalidOperationException("Das gewählte Fach existiert nicht mehr."); g.UpdatedAt = DateTime.UtcNow; db.Groups.Upsert(g); } public void Delete(Guid id) { foreach (var membership in db.Memberships.Find(e => e.GroupId == id).ToList()) db.Memberships.Delete(membership.Id); foreach (var exam in db.Exams.Find(e => e.GroupId == id).ToList()) { foreach (var result in db.ExamResults.Find(r => r.ExamId == exam.Id).ToList()) db.ExamResults.Delete(result.Id); db.Exams.Delete(exam.Id); } foreach (var grade in db.Grades.Find(g => g.GroupId == id).ToList()) db.Grades.Delete(grade.Id); foreach (var unit in db.Units.Find(u => u.GroupId == id).ToList()) { foreach (var lesson in db.Lessons.Find(l => l.UnitId == unit.Id).ToList()) db.Lessons.Delete(lesson.Id); db.Units.Delete(unit.Id); } foreach (var lesson in db.Lessons.Find(l => l.GroupId == id).ToList()) db.Lessons.Delete(lesson.Id); foreach (var session in db.ParticipationSessions.Find(s => s.GroupId == id).ToList()) { foreach (var entry in db.ParticipationEntries.Find(e => e.SessionId == session.Id).ToList()) db.ParticipationEntries.Delete(entry.Id); db.ParticipationSessions.Delete(session.Id); } foreach (var aspect in db.ParticipationAspects.Find(a => a.GroupId == id).ToList()) db.ParticipationAspects.Delete(aspect.Id); db.Groups.Delete(id); } } public class GroupMembershipRepository(LiteDbContext db) : IGroupMembershipRepository { public List GetByStudent(Guid id) => db.Memberships.Find(e => e.StudentId == id).ToList(); public List GetByGroup(Guid id) => db.Memberships.Find(e => e.GroupId == id).ToList(); public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) => db.Memberships.FindOne(e => e.StudentId == studentId && e.GroupId == groupId); public void Save(GroupMembership membership) { var existing = GetByStudentAndGroup(membership.StudentId, membership.GroupId); if (existing is not null && existing.Id != membership.Id) throw new InvalidOperationException("Der Schüler ist dieser Lerngruppe bereits zugeordnet."); db.Memberships.Upsert(membership); } public void Delete(Guid id) => db.Memberships.Delete(id); } public class ExamRepository(LiteDbContext db) : IExamRepository { public Exam? GetById(Guid id) => db.Exams.FindById(id); public List GetByGroup(Guid groupId) => db.Exams.Find(e => e.GroupId == groupId).OrderByDescending(e => e.Date).ToList(); public void Save(Exam e) { e.UpdatedAt = DateTime.UtcNow; db.Exams.Upsert(e); } public void Delete(Guid id) { foreach (var result in db.ExamResults.Find(r => r.ExamId == id).ToList()) db.ExamResults.Delete(result.Id); db.Exams.Delete(id); } } public class ExamResultRepository(LiteDbContext db) : IExamResultRepository { public List GetByExam(Guid id) => db.ExamResults.Find(r => r.ExamId == id).ToList(); public List GetByStudent(Guid id) => db.ExamResults.Find(r => r.StudentId == id).ToList(); public ExamResult? GetByExamAndStudent(Guid examId, Guid studentId) => db.ExamResults.FindOne(r => r.ExamId == examId && r.StudentId == studentId); public void Save(ExamResult r) { r.UpdatedAt = DateTime.UtcNow; db.ExamResults.Upsert(r); } public void SaveMany(List results) { var now = DateTime.UtcNow; foreach (var r in results) r.UpdatedAt = now; db.ExamResults.Upsert(results); } } public class GradingKeyTemplateRepository(LiteDbContext db) : IGradingKeyTemplateRepository { public List GetAll() => db.GradingKeyTemplates.FindAll().OrderBy(t => t.Name).ToList(); public List GetByGradingSystem(GradingSystem system) => db.GradingKeyTemplates.Find(t => t.GradingSystem == system).OrderBy(t => t.Name).ToList(); public GradingKeyTemplate? GetById(Guid id) => db.GradingKeyTemplates.FindById(id); public void Save(GradingKeyTemplate t) { t.UpdatedAt = DateTime.UtcNow; db.GradingKeyTemplates.Upsert(t); } public void Delete(Guid id) => db.GradingKeyTemplates.Delete(id); } public class GradeRepository(LiteDbContext db) : IGradeRepository { public List GetByStudentAndGroup(Guid sid, Guid gid) => db.Grades.Find(g => g.StudentId == sid && g.GroupId == gid).OrderBy(g => g.Date).ToList(); public List GetByGroup(Guid id) => db.Grades.Find(g => g.GroupId == id).OrderBy(g => g.Date).ToList(); public void Save(Grade g) => db.Grades.Upsert(g); public void Delete(Guid id) => db.Grades.Delete(id); } public class GradingSchemeRepository(LiteDbContext db) : IGradingSchemeRepository { public GradingScheme? GetByGroup(Guid groupId) => db.GradingSchemes.FindOne(s => s.GroupId == groupId); public GradingScheme? GetDefaultForType(GroupType type) => db.GradingSchemes.FindOne(s => s.GroupId == null && s.GroupType == type); public void Save(GradingScheme s) { s.UpdatedAt = DateTime.UtcNow; db.GradingSchemes.Upsert(s); } public void Delete(Guid id) => db.GradingSchemes.Delete(id); } public class ReportGradeRepository(LiteDbContext db) : IReportGradeRepository { public List GetByGroup(Guid groupId) => db.ReportGrades.Find(r => r.GroupId == groupId).ToList(); public ReportGrade? GetByStudentGroupPeriod(Guid studentId, Guid groupId, string period) => db.ReportGrades.FindOne(r => r.StudentId == studentId && r.GroupId == groupId && r.Period == period); public void Save(ReportGrade r) { r.UpdatedAt = DateTime.UtcNow; db.ReportGrades.Upsert(r); } public void Delete(Guid id) => db.ReportGrades.Delete(id); } public class UnitRepository(LiteDbContext db) : IUnitRepository { public Unit? GetById(Guid id) => db.Units.FindById(id); public List GetByGroup(Guid id) => db.Units.Find(u => u.GroupId == id).OrderBy(u => u.StartDate).ToList(); public void Save(Unit u) { u.UpdatedAt = DateTime.UtcNow; db.Units.Upsert(u); } public void Delete(Guid id) => db.Units.Delete(id); } public class LessonRepository(LiteDbContext db) : ILessonRepository { public List GetByUnit(Guid id) => db.Lessons.Find(l => l.UnitId == id).OrderBy(l => l.Date).ToList(); public List GetByGroupAndDate(Guid gid, DateOnly date) => db.Lessons.Find(l => l.GroupId == gid && l.Date == date).ToList(); public List GetByGroupAndRange(Guid gid, DateOnly from, DateOnly to) => db.Lessons.Find(l => l.GroupId == gid && l.Date >= from && l.Date <= to) .OrderBy(l => l.Date).ToList(); public void Save(Lesson l) { l.UpdatedAt = DateTime.UtcNow; db.Lessons.Upsert(l); } public void Delete(Guid id) => db.Lessons.Delete(id); } public class DocumentationRepository(LiteDbContext db) : IDocumentationRepository { public List GetByStudent(Guid id) => db.Documentation.Find(d => d.StudentId == id).OrderByDescending(d => d.Date).ToList(); public List GetByStudentAndType(Guid sid, DocumentationType type) => db.Documentation.Find(d => d.StudentId == sid && d.Type == type) .OrderByDescending(d => d.Date).ToList(); public void Save(Documentation d) { d.UpdatedAt = DateTime.UtcNow; db.Documentation.Upsert(d); } public void Delete(Guid id) => db.Documentation.Delete(id); } public class WorkTaskRepository(LiteDbContext db) : IWorkTaskRepository { public List GetByStatus(WorkTaskStatus s) => db.Tasks.Find(t => t.Status == s).OrderBy(t => t.DueDate).ToList(); public List GetAll() => db.Tasks.FindAll().OrderBy(t => t.Status).ThenBy(t => t.DueDate).ToList(); public void Save(WorkTask t) { t.UpdatedAt = DateTime.UtcNow; db.Tasks.Upsert(t); } public void Delete(Guid id) => db.Tasks.Delete(id); } public class TimeEntryRepository(LiteDbContext db) : ITimeEntryRepository { public List GetByDate(DateOnly date) => db.TimeEntries.Find(e => e.Date == date).OrderBy(e => e.StartTime).ToList(); public List GetByDateRange(DateOnly from, DateOnly to) => db.TimeEntries.Find(e => e.Date >= from && e.Date <= to).OrderBy(e => e.Date).ToList(); public List GetByTask(Guid id) => db.TimeEntries.Find(e => e.TaskId == id).ToList(); public void Save(TimeEntry e) => db.TimeEntries.Upsert(e); public void Delete(Guid id) => db.TimeEntries.Delete(id); } public class ParticipationSessionRepository(LiteDbContext db) : IParticipationSessionRepository { public List GetByGroup(Guid groupId) => db.ParticipationSessions.Find(s => s.GroupId == groupId).OrderByDescending(s => s.Date).ToList(); public ParticipationSession? GetById(Guid id) => db.ParticipationSessions.FindById(id); public void Save(ParticipationSession s) { s.UpdatedAt = DateTime.UtcNow; db.ParticipationSessions.Upsert(s); } public void Delete(Guid id) { db.ParticipationSessions.Delete(id); foreach (var e in db.ParticipationEntries.Find(e => e.SessionId == id).ToList()) db.ParticipationEntries.Delete(e.Id); } } public class ParticipationRepository(LiteDbContext db) : IParticipationRepository { public List GetBySession(Guid sessionId) => db.ParticipationEntries.Find(e => e.SessionId == sessionId).ToList(); public List GetByStudent(Guid studentId) => db.ParticipationEntries.Find(e => e.StudentId == studentId).ToList(); public ParticipationEntry? GetBySessionAndStudent(Guid sessionId, Guid studentId) => db.ParticipationEntries.FindOne(e => e.SessionId == sessionId && e.StudentId == studentId); public void Save(ParticipationEntry e) { e.UpdatedAt = DateTime.UtcNow; db.ParticipationEntries.Upsert(e); } public void SaveMany(List entries) { var now = DateTime.UtcNow; foreach (var e in entries) e.UpdatedAt = now; db.ParticipationEntries.Upsert(entries); } public void DeleteBySession(Guid sessionId) { foreach (var e in db.ParticipationEntries.Find(e => e.SessionId == sessionId).ToList()) db.ParticipationEntries.Delete(e.Id); } } public class ParticipationAspectRepository(LiteDbContext db) : IParticipationAspectRepository { public List GetDefaults() => db.ParticipationAspects.Find(a => a.GroupId == null && a.IsActive).OrderBy(a => a.SortOrder).ToList(); public List GetByGroup(Guid groupId) => db.ParticipationAspects.Find(a => a.GroupId == groupId && a.IsActive).OrderBy(a => a.SortOrder).ToList(); public void Save(ParticipationAspect a) { a.UpdatedAt = DateTime.UtcNow; db.ParticipationAspects.Upsert(a); } public void Delete(Guid id) => db.ParticipationAspects.Delete(id); } public class ParticipationSectionRepository(LiteDbContext db) : IParticipationSectionRepository { public List GetByGroup(Guid groupId) => db.ParticipationSections.Find(s => s.GroupId == groupId).OrderBy(s => s.StartDate).ToList(); public void Save(ParticipationSection s) => db.ParticipationSections.Upsert(s); public void Delete(Guid id) => db.ParticipationSections.Delete(id); } public class SubjectRepository(LiteDbContext db) : ISubjectRepository { public List GetAll() => db.Subjects.FindAll().OrderBy(s => s.Name).ToList(); public Subject? GetById(Guid id) => db.Subjects.FindById(id); public Subject? GetByName(string name) => db.Subjects.FindAll().FirstOrDefault(s => string.Equals(s.Name.Trim(), name.Trim(), StringComparison.OrdinalIgnoreCase)); public void Save(Subject s) { s.Name = s.Name.Trim(); s.ShortName = s.ShortName.Trim(); if (s.Name.Length == 0) throw new ArgumentException("Der Fachname darf nicht leer sein."); var duplicate = GetByName(s.Name); if (duplicate is not null && duplicate.Id != s.Id) throw new InvalidOperationException("Ein Fach mit diesem Namen existiert bereits."); s.UpdatedAt = DateTime.UtcNow; db.Subjects.Upsert(s); } public void Delete(Guid id) { if (db.Groups.Exists(g => g.SubjectId == id) || db.CompetencyDomains.Exists(d => d.SubjectId == id)) throw new InvalidOperationException("Das Fach wird noch von einer Lerngruppe oder einem Kompetenzkatalog verwendet."); db.Subjects.Delete(id); } } public class CompetencyDomainRepository(LiteDbContext db) : ICompetencyDomainRepository { public List GetBySubjectAndGrade(Guid subjectId, int gradeLevel) => db.CompetencyDomains .Find(d => d.SubjectId == subjectId && d.GradeLevel == gradeLevel) .OrderBy(d => d.SortOrder) .ToList(); public CompetencyDomain? GetById(Guid id) => db.CompetencyDomains.FindById(id); public void Save(CompetencyDomain d) { d.UpdatedAt = DateTime.UtcNow; db.CompetencyDomains.Upsert(d); } public void Delete(Guid id) => db.CompetencyDomains.Delete(id); public void DeleteBySubjectAndGrade(Guid subjectId, int gradeLevel) { foreach (var d in db.CompetencyDomains .Find(d => d.SubjectId == subjectId && d.GradeLevel == gradeLevel) .ToList()) db.CompetencyDomains.Delete(d.Id); } }