Enha: create tx; cardword test
This commit is contained in:
@ -159,6 +159,21 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) {
|
|||||||
abortWithError(w, err.Error())
|
abortWithError(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize transaction
|
||||||
|
ctx, tx, err := repo.InitTx(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to init transaction", "error", err)
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
fi.Room.IsRunning = true
|
fi.Room.IsRunning = true
|
||||||
fi.Room.IsOver = false
|
fi.Room.IsOver = false
|
||||||
fi.Room.TeamTurn = "blue"
|
fi.Room.TeamTurn = "blue"
|
||||||
@ -174,10 +189,42 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) {
|
|||||||
Action: models.ActionTypeGameStarted,
|
Action: models.ActionTypeGameStarted,
|
||||||
}
|
}
|
||||||
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
fi.Room.ActionHistory = append(fi.Room.ActionHistory, action)
|
||||||
if err := saveFullInfo(r.Context(), fi); err != nil {
|
|
||||||
|
// Use the new context with transaction
|
||||||
|
if err := saveFullInfo(ctx, fi); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
abortWithError(w, err.Error())
|
abortWithError(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save action history
|
||||||
|
action.RoomID = fi.Room.ID
|
||||||
|
action.CreatedAtUnix = time.Now().Unix()
|
||||||
|
if err := repo.CreateAction(ctx, fi.Room.ID, &action); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
log.Error("failed to save action", "error", err)
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save word cards
|
||||||
|
for _, card := range fi.Room.Cards {
|
||||||
|
card.RoomID = fi.Room.ID // Ensure RoomID is set for each card
|
||||||
|
if err := repo.WordCardsCreate(ctx, &card); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
log.Error("failed to save word card", "error", err)
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
log.Error("failed to commit transaction", "error", err)
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// reveal all cards
|
// reveal all cards
|
||||||
if fi.State.Role == "mime" {
|
if fi.State.Role == "mime" {
|
||||||
fi.Room.MimeView()
|
fi.Room.MimeView()
|
||||||
|
@ -17,6 +17,7 @@ type AllRepos interface {
|
|||||||
PlayersRepo
|
PlayersRepo
|
||||||
SessionsRepo
|
SessionsRepo
|
||||||
WordCardsRepo
|
WordCardsRepo
|
||||||
|
InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RepoProvider struct {
|
type RepoProvider struct {
|
||||||
@ -95,3 +96,11 @@ func getDB(ctx context.Context, db *sqlx.DB) sqlx.ExtContext {
|
|||||||
}
|
}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *RepoProvider) InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) {
|
||||||
|
tx, err := p.DB.BeginTxx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return context.WithValue(ctx, "tx", tx), tx, nil
|
||||||
|
}
|
||||||
|
496
repos/word_cards_test.go
Normal file
496
repos/word_cards_test.go
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
package repos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"gralias/models"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWordCardsRepo_Create(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_1"
|
||||||
|
// Insert a room first, as word_cards has a foreign key to rooms
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Test single card creation
|
||||||
|
card1 := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "apple",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
_, err = db.Exec(`INSERT INTO word_cards (room_id, word, color, revealed, mime_view) VALUES (?, ?, ?, ?, ?)`, card1.RoomID, card1.Word, card1.Color, card1.Revealed, card1.Mime)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, count)
|
||||||
|
|
||||||
|
// Test batch card creation with transaction commit
|
||||||
|
tx, err := db.BeginTxx(ctx, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
card2 := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "banana",
|
||||||
|
Color: models.WordColorBlue,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
card3 := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "cherry",
|
||||||
|
Color: models.WordColorBlack,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(`INSERT INTO word_cards (room_id, word, color, revealed, mime_view) VALUES (?, ?, ?, ?, ?)`, card2.RoomID, card2.Word, card2.Color, card2.Revealed, card2.Mime)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = tx.Exec(`INSERT INTO word_cards (room_id, word, color, revealed, mime_view) VALUES (?, ?, ?, ?, ?)`, card3.RoomID, card3.Word, card3.Color, card3.Revealed, card3.Mime)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Before commit, count should not reflect changes if using a transaction context
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, count) // Should still be 1 if not committed
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// After commit, count should reflect changes
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 3, count)
|
||||||
|
|
||||||
|
// Test transaction rollback
|
||||||
|
tx2, err := db.BeginTxx(ctx, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
card4 := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "date",
|
||||||
|
Color: models.WordColorWhite,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
_, err = tx2.Exec(`INSERT INTO word_cards (room_id, word, color, revealed, mime_view) VALUES (?, ?, ?, ?, ?)`, card4.RoomID, card4.Word, card4.Color, card4.Revealed, card4.Mime)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = tx2.Rollback()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// After rollback, count should not reflect changes
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 3, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func TestWordCardsRepo_GetByWordAndRoomID(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_3"
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
card := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "gamma",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
err = repo.WordCardsCreate(ctx, card)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
retrievedCard, err := repo.WordCardGetByWordAndRoomID(ctx, "gamma", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, retrievedCard)
|
||||||
|
assert.Equal(t, "gamma", retrievedCard.Word)
|
||||||
|
assert.Equal(t, roomID, retrievedCard.RoomID)
|
||||||
|
|
||||||
|
// Test non-existent card
|
||||||
|
_, err = repo.WordCardGetByWordAndRoomID(ctx, "non_existent", roomID)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordCardsRepo_Reveal(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_4"
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
card := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "delta",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
err = repo.WordCardsCreate(ctx, card)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify initial state
|
||||||
|
var revealed bool
|
||||||
|
err = db.Get(&revealed, "SELECT revealed FROM word_cards WHERE word = ? AND room_id = ?", "delta", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, revealed)
|
||||||
|
|
||||||
|
// Reveal the card
|
||||||
|
err = repo.WordCardReveal(ctx, "delta", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify revealed state
|
||||||
|
err = db.Get(&revealed, "SELECT revealed FROM word_cards WHERE word = ? AND room_id = ?", "delta", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, revealed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordCardsRepo_RevealAll(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_5"
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
cardsToInsert := []*models.WordCard{
|
||||||
|
{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "echo",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RoomID: roomID,
|
||||||
|
Color: models.WordColorBlue,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, card := range cardsToInsert {
|
||||||
|
err = repo.WordCardsCreate(ctx, card)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify initial state
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ? AND revealed = FALSE", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, count)
|
||||||
|
|
||||||
|
// Reveal all cards
|
||||||
|
err = repo.WordCardsRevealAll(ctx, roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify all cards are revealed
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ? AND revealed = FALSE", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordCardsRepo_DeleteByRoomID(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_6"
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
cardsToInsert := []*models.WordCard{
|
||||||
|
{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "golf",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "hotel",
|
||||||
|
Color: models.WordColorBlue,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, card := range cardsToInsert {
|
||||||
|
err = repo.WordCardsCreate(ctx, card)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify initial state
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, count)
|
||||||
|
|
||||||
|
// Delete cards by room ID
|
||||||
|
err = repo.WordCardsDeleteByRoomID(ctx, roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify cards are deleted
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordCardsRepo_CascadeDeleteRoom(t *testing.T) {
|
||||||
|
// Setup temporary file-based SQLite database for this test
|
||||||
|
tempFile, err := os.CreateTemp("", "test_db_*.db")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
tempFile.Close()
|
||||||
|
defer os.Remove(tempFile.Name())
|
||||||
|
|
||||||
|
db, err := sqlx.Connect("sqlite3", tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Enable foreign key constraints
|
||||||
|
_, err = db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Apply schema
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
creator_name TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS word_cards (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT NOT NULL,
|
||||||
|
word TEXT NOT NULL,
|
||||||
|
color TEXT NOT NULL DEFAULT '',
|
||||||
|
revealed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
mime_view BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
roomID := "test_room_7"
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name) VALUES (?, ?, ?)`, roomID, time.Now(), "test_creator")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
card := &models.WordCard{
|
||||||
|
RoomID: roomID,
|
||||||
|
Word: "india",
|
||||||
|
Color: models.WordColorRed,
|
||||||
|
Revealed: false,
|
||||||
|
Mime: false,
|
||||||
|
}
|
||||||
|
err = repo.WordCardsCreate(ctx, card)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, count)
|
||||||
|
|
||||||
|
_, err = db.Exec(`DELETE FROM rooms WHERE id = ?`, roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM word_cards WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user