fix: use two-phase bump when shifting sort_order on content insert

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Yared Yemane 2026-06-10 05:26:17 -07:00
parent a704c3b29f
commit a4792206f7

View File

@ -9,61 +9,83 @@ import (
// Sequential siblings (programs global, courses per program, modules per course, lessons per module) use unique sort_order.
// These helpers move id from oldPos to newPos without collisions by temporarily assigning sort_order = -id then shifting intermediates.
// shift*SortOrderForInsert makes room at fromPos by incrementing existing rows at/after that position.
// Rows are updated highest-first so the unique (parent, sort_order) index is never violated mid-shift.
// sortOrderInsertShiftBump moves affected rows into a high temporary range, then back to
// (old + 1). A single UPDATE ... SET sort_order = sort_order + 1 can violate unique
// (parent, sort_order) indexes because PostgreSQL does not apply row updates in sort order.
const sortOrderInsertShiftBump = int32(1_000_000)
func shiftProgramsSortOrderForInsert(ctx context.Context, tx pgx.Tx, fromPos int32) error {
bump := sortOrderInsertShiftBump
if _, err := tx.Exec(ctx, `
UPDATE programs
SET sort_order = sort_order + $2
WHERE sort_order >= $1`, fromPos, bump); err != nil {
return err
}
_, err := tx.Exec(ctx, `
UPDATE programs AS t
SET sort_order = t.sort_order + 1
FROM (
SELECT id FROM programs WHERE sort_order >= $1 ORDER BY sort_order DESC
) AS s
WHERE t.id = s.id`, fromPos)
UPDATE programs
SET sort_order = sort_order - $2
WHERE sort_order >= $1`, bump, bump-1)
return err
}
func shiftCoursesSortOrderForInsert(ctx context.Context, tx pgx.Tx, programID int64, fromPos int32) error {
bump := sortOrderInsertShiftBump
if _, err := tx.Exec(ctx, `
UPDATE courses
SET sort_order = sort_order + $3
WHERE program_id = $1 AND sort_order >= $2`, programID, fromPos, bump); err != nil {
return err
}
_, err := tx.Exec(ctx, `
UPDATE courses AS t
SET sort_order = t.sort_order + 1
FROM (
SELECT id FROM courses WHERE program_id = $1 AND sort_order >= $2 ORDER BY sort_order DESC
) AS s
WHERE t.id = s.id`, programID, fromPos)
UPDATE courses
SET sort_order = sort_order - $3
WHERE program_id = $1 AND sort_order >= $2`, programID, bump, bump-1)
return err
}
func shiftModulesSortOrderForInsert(ctx context.Context, tx pgx.Tx, courseID int64, fromPos int32) error {
bump := sortOrderInsertShiftBump
if _, err := tx.Exec(ctx, `
UPDATE modules
SET sort_order = sort_order + $3
WHERE course_id = $1 AND sort_order >= $2`, courseID, fromPos, bump); err != nil {
return err
}
_, err := tx.Exec(ctx, `
UPDATE modules AS t
SET sort_order = t.sort_order + 1
FROM (
SELECT id FROM modules WHERE course_id = $1 AND sort_order >= $2 ORDER BY sort_order DESC
) AS s
WHERE t.id = s.id`, courseID, fromPos)
UPDATE modules
SET sort_order = sort_order - $3
WHERE course_id = $1 AND sort_order >= $2`, courseID, bump, bump-1)
return err
}
func shiftLessonsSortOrderForInsert(ctx context.Context, tx pgx.Tx, moduleID int64, fromPos int32) error {
bump := sortOrderInsertShiftBump
if _, err := tx.Exec(ctx, `
UPDATE lessons
SET sort_order = sort_order + $3
WHERE module_id = $1 AND sort_order >= $2`, moduleID, fromPos, bump); err != nil {
return err
}
_, err := tx.Exec(ctx, `
UPDATE lessons AS t
SET sort_order = t.sort_order + 1
FROM (
SELECT id FROM lessons WHERE module_id = $1 AND sort_order >= $2 ORDER BY sort_order DESC
) AS s
WHERE t.id = s.id`, moduleID, fromPos)
UPDATE lessons
SET sort_order = sort_order - $3
WHERE module_id = $1 AND sort_order >= $2`, moduleID, bump, bump-1)
return err
}
func shiftExamPrepUnitsSortOrderForInsert(ctx context.Context, tx pgx.Tx, catalogCourseID int64, fromPos int32) error {
bump := sortOrderInsertShiftBump
if _, err := tx.Exec(ctx, `
UPDATE exam_prep.units
SET sort_order = sort_order + $3
WHERE catalog_course_id = $1 AND sort_order >= $2`, catalogCourseID, fromPos, bump); err != nil {
return err
}
_, err := tx.Exec(ctx, `
UPDATE exam_prep.units AS t
SET sort_order = t.sort_order + 1
FROM (
SELECT id FROM exam_prep.units WHERE catalog_course_id = $1 AND sort_order >= $2 ORDER BY sort_order DESC
) AS s
WHERE t.id = s.id`, catalogCourseID, fromPos)
UPDATE exam_prep.units
SET sort_order = sort_order - $3
WHERE catalog_course_id = $1 AND sort_order >= $2`, catalogCourseID, bump, bump-1)
return err
}