using Microsoft.EntityFrameworkCore; namespace Jiaowu.Api.Infrastructure.Persistence; public sealed class DevelopmentSqliteMigrator( AppDbContext db, ILogger logger) { private const string PeopleAndCoursesMigration = "20260724_01_people_courses"; private const string CurriculumPlansMigration = "20260724_02_curriculum_plans"; private const string TeachingTasksMigration = "20260724_03_teaching_tasks"; private const string SchedulesMigration = "20260724_04_schedules"; private const string ClassCounselorMigration = "20260724_05_class_counselor"; private const string CourseSelectionMigration = "20260724_06_course_selection"; private const string GradesMigration = "20260724_07_grades"; private const string ExamsMigration = "20260724_08_exams"; private const string StudentStatusChangesMigration = "20260724_09_student_status_changes"; private const string GraduationAuditsMigration = "20260724_10_graduation_audits"; private const string DegreeAwardsMigration = "20260724_11_degree_awards"; private const string GraduationClearanceMigration = "20260724_12_graduation_clearance"; private const string CourseCategoriesMigration = "20260724_13_course_categories"; private const string SchedulingOptimizationMigration = "20260724_14_scheduling_optimization"; public async Task MigrateAsync(CancellationToken cancellationToken = default) { if (!db.Database.IsSqlite()) { return; } await db.Database.ExecuteSqlRawAsync( """ CREATE TABLE IF NOT EXISTS "__DevelopmentSchemaHistory" ( "MigrationId" TEXT NOT NULL CONSTRAINT "PK___DevelopmentSchemaHistory" PRIMARY KEY, "AppliedAt" TEXT NOT NULL ); """, cancellationToken); await ApplyMigrationAsync( PeopleAndCoursesMigration, PeopleAndCoursesStatements, cancellationToken); await ApplyMigrationAsync( CurriculumPlansMigration, CurriculumPlansStatements, cancellationToken); await ApplyMigrationAsync( TeachingTasksMigration, TeachingTasksStatements, cancellationToken); await ApplyMigrationAsync( SchedulesMigration, SchedulesStatements, cancellationToken); var counselorColumnExists = await db.Database .SqlQueryRaw( """ SELECT COUNT(*) AS "Value" FROM pragma_table_info('AdministrativeClasses') WHERE name = 'CounselorUserId' """) .AnyAsync(value => value > 0, cancellationToken); await ApplyMigrationAsync( ClassCounselorMigration, counselorColumnExists ? ClassCounselorStatements.Skip(1) : ClassCounselorStatements, cancellationToken); await ApplyMigrationAsync( CourseSelectionMigration, CourseSelectionStatements, cancellationToken); await ApplyMigrationAsync( GradesMigration, GradesStatements, cancellationToken); await ApplyMigrationAsync(ExamsMigration, ExamsStatements, cancellationToken); await ApplyMigrationAsync( StudentStatusChangesMigration, StudentStatusChangesStatements, cancellationToken); await ApplyMigrationAsync( GraduationAuditsMigration, GraduationAuditsStatements, cancellationToken); await ApplyMigrationAsync( DegreeAwardsMigration, DegreeAwardsStatements, cancellationToken); await ApplyMigrationAsync( GraduationClearanceMigration, GraduationClearanceStatements, cancellationToken); var courseCategoryColumnExists = await db.Database .SqlQueryRaw( """ SELECT COUNT(*) AS "Value" FROM pragma_table_info('Courses') WHERE name = 'CourseCategoryId' """) .AnyAsync(value => value > 0, cancellationToken); await ApplyMigrationAsync( CourseCategoriesMigration, courseCategoryColumnExists ? CourseCategoriesStatements.Where( statement => !statement.StartsWith( "ALTER TABLE", StringComparison.OrdinalIgnoreCase)) : CourseCategoriesStatements, cancellationToken); var schedulingOptimizationExists = await db.Database .SqlQueryRaw( """ SELECT COUNT(*) AS "Value" FROM sqlite_master WHERE type = 'table' AND name = 'ScheduleTimeSlots' """) .AnyAsync(value => value > 0, cancellationToken); await ApplyMigrationAsync( SchedulingOptimizationMigration, schedulingOptimizationExists ? [] : SchedulingOptimizationStatements, cancellationToken); } private async Task ApplyMigrationAsync( string migrationId, IEnumerable statements, CancellationToken cancellationToken) { var applied = await db.Database .SqlQuery( $""" SELECT "MigrationId" AS "Value" FROM "__DevelopmentSchemaHistory" WHERE "MigrationId" = {migrationId} """) .AnyAsync(cancellationToken); if (applied) { return; } await using var transaction = await db.Database.BeginTransactionAsync(cancellationToken); foreach (var statement in statements) { await db.Database.ExecuteSqlRawAsync(statement, cancellationToken); } await db.Database.ExecuteSqlInterpolatedAsync( $""" INSERT INTO "__DevelopmentSchemaHistory" ("MigrationId", "AppliedAt") VALUES ({migrationId}, {DateTime.UtcNow}); """, cancellationToken); await transaction.CommitAsync(cancellationToken); logger.LogInformation( "Applied SQLite development schema migration {MigrationId}.", migrationId); } private static readonly string[] PeopleAndCoursesStatements = [ """ CREATE TABLE IF NOT EXISTS "Teachers" ( "Id" TEXT NOT NULL CONSTRAINT "PK_Teachers" PRIMARY KEY, "TeacherNumber" TEXT NOT NULL, "Name" TEXT NOT NULL, "Gender" INTEGER NOT NULL, "CollegeId" TEXT NOT NULL, "Title" TEXT NULL, "Status" INTEGER NOT NULL, "HireDate" TEXT NULL, "IsExternal" INTEGER NOT NULL, "Phone" TEXT NULL, "Email" TEXT NULL, "Notes" TEXT NULL, "UserId" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_Teachers_Colleges_CollegeId" FOREIGN KEY ("CollegeId") REFERENCES "Colleges" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_Teachers_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE SET NULL ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_Teachers_TeacherNumber" ON "Teachers" ("TeacherNumber"); """, """ CREATE INDEX IF NOT EXISTS "IX_Teachers_CollegeId_Status" ON "Teachers" ("CollegeId", "Status"); """, """ CREATE INDEX IF NOT EXISTS "IX_Teachers_UserId" ON "Teachers" ("UserId"); """, """ CREATE TABLE IF NOT EXISTS "Students" ( "Id" TEXT NOT NULL CONSTRAINT "PK_Students" PRIMARY KEY, "StudentNumber" TEXT NOT NULL, "Name" TEXT NOT NULL, "Gender" INTEGER NOT NULL, "AdministrativeClassId" TEXT NOT NULL, "EnrollmentYear" INTEGER NOT NULL, "EnrollmentDate" TEXT NOT NULL, "Status" INTEGER NOT NULL, "DateOfBirth" TEXT NULL, "Phone" TEXT NULL, "Email" TEXT NULL, "Notes" TEXT NULL, "UserId" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_Students_AdministrativeClasses_AdministrativeClassId" FOREIGN KEY ("AdministrativeClassId") REFERENCES "AdministrativeClasses" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_Students_AspNetUsers_UserId" FOREIGN KEY ("UserId") REFERENCES "AspNetUsers" ("Id") ON DELETE SET NULL ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_Students_StudentNumber" ON "Students" ("StudentNumber"); """, """ CREATE INDEX IF NOT EXISTS "IX_Students_AdministrativeClassId_Status" ON "Students" ("AdministrativeClassId", "Status"); """, """ CREATE INDEX IF NOT EXISTS "IX_Students_EnrollmentYear" ON "Students" ("EnrollmentYear"); """, """ CREATE INDEX IF NOT EXISTS "IX_Students_UserId" ON "Students" ("UserId"); """, """ CREATE TABLE IF NOT EXISTS "Courses" ( "Id" TEXT NOT NULL CONSTRAINT "PK_Courses" PRIMARY KEY, "CollegeId" TEXT NOT NULL, "EnglishName" TEXT NULL, "Credits" TEXT NOT NULL, "TotalHours" INTEGER NOT NULL, "LectureHours" INTEGER NOT NULL, "PracticeHours" INTEGER NOT NULL, "Nature" INTEGER NOT NULL, "AssessmentMethod" INTEGER NOT NULL, "Description" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, "Code" TEXT NOT NULL, "Name" TEXT NOT NULL, "SortOrder" INTEGER NOT NULL, "IsEnabled" INTEGER NOT NULL, CONSTRAINT "FK_Courses_Colleges_CollegeId" FOREIGN KEY ("CollegeId") REFERENCES "Colleges" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_Courses_Code" ON "Courses" ("Code"); """, """ CREATE INDEX IF NOT EXISTS "IX_Courses_IsEnabled_SortOrder" ON "Courses" ("IsEnabled", "SortOrder"); """, """ CREATE INDEX IF NOT EXISTS "IX_Courses_CollegeId_Nature" ON "Courses" ("CollegeId", "Nature"); """ ]; private static readonly string[] CurriculumPlansStatements = [ """ CREATE TABLE IF NOT EXISTS "CurriculumPlans" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CurriculumPlans" PRIMARY KEY, "MajorId" TEXT NOT NULL, "Name" TEXT NOT NULL, "Version" TEXT NOT NULL, "EffectiveGrade" INTEGER NOT NULL, "TotalCredits" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Description" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CurriculumPlans_Majors_MajorId" FOREIGN KEY ("MajorId") REFERENCES "Majors" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CurriculumPlans_MajorId_EffectiveGrade_Version" ON "CurriculumPlans" ("MajorId", "EffectiveGrade", "Version"); """, """ CREATE INDEX IF NOT EXISTS "IX_CurriculumPlans_Status_EffectiveGrade" ON "CurriculumPlans" ("Status", "EffectiveGrade"); """, """ CREATE TABLE IF NOT EXISTS "CurriculumModules" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CurriculumModules" PRIMARY KEY, "CurriculumPlanId" TEXT NOT NULL, "Code" TEXT NOT NULL, "Name" TEXT NOT NULL, "RequiredCredits" TEXT NOT NULL, "SortOrder" INTEGER NOT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CurriculumModules_CurriculumPlans_CurriculumPlanId" FOREIGN KEY ("CurriculumPlanId") REFERENCES "CurriculumPlans" ("Id") ON DELETE CASCADE ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CurriculumModules_CurriculumPlanId_Code" ON "CurriculumModules" ("CurriculumPlanId", "Code"); """, """ CREATE TABLE IF NOT EXISTS "CurriculumCourses" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CurriculumCourses" PRIMARY KEY, "CurriculumModuleId" TEXT NOT NULL, "CourseId" TEXT NOT NULL, "RecommendedSemester" INTEGER NOT NULL, "Type" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CurriculumCourses_CurriculumModules_CurriculumModuleId" FOREIGN KEY ("CurriculumModuleId") REFERENCES "CurriculumModules" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_CurriculumCourses_Courses_CourseId" FOREIGN KEY ("CourseId") REFERENCES "Courses" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CurriculumCourses_CurriculumModuleId_CourseId" ON "CurriculumCourses" ("CurriculumModuleId", "CourseId"); """, """ CREATE INDEX IF NOT EXISTS "IX_CurriculumCourses_CourseId" ON "CurriculumCourses" ("CourseId"); """ ]; private static readonly string[] TeachingTasksStatements = [ """ CREATE TABLE IF NOT EXISTS "TeachingTasks" ( "Id" TEXT NOT NULL CONSTRAINT "PK_TeachingTasks" PRIMARY KEY, "TaskNumber" TEXT NOT NULL, "Name" TEXT NOT NULL, "AcademicTermId" TEXT NOT NULL, "CourseId" TEXT NOT NULL, "Capacity" INTEGER NOT NULL, "StartWeek" INTEGER NOT NULL, "EndWeek" INTEGER NOT NULL, "WeeklyHours" INTEGER NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_TeachingTasks_AcademicTerms_AcademicTermId" FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_TeachingTasks_Courses_CourseId" FOREIGN KEY ("CourseId") REFERENCES "Courses" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_TeachingTasks_TaskNumber" ON "TeachingTasks" ("TaskNumber"); """, """ CREATE INDEX IF NOT EXISTS "IX_TeachingTasks_AcademicTermId_Status" ON "TeachingTasks" ("AcademicTermId", "Status"); """, """ CREATE INDEX IF NOT EXISTS "IX_TeachingTasks_CourseId" ON "TeachingTasks" ("CourseId"); """, """ CREATE TABLE IF NOT EXISTS "TeachingTaskTeachers" ( "TeachingTaskId" TEXT NOT NULL, "TeacherId" TEXT NOT NULL, "IsPrimary" INTEGER NOT NULL, CONSTRAINT "PK_TeachingTaskTeachers" PRIMARY KEY ("TeachingTaskId", "TeacherId"), CONSTRAINT "FK_TeachingTaskTeachers_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_TeachingTaskTeachers_Teachers_TeacherId" FOREIGN KEY ("TeacherId") REFERENCES "Teachers" ("Id") ON DELETE RESTRICT ); """, """ CREATE INDEX IF NOT EXISTS "IX_TeachingTaskTeachers_TeacherId" ON "TeachingTaskTeachers" ("TeacherId"); """, """ CREATE TABLE IF NOT EXISTS "TeachingTaskClasses" ( "TeachingTaskId" TEXT NOT NULL, "AdministrativeClassId" TEXT NOT NULL, CONSTRAINT "PK_TeachingTaskClasses" PRIMARY KEY ("TeachingTaskId", "AdministrativeClassId"), CONSTRAINT "FK_TeachingTaskClasses_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_TeachingTaskClasses_AdministrativeClasses_AdministrativeClassId" FOREIGN KEY ("AdministrativeClassId") REFERENCES "AdministrativeClasses" ("Id") ON DELETE RESTRICT ); """, """ CREATE INDEX IF NOT EXISTS "IX_TeachingTaskClasses_AdministrativeClassId" ON "TeachingTaskClasses" ("AdministrativeClassId"); """ ]; private static readonly string[] SchedulesStatements = [ """ CREATE TABLE IF NOT EXISTS "SchedulePlans" ( "Id" TEXT NOT NULL CONSTRAINT "PK_SchedulePlans" PRIMARY KEY, "AcademicTermId" TEXT NOT NULL, "Name" TEXT NOT NULL, "Version" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_SchedulePlans_AcademicTerms_AcademicTermId" FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_SchedulePlans_AcademicTermId_Version" ON "SchedulePlans" ("AcademicTermId", "Version"); """, """ CREATE INDEX IF NOT EXISTS "IX_SchedulePlans_AcademicTermId_Status" ON "SchedulePlans" ("AcademicTermId", "Status"); """, """ CREATE TABLE IF NOT EXISTS "ScheduleEntries" ( "Id" TEXT NOT NULL CONSTRAINT "PK_ScheduleEntries" PRIMARY KEY, "SchedulePlanId" TEXT NOT NULL, "TeachingTaskId" TEXT NOT NULL, "ClassroomId" TEXT NOT NULL, "DayOfWeek" INTEGER NOT NULL, "StartPeriod" INTEGER NOT NULL, "PeriodCount" INTEGER NOT NULL, "StartWeek" INTEGER NOT NULL, "EndWeek" INTEGER NOT NULL, "WeekPattern" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_ScheduleEntries_SchedulePlans_SchedulePlanId" FOREIGN KEY ("SchedulePlanId") REFERENCES "SchedulePlans" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_ScheduleEntries_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_ScheduleEntries_Classrooms_ClassroomId" FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id") ON DELETE RESTRICT ); """, """ CREATE INDEX IF NOT EXISTS "IX_ScheduleEntries_SchedulePlanId_DayOfWeek_StartPeriod" ON "ScheduleEntries" ("SchedulePlanId", "DayOfWeek", "StartPeriod"); """, """ CREATE INDEX IF NOT EXISTS "IX_ScheduleEntries_TeachingTaskId" ON "ScheduleEntries" ("TeachingTaskId"); """, """ CREATE INDEX IF NOT EXISTS "IX_ScheduleEntries_ClassroomId" ON "ScheduleEntries" ("ClassroomId"); """ ]; private static readonly string[] ClassCounselorStatements = [ """ ALTER TABLE "AdministrativeClasses" ADD COLUMN "CounselorUserId" TEXT NULL; """, """ CREATE INDEX IF NOT EXISTS "IX_AdministrativeClasses_CounselorUserId" ON "AdministrativeClasses" ("CounselorUserId"); """ ]; private static readonly string[] CourseSelectionStatements = [ """ CREATE TABLE IF NOT EXISTS "CourseSelectionRounds" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CourseSelectionRounds" PRIMARY KEY, "AcademicTermId" TEXT NOT NULL, "Name" TEXT NOT NULL, "StartsAt" TEXT NOT NULL, "EndsAt" TEXT NOT NULL, "WithdrawalEndsAt" TEXT NOT NULL, "MaxCredits" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CourseSelectionRounds_AcademicTerms_AcademicTermId" FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id") ON DELETE RESTRICT ); """, """ CREATE INDEX IF NOT EXISTS "IX_CourseSelectionRounds_AcademicTermId_Status" ON "CourseSelectionRounds" ("AcademicTermId", "Status"); """, """ CREATE TABLE IF NOT EXISTS "CourseSelectionOfferings" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CourseSelectionOfferings" PRIMARY KEY, "CourseSelectionRoundId" TEXT NOT NULL, "TeachingTaskId" TEXT NOT NULL, "Capacity" INTEGER NOT NULL, "IsOpenToAll" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CourseSelectionOfferings_CourseSelectionRounds_CourseSelectionRoundId" FOREIGN KEY ("CourseSelectionRoundId") REFERENCES "CourseSelectionRounds" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_CourseSelectionOfferings_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CourseSelectionOfferings_CourseSelectionRoundId_TeachingTaskId" ON "CourseSelectionOfferings" ("CourseSelectionRoundId", "TeachingTaskId"); """, """ CREATE INDEX IF NOT EXISTS "IX_CourseSelectionOfferings_TeachingTaskId" ON "CourseSelectionOfferings" ("TeachingTaskId"); """, """ CREATE TABLE IF NOT EXISTS "CourseEnrollments" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CourseEnrollments" PRIMARY KEY, "CourseSelectionOfferingId" TEXT NOT NULL, "StudentId" TEXT NOT NULL, "Status" INTEGER NOT NULL, "EnrolledAt" TEXT NOT NULL, "WithdrawnAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_CourseEnrollments_CourseSelectionOfferings_CourseSelectionOfferingId" FOREIGN KEY ("CourseSelectionOfferingId") REFERENCES "CourseSelectionOfferings" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_CourseEnrollments_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CourseEnrollments_CourseSelectionOfferingId_StudentId" ON "CourseEnrollments" ("CourseSelectionOfferingId", "StudentId"); """, """ CREATE INDEX IF NOT EXISTS "IX_CourseEnrollments_StudentId_Status" ON "CourseEnrollments" ("StudentId", "Status"); """ ]; private static readonly string[] GradesStatements = [ """ CREATE TABLE IF NOT EXISTS "GradeSheets" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GradeSheets" PRIMARY KEY, "TeachingTaskId" TEXT NOT NULL, "RegularWeight" TEXT NOT NULL, "MidtermWeight" TEXT NOT NULL, "FinalWeight" TEXT NOT NULL, "Status" INTEGER NOT NULL, "ReviewComment" TEXT NULL, "SubmittedAt" TEXT NULL, "ReviewedAt" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_GradeSheets_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_GradeSheets_TeachingTaskId" ON "GradeSheets" ("TeachingTaskId"); """, """ CREATE INDEX IF NOT EXISTS "IX_GradeSheets_Status" ON "GradeSheets" ("Status"); """, """ CREATE TABLE IF NOT EXISTS "GradeRecords" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GradeRecords" PRIMARY KEY, "GradeSheetId" TEXT NOT NULL, "StudentId" TEXT NOT NULL, "RegularScore" TEXT NULL, "MidtermScore" TEXT NULL, "FinalScore" TEXT NULL, "TotalScore" TEXT NULL, "GradePoint" TEXT NULL, "ExamStatus" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_GradeRecords_GradeSheets_GradeSheetId" FOREIGN KEY ("GradeSheetId") REFERENCES "GradeSheets" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_GradeRecords_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_GradeRecords_GradeSheetId_StudentId" ON "GradeRecords" ("GradeSheetId", "StudentId"); """, """ CREATE INDEX IF NOT EXISTS "IX_GradeRecords_StudentId_TotalScore" ON "GradeRecords" ("StudentId", "TotalScore"); """ ]; private static readonly string[] ExamsStatements = [ """ CREATE TABLE IF NOT EXISTS "ExamPlans" ( "Id" TEXT NOT NULL CONSTRAINT "PK_ExamPlans" PRIMARY KEY, "AcademicTermId" TEXT NOT NULL, "Name" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_ExamPlans_AcademicTerms_AcademicTermId" FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id") ON DELETE RESTRICT ); """, """CREATE INDEX IF NOT EXISTS "IX_ExamPlans_AcademicTermId_Status" ON "ExamPlans" ("AcademicTermId", "Status");""", """ CREATE TABLE IF NOT EXISTS "ExamSessions" ( "Id" TEXT NOT NULL CONSTRAINT "PK_ExamSessions" PRIMARY KEY, "ExamPlanId" TEXT NOT NULL, "TeachingTaskId" TEXT NOT NULL, "ClassroomId" TEXT NOT NULL, "StartsAt" TEXT NOT NULL, "EndsAt" TEXT NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_ExamSessions_ExamPlans_ExamPlanId" FOREIGN KEY ("ExamPlanId") REFERENCES "ExamPlans" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_ExamSessions_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_ExamSessions_Classrooms_ClassroomId" FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id") ON DELETE RESTRICT ); """, """CREATE INDEX IF NOT EXISTS "IX_ExamSessions_ExamPlanId_StartsAt" ON "ExamSessions" ("ExamPlanId", "StartsAt");""", """CREATE INDEX IF NOT EXISTS "IX_ExamSessions_TeachingTaskId" ON "ExamSessions" ("TeachingTaskId");""", """CREATE INDEX IF NOT EXISTS "IX_ExamSessions_ClassroomId" ON "ExamSessions" ("ClassroomId");""", """ CREATE TABLE IF NOT EXISTS "ExamSessionInvigilators" ( "ExamSessionId" TEXT NOT NULL, "TeacherId" TEXT NOT NULL, CONSTRAINT "PK_ExamSessionInvigilators" PRIMARY KEY ("ExamSessionId", "TeacherId"), CONSTRAINT "FK_ExamSessionInvigilators_ExamSessions_ExamSessionId" FOREIGN KEY ("ExamSessionId") REFERENCES "ExamSessions" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_ExamSessionInvigilators_Teachers_TeacherId" FOREIGN KEY ("TeacherId") REFERENCES "Teachers" ("Id") ON DELETE RESTRICT ); """, """CREATE INDEX IF NOT EXISTS "IX_ExamSessionInvigilators_TeacherId" ON "ExamSessionInvigilators" ("TeacherId");""" ]; private static readonly string[] StudentStatusChangesStatements = [ """ CREATE TABLE IF NOT EXISTS "StudentStatusChanges" ( "Id" TEXT NOT NULL CONSTRAINT "PK_StudentStatusChanges" PRIMARY KEY, "StudentId" TEXT NOT NULL, "Type" INTEGER NOT NULL, "OriginalStatus" INTEGER NOT NULL, "TargetStatus" INTEGER NOT NULL, "Reason" TEXT NOT NULL, "State" INTEGER NOT NULL, "ReviewComment" TEXT NULL, "SubmittedAt" TEXT NOT NULL, "ReviewedAt" TEXT NULL, "ApprovedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_StudentStatusChanges_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT ); """, """CREATE INDEX IF NOT EXISTS "IX_StudentStatusChanges_StudentId_State" ON "StudentStatusChanges" ("StudentId", "State");""" ]; private static readonly string[] GraduationAuditsStatements = [ """ CREATE TABLE IF NOT EXISTS "GraduationAuditBatches" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GraduationAuditBatches" PRIMARY KEY, "Name" TEXT NOT NULL, "GraduationYear" INTEGER NOT NULL, "EnrollmentYear" INTEGER NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "CalculatedAt" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL ); """, """CREATE INDEX IF NOT EXISTS "IX_GraduationAuditBatches_GraduationYear_EnrollmentYear" ON "GraduationAuditBatches" ("GraduationYear", "EnrollmentYear");""", """CREATE INDEX IF NOT EXISTS "IX_GraduationAuditBatches_Status" ON "GraduationAuditBatches" ("Status");""", """ CREATE TABLE IF NOT EXISTS "GraduationAuditResults" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GraduationAuditResults" PRIMARY KEY, "GraduationAuditBatchId" TEXT NOT NULL, "StudentId" TEXT NOT NULL, "CurriculumPlanId" TEXT NULL, "StudentStatusSnapshot" INTEGER NOT NULL, "RequiredCredits" TEXT NOT NULL, "EarnedCredits" TEXT NOT NULL, "RequiredCourseCount" INTEGER NOT NULL, "PassedRequiredCourseCount" INTEGER NOT NULL, "FailedCourseCount" INTEGER NOT NULL, "MissingCourseNames" TEXT NOT NULL, "CalculatedConclusion" INTEGER NOT NULL, "Conclusion" INTEGER NOT NULL, "IsOverridden" INTEGER NOT NULL, "ReviewComment" TEXT NULL, "ReviewedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_GraduationAuditResults_GraduationAuditBatches_GraduationAuditBatchId" FOREIGN KEY ("GraduationAuditBatchId") REFERENCES "GraduationAuditBatches" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_GraduationAuditResults_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_GraduationAuditResults_CurriculumPlans_CurriculumPlanId" FOREIGN KEY ("CurriculumPlanId") REFERENCES "CurriculumPlans" ("Id") ON DELETE SET NULL ); """, """CREATE UNIQUE INDEX IF NOT EXISTS "IX_GraduationAuditResults_GraduationAuditBatchId_StudentId" ON "GraduationAuditResults" ("GraduationAuditBatchId", "StudentId");""", """CREATE INDEX IF NOT EXISTS "IX_GraduationAuditResults_StudentId" ON "GraduationAuditResults" ("StudentId");""", """CREATE INDEX IF NOT EXISTS "IX_GraduationAuditResults_CurriculumPlanId" ON "GraduationAuditResults" ("CurriculumPlanId");""", """CREATE INDEX IF NOT EXISTS "IX_GraduationAuditResults_Conclusion_IsOverridden" ON "GraduationAuditResults" ("Conclusion", "IsOverridden");""" ]; private static readonly string[] DegreeAwardsStatements = [ """ CREATE TABLE IF NOT EXISTS "DegreeAwardBatches" ( "Id" TEXT NOT NULL CONSTRAINT "PK_DegreeAwardBatches" PRIMARY KEY, "Name" TEXT NOT NULL, "GraduationYear" INTEGER NOT NULL, "DegreeName" TEXT NOT NULL, "MinimumGradePoint" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "CalculatedAt" TEXT NULL, "PublishedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL ); """, """CREATE INDEX IF NOT EXISTS "IX_DegreeAwardBatches_GraduationYear_Status" ON "DegreeAwardBatches" ("GraduationYear", "Status");""", """ CREATE TABLE IF NOT EXISTS "DegreeAwardResults" ( "Id" TEXT NOT NULL CONSTRAINT "PK_DegreeAwardResults" PRIMARY KEY, "DegreeAwardBatchId" TEXT NOT NULL, "StudentId" TEXT NOT NULL, "GraduationAuditResultId" TEXT NOT NULL, "AverageGradePoint" TEXT NOT NULL, "CalculatedConclusion" INTEGER NOT NULL, "Conclusion" INTEGER NOT NULL, "ExceptionReason" TEXT NOT NULL, "IsOverridden" INTEGER NOT NULL, "ReviewComment" TEXT NULL, "ReviewedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_DegreeAwardResults_DegreeAwardBatches_DegreeAwardBatchId" FOREIGN KEY ("DegreeAwardBatchId") REFERENCES "DegreeAwardBatches" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_DegreeAwardResults_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_DegreeAwardResults_GraduationAuditResults_GraduationAuditResultId" FOREIGN KEY ("GraduationAuditResultId") REFERENCES "GraduationAuditResults" ("Id") ON DELETE RESTRICT ); """, """CREATE UNIQUE INDEX IF NOT EXISTS "IX_DegreeAwardResults_DegreeAwardBatchId_StudentId" ON "DegreeAwardResults" ("DegreeAwardBatchId", "StudentId");""", """CREATE INDEX IF NOT EXISTS "IX_DegreeAwardResults_StudentId" ON "DegreeAwardResults" ("StudentId");""", """CREATE INDEX IF NOT EXISTS "IX_DegreeAwardResults_GraduationAuditResultId" ON "DegreeAwardResults" ("GraduationAuditResultId");""", """CREATE INDEX IF NOT EXISTS "IX_DegreeAwardResults_Conclusion_IsOverridden" ON "DegreeAwardResults" ("Conclusion", "IsOverridden");""" ]; private static readonly string[] GraduationClearanceStatements = [ """ CREATE TABLE IF NOT EXISTS "GraduationClearanceBatches" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GraduationClearanceBatches" PRIMARY KEY, "Name" TEXT NOT NULL, "GraduationYear" INTEGER NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "ClosedAt" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL ); """, """CREATE INDEX IF NOT EXISTS "IX_GraduationClearanceBatches_GraduationYear_Status" ON "GraduationClearanceBatches" ("GraduationYear", "Status");""", """ CREATE TABLE IF NOT EXISTS "GraduationClearanceItems" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GraduationClearanceItems" PRIMARY KEY, "GraduationClearanceBatchId" TEXT NOT NULL, "Code" TEXT NOT NULL, "Name" TEXT NOT NULL, "ResponsibleUnit" TEXT NOT NULL, "ResponsibleRole" TEXT NOT NULL, "IsRequired" INTEGER NOT NULL, "SortOrder" INTEGER NOT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_GraduationClearanceItems_GraduationClearanceBatches_GraduationClearanceBatchId" FOREIGN KEY ("GraduationClearanceBatchId") REFERENCES "GraduationClearanceBatches" ("Id") ON DELETE CASCADE ); """, """CREATE UNIQUE INDEX IF NOT EXISTS "IX_GraduationClearanceItems_GraduationClearanceBatchId_Code" ON "GraduationClearanceItems" ("GraduationClearanceBatchId", "Code");""", """ CREATE TABLE IF NOT EXISTS "GraduationClearanceRecords" ( "Id" TEXT NOT NULL CONSTRAINT "PK_GraduationClearanceRecords" PRIMARY KEY, "GraduationClearanceItemId" TEXT NOT NULL, "StudentId" TEXT NOT NULL, "Status" INTEGER NOT NULL, "Notes" TEXT NULL, "CompletedAt" TEXT NULL, "CompletedByUserId" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_GraduationClearanceRecords_GraduationClearanceItems_GraduationClearanceItemId" FOREIGN KEY ("GraduationClearanceItemId") REFERENCES "GraduationClearanceItems" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_GraduationClearanceRecords_Students_StudentId" FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT ); """, """CREATE UNIQUE INDEX IF NOT EXISTS "IX_GraduationClearanceRecords_GraduationClearanceItemId_StudentId" ON "GraduationClearanceRecords" ("GraduationClearanceItemId", "StudentId");""", """CREATE INDEX IF NOT EXISTS "IX_GraduationClearanceRecords_StudentId_Status" ON "GraduationClearanceRecords" ("StudentId", "Status");""" ]; private static readonly string[] CourseCategoriesStatements = [ """ CREATE TABLE IF NOT EXISTS "CourseCategories" ( "Id" TEXT NOT NULL CONSTRAINT "PK_CourseCategories" PRIMARY KEY, "Code" TEXT NOT NULL, "Name" TEXT NOT NULL, "SortOrder" INTEGER NOT NULL, "IsEnabled" INTEGER NOT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL ); """, """ CREATE UNIQUE INDEX IF NOT EXISTS "IX_CourseCategories_Code" ON "CourseCategories" ("Code"); """, """ CREATE INDEX IF NOT EXISTS "IX_CourseCategories_IsEnabled_SortOrder" ON "CourseCategories" ("IsEnabled", "SortOrder"); """, """ ALTER TABLE "Courses" ADD COLUMN "CourseCategoryId" TEXT NULL; """, """ CREATE INDEX IF NOT EXISTS "IX_Courses_CourseCategoryId" ON "Courses" ("CourseCategoryId"); """ ]; private static readonly string[] SchedulingOptimizationStatements = [ """ CREATE TABLE "ScheduleEntries_New" ( "Id" TEXT NOT NULL CONSTRAINT "PK_ScheduleEntries" PRIMARY KEY, "SchedulePlanId" TEXT NOT NULL, "TeachingTaskId" TEXT NOT NULL, "ClassroomId" TEXT NULL, "DayOfWeek" INTEGER NOT NULL, "StartPeriod" INTEGER NOT NULL, "PeriodCount" INTEGER NOT NULL, "StartWeek" INTEGER NOT NULL, "EndWeek" INTEGER NOT NULL, "WeekPattern" INTEGER NOT NULL, "Notes" TEXT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_ScheduleEntries_SchedulePlans_SchedulePlanId" FOREIGN KEY ("SchedulePlanId") REFERENCES "SchedulePlans" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_ScheduleEntries_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_ScheduleEntries_Classrooms_ClassroomId" FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id") ON DELETE SET NULL ); """, """ INSERT INTO "ScheduleEntries_New" SELECT "Id", "SchedulePlanId", "TeachingTaskId", "ClassroomId", "DayOfWeek", "StartPeriod", "PeriodCount", "StartWeek", "EndWeek", "WeekPattern", "Notes", "CreatedAt", "UpdatedAt" FROM "ScheduleEntries"; """, """DROP TABLE "ScheduleEntries";""", """ALTER TABLE "ScheduleEntries_New" RENAME TO "ScheduleEntries";""", """ CREATE INDEX "IX_ScheduleEntries_SchedulePlanId_DayOfWeek_StartPeriod" ON "ScheduleEntries" ("SchedulePlanId", "DayOfWeek", "StartPeriod"); """, """ CREATE INDEX "IX_ScheduleEntries_TeachingTaskId" ON "ScheduleEntries" ("TeachingTaskId"); """, """ CREATE INDEX "IX_ScheduleEntries_ClassroomId" ON "ScheduleEntries" ("ClassroomId"); """, """ CREATE TABLE "ScheduleTimeSlots" ( "Id" TEXT NOT NULL CONSTRAINT "PK_ScheduleTimeSlots" PRIMARY KEY, "AcademicTermId" TEXT NOT NULL, "PeriodNumber" INTEGER NOT NULL, "Name" TEXT NOT NULL, "StartsAt" TEXT NOT NULL, "EndsAt" TEXT NOT NULL, "IsEnabled" INTEGER NOT NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_ScheduleTimeSlots_AcademicTerms_AcademicTermId" FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id") ON DELETE CASCADE ); """, """ CREATE UNIQUE INDEX "IX_ScheduleTimeSlots_AcademicTermId_PeriodNumber" ON "ScheduleTimeSlots" ("AcademicTermId", "PeriodNumber"); """, """ CREATE TABLE "TeachingTaskScheduleConstraints" ( "Id" TEXT NOT NULL CONSTRAINT "PK_TeachingTaskScheduleConstraints" PRIMARY KEY, "TeachingTaskId" TEXT NOT NULL, "RequiresClassroom" INTEGER NOT NULL, "RequiredCampusId" TEXT NULL, "RequiredBuildingId" TEXT NULL, "AllowedDayOfWeeks" TEXT NULL, "EarliestPeriod" INTEGER NULL, "LatestPeriod" INTEGER NULL, "CreatedAt" TEXT NOT NULL, "UpdatedAt" TEXT NOT NULL, CONSTRAINT "FK_TeachingTaskScheduleConstraints_TeachingTasks_TeachingTaskId" FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_TeachingTaskScheduleConstraints_Campuses_RequiredCampusId" FOREIGN KEY ("RequiredCampusId") REFERENCES "Campuses" ("Id") ON DELETE RESTRICT, CONSTRAINT "FK_TeachingTaskScheduleConstraints_Buildings_RequiredBuildingId" FOREIGN KEY ("RequiredBuildingId") REFERENCES "Buildings" ("Id") ON DELETE RESTRICT ); """, """ CREATE UNIQUE INDEX "IX_TeachingTaskScheduleConstraints_TeachingTaskId" ON "TeachingTaskScheduleConstraints" ("TeachingTaskId"); """, """ CREATE INDEX "IX_TeachingTaskScheduleConstraints_RequiredCampusId" ON "TeachingTaskScheduleConstraints" ("RequiredCampusId"); """, """ CREATE INDEX "IX_TeachingTaskScheduleConstraints_RequiredBuildingId" ON "TeachingTaskScheduleConstraints" ("RequiredBuildingId"); """, """ CREATE TABLE "TeachingTaskAllowedClassrooms" ( "TeachingTaskScheduleConstraintId" TEXT NOT NULL, "ClassroomId" TEXT NOT NULL, CONSTRAINT "PK_TeachingTaskAllowedClassrooms" PRIMARY KEY ("TeachingTaskScheduleConstraintId", "ClassroomId"), CONSTRAINT "FK_TeachingTaskAllowedClassrooms_Constraints" FOREIGN KEY ("TeachingTaskScheduleConstraintId") REFERENCES "TeachingTaskScheduleConstraints" ("Id") ON DELETE CASCADE, CONSTRAINT "FK_TeachingTaskAllowedClassrooms_Classrooms_ClassroomId" FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id") ON DELETE RESTRICT ); """, """ CREATE INDEX "IX_TeachingTaskAllowedClassrooms_ClassroomId" ON "TeachingTaskAllowedClassrooms" ("ClassroomId"); """ ]; }