Accept optional sort_order when creating LMS programs.

Preserve append-after-max ordering when omitting sort_order and keep global uniqueness enforced by DB.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Yared Yemane 2026-05-19 02:10:49 -07:00
parent 4a681265d7
commit d28bddace1
8 changed files with 45 additions and 19 deletions

View File

@ -1,13 +1,13 @@
-- name: CreateProgram :one
INSERT INTO programs (name, description, thumbnail, sort_order)
SELECT
$1,
$2,
$3,
coalesce((
sqlc.arg('name'),
sqlc.arg('description'),
sqlc.arg('thumbnail'),
COALESCE(sqlc.narg('sort_order')::int, COALESCE((
SELECT
max(p.sort_order)
FROM programs AS p), 0) + 1
FROM programs AS p), 0) + 1)
RETURNING
*;

View File

@ -4150,7 +4150,7 @@ const docTemplate = `{
}
},
"post": {
"description": "Create a top-level LMS program",
"description": "Create a top-level LMS program. Optional sort_order inserts at that global ordering; omit it to append after the current highest sort_order. Unique constraint applies to sort_order.",
"consumes": [
"application/json"
],
@ -10563,6 +10563,11 @@ const docTemplate = `{
"name": {
"type": "string"
},
"sort_order": {
"description": "SortOrder inserts at this global program order when set; omit to append after current max (sort_order uniqueness is enforced).",
"type": "integer",
"minimum": 0
},
"thumbnail": {
"type": "string"
}

View File

@ -4142,7 +4142,7 @@
}
},
"post": {
"description": "Create a top-level LMS program",
"description": "Create a top-level LMS program. Optional sort_order inserts at that global ordering; omit it to append after the current highest sort_order. Unique constraint applies to sort_order.",
"consumes": [
"application/json"
],
@ -10555,6 +10555,11 @@
"name": {
"type": "string"
},
"sort_order": {
"description": "SortOrder inserts at this global program order when set; omit to append after current max (sort_order uniqueness is enforced).",
"type": "integer",
"minimum": 0
},
"thumbnail": {
"type": "string"
}

View File

@ -468,6 +468,11 @@ definitions:
type: string
name:
type: string
sort_order:
description: SortOrder inserts at this global program order when set; omit
to append after current max (sort_order uniqueness is enforced).
minimum: 0
type: integer
thumbnail:
type: string
required:
@ -5230,7 +5235,9 @@ paths:
post:
consumes:
- application/json
description: Create a top-level LMS program
description: Create a top-level LMS program. Optional sort_order inserts at
that global ordering; omit it to append after the current highest sort_order.
Unique constraint applies to sort_order.
parameters:
- description: Program
in: body

View File

@ -17,10 +17,10 @@ SELECT
$1,
$2,
$3,
coalesce((
COALESCE($4::int, COALESCE((
SELECT
max(p.sort_order)
FROM programs AS p), 0) + 1
FROM programs AS p), 0) + 1)
RETURNING
id, name, description, thumbnail, created_at, updated_at, sort_order
`
@ -29,10 +29,16 @@ type CreateProgramParams struct {
Name string `json:"name"`
Description pgtype.Text `json:"description"`
Thumbnail pgtype.Text `json:"thumbnail"`
SortOrder pgtype.Int4 `json:"sort_order"`
}
func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (Program, error) {
row := q.db.QueryRow(ctx, CreateProgram, arg.Name, arg.Description, arg.Thumbnail)
row := q.db.QueryRow(ctx, CreateProgram,
arg.Name,
arg.Description,
arg.Thumbnail,
arg.SortOrder,
)
var i Program
err := row.Scan(
&i.ID,

View File

@ -4,13 +4,13 @@ import "time"
// Program is the top-level container in the LMS hierarchy (e.g. tracks like Beginner / Intermediate / Advanced).
type Program struct {
ID int64 `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Thumbnail *string `json:"thumbnail,omitempty"`
SortOrder int `json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
ID int64 `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
Thumbnail *string `json:"thumbnail,omitempty"`
SortOrder int `json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
Access *LMSEntityAccess `json:"access,omitempty"`
}
@ -18,6 +18,8 @@ type CreateProgramInput struct {
Name string `json:"name" validate:"required"`
Description *string `json:"description,omitempty"`
Thumbnail *string `json:"thumbnail,omitempty"`
// SortOrder inserts at this global program order when set; omit to append after current max (sort_order uniqueness is enforced).
SortOrder *int `json:"sort_order,omitempty" validate:"omitempty,min=0"`
}
type UpdateProgramInput struct {

View File

@ -32,6 +32,7 @@ func (s *Store) CreateProgram(ctx context.Context, input domain.CreateProgramInp
Name: input.Name,
Description: toPgText(input.Description),
Thumbnail: toPgText(input.Thumbnail),
SortOrder: optionalInt4Update(input.SortOrder),
})
if err != nil {
return domain.Program{}, err

View File

@ -12,7 +12,7 @@ import (
// CreateProgram godoc
// @Summary Create program
// @Description Create a top-level LMS program
// @Description Create a top-level LMS program. Optional sort_order inserts at that global ordering; omit it to append after the current highest sort_order. Unique constraint applies to sort_order.
// @Tags programs
// @Accept json
// @Produce json