Implement collections tests and fix database usage
This commit is contained in:
parent
9fd69fba38
commit
f9fdef9466
1242
internal/collections/collections_test.go
Normal file
1242
internal/collections/collections_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,31 +23,20 @@ func NewDatabaseCollectionManager(db *database.DB) *DatabaseCollectionManager {
|
|||||||
func (dcm *DatabaseCollectionManager) LoadCollections(ctx context.Context) ([]CollectionData, error) {
|
func (dcm *DatabaseCollectionManager) LoadCollections(ctx context.Context) ([]CollectionData, error) {
|
||||||
query := "SELECT `id`, `collection_name`, `collection_category`, `level` FROM `collections`"
|
query := "SELECT `id`, `collection_name`, `collection_category`, `level` FROM `collections`"
|
||||||
|
|
||||||
rows, err := dcm.db.QueryContext(ctx, query)
|
var collections []CollectionData
|
||||||
|
err := dcm.db.Query(query, func(row *database.Row) error {
|
||||||
|
var collection CollectionData
|
||||||
|
collection.ID = int32(row.Int(0))
|
||||||
|
collection.Name = row.Text(1)
|
||||||
|
collection.Category = row.Text(2)
|
||||||
|
collection.Level = int8(row.Int(3))
|
||||||
|
collections = append(collections, collection)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to query collections: %w", err)
|
return nil, fmt.Errorf("failed to query collections: %w", err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var collections []CollectionData
|
|
||||||
for rows.Next() {
|
|
||||||
var collection CollectionData
|
|
||||||
err := rows.Scan(
|
|
||||||
&collection.ID,
|
|
||||||
&collection.Name,
|
|
||||||
&collection.Category,
|
|
||||||
&collection.Level,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan collection row: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
collections = append(collections, collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, fmt.Errorf("error iterating collection rows: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return collections, nil
|
return collections, nil
|
||||||
}
|
}
|
||||||
@ -59,30 +48,19 @@ func (dcm *DatabaseCollectionManager) LoadCollectionItems(ctx context.Context, c
|
|||||||
WHERE collection_id = ?
|
WHERE collection_id = ?
|
||||||
ORDER BY item_index ASC`
|
ORDER BY item_index ASC`
|
||||||
|
|
||||||
rows, err := dcm.db.QueryContext(ctx, query, collectionID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to query collection items for collection %d: %w", collectionID, err)
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var items []CollectionItem
|
var items []CollectionItem
|
||||||
for rows.Next() {
|
err := dcm.db.Query(query, func(row *database.Row) error {
|
||||||
var item CollectionItem
|
var item CollectionItem
|
||||||
err := rows.Scan(
|
item.ItemID = int32(row.Int(0))
|
||||||
&item.ItemID,
|
item.Index = int8(row.Int(1))
|
||||||
&item.Index,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan collection item row: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Items start as not found
|
// Items start as not found
|
||||||
item.Found = ItemNotFound
|
item.Found = ItemNotFound
|
||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
}
|
return nil
|
||||||
|
}, collectionID)
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error iterating collection item rows: %w", err)
|
return nil, fmt.Errorf("failed to query collection items for collection %d: %w", collectionID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items, nil
|
return items, nil
|
||||||
@ -94,31 +72,20 @@ func (dcm *DatabaseCollectionManager) LoadCollectionRewards(ctx context.Context,
|
|||||||
FROM collection_rewards
|
FROM collection_rewards
|
||||||
WHERE collection_id = ?`
|
WHERE collection_id = ?`
|
||||||
|
|
||||||
rows, err := dcm.db.QueryContext(ctx, query, collectionID)
|
var rewards []CollectionRewardData
|
||||||
|
err := dcm.db.Query(query, func(row *database.Row) error {
|
||||||
|
var reward CollectionRewardData
|
||||||
|
reward.CollectionID = int32(row.Int(0))
|
||||||
|
reward.RewardType = row.Text(1)
|
||||||
|
reward.RewardValue = row.Text(2)
|
||||||
|
reward.Quantity = int8(row.Int(3))
|
||||||
|
rewards = append(rewards, reward)
|
||||||
|
return nil
|
||||||
|
}, collectionID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to query collection rewards for collection %d: %w", collectionID, err)
|
return nil, fmt.Errorf("failed to query collection rewards for collection %d: %w", collectionID, err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var rewards []CollectionRewardData
|
|
||||||
for rows.Next() {
|
|
||||||
var reward CollectionRewardData
|
|
||||||
err := rows.Scan(
|
|
||||||
&reward.CollectionID,
|
|
||||||
&reward.RewardType,
|
|
||||||
&reward.RewardValue,
|
|
||||||
&reward.Quantity,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan collection reward row: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rewards = append(rewards, reward)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, fmt.Errorf("error iterating collection reward rows: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return rewards, nil
|
return rewards, nil
|
||||||
}
|
}
|
||||||
@ -129,32 +96,19 @@ func (dcm *DatabaseCollectionManager) LoadPlayerCollections(ctx context.Context,
|
|||||||
FROM character_collections
|
FROM character_collections
|
||||||
WHERE char_id = ?`
|
WHERE char_id = ?`
|
||||||
|
|
||||||
rows, err := dcm.db.QueryContext(ctx, query, characterID)
|
var collections []PlayerCollectionData
|
||||||
|
err := dcm.db.Query(query, func(row *database.Row) error {
|
||||||
|
var collection PlayerCollectionData
|
||||||
|
collection.CharacterID = int32(row.Int(0))
|
||||||
|
collection.CollectionID = int32(row.Int(1))
|
||||||
|
collection.Completed = row.Bool(2)
|
||||||
|
collections = append(collections, collection)
|
||||||
|
return nil
|
||||||
|
}, characterID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to query player collections for character %d: %w", characterID, err)
|
return nil, fmt.Errorf("failed to query player collections for character %d: %w", characterID, err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var collections []PlayerCollectionData
|
|
||||||
for rows.Next() {
|
|
||||||
var collection PlayerCollectionData
|
|
||||||
var completed int
|
|
||||||
err := rows.Scan(
|
|
||||||
&collection.CharacterID,
|
|
||||||
&collection.CollectionID,
|
|
||||||
&completed,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan player collection row: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
collection.Completed = completed == 1
|
|
||||||
collections = append(collections, collection)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, fmt.Errorf("error iterating player collection rows: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return collections, nil
|
return collections, nil
|
||||||
}
|
}
|
||||||
@ -165,26 +119,16 @@ func (dcm *DatabaseCollectionManager) LoadPlayerCollectionItems(ctx context.Cont
|
|||||||
FROM character_collection_items
|
FROM character_collection_items
|
||||||
WHERE char_id = ? AND collection_id = ?`
|
WHERE char_id = ? AND collection_id = ?`
|
||||||
|
|
||||||
rows, err := dcm.db.QueryContext(ctx, query, characterID, collectionID)
|
var itemIDs []int32
|
||||||
|
err := dcm.db.Query(query, func(row *database.Row) error {
|
||||||
|
itemID := int32(row.Int(0))
|
||||||
|
itemIDs = append(itemIDs, itemID)
|
||||||
|
return nil
|
||||||
|
}, characterID, collectionID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to query player collection items for character %d, collection %d: %w", characterID, collectionID, err)
|
return nil, fmt.Errorf("failed to query player collection items for character %d, collection %d: %w", characterID, collectionID, err)
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var itemIDs []int32
|
|
||||||
for rows.Next() {
|
|
||||||
var itemID int32
|
|
||||||
err := rows.Scan(&itemID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to scan player collection item row: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
itemIDs = append(itemIDs, itemID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, fmt.Errorf("error iterating player collection item rows: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemIDs, nil
|
return itemIDs, nil
|
||||||
}
|
}
|
||||||
@ -201,7 +145,7 @@ func (dcm *DatabaseCollectionManager) SavePlayerCollection(ctx context.Context,
|
|||||||
ON CONFLICT(char_id, collection_id)
|
ON CONFLICT(char_id, collection_id)
|
||||||
DO UPDATE SET completed = ?`
|
DO UPDATE SET completed = ?`
|
||||||
|
|
||||||
_, err := dcm.db.ExecContext(ctx, query, characterID, collectionID, completedInt, completedInt)
|
err := dcm.db.Exec(query, characterID, collectionID, completedInt, completedInt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to save player collection for character %d, collection %d: %w", characterID, collectionID, err)
|
return fmt.Errorf("failed to save player collection for character %d, collection %d: %w", characterID, collectionID, err)
|
||||||
}
|
}
|
||||||
@ -214,7 +158,7 @@ func (dcm *DatabaseCollectionManager) SavePlayerCollectionItem(ctx context.Conte
|
|||||||
query := `INSERT OR IGNORE INTO character_collection_items (char_id, collection_id, collection_item_id)
|
query := `INSERT OR IGNORE INTO character_collection_items (char_id, collection_id, collection_item_id)
|
||||||
VALUES (?, ?, ?)`
|
VALUES (?, ?, ?)`
|
||||||
|
|
||||||
_, err := dcm.db.ExecContext(ctx, query, characterID, collectionID, itemID)
|
err := dcm.db.Exec(query, characterID, collectionID, itemID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to save player collection item for character %d, collection %d, item %d: %w", characterID, collectionID, itemID, err)
|
return fmt.Errorf("failed to save player collection item for character %d, collection %d, item %d: %w", characterID, collectionID, itemID, err)
|
||||||
}
|
}
|
||||||
@ -229,37 +173,34 @@ func (dcm *DatabaseCollectionManager) SavePlayerCollections(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use a transaction for atomic updates
|
// Use a transaction for atomic updates
|
||||||
tx, err := dcm.db.BeginTx(ctx, nil)
|
err := dcm.db.Transaction(func(db *database.DB) error {
|
||||||
|
for _, collection := range collections {
|
||||||
|
if !collection.GetSaveNeeded() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save collection completion status
|
||||||
|
if err := dcm.savePlayerCollectionInTx(db, characterID, collection); err != nil {
|
||||||
|
return fmt.Errorf("failed to save collection %d: %w", collection.GetID(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save found items
|
||||||
|
if err := dcm.savePlayerCollectionItemsInTx(db, characterID, collection); err != nil {
|
||||||
|
return fmt.Errorf("failed to save collection items for collection %d: %w", collection.GetID(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to begin transaction: %w", err)
|
return fmt.Errorf("transaction failed: %w", err)
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
for _, collection := range collections {
|
|
||||||
if !collection.GetSaveNeeded() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save collection completion status
|
|
||||||
if err := dcm.savePlayerCollectionTx(ctx, tx, characterID, collection); err != nil {
|
|
||||||
return fmt.Errorf("failed to save collection %d: %w", collection.GetID(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save found items
|
|
||||||
if err := dcm.savePlayerCollectionItemsTx(ctx, tx, characterID, collection); err != nil {
|
|
||||||
return fmt.Errorf("failed to save collection items for collection %d: %w", collection.GetID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
|
||||||
return fmt.Errorf("failed to commit transaction: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// savePlayerCollectionTx saves a single collection within a transaction
|
// savePlayerCollectionInTx saves a single collection within a transaction
|
||||||
func (dcm *DatabaseCollectionManager) savePlayerCollectionTx(ctx context.Context, tx database.Tx, characterID int32, collection *Collection) error {
|
func (dcm *DatabaseCollectionManager) savePlayerCollectionInTx(db *database.DB, characterID int32, collection *Collection) error {
|
||||||
completedInt := 0
|
completedInt := 0
|
||||||
if collection.GetCompleted() {
|
if collection.GetCompleted() {
|
||||||
completedInt = 1
|
completedInt = 1
|
||||||
@ -270,12 +211,12 @@ func (dcm *DatabaseCollectionManager) savePlayerCollectionTx(ctx context.Context
|
|||||||
ON CONFLICT(char_id, collection_id)
|
ON CONFLICT(char_id, collection_id)
|
||||||
DO UPDATE SET completed = ?`
|
DO UPDATE SET completed = ?`
|
||||||
|
|
||||||
_, err := tx.ExecContext(ctx, query, characterID, collection.GetID(), completedInt, completedInt)
|
err := db.Exec(query, characterID, collection.GetID(), completedInt, completedInt)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// savePlayerCollectionItemsTx saves collection items within a transaction
|
// savePlayerCollectionItemsInTx saves collection items within a transaction
|
||||||
func (dcm *DatabaseCollectionManager) savePlayerCollectionItemsTx(ctx context.Context, tx database.Tx, characterID int32, collection *Collection) error {
|
func (dcm *DatabaseCollectionManager) savePlayerCollectionItemsInTx(db *database.DB, characterID int32, collection *Collection) error {
|
||||||
items := collection.GetCollectionItems()
|
items := collection.GetCollectionItems()
|
||||||
|
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
@ -283,7 +224,7 @@ func (dcm *DatabaseCollectionManager) savePlayerCollectionItemsTx(ctx context.Co
|
|||||||
query := `INSERT OR IGNORE INTO character_collection_items (char_id, collection_id, collection_item_id)
|
query := `INSERT OR IGNORE INTO character_collection_items (char_id, collection_id, collection_item_id)
|
||||||
VALUES (?, ?, ?)`
|
VALUES (?, ?, ?)`
|
||||||
|
|
||||||
_, err := tx.ExecContext(ctx, query, characterID, collection.GetID(), item.ItemID)
|
err := db.Exec(query, characterID, collection.GetID(), item.ItemID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to save item %d: %w", item.ItemID, err)
|
return fmt.Errorf("failed to save item %d: %w", item.ItemID, err)
|
||||||
}
|
}
|
||||||
@ -339,7 +280,7 @@ func (dcm *DatabaseCollectionManager) EnsureCollectionTables(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, query := range queries {
|
for i, query := range queries {
|
||||||
_, err := dcm.db.ExecContext(ctx, query)
|
err := dcm.db.Exec(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create collection table %d: %w", i+1, err)
|
return fmt.Errorf("failed to create collection table %d: %w", i+1, err)
|
||||||
}
|
}
|
||||||
@ -357,7 +298,7 @@ func (dcm *DatabaseCollectionManager) EnsureCollectionTables(ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, query := range indexes {
|
for i, query := range indexes {
|
||||||
_, err := dcm.db.ExecContext(ctx, query)
|
err := dcm.db.Exec(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create collection index %d: %w", i+1, err)
|
return fmt.Errorf("failed to create collection index %d: %w", i+1, err)
|
||||||
}
|
}
|
||||||
@ -370,68 +311,78 @@ func (dcm *DatabaseCollectionManager) EnsureCollectionTables(ctx context.Context
|
|||||||
func (dcm *DatabaseCollectionManager) GetCollectionCount(ctx context.Context) (int, error) {
|
func (dcm *DatabaseCollectionManager) GetCollectionCount(ctx context.Context) (int, error) {
|
||||||
query := "SELECT COUNT(*) FROM collections"
|
query := "SELECT COUNT(*) FROM collections"
|
||||||
|
|
||||||
var count int
|
row, err := dcm.db.QueryRow(query)
|
||||||
err := dcm.db.QueryRowContext(ctx, query).Scan(&count)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to get collection count: %w", err)
|
return 0, fmt.Errorf("failed to get collection count: %w", err)
|
||||||
}
|
}
|
||||||
|
defer row.Close()
|
||||||
|
|
||||||
return count, nil
|
if row == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return row.Int(0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayerCollectionCount returns the number of collections a player has
|
// GetPlayerCollectionCount returns the number of collections a player has
|
||||||
func (dcm *DatabaseCollectionManager) GetPlayerCollectionCount(ctx context.Context, characterID int32) (int, error) {
|
func (dcm *DatabaseCollectionManager) GetPlayerCollectionCount(ctx context.Context, characterID int32) (int, error) {
|
||||||
query := "SELECT COUNT(*) FROM character_collections WHERE char_id = ?"
|
query := "SELECT COUNT(*) FROM character_collections WHERE char_id = ?"
|
||||||
|
|
||||||
var count int
|
row, err := dcm.db.QueryRow(query, characterID)
|
||||||
err := dcm.db.QueryRowContext(ctx, query, characterID).Scan(&count)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to get player collection count for character %d: %w", characterID, err)
|
return 0, fmt.Errorf("failed to get player collection count for character %d: %w", characterID, err)
|
||||||
}
|
}
|
||||||
|
defer row.Close()
|
||||||
|
|
||||||
return count, nil
|
if row == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return row.Int(0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCompletedCollectionCount returns the number of completed collections for a player
|
// GetCompletedCollectionCount returns the number of completed collections for a player
|
||||||
func (dcm *DatabaseCollectionManager) GetCompletedCollectionCount(ctx context.Context, characterID int32) (int, error) {
|
func (dcm *DatabaseCollectionManager) GetCompletedCollectionCount(ctx context.Context, characterID int32) (int, error) {
|
||||||
query := "SELECT COUNT(*) FROM character_collections WHERE char_id = ? AND completed = 1"
|
query := "SELECT COUNT(*) FROM character_collections WHERE char_id = ? AND completed = 1"
|
||||||
|
|
||||||
var count int
|
row, err := dcm.db.QueryRow(query, characterID)
|
||||||
err := dcm.db.QueryRowContext(ctx, query, characterID).Scan(&count)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("failed to get completed collection count for character %d: %w", characterID, err)
|
return 0, fmt.Errorf("failed to get completed collection count for character %d: %w", characterID, err)
|
||||||
}
|
}
|
||||||
|
defer row.Close()
|
||||||
|
|
||||||
return count, nil
|
if row == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return row.Int(0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePlayerCollection removes a player's collection progress
|
// DeletePlayerCollection removes a player's collection progress
|
||||||
func (dcm *DatabaseCollectionManager) DeletePlayerCollection(ctx context.Context, characterID, collectionID int32) error {
|
func (dcm *DatabaseCollectionManager) DeletePlayerCollection(ctx context.Context, characterID, collectionID int32) error {
|
||||||
// Use a transaction to ensure both tables are updated atomically
|
// Use a transaction to ensure both tables are updated atomically
|
||||||
tx, err := dcm.db.BeginTx(ctx, nil)
|
err := dcm.db.Transaction(func(db *database.DB) error {
|
||||||
if err != nil {
|
// Delete collection items first due to foreign key constraint
|
||||||
return fmt.Errorf("failed to begin transaction: %w", err)
|
err := db.Exec(
|
||||||
}
|
"DELETE FROM character_collection_items WHERE char_id = ? AND collection_id = ?",
|
||||||
defer tx.Rollback()
|
characterID, collectionID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to delete player collection items: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Delete collection items first due to foreign key constraint
|
// Delete collection
|
||||||
_, err = tx.ExecContext(ctx,
|
err = db.Exec(
|
||||||
"DELETE FROM character_collection_items WHERE char_id = ? AND collection_id = ?",
|
"DELETE FROM character_collections WHERE char_id = ? AND collection_id = ?",
|
||||||
characterID, collectionID)
|
characterID, collectionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to delete player collection items: %w", err)
|
return fmt.Errorf("failed to delete player collection: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete collection
|
return nil
|
||||||
_, err = tx.ExecContext(ctx,
|
})
|
||||||
"DELETE FROM character_collections WHERE char_id = ? AND collection_id = ?",
|
|
||||||
characterID, collectionID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to delete player collection: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tx.Commit(); err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to commit transaction: %w", err)
|
return fmt.Errorf("transaction failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -442,50 +393,78 @@ func (dcm *DatabaseCollectionManager) GetCollectionStatistics(ctx context.Contex
|
|||||||
var stats CollectionStatistics
|
var stats CollectionStatistics
|
||||||
|
|
||||||
// Total collections
|
// Total collections
|
||||||
err := dcm.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM collections").Scan(&stats.TotalCollections)
|
row, err := dcm.db.QueryRow("SELECT COUNT(*) FROM collections")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get total collections: %w", err)
|
return stats, fmt.Errorf("failed to get total collections: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.TotalCollections = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Total collection items
|
// Total collection items
|
||||||
err = dcm.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM collection_details").Scan(&stats.TotalItems)
|
row, err = dcm.db.QueryRow("SELECT COUNT(*) FROM collection_details")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get total items: %w", err)
|
return stats, fmt.Errorf("failed to get total items: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.TotalItems = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Players with collections
|
// Players with collections
|
||||||
err = dcm.db.QueryRowContext(ctx, "SELECT COUNT(DISTINCT char_id) FROM character_collections").Scan(&stats.PlayersWithCollections)
|
row, err = dcm.db.QueryRow("SELECT COUNT(DISTINCT char_id) FROM character_collections")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get players with collections: %w", err)
|
return stats, fmt.Errorf("failed to get players with collections: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.PlayersWithCollections = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Completed collections across all players
|
// Completed collections across all players
|
||||||
err = dcm.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM character_collections WHERE completed = 1").Scan(&stats.CompletedCollections)
|
row, err = dcm.db.QueryRow("SELECT COUNT(*) FROM character_collections WHERE completed = 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get completed collections: %w", err)
|
return stats, fmt.Errorf("failed to get completed collections: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.CompletedCollections = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Active collections (incomplete with at least one item found) across all players
|
// Active collections (incomplete with at least one item found) across all players
|
||||||
query := `SELECT COUNT(DISTINCT cc.char_id, cc.collection_id)
|
query := `SELECT COUNT(DISTINCT cc.char_id || '-' || cc.collection_id)
|
||||||
FROM character_collections cc
|
FROM character_collections cc
|
||||||
JOIN character_collection_items cci ON cc.char_id = cci.char_id AND cc.collection_id = cci.collection_id
|
JOIN character_collection_items cci ON cc.char_id = cci.char_id AND cc.collection_id = cci.collection_id
|
||||||
WHERE cc.completed = 0`
|
WHERE cc.completed = 0`
|
||||||
err = dcm.db.QueryRowContext(ctx, query).Scan(&stats.ActiveCollections)
|
row, err = dcm.db.QueryRow(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get active collections: %w", err)
|
return stats, fmt.Errorf("failed to get active collections: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.ActiveCollections = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Found items across all players
|
// Found items across all players
|
||||||
err = dcm.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM character_collection_items").Scan(&stats.FoundItems)
|
row, err = dcm.db.QueryRow("SELECT COUNT(*) FROM character_collection_items")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get found items: %w", err)
|
return stats, fmt.Errorf("failed to get found items: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.FoundItems = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// Total rewards
|
// Total rewards
|
||||||
err = dcm.db.QueryRowContext(ctx, "SELECT COUNT(*) FROM collection_rewards").Scan(&stats.TotalRewards)
|
row, err = dcm.db.QueryRow("SELECT COUNT(*) FROM collection_rewards")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stats, fmt.Errorf("failed to get total rewards: %w", err)
|
return stats, fmt.Errorf("failed to get total rewards: %w", err)
|
||||||
}
|
}
|
||||||
|
if row != nil {
|
||||||
|
stats.TotalRewards = row.Int(0)
|
||||||
|
row.Close()
|
||||||
|
}
|
||||||
|
|
||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user