Platforms no longer have a user_id: there's one global list, unique by name, that every authenticated user reads from and writes to. Games are unchanged - still private per user, still referencing platform_id. - Migration: dropped platform.user_id and its FK, UNIQUE(user_id, name) -> UNIQUE(name), index on change_seq alone instead of (user_id, change_seq). Amended the one init migration in place rather than stacking a second one, since nothing is deployed yet. - db/query.sql: platform queries no longer take a user_id parameter. DeletePlatform's NOT EXISTS guard already checked games from any user (it never filtered the subquery by user_id), so deleting a shared platform is correctly blocked by any user's games on it, not just the deleter's. - routes.go: platform handlers still require auth (the list isn't public to anonymous requests) but no longer scope by user. - Tests: updated the mocks for the new signatures, added TestListPlatformsIsSharedAcrossUsers. Verified against a real Postgres: user A creates "PC", user B sees it immediately, both can add games against it, each only sees their own games, deleting the platform is blocked while either user has a game on it, and the name stays globally unique. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
87 lines
4.3 KiB
Go
87 lines
4.3 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"completed/internal/db"
|
|
)
|
|
|
|
// MockQuerier is a hand-written fake implementing db.Querier for handler
|
|
// tests. Each test sets only the *Func fields its handler path reaches;
|
|
// any other field left nil panics on call, which is deliberate: it makes an
|
|
// unexpectedly-reached query visible as a test failure instead of a nil
|
|
// pointer deep in sqlc-generated code.
|
|
type MockQuerier struct {
|
|
CreateGameFunc func(ctx context.Context, arg db.CreateGameParams) (db.CreateGameRow, error)
|
|
CreatePlatformFunc func(ctx context.Context, name string) (db.CreatePlatformRow, error)
|
|
CreateSessionFunc func(ctx context.Context, arg db.CreateSessionParams) error
|
|
CreateUserFunc func(ctx context.Context, arg db.CreateUserParams) (db.CreateUserRow, error)
|
|
DeleteGameFunc func(ctx context.Context, arg db.DeleteGameParams) (int64, error)
|
|
DeletePlatformFunc func(ctx context.Context, id uuid.UUID) (int64, error)
|
|
DeleteSessionFunc func(ctx context.Context, tokenHash []byte) error
|
|
GetGameFunc func(ctx context.Context, arg db.GetGameParams) (db.GetGameRow, error)
|
|
GetPlatformFunc func(ctx context.Context, id uuid.UUID) (db.GetPlatformRow, error)
|
|
GetSessionAndUserFunc func(ctx context.Context, tokenHash []byte) (db.GetSessionAndUserRow, error)
|
|
GetUserByEmailFunc func(ctx context.Context, email string) (db.GetUserByEmailRow, error)
|
|
GetUserByIDFunc func(ctx context.Context, id uuid.UUID) (db.GetUserByIDRow, error)
|
|
ListGamesFunc func(ctx context.Context, userID uuid.UUID) ([]db.ListGamesRow, error)
|
|
ListPlatformsFunc func(ctx context.Context) ([]db.ListPlatformsRow, error)
|
|
TouchSessionFunc func(ctx context.Context, tokenHash []byte) error
|
|
UpdateGameFunc func(ctx context.Context, arg db.UpdateGameParams) (db.UpdateGameRow, error)
|
|
UpdatePlatformFunc func(ctx context.Context, arg db.UpdatePlatformParams) (db.UpdatePlatformRow, error)
|
|
}
|
|
|
|
func (m *MockQuerier) CreateGame(ctx context.Context, arg db.CreateGameParams) (db.CreateGameRow, error) {
|
|
return m.CreateGameFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) CreatePlatform(ctx context.Context, name string) (db.CreatePlatformRow, error) {
|
|
return m.CreatePlatformFunc(ctx, name)
|
|
}
|
|
func (m *MockQuerier) CreateSession(ctx context.Context, arg db.CreateSessionParams) error {
|
|
return m.CreateSessionFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) CreateUser(ctx context.Context, arg db.CreateUserParams) (db.CreateUserRow, error) {
|
|
return m.CreateUserFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) DeleteGame(ctx context.Context, arg db.DeleteGameParams) (int64, error) {
|
|
return m.DeleteGameFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) DeletePlatform(ctx context.Context, id uuid.UUID) (int64, error) {
|
|
return m.DeletePlatformFunc(ctx, id)
|
|
}
|
|
func (m *MockQuerier) DeleteSession(ctx context.Context, tokenHash []byte) error {
|
|
return m.DeleteSessionFunc(ctx, tokenHash)
|
|
}
|
|
func (m *MockQuerier) GetGame(ctx context.Context, arg db.GetGameParams) (db.GetGameRow, error) {
|
|
return m.GetGameFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) GetPlatform(ctx context.Context, id uuid.UUID) (db.GetPlatformRow, error) {
|
|
return m.GetPlatformFunc(ctx, id)
|
|
}
|
|
func (m *MockQuerier) GetSessionAndUser(ctx context.Context, tokenHash []byte) (db.GetSessionAndUserRow, error) {
|
|
return m.GetSessionAndUserFunc(ctx, tokenHash)
|
|
}
|
|
func (m *MockQuerier) GetUserByEmail(ctx context.Context, email string) (db.GetUserByEmailRow, error) {
|
|
return m.GetUserByEmailFunc(ctx, email)
|
|
}
|
|
func (m *MockQuerier) GetUserByID(ctx context.Context, id uuid.UUID) (db.GetUserByIDRow, error) {
|
|
return m.GetUserByIDFunc(ctx, id)
|
|
}
|
|
func (m *MockQuerier) ListGames(ctx context.Context, userID uuid.UUID) ([]db.ListGamesRow, error) {
|
|
return m.ListGamesFunc(ctx, userID)
|
|
}
|
|
func (m *MockQuerier) ListPlatforms(ctx context.Context) ([]db.ListPlatformsRow, error) {
|
|
return m.ListPlatformsFunc(ctx)
|
|
}
|
|
func (m *MockQuerier) TouchSession(ctx context.Context, tokenHash []byte) error {
|
|
return m.TouchSessionFunc(ctx, tokenHash)
|
|
}
|
|
func (m *MockQuerier) UpdateGame(ctx context.Context, arg db.UpdateGameParams) (db.UpdateGameRow, error) {
|
|
return m.UpdateGameFunc(ctx, arg)
|
|
}
|
|
func (m *MockQuerier) UpdatePlatform(ctx context.Context, arg db.UpdatePlatformParams) (db.UpdatePlatformRow, error) {
|
|
return m.UpdatePlatformFunc(ctx, arg)
|
|
}
|