fix: avoid unique sort_order conflicts during LMS hierarchy reorder

Bump sort_order before reassignment for programs, courses, and modules so batch reorder no longer violates uq_courses_program_sort and sibling constraints.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Yared Yemane 2026-06-10 03:42:40 -07:00
parent dfdb2a52dc
commit 58790f0998

View File

@ -6,12 +6,21 @@ import (
)
// ReorderPrograms sets sort_order to 1..n in the given order (transactional).
// Uses an intermediate bump so UNIQUE (sort_order) is never violated mid-reorder.
func (s *Store) ReorderPrograms(ctx context.Context, 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 programs
SET sort_order = sort_order + $1,
updated_at = CURRENT_TIMESTAMP`, lessonReorderSortBump); err != nil {
return err
}
for i, id := range orderedIDs {
tag, err := tx.Exec(ctx, `UPDATE programs SET sort_order = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2`, int32(i+1), id)
if err != nil {
@ -25,12 +34,22 @@ func (s *Store) ReorderPrograms(ctx context.Context, orderedIDs []int64) error {
}
// ReorderCoursesInProgram sets sort_order for courses under programID (transactional).
// Uses an intermediate bump so UNIQUE (program_id, sort_order) is never violated mid-reorder.
func (s *Store) ReorderCoursesInProgram(ctx context.Context, programID 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 courses
SET sort_order = sort_order + $1,
updated_at = CURRENT_TIMESTAMP
WHERE program_id = $2`, lessonReorderSortBump, programID); err != nil {
return err
}
for i, id := range orderedIDs {
tag, err := tx.Exec(ctx, `
UPDATE courses
@ -49,12 +68,22 @@ WHERE id = $2
}
// ReorderModulesInCourse sets sort_order for modules under courseID (transactional).
// Uses an intermediate bump so UNIQUE (course_id, sort_order) is never violated mid-reorder.
func (s *Store) ReorderModulesInCourse(ctx context.Context, courseID 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 modules
SET sort_order = sort_order + $1,
updated_at = CURRENT_TIMESTAMP
WHERE course_id = $2`, lessonReorderSortBump, courseID); err != nil {
return err
}
for i, id := range orderedIDs {
tag, err := tx.Exec(ctx, `
UPDATE modules