fix(handler): ensure target ID is provided for updates
Tests / Unit Tests (push) Failing after 9s
Tests / Integration Tests (push) Failing after 12s
Build , Vet Test, and Lint / Run Vet Tests (1.23.x) (push) Successful in 48s
Build , Vet Test, and Lint / Build (push) Successful in 1m18s
Build , Vet Test, and Lint / Run Vet Tests (1.24.x) (push) Successful in 1m27s
Build , Vet Test, and Lint / Lint Code (push) Successful in 1m28s

This commit is contained in:
Hein
2026-07-24 16:35:22 +02:00
parent b23916048a
commit 873e8925d4
+18 -13
View File
@@ -1056,6 +1056,12 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
// Get the primary key name // Get the primary key name
pkName := reflection.GetPrimaryKeyName(model) pkName := reflection.GetPrimaryKeyName(model)
if targetID == nil {
logger.Error("Update request for %s.%s has no ID (not in URL, request ID, or data)", schema, entity)
h.sendError(w, http.StatusBadRequest, "missing_id", "No ID provided for update", nil)
return
}
// Wrap in transaction to ensure BeforeUpdate hook is inside transaction // Wrap in transaction to ensure BeforeUpdate hook is inside transaction
err := h.db.RunInTransaction(ctx, func(tx common.Database) error { err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
// Execute BeforeUpdate hooks inside transaction, before any queries run. // Execute BeforeUpdate hooks inside transaction, before any queries run.
@@ -1088,21 +1094,20 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
existingRecord := reflect.New(reflection.GetPointerElement(reflect.TypeOf(model))).Interface() existingRecord := reflect.New(reflection.GetPointerElement(reflect.TypeOf(model))).Interface()
selectQuery := tx.NewSelect().Model(existingRecord).Column(reflection.GetSQLModelColumns(model)...) selectQuery := tx.NewSelect().Model(existingRecord).Column(reflection.GetSQLModelColumns(model)...)
// Apply conditions to select // Apply conditions to select, based on the resolved target ID
if urlID != "" { // (URL ID, request ID, or the "id" field embedded in the data payload).
logger.Debug("Updating by URL ID: %s", urlID) switch id := targetID.(type) {
selectQuery = selectQuery.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), urlID)
} else if reqID != nil {
switch id := reqID.(type) {
case string: case string:
logger.Debug("Updating by request ID: %s", id) logger.Debug("Updating by ID: %s", id)
selectQuery = selectQuery.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id) selectQuery = selectQuery.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id)
case []string: case []string:
if len(id) > 0 { if len(id) > 0 {
logger.Debug("Updating by multiple IDs: %v", id) logger.Debug("Updating by multiple IDs: %v", id)
selectQuery = selectQuery.Where(fmt.Sprintf("%s IN (?)", common.QuoteIdent(pkName)), id) selectQuery = selectQuery.Where(fmt.Sprintf("%s IN (?)", common.QuoteIdent(pkName)), id)
} }
} default:
logger.Debug("Updating by ID: %v", id)
selectQuery = selectQuery.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id)
} }
if err := selectQuery.ScanModel(ctx); err != nil { if err := selectQuery.ScanModel(ctx); err != nil {
@@ -1141,16 +1146,16 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
// Build update query with merged data // Build update query with merged data
query := tx.NewUpdate().Table(tableName).SetMap(existingMap) query := tx.NewUpdate().Table(tableName).SetMap(existingMap)
// Apply conditions // Apply conditions, using the same target ID resolved for the select above
if urlID != "" { switch id := targetID.(type) {
query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), urlID)
} else if reqID != nil {
switch id := reqID.(type) {
case string: case string:
query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id) query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id)
case []string: case []string:
if len(id) > 0 {
query = query.Where(fmt.Sprintf("%s IN (?)", common.QuoteIdent(pkName)), id) query = query.Where(fmt.Sprintf("%s IN (?)", common.QuoteIdent(pkName)), id)
} }
default:
query = query.Where(fmt.Sprintf("%s = ?", common.QuoteIdent(pkName)), id)
} }
result, err := query.Exec(ctx) result, err := query.Exec(ctx)