package repository import ( "context" "fmt" ) const lessonReorderSortBump int32 = 1_000_000 // ReorderExamPrepCatalogCourses sets sort_order to 1..n for all catalog course rows (transactional). func (s *Store) ReorderExamPrepCatalogCourses(ctx context.Context, orderedIDs []int64) error { tx, err := s.conn.Begin(ctx) if err != nil { return err } defer func() { _ = tx.Rollback(ctx) }() for i, id := range orderedIDs { tag, err := tx.Exec(ctx, ` UPDATE exam_prep.catalog_courses SET sort_order = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2`, int32(i+1), id) if err != nil { return err } if tag.RowsAffected() == 0 { return fmt.Errorf("exam prep catalog course id %d not found", id) } } return tx.Commit(ctx) } // ReorderExamPrepUnitsInCatalogCourse sets sort_order to 1..n for units under catalogCourseID. func (s *Store) ReorderExamPrepUnitsInCatalogCourse(ctx context.Context, catalogCourseID int64, orderedIDs []int64) error { tx, err := s.conn.Begin(ctx) if err != nil { return err } defer func() { _ = tx.Rollback(ctx) }() for i, id := range orderedIDs { tag, err := tx.Exec(ctx, ` UPDATE exam_prep.units SET sort_order = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2 AND catalog_course_id = $3`, int32(i+1), id, catalogCourseID) if err != nil { return err } if tag.RowsAffected() == 0 { return fmt.Errorf("unit id %d not in catalog course %d", id, catalogCourseID) } } return tx.Commit(ctx) } // ReorderExamPrepUnitModulesInUnit sets sort_order to 1..n for modules under unitID. func (s *Store) ReorderExamPrepUnitModulesInUnit(ctx context.Context, unitID int64, orderedIDs []int64) error { tx, err := s.conn.Begin(ctx) if err != nil { return err } defer func() { _ = tx.Rollback(ctx) }() for i, id := range orderedIDs { tag, err := tx.Exec(ctx, ` UPDATE exam_prep.unit_modules SET sort_order = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2 AND unit_id = $3`, int32(i+1), id, unitID) if err != nil { return err } if tag.RowsAffected() == 0 { return fmt.Errorf("module id %d not in unit %d", id, unitID) } } return tx.Commit(ctx) } // ReorderExamPrepUnitModuleLessonsInUnitModule sets sort_order to 1..n under unitModuleID. // Uses an intermediate bump so UNIQUE (unit_module_id, sort_order) is never violated mid-reorder. func (s *Store) ReorderExamPrepUnitModuleLessonsInUnitModule(ctx context.Context, unitModuleID int64, orderedIDs []int64) error { tx, err := s.conn.Begin(ctx) if err != nil { return err } defer func() { _ = tx.Rollback(ctx) }() if _, err := tx.Exec(ctx, ` UPDATE exam_prep.unit_module_lessons SET sort_order = sort_order + $1, updated_at = CURRENT_TIMESTAMP WHERE unit_module_id = $2`, lessonReorderSortBump, unitModuleID); err != nil { return err } for i, id := range orderedIDs { tag, err := tx.Exec(ctx, ` UPDATE exam_prep.unit_module_lessons SET sort_order = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2 AND unit_module_id = $3`, int32(i+1), id, unitModuleID) if err != nil { return err } if tag.RowsAffected() == 0 { return fmt.Errorf("lesson id %d not in exam prep module %d", id, unitModuleID) } } return tx.Commit(ctx) }