diff --git a/db/query/question_set_items.sql b/db/query/question_set_items.sql index 4294a11..cb22474 100644 --- a/db/query/question_set_items.sql +++ b/db/query/question_set_items.sql @@ -4,7 +4,18 @@ INSERT INTO question_set_items ( question_id, display_order ) -VALUES ($1, $2, COALESCE($3, 0)) +VALUES ( + sqlc.arg('set_id'), + sqlc.arg('question_id'), + COALESCE( + sqlc.narg('display_order')::int, + COALESCE(( + SELECT max(qsi.display_order) + FROM question_set_items AS qsi + WHERE qsi.set_id = sqlc.arg('set_id') + ), 0) + 1 + ) +) ON CONFLICT (set_id, question_id) DO UPDATE SET display_order = EXCLUDED.display_order RETURNING *; diff --git a/gen/db/question_set_items.sql.go b/gen/db/question_set_items.sql.go index a9f593c..28c8ae0 100644 --- a/gen/db/question_set_items.sql.go +++ b/gen/db/question_set_items.sql.go @@ -17,19 +17,30 @@ INSERT INTO question_set_items ( question_id, display_order ) -VALUES ($1, $2, COALESCE($3, 0)) +VALUES ( + $1, + $2, + COALESCE( + $3::int, + COALESCE(( + SELECT max(qsi.display_order) + FROM question_set_items AS qsi + WHERE qsi.set_id = $1 + ), 0) + 1 + ) +) ON CONFLICT (set_id, question_id) DO UPDATE SET display_order = EXCLUDED.display_order RETURNING id, set_id, question_id, display_order, created_at ` type AddQuestionToSetParams struct { - SetID int64 `json:"set_id"` - QuestionID int64 `json:"question_id"` - Column3 interface{} `json:"column_3"` + SetID int64 `json:"set_id"` + QuestionID int64 `json:"question_id"` + DisplayOrder pgtype.Int4 `json:"display_order"` } func (q *Queries) AddQuestionToSet(ctx context.Context, arg AddQuestionToSetParams) (QuestionSetItem, error) { - row := q.db.QueryRow(ctx, AddQuestionToSet, arg.SetID, arg.QuestionID, arg.Column3) + row := q.db.QueryRow(ctx, AddQuestionToSet, arg.SetID, arg.QuestionID, arg.DisplayOrder) var i QuestionSetItem err := row.Scan( &i.ID, diff --git a/internal/repository/questions.go b/internal/repository/questions.go index 4bebecd..6090ace 100644 --- a/internal/repository/questions.go +++ b/internal/repository/questions.go @@ -1096,15 +1096,15 @@ func (s *Store) DeleteQuestionSet(ctx context.Context, id int64) error { } func (s *Store) AddQuestionToSet(ctx context.Context, setID, questionID int64, displayOrder *int32) (domain.QuestionSetItem, error) { - var order interface{} + orderParam := pgtype.Int4{Valid: false} if displayOrder != nil { - order = *displayOrder + orderParam = pgtype.Int4{Int32: *displayOrder, Valid: true} } item, err := s.queries.AddQuestionToSet(ctx, dbgen.AddQuestionToSetParams{ - SetID: setID, - QuestionID: questionID, - Column3: order, + SetID: setID, + QuestionID: questionID, + DisplayOrder: orderParam, }) if err != nil { return domain.QuestionSetItem{}, err diff --git a/internal/web_server/handlers/questions.go b/internal/web_server/handlers/questions.go index 257f280..a41cf17 100644 --- a/internal/web_server/handlers/questions.go +++ b/internal/web_server/handlers/questions.go @@ -58,6 +58,7 @@ type shortAnswerRes struct { type questionRes struct { ID int64 `json:"id"` + DisplayOrder *int32 `json:"display_order,omitempty"` QuestionText *string `json:"question_text,omitempty"` QuestionType string `json:"question_type"` QuestionTypeDefinitionID *int64 `json:"question_type_definition_id,omitempty"` @@ -1264,8 +1265,9 @@ func (h *Handler) DeleteQuestionSet(c *fiber.Ctx) error { // Question Set Items type addQuestionToSetReq struct { - QuestionID int64 `json:"question_id" validate:"required"` - DisplayOrder *int32 `json:"display_order"` + QuestionID int64 `json:"question_id" validate:"required"` + // Omit to append after the current highest display_order in the set; set explicitly to insert at a position. + DisplayOrder *int32 `json:"display_order,omitempty" validate:"omitempty,min=0"` } type questionSetItemRes struct { @@ -1321,7 +1323,7 @@ func questionSetItemsToRes(items []domain.QuestionSetItemWithQuestion) []questio // AddQuestionToSet godoc // @Summary Add question to set -// @Description Links a question to a question set +// @Description Links a question to a question set. Omit display_order to append after the current max; the assigned value is returned in the response. // @Tags question-set-items // @Accept json // @Produce json @@ -1348,6 +1350,12 @@ func (h *Handler) AddQuestionToSet(c *fiber.Ctx) error { Error: err.Error(), }) } + if valErrs, ok := h.validator.Validate(c, req); !ok { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Validation failed", + Error: firstValidationError(valErrs), + }) + } item, err := h.questionsSvc.AddQuestionToSet(c.Context(), setID, req.QuestionID, req.DisplayOrder) if err != nil { @@ -1487,7 +1495,10 @@ func (h *Handler) GetQuestionsInSet(c *fiber.Ctx) error { }) } - questionResponses = append(questionResponses, buildQuestionRes(question, catalog)) + res := buildQuestionRes(question, catalog) + order := item.DisplayOrder + res.DisplayOrder = &order + questionResponses = append(questionResponses, res) } return c.JSON(domain.Response{