fix(store): Reorder validiert Vollständigkeit und RowsAffected

This commit is contained in:
Jesko Anschütz 2026-03-26 22:23:28 +01:00
parent b463aeeae1
commit 1c11aa9877

View file

@ -3,12 +3,17 @@ package store
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"time" "time"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
// ErrReorderMismatch wird von Reorder zurückgegeben, wenn die übergebene
// ID-Liste nicht mit den tatsächlichen Items der Playlist übereinstimmt.
var ErrReorderMismatch = errors.New("reorder: item list does not match playlist")
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// Domain types // Domain types
// ------------------------------------------------------------------ // ------------------------------------------------------------------
@ -531,20 +536,46 @@ func (s *PlaylistStore) ScreenSlugByItemID(ctx context.Context, itemID string) (
} }
// Reorder sets order_index for each item ID in the given slice order. // Reorder sets order_index for each item ID in the given slice order.
// Returns ErrReorderMismatch if the number of provided IDs does not match
// the number of items in the playlist, or if any ID does not belong to it.
func (s *PlaylistStore) Reorder(ctx context.Context, playlistID string, itemIDs []string) error { func (s *PlaylistStore) Reorder(ctx context.Context, playlistID string, itemIDs []string) error {
seen := make(map[string]struct{}, len(itemIDs))
for _, id := range itemIDs {
if _, dup := seen[id]; dup {
return fmt.Errorf("%w: duplicate id %s", ErrReorderMismatch, id)
}
seen[id] = struct{}{}
}
tx, err := s.pool.Begin(ctx) tx, err := s.pool.Begin(ctx)
if err != nil { if err != nil {
return err return err
} }
defer tx.Rollback(ctx) //nolint:errcheck defer tx.Rollback(ctx) //nolint:errcheck
var count int
if err := tx.QueryRow(ctx,
`select count(*) from playlist_items where playlist_id=$1`, playlistID,
).Scan(&count); err != nil {
return err
}
if count != len(itemIDs) {
return fmt.Errorf("%w: got %d ids, playlist has %d items",
ErrReorderMismatch, len(itemIDs), count)
}
for i, id := range itemIDs { for i, id := range itemIDs {
if _, err := tx.Exec(ctx, tag, err := tx.Exec(ctx,
`update playlist_items set order_index=$1 where id=$2 and playlist_id=$3`, `update playlist_items set order_index=$1 where id=$2 and playlist_id=$3`,
i, id, playlistID, i, id, playlistID,
); err != nil { )
if err != nil {
return err return err
} }
if tag.RowsAffected() != 1 {
return fmt.Errorf("%w: id %s not found in playlist %s",
ErrReorderMismatch, id, playlistID)
}
} }
return tx.Commit(ctx) return tx.Commit(ctx)
} }