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()) | ||||
| 		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.IsOver = false | ||||
| 	fi.Room.TeamTurn = "blue" | ||||
| @@ -174,10 +189,42 @@ func HandleStartGame(w http.ResponseWriter, r *http.Request) { | ||||
| 		Action:     models.ActionTypeGameStarted, | ||||
| 	} | ||||
| 	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()) | ||||
| 		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 | ||||
| 	if fi.State.Role == "mime" { | ||||
| 		fi.Room.MimeView() | ||||
|   | ||||
| @@ -17,6 +17,7 @@ type AllRepos interface { | ||||
| 	PlayersRepo | ||||
| 	SessionsRepo | ||||
| 	WordCardsRepo | ||||
| 	InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) | ||||
| } | ||||
|  | ||||
| type RepoProvider struct { | ||||
| @@ -95,3 +96,11 @@ func getDB(ctx context.Context, db *sqlx.DB) sqlx.ExtContext { | ||||
| 	} | ||||
| 	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
	 Grail Finder
					Grail Finder