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 (
"context"
"errors"
"fmt"
"time"
"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
// ------------------------------------------------------------------
@ -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.
// 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 {
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)
if err != nil {
return err
}
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 {
if _, err := tx.Exec(ctx,
tag, err := tx.Exec(ctx,
`update playlist_items set order_index=$1 where id=$2 and playlist_id=$3`,
i, id, playlistID,
); err != nil {
)
if err != nil {
return err
}
if tag.RowsAffected() != 1 {
return fmt.Errorf("%w: id %s not found in playlist %s",
ErrReorderMismatch, id, playlistID)
}
}
return tx.Commit(ctx)
}