241 lines
5.4 KiB
Go
241 lines
5.4 KiB
Go
package items
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"dk/internal/database"
|
|
"zombiezen.com/go/sqlite"
|
|
)
|
|
|
|
// Item represents an item in the database
|
|
type Item struct {
|
|
ID int `json:"id"`
|
|
Type int `json:"type"`
|
|
Name string `json:"name"`
|
|
Value int `json:"value"`
|
|
Att int `json:"att"`
|
|
Special string `json:"special"`
|
|
|
|
db *database.DB
|
|
}
|
|
|
|
// ItemType constants for item types
|
|
const (
|
|
TypeWeapon = 1
|
|
TypeArmor = 2
|
|
TypeShield = 3
|
|
)
|
|
|
|
// Find retrieves an item by ID
|
|
func Find(db *database.DB, id int) (*Item, error) {
|
|
item := &Item{db: db}
|
|
|
|
query := "SELECT id, type, name, value, att, special FROM items WHERE id = ?"
|
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
|
item.ID = stmt.ColumnInt(0)
|
|
item.Type = stmt.ColumnInt(1)
|
|
item.Name = stmt.ColumnText(2)
|
|
item.Value = stmt.ColumnInt(3)
|
|
item.Att = stmt.ColumnInt(4)
|
|
item.Special = stmt.ColumnText(5)
|
|
return nil
|
|
}, id)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to find item: %w", err)
|
|
}
|
|
|
|
if item.ID == 0 {
|
|
return nil, fmt.Errorf("item with ID %d not found", id)
|
|
}
|
|
|
|
return item, nil
|
|
}
|
|
|
|
// All retrieves all items
|
|
func All(db *database.DB) ([]*Item, error) {
|
|
var items []*Item
|
|
|
|
query := "SELECT id, type, name, value, att, special FROM items ORDER BY id"
|
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
|
item := &Item{
|
|
ID: stmt.ColumnInt(0),
|
|
Type: stmt.ColumnInt(1),
|
|
Name: stmt.ColumnText(2),
|
|
Value: stmt.ColumnInt(3),
|
|
Att: stmt.ColumnInt(4),
|
|
Special: stmt.ColumnText(5),
|
|
db: db,
|
|
}
|
|
items = append(items, item)
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to retrieve all items: %w", err)
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
// ByType retrieves items by type
|
|
func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
|
var items []*Item
|
|
|
|
query := "SELECT id, type, name, value, att, special FROM items WHERE type = ? ORDER BY id"
|
|
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
|
item := &Item{
|
|
ID: stmt.ColumnInt(0),
|
|
Type: stmt.ColumnInt(1),
|
|
Name: stmt.ColumnText(2),
|
|
Value: stmt.ColumnInt(3),
|
|
Att: stmt.ColumnInt(4),
|
|
Special: stmt.ColumnText(5),
|
|
db: db,
|
|
}
|
|
items = append(items, item)
|
|
return nil
|
|
}, itemType)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to retrieve items by type: %w", err)
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
// Builder provides a fluent interface for creating items
|
|
type Builder struct {
|
|
item *Item
|
|
db *database.DB
|
|
}
|
|
|
|
// NewBuilder creates a new item builder
|
|
func NewBuilder(db *database.DB) *Builder {
|
|
return &Builder{
|
|
item: &Item{db: db},
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// WithType sets the item type
|
|
func (b *Builder) WithType(itemType int) *Builder {
|
|
b.item.Type = itemType
|
|
return b
|
|
}
|
|
|
|
// WithName sets the item name
|
|
func (b *Builder) WithName(name string) *Builder {
|
|
b.item.Name = name
|
|
return b
|
|
}
|
|
|
|
// WithValue sets the item value
|
|
func (b *Builder) WithValue(value int) *Builder {
|
|
b.item.Value = value
|
|
return b
|
|
}
|
|
|
|
// WithAtt sets the item attack/defense value
|
|
func (b *Builder) WithAtt(att int) *Builder {
|
|
b.item.Att = att
|
|
return b
|
|
}
|
|
|
|
// WithSpecial sets the item special attributes
|
|
func (b *Builder) WithSpecial(special string) *Builder {
|
|
b.item.Special = special
|
|
return b
|
|
}
|
|
|
|
// Create saves the item to the database and returns it
|
|
func (b *Builder) Create() (*Item, error) {
|
|
// Use a transaction to ensure we can get the ID
|
|
var item *Item
|
|
err := b.db.Transaction(func(tx *database.Tx) error {
|
|
query := `INSERT INTO items (type, name, value, att, special)
|
|
VALUES (?, ?, ?, ?, ?)`
|
|
|
|
if err := tx.Exec(query, b.item.Type, b.item.Name, b.item.Value, b.item.Att, b.item.Special); err != nil {
|
|
return fmt.Errorf("failed to insert item: %w", err)
|
|
}
|
|
|
|
// Get the last inserted ID within the same transaction
|
|
var lastID int
|
|
err := tx.Query("SELECT last_insert_rowid()", func(stmt *sqlite.Stmt) error {
|
|
lastID = stmt.ColumnInt(0)
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get last insert ID: %w", err)
|
|
}
|
|
|
|
// Create the item with the ID
|
|
item = &Item{
|
|
ID: lastID,
|
|
Type: b.item.Type,
|
|
Name: b.item.Name,
|
|
Value: b.item.Value,
|
|
Att: b.item.Att,
|
|
Special: b.item.Special,
|
|
db: b.db,
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create item: %w", err)
|
|
}
|
|
|
|
return item, nil
|
|
}
|
|
|
|
// Save updates an existing item in the database
|
|
func (i *Item) Save() error {
|
|
if i.ID == 0 {
|
|
return fmt.Errorf("cannot save item without ID")
|
|
}
|
|
|
|
query := `UPDATE items SET type = ?, name = ?, value = ?, att = ?, special = ? WHERE id = ?`
|
|
return i.db.Exec(query, i.Type, i.Name, i.Value, i.Att, i.Special, i.ID)
|
|
}
|
|
|
|
// Delete removes the item from the database
|
|
func (i *Item) Delete() error {
|
|
if i.ID == 0 {
|
|
return fmt.Errorf("cannot delete item without ID")
|
|
}
|
|
|
|
query := "DELETE FROM items WHERE id = ?"
|
|
return i.db.Exec(query, i.ID)
|
|
}
|
|
|
|
// IsWeapon returns true if the item is a weapon
|
|
func (i *Item) IsWeapon() bool {
|
|
return i.Type == TypeWeapon
|
|
}
|
|
|
|
// IsArmor returns true if the item is armor
|
|
func (i *Item) IsArmor() bool {
|
|
return i.Type == TypeArmor
|
|
}
|
|
|
|
// IsShield returns true if the item is a shield
|
|
func (i *Item) IsShield() bool {
|
|
return i.Type == TypeShield
|
|
}
|
|
|
|
// TypeName returns the string representation of the item type
|
|
func (i *Item) TypeName() string {
|
|
switch i.Type {
|
|
case TypeWeapon:
|
|
return "Weapon"
|
|
case TypeArmor:
|
|
return "Armor"
|
|
case TypeShield:
|
|
return "Shield"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
} |