fully migrate db ops to singleton pattern
This commit is contained in:
parent
b1f436585e
commit
820bc87418
@ -16,16 +16,14 @@ type Babble struct {
|
||||
Posted int64 `json:"posted"`
|
||||
Author string `json:"author"`
|
||||
Babble string `json:"babble"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// Find retrieves a babble message by ID
|
||||
func Find(db *database.DB, id int) (*Babble, error) {
|
||||
babble := &Babble{db: db}
|
||||
func Find(id int) (*Babble, error) {
|
||||
babble := &Babble{}
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble.ID = stmt.ColumnInt(0)
|
||||
babble.Posted = stmt.ColumnInt64(1)
|
||||
babble.Author = stmt.ColumnText(2)
|
||||
@ -45,17 +43,16 @@ func Find(db *database.DB, id int) (*Babble, error) {
|
||||
}
|
||||
|
||||
// All retrieves all babble messages ordered by posted time (newest first)
|
||||
func All(db *database.DB) ([]*Babble, error) {
|
||||
func All() ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -69,17 +66,16 @@ func All(db *database.DB) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// ByAuthor retrieves babble messages by a specific author
|
||||
func ByAuthor(db *database.DB, author string) ([]*Babble, error) {
|
||||
func ByAuthor(author string) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE LOWER(author) = LOWER(?) ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -93,17 +89,16 @@ func ByAuthor(db *database.DB, author string) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// Recent retrieves the most recent babble messages (limited by count)
|
||||
func Recent(db *database.DB, limit int) ([]*Babble, error) {
|
||||
func Recent(limit int) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble ORDER BY posted DESC, id DESC LIMIT ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -117,17 +112,16 @@ func Recent(db *database.DB, limit int) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// Since retrieves babble messages since a specific timestamp
|
||||
func Since(db *database.DB, since int64) ([]*Babble, error) {
|
||||
func Since(since int64) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE posted >= ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -141,17 +135,16 @@ func Since(db *database.DB, since int64) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// Between retrieves babble messages between two timestamps (inclusive)
|
||||
func Between(db *database.DB, start, end int64) ([]*Babble, error) {
|
||||
func Between(start, end int64) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE posted >= ? AND posted <= ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -165,19 +158,18 @@ func Between(db *database.DB, start, end int64) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// Search retrieves babble messages containing the search term (case-insensitive)
|
||||
func Search(db *database.DB, term string) ([]*Babble, error) {
|
||||
func Search(term string) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE LOWER(babble) LIKE LOWER(?) ORDER BY posted DESC, id DESC"
|
||||
searchTerm := "%" + term + "%"
|
||||
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -191,17 +183,16 @@ func Search(db *database.DB, term string) ([]*Babble, error) {
|
||||
}
|
||||
|
||||
// RecentByAuthor retrieves recent messages from a specific author
|
||||
func RecentByAuthor(db *database.DB, author string, limit int) ([]*Babble, error) {
|
||||
func RecentByAuthor(author string, limit int) ([]*Babble, error) {
|
||||
var babbles []*Babble
|
||||
|
||||
query := "SELECT id, posted, author, babble FROM babble WHERE LOWER(author) = LOWER(?) ORDER BY posted DESC, id DESC LIMIT ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
babble := &Babble{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
Author: stmt.ColumnText(2),
|
||||
Babble: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
babbles = append(babbles, babble)
|
||||
return nil
|
||||
@ -221,7 +212,7 @@ func (b *Babble) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE babble SET posted = ?, author = ?, babble = ? WHERE id = ?`
|
||||
return b.db.Exec(query, b.Posted, b.Author, b.Babble, b.ID)
|
||||
return database.Exec(query, b.Posted, b.Author, b.Babble, b.ID)
|
||||
}
|
||||
|
||||
// Delete removes the babble message from the database
|
||||
@ -230,8 +221,7 @@ func (b *Babble) Delete() error {
|
||||
return fmt.Errorf("cannot delete babble without ID")
|
||||
}
|
||||
|
||||
query := "DELETE FROM babble WHERE id = ?"
|
||||
return b.db.Exec(query, b.ID)
|
||||
return database.Exec("DELETE FROM babble WHERE id = ?", b.ID)
|
||||
}
|
||||
|
||||
// PostedTime returns the posted timestamp as a time.Time
|
||||
|
@ -12,17 +12,14 @@ import (
|
||||
// Builder provides a fluent interface for creating babble messages
|
||||
type Builder struct {
|
||||
babble *Babble
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new babble builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
babble: &Babble{
|
||||
db: db,
|
||||
Posted: time.Now().Unix(), // Default to current time
|
||||
},
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +56,7 @@ func (b *Builder) WithPostedTime(t time.Time) *Builder {
|
||||
func (b *Builder) Create() (*Babble, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var babble *Babble
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO babble (posted, author, babble)
|
||||
VALUES (?, ?, ?)`
|
||||
|
||||
|
@ -9,25 +9,22 @@ import (
|
||||
)
|
||||
|
||||
// Control represents the game control settings in the database
|
||||
// There is only ever one control record with ID 1
|
||||
type Control struct {
|
||||
ID int `json:"id"`
|
||||
WorldSize int `json:"world_size"`
|
||||
Open int `json:"open"`
|
||||
AdminEmail string `json:"admin_email"`
|
||||
Class1Name string `json:"class_1_name"`
|
||||
Class2Name string `json:"class_2_name"`
|
||||
Class3Name string `json:"class_3_name"`
|
||||
|
||||
db *database.DB
|
||||
ID int `json:"id"`
|
||||
WorldSize int `json:"world_size"`
|
||||
Open int `json:"open"`
|
||||
AdminEmail string `json:"admin_email"`
|
||||
Class1Name string `json:"class_1_name"`
|
||||
Class2Name string `json:"class_2_name"`
|
||||
Class3Name string `json:"class_3_name"`
|
||||
}
|
||||
|
||||
// Find retrieves the control record by ID (typically only ID 1 exists)
|
||||
func Find(db *database.DB, id int) (*Control, error) {
|
||||
control := &Control{db: db}
|
||||
func Find(id int) (*Control, error) {
|
||||
control := &Control{}
|
||||
|
||||
query := "SELECT id, world_size, open, admin_email, class_1_name, class_2_name, class_3_name FROM control WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
control.ID = stmt.ColumnInt(0)
|
||||
control.WorldSize = stmt.ColumnInt(1)
|
||||
control.Open = stmt.ColumnInt(2)
|
||||
@ -50,8 +47,8 @@ func Find(db *database.DB, id int) (*Control, error) {
|
||||
}
|
||||
|
||||
// Get retrieves the main control record (ID 1)
|
||||
func Get(db *database.DB) (*Control, error) {
|
||||
return Find(db, 1)
|
||||
func Get() (*Control, error) {
|
||||
return Find(1)
|
||||
}
|
||||
|
||||
// Save updates the control record in the database
|
||||
@ -61,7 +58,7 @@ func (c *Control) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE control SET world_size = ?, open = ?, admin_email = ?, class_1_name = ?, class_2_name = ?, class_3_name = ? WHERE id = ?`
|
||||
return c.db.Exec(query, c.WorldSize, c.Open, c.AdminEmail, c.Class1Name, c.Class2Name, c.Class3Name, c.ID)
|
||||
return database.Exec(query, c.WorldSize, c.Open, c.AdminEmail, c.Class1Name, c.Class2Name, c.Class3Name, c.ID)
|
||||
}
|
||||
|
||||
// IsOpen returns true if the game world is open for new players
|
||||
|
@ -11,75 +11,80 @@ import (
|
||||
|
||||
const DefaultPath = "dk.db"
|
||||
|
||||
// database wraps a SQLite connection pool with simplified methods
|
||||
type database struct {
|
||||
pool *sqlitex.Pool
|
||||
}
|
||||
// Global singleton instance
|
||||
var pool *sqlitex.Pool
|
||||
|
||||
// DB is a backward-compatible type alias
|
||||
type DB = database
|
||||
|
||||
// instance is the global singleton instance
|
||||
var instance *database
|
||||
|
||||
// Open creates a new database connection pool
|
||||
func Open(path string) (*database, error) {
|
||||
// Init initializes the global database connection pool
|
||||
func Init(path string) error {
|
||||
if path == "" {
|
||||
path = DefaultPath
|
||||
}
|
||||
|
||||
poolSize := max(runtime.GOMAXPROCS(0), 2)
|
||||
|
||||
pool, err := sqlitex.NewPool(path, sqlitex.PoolOptions{
|
||||
var err error
|
||||
pool, err = sqlitex.NewPool(path, sqlitex.PoolOptions{
|
||||
PoolSize: poolSize,
|
||||
Flags: sqlite.OpenCreate | sqlite.OpenReadWrite | sqlite.OpenWAL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open database pool: %w", err)
|
||||
return fmt.Errorf("failed to open database pool: %w", err)
|
||||
}
|
||||
|
||||
conn, err := pool.Take(context.Background())
|
||||
if err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("failed to get connection from pool: %w", err)
|
||||
return fmt.Errorf("failed to get connection from pool: %w", err)
|
||||
}
|
||||
defer pool.Put(conn)
|
||||
|
||||
if err := sqlitex.ExecuteTransient(conn, "PRAGMA journal_mode = WAL", nil); err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("failed to set WAL mode: %w", err)
|
||||
return fmt.Errorf("failed to set WAL mode: %w", err)
|
||||
}
|
||||
|
||||
if err := sqlitex.ExecuteTransient(conn, "PRAGMA synchronous = NORMAL", nil); err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("failed to set synchronous mode: %w", err)
|
||||
return fmt.Errorf("failed to set synchronous mode: %w", err)
|
||||
}
|
||||
|
||||
return &database{pool: pool}, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the database connection pool
|
||||
func (db *database) Close() error {
|
||||
return db.pool.Close()
|
||||
// Close closes the global database connection pool
|
||||
func Close() error {
|
||||
if pool == nil {
|
||||
return nil
|
||||
}
|
||||
return pool.Close()
|
||||
}
|
||||
|
||||
// GetConn gets a connection from the pool - caller must call Put when done
|
||||
func (db *database) GetConn(ctx context.Context) (*sqlite.Conn, error) {
|
||||
return db.pool.Take(ctx)
|
||||
// GetConn gets a connection from the pool - caller must call PutConn when done
|
||||
func GetConn(ctx context.Context) (*sqlite.Conn, error) {
|
||||
if pool == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
return pool.Take(ctx)
|
||||
}
|
||||
|
||||
// PutConn returns a connection to the pool
|
||||
func (db *database) PutConn(conn *sqlite.Conn) {
|
||||
db.pool.Put(conn)
|
||||
func PutConn(conn *sqlite.Conn) {
|
||||
if pool != nil {
|
||||
pool.Put(conn)
|
||||
}
|
||||
}
|
||||
|
||||
// Exec executes a SQL statement without returning results
|
||||
func (db *database) Exec(query string, args ...any) error {
|
||||
conn, err := db.pool.Take(context.Background())
|
||||
func Exec(query string, args ...any) error {
|
||||
if pool == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
|
||||
conn, err := pool.Take(context.Background())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get connection from pool: %w", err)
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
defer pool.Put(conn)
|
||||
|
||||
if len(args) == 0 {
|
||||
return sqlitex.ExecuteTransient(conn, query, nil)
|
||||
@ -91,12 +96,16 @@ func (db *database) Exec(query string, args ...any) error {
|
||||
}
|
||||
|
||||
// Query executes a SQL query and calls fn for each row
|
||||
func (db *database) Query(query string, fn func(*sqlite.Stmt) error, args ...any) error {
|
||||
conn, err := db.pool.Take(context.Background())
|
||||
func Query(query string, fn func(*sqlite.Stmt) error, args ...any) error {
|
||||
if pool == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
|
||||
conn, err := pool.Take(context.Background())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get connection from pool: %w", err)
|
||||
}
|
||||
defer db.pool.Put(conn)
|
||||
defer pool.Put(conn)
|
||||
|
||||
if len(args) == 0 {
|
||||
return sqlitex.ExecuteTransient(conn, query, &sqlitex.ExecOptions{
|
||||
@ -111,23 +120,31 @@ func (db *database) Query(query string, fn func(*sqlite.Stmt) error, args ...any
|
||||
}
|
||||
|
||||
// Begin starts a new transaction
|
||||
func (db *database) Begin() (*Tx, error) {
|
||||
conn, err := db.pool.Take(context.Background())
|
||||
func Begin() (*Tx, error) {
|
||||
if pool == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
|
||||
conn, err := pool.Take(context.Background())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get connection from pool: %w", err)
|
||||
}
|
||||
|
||||
if err := sqlitex.ExecuteTransient(conn, "BEGIN", nil); err != nil {
|
||||
db.pool.Put(conn)
|
||||
pool.Put(conn)
|
||||
return nil, fmt.Errorf("failed to begin transaction: %w", err)
|
||||
}
|
||||
|
||||
return &Tx{conn: conn, pool: db.pool}, nil
|
||||
return &Tx{conn: conn, pool: pool}, nil
|
||||
}
|
||||
|
||||
// Transaction runs a function within a transaction
|
||||
func (db *database) Transaction(fn func(*Tx) error) error {
|
||||
tx, err := db.Begin()
|
||||
func Transaction(fn func(*Tx) error) error {
|
||||
if pool == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
|
||||
tx, err := Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -182,75 +199,3 @@ func (tx *Tx) Rollback() error {
|
||||
defer tx.pool.Put(tx.conn)
|
||||
return sqlitex.ExecuteTransient(tx.conn, "ROLLBACK", nil)
|
||||
}
|
||||
|
||||
// InitializeDB initializes the global DB singleton
|
||||
func InitializeDB(path string) error {
|
||||
db, err := Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
instance = db
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDB returns the global database instance
|
||||
func GetDB() *DB {
|
||||
return instance
|
||||
}
|
||||
|
||||
// Global convenience functions that use the singleton
|
||||
|
||||
// Exec executes a SQL statement without returning results using the global DB
|
||||
func Exec(query string, args ...any) error {
|
||||
if instance == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
return instance.Exec(query, args...)
|
||||
}
|
||||
|
||||
// Query executes a SQL query and calls fn for each row using the global DB
|
||||
func Query(query string, fn func(*sqlite.Stmt) error, args ...any) error {
|
||||
if instance == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
return instance.Query(query, fn, args...)
|
||||
}
|
||||
|
||||
// Begin starts a new transaction using the global DB
|
||||
func Begin() (*Tx, error) {
|
||||
if instance == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
return instance.Begin()
|
||||
}
|
||||
|
||||
// Transaction runs a function within a transaction using the global DB
|
||||
func Transaction(fn func(*Tx) error) error {
|
||||
if instance == nil {
|
||||
return fmt.Errorf("database not initialized")
|
||||
}
|
||||
return instance.Transaction(fn)
|
||||
}
|
||||
|
||||
// GetConn gets a connection from the pool using the global DB
|
||||
func GetConn(ctx context.Context) (*sqlite.Conn, error) {
|
||||
if instance == nil {
|
||||
return nil, fmt.Errorf("database not initialized")
|
||||
}
|
||||
return instance.GetConn(ctx)
|
||||
}
|
||||
|
||||
// PutConn returns a connection to the pool using the global DB
|
||||
func PutConn(conn *sqlite.Conn) {
|
||||
if instance != nil {
|
||||
instance.PutConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the global database connection pool
|
||||
func Close() error {
|
||||
if instance == nil {
|
||||
return nil
|
||||
}
|
||||
return instance.Close()
|
||||
}
|
||||
|
@ -12,28 +12,28 @@ func TestDatabaseOperations(t *testing.T) {
|
||||
testDB := "test.db"
|
||||
defer os.Remove(testDB)
|
||||
|
||||
// Test opening database
|
||||
db, err := Open(testDB)
|
||||
// Initialize the singleton database
|
||||
err := Init(testDB)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open database: %v", err)
|
||||
t.Fatalf("Failed to initialize database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
defer Close()
|
||||
|
||||
// Test creating a simple table
|
||||
err = db.Exec("CREATE TABLE test_users (id INTEGER PRIMARY KEY, name TEXT)")
|
||||
err = Exec("CREATE TABLE test_users (id INTEGER PRIMARY KEY, name TEXT)")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create table: %v", err)
|
||||
}
|
||||
|
||||
// Test inserting data
|
||||
err = db.Exec("INSERT INTO test_users (name) VALUES (?)", "Alice")
|
||||
err = Exec("INSERT INTO test_users (name) VALUES (?)", "Alice")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert data: %v", err)
|
||||
}
|
||||
|
||||
// Test querying data
|
||||
var foundName string
|
||||
err = db.Query("SELECT name FROM test_users WHERE name = ?", func(stmt *sqlite.Stmt) error {
|
||||
err = Query("SELECT name FROM test_users WHERE name = ?", func(stmt *sqlite.Stmt) error {
|
||||
foundName = stmt.ColumnText(0)
|
||||
return nil
|
||||
}, "Alice")
|
||||
@ -47,7 +47,7 @@ func TestDatabaseOperations(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test transaction
|
||||
err = db.Transaction(func(tx *Tx) error {
|
||||
err = Transaction(func(tx *Tx) error {
|
||||
return tx.Exec("INSERT INTO test_users (name) VALUES (?)", "Bob")
|
||||
})
|
||||
|
||||
@ -57,7 +57,7 @@ func TestDatabaseOperations(t *testing.T) {
|
||||
|
||||
// Verify transaction worked
|
||||
var count int
|
||||
err = db.Query("SELECT COUNT(*) FROM test_users", func(stmt *sqlite.Stmt) error {
|
||||
err = Query("SELECT COUNT(*) FROM test_users", func(stmt *sqlite.Stmt) error {
|
||||
count = stmt.ColumnInt(0)
|
||||
return nil
|
||||
})
|
||||
|
@ -10,14 +10,12 @@ import (
|
||||
// Builder provides a fluent interface for creating drops
|
||||
type Builder struct {
|
||||
drop *Drop
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new drop builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
drop: &Drop{db: db},
|
||||
db: db,
|
||||
drop: &Drop{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +47,7 @@ func (b *Builder) WithAtt(att string) *Builder {
|
||||
func (b *Builder) Create() (*Drop, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var drop *Drop
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO drops (name, level, type, att)
|
||||
VALUES (?, ?, ?, ?)`
|
||||
|
||||
@ -74,7 +72,6 @@ func (b *Builder) Create() (*Drop, error) {
|
||||
Level: b.drop.Level,
|
||||
Type: b.drop.Type,
|
||||
Att: b.drop.Att,
|
||||
db: b.db,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -15,8 +15,6 @@ type Drop struct {
|
||||
Level int `json:"level"`
|
||||
Type int `json:"type"`
|
||||
Att string `json:"att"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// DropType constants for drop types
|
||||
@ -25,11 +23,11 @@ const (
|
||||
)
|
||||
|
||||
// Find retrieves a drop by ID
|
||||
func Find(db *database.DB, id int) (*Drop, error) {
|
||||
drop := &Drop{db: db}
|
||||
func Find(id int) (*Drop, error) {
|
||||
drop := &Drop{}
|
||||
|
||||
query := "SELECT id, name, level, type, att FROM drops WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
drop.ID = stmt.ColumnInt(0)
|
||||
drop.Name = stmt.ColumnText(1)
|
||||
drop.Level = stmt.ColumnInt(2)
|
||||
@ -50,18 +48,17 @@ func Find(db *database.DB, id int) (*Drop, error) {
|
||||
}
|
||||
|
||||
// All retrieves all drops
|
||||
func All(db *database.DB) ([]*Drop, error) {
|
||||
func All() ([]*Drop, error) {
|
||||
var drops []*Drop
|
||||
|
||||
query := "SELECT id, name, level, type, att FROM drops ORDER BY id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
drop := &Drop{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Level: stmt.ColumnInt(2),
|
||||
Type: stmt.ColumnInt(3),
|
||||
Att: stmt.ColumnText(4),
|
||||
db: db,
|
||||
}
|
||||
drops = append(drops, drop)
|
||||
return nil
|
||||
@ -75,18 +72,17 @@ func All(db *database.DB) ([]*Drop, error) {
|
||||
}
|
||||
|
||||
// ByLevel retrieves drops by minimum level requirement
|
||||
func ByLevel(db *database.DB, minLevel int) ([]*Drop, error) {
|
||||
func ByLevel(minLevel int) ([]*Drop, error) {
|
||||
var drops []*Drop
|
||||
|
||||
query := "SELECT id, name, level, type, att FROM drops WHERE level <= ? ORDER BY level, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
drop := &Drop{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Level: stmt.ColumnInt(2),
|
||||
Type: stmt.ColumnInt(3),
|
||||
Att: stmt.ColumnText(4),
|
||||
db: db,
|
||||
}
|
||||
drops = append(drops, drop)
|
||||
return nil
|
||||
@ -100,18 +96,17 @@ func ByLevel(db *database.DB, minLevel int) ([]*Drop, error) {
|
||||
}
|
||||
|
||||
// ByType retrieves drops by type
|
||||
func ByType(db *database.DB, dropType int) ([]*Drop, error) {
|
||||
func ByType(dropType int) ([]*Drop, error) {
|
||||
var drops []*Drop
|
||||
|
||||
query := "SELECT id, name, level, type, att FROM drops WHERE type = ? ORDER BY level, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
drop := &Drop{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Level: stmt.ColumnInt(2),
|
||||
Type: stmt.ColumnInt(3),
|
||||
Att: stmt.ColumnText(4),
|
||||
db: db,
|
||||
}
|
||||
drops = append(drops, drop)
|
||||
return nil
|
||||
@ -131,7 +126,7 @@ func (d *Drop) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE drops SET name = ?, level = ?, type = ?, att = ? WHERE id = ?`
|
||||
return d.db.Exec(query, d.Name, d.Level, d.Type, d.Att, d.ID)
|
||||
return database.Exec(query, d.Name, d.Level, d.Type, d.Att, d.ID)
|
||||
}
|
||||
|
||||
// Delete removes the drop from the database
|
||||
@ -140,8 +135,7 @@ func (d *Drop) Delete() error {
|
||||
return fmt.Errorf("cannot delete drop without ID")
|
||||
}
|
||||
|
||||
query := "DELETE FROM drops WHERE id = ?"
|
||||
return d.db.Exec(query, d.ID)
|
||||
return database.Exec("DELETE FROM drops WHERE id = ?", d.ID)
|
||||
}
|
||||
|
||||
// IsConsumable returns true if the drop is a consumable item
|
||||
|
@ -12,21 +12,18 @@ import (
|
||||
// Builder provides a fluent interface for creating forum posts
|
||||
type Builder struct {
|
||||
forum *Forum
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new forum post builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
now := time.Now().Unix()
|
||||
return &Builder{
|
||||
forum: &Forum{
|
||||
db: db,
|
||||
Posted: now,
|
||||
LastPost: now, // Default to same as posted time
|
||||
Parent: 0, // Default to thread (no parent)
|
||||
Replies: 0, // Default to no replies
|
||||
},
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +96,7 @@ func (b *Builder) WithReplies(replies int) *Builder {
|
||||
func (b *Builder) Create() (*Forum, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var forum *Forum
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO forum (posted, last_post, author, parent, replies, title, content)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
||||
|
||||
|
@ -20,16 +20,14 @@ type Forum struct {
|
||||
Replies int `json:"replies"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// Find retrieves a forum post by ID
|
||||
func Find(db *database.DB, id int) (*Forum, error) {
|
||||
forum := &Forum{db: db}
|
||||
func Find(id int) (*Forum, error) {
|
||||
forum := &Forum{}
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum.ID = stmt.ColumnInt(0)
|
||||
forum.Posted = stmt.ColumnInt64(1)
|
||||
forum.LastPost = stmt.ColumnInt64(2)
|
||||
@ -53,11 +51,11 @@ func Find(db *database.DB, id int) (*Forum, error) {
|
||||
}
|
||||
|
||||
// All retrieves all forum posts ordered by last post time (most recent first)
|
||||
func All(db *database.DB) ([]*Forum, error) {
|
||||
func All() ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum ORDER BY last_post DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -67,7 +65,6 @@ func All(db *database.DB) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -81,11 +78,11 @@ func All(db *database.DB) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// Threads retrieves all top-level forum threads (parent = 0)
|
||||
func Threads(db *database.DB) ([]*Forum, error) {
|
||||
func Threads() ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE parent = 0 ORDER BY last_post DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -95,7 +92,6 @@ func Threads(db *database.DB) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -109,11 +105,11 @@ func Threads(db *database.DB) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// ByParent retrieves all replies to a specific thread/post
|
||||
func ByParent(db *database.DB, parentID int) ([]*Forum, error) {
|
||||
func ByParent(parentID int) ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE parent = ? ORDER BY posted ASC, id ASC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -123,7 +119,6 @@ func ByParent(db *database.DB, parentID int) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -137,11 +132,11 @@ func ByParent(db *database.DB, parentID int) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// ByAuthor retrieves forum posts by a specific author
|
||||
func ByAuthor(db *database.DB, authorID int) ([]*Forum, error) {
|
||||
func ByAuthor(authorID int) ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE author = ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -151,7 +146,6 @@ func ByAuthor(db *database.DB, authorID int) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -165,11 +159,11 @@ func ByAuthor(db *database.DB, authorID int) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// Recent retrieves the most recent forum activity (limited by count)
|
||||
func Recent(db *database.DB, limit int) ([]*Forum, error) {
|
||||
func Recent(limit int) ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum ORDER BY last_post DESC, id DESC LIMIT ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -179,7 +173,6 @@ func Recent(db *database.DB, limit int) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -193,13 +186,13 @@ func Recent(db *database.DB, limit int) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// Search retrieves forum posts containing the search term in title or content
|
||||
func Search(db *database.DB, term string) ([]*Forum, error) {
|
||||
func Search(term string) ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE LOWER(title) LIKE LOWER(?) OR LOWER(content) LIKE LOWER(?) ORDER BY last_post DESC, id DESC"
|
||||
searchTerm := "%" + term + "%"
|
||||
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -209,7 +202,6 @@ func Search(db *database.DB, term string) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -223,11 +215,11 @@ func Search(db *database.DB, term string) ([]*Forum, error) {
|
||||
}
|
||||
|
||||
// Since retrieves forum posts with activity since a specific timestamp
|
||||
func Since(db *database.DB, since int64) ([]*Forum, error) {
|
||||
func Since(since int64) ([]*Forum, error) {
|
||||
var forums []*Forum
|
||||
|
||||
query := "SELECT id, posted, last_post, author, parent, replies, title, content FROM forum WHERE last_post >= ? ORDER BY last_post DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
forum := &Forum{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Posted: stmt.ColumnInt64(1),
|
||||
@ -237,7 +229,6 @@ func Since(db *database.DB, since int64) ([]*Forum, error) {
|
||||
Replies: stmt.ColumnInt(5),
|
||||
Title: stmt.ColumnText(6),
|
||||
Content: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
forums = append(forums, forum)
|
||||
return nil
|
||||
@ -257,7 +248,7 @@ func (f *Forum) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE forum SET posted = ?, last_post = ?, author = ?, parent = ?, replies = ?, title = ?, content = ? WHERE id = ?`
|
||||
return f.db.Exec(query, f.Posted, f.LastPost, f.Author, f.Parent, f.Replies, f.Title, f.Content, f.ID)
|
||||
return database.Exec(query, f.Posted, f.LastPost, f.Author, f.Parent, f.Replies, f.Title, f.Content, f.ID)
|
||||
}
|
||||
|
||||
// Delete removes the forum post from the database
|
||||
@ -266,8 +257,7 @@ func (f *Forum) Delete() error {
|
||||
return fmt.Errorf("cannot delete forum post without ID")
|
||||
}
|
||||
|
||||
query := "DELETE FROM forum WHERE id = ?"
|
||||
return f.db.Exec(query, f.ID)
|
||||
return database.Exec("DELETE FROM forum WHERE id = ?", f.ID)
|
||||
}
|
||||
|
||||
// PostedTime returns the posted timestamp as a time.Time
|
||||
@ -397,7 +387,7 @@ func (f *Forum) DecrementReplies() {
|
||||
|
||||
// GetReplies retrieves all direct replies to this post
|
||||
func (f *Forum) GetReplies() ([]*Forum, error) {
|
||||
return ByParent(f.db, f.ID)
|
||||
return ByParent(f.ID)
|
||||
}
|
||||
|
||||
// GetThread retrieves the parent thread (if this is a reply) or returns self (if this is a thread)
|
||||
@ -405,5 +395,5 @@ func (f *Forum) GetThread() (*Forum, error) {
|
||||
if f.IsThread() {
|
||||
return f, nil
|
||||
}
|
||||
return Find(f.db, f.Parent)
|
||||
return Find(f.Parent)
|
||||
}
|
@ -24,21 +24,20 @@ func Run() error {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
db, err := database.Open(dbPath)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := database.Init("dk.db"); err != nil {
|
||||
return fmt.Errorf("failed to initialize database: %w", err)
|
||||
}
|
||||
defer db.Close()
|
||||
defer database.Close()
|
||||
|
||||
if err := createTables(db); err != nil {
|
||||
if err := createTables(); err != nil {
|
||||
return fmt.Errorf("failed to create tables: %w", err)
|
||||
}
|
||||
|
||||
if err := populateData(db); err != nil {
|
||||
if err := populateData(); err != nil {
|
||||
return fmt.Errorf("failed to populate data: %w", err)
|
||||
}
|
||||
|
||||
if err := createDemoUser(db); err != nil {
|
||||
if err := createDemoUser(); err != nil {
|
||||
return fmt.Errorf("failed to create demo user: %w", err)
|
||||
}
|
||||
|
||||
@ -53,7 +52,7 @@ func Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTables(db *database.DB) error {
|
||||
func createTables() error {
|
||||
tables := []struct {
|
||||
name string
|
||||
sql string
|
||||
@ -187,7 +186,7 @@ func createTables(db *database.DB) error {
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
if err := db.Exec(table.sql); err != nil {
|
||||
if err := database.Exec(table.sql); err != nil {
|
||||
return fmt.Errorf("failed to create %s table: %w", table.name, err)
|
||||
}
|
||||
fmt.Printf("✓ %s table created\n", table.name)
|
||||
@ -196,8 +195,8 @@ func createTables(db *database.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateData(db *database.DB) error {
|
||||
if err := db.Exec("INSERT INTO control VALUES (1, 250, 1, '', 'Mage', 'Warrior', 'Paladin')"); err != nil {
|
||||
func populateData() error {
|
||||
if err := database.Exec("INSERT INTO control VALUES (1, 250, 1, '', 'Mage', 'Warrior', 'Paladin')"); err != nil {
|
||||
return fmt.Errorf("failed to populate control table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ control table populated")
|
||||
@ -235,7 +234,7 @@ func populateData(db *database.DB) error {
|
||||
(30, 'Diamond', 50, 1, 'defensepower,150'),
|
||||
(31, 'Memory Drop', 5, 1, 'expbonus,10'),
|
||||
(32, 'Fortune Drop', 5, 1, 'goldbonus,10')`
|
||||
if err := db.Exec(dropsSQL); err != nil {
|
||||
if err := database.Exec(dropsSQL); err != nil {
|
||||
return fmt.Errorf("failed to populate drops table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ drops table populated")
|
||||
@ -274,7 +273,7 @@ func populateData(db *database.DB) error {
|
||||
(31, 3, 'Large Shield', 2500, 30, ''),
|
||||
(32, 3, 'Silver Shield', 10000, 60, ''),
|
||||
(33, 3, 'Destiny Aegis', 25000, 100, 'maxhp,50')`
|
||||
if err := db.Exec(itemsSQL); err != nil {
|
||||
if err := database.Exec(itemsSQL); err != nil {
|
||||
return fmt.Errorf("failed to populate items table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ items table populated")
|
||||
@ -431,12 +430,12 @@ func populateData(db *database.DB) error {
|
||||
(149, 'Titan', 360, 340, 270, 50, 2400, 800, 0),
|
||||
(150, 'Black Daemon', 400, 400, 280, 50, 3000, 1000, 1),
|
||||
(151, 'Lucifuge', 600, 600, 400, 50, 10000, 10000, 2)`
|
||||
if err := db.Exec(monstersSQL); err != nil {
|
||||
if err := database.Exec(monstersSQL); err != nil {
|
||||
return fmt.Errorf("failed to populate monsters table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ monsters table populated")
|
||||
|
||||
if err := db.Exec("INSERT INTO news (author, content) VALUES (1, 'Welcome to Dragon Knight! This is your first news post.')"); err != nil {
|
||||
if err := database.Exec("INSERT INTO news (author, content) VALUES (1, 'Welcome to Dragon Knight! This is your first news post.')"); err != nil {
|
||||
return fmt.Errorf("failed to populate news table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ news table populated")
|
||||
@ -461,7 +460,7 @@ func populateData(db *database.DB) error {
|
||||
(17, 'Ward', 10, 10, 5),
|
||||
(18, 'Fend', 20, 25, 5),
|
||||
(19, 'Barrier', 30, 50, 5)`
|
||||
if err := db.Exec(spellsSQL); err != nil {
|
||||
if err := database.Exec(spellsSQL); err != nil {
|
||||
return fmt.Errorf("failed to populate spells table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ spells table populated")
|
||||
@ -475,7 +474,7 @@ func populateData(db *database.DB) error {
|
||||
(6, 'Hambry', 170, 170, 90, 1000, 80, '10,11,12,13,14,23,24,30,31'),
|
||||
(7, 'Gilead', 200, -200, 100, 3000, 110, '12,13,14,15,24,25,26,32'),
|
||||
(8, 'Endworld', -250, -250, 125, 9000, 160, '16,27,33')`
|
||||
if err := db.Exec(townsSQL); err != nil {
|
||||
if err := database.Exec(townsSQL); err != nil {
|
||||
return fmt.Errorf("failed to populate towns table: %w", err)
|
||||
}
|
||||
fmt.Println("✓ towns table populated")
|
||||
@ -483,7 +482,7 @@ func populateData(db *database.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDemoUser(db *database.DB) error {
|
||||
func createDemoUser() error {
|
||||
hashedPassword, err := password.Hash("Demo123!")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to hash password: %w", err)
|
||||
@ -492,7 +491,7 @@ func createDemoUser(db *database.DB) error {
|
||||
stmt := `INSERT INTO users (username, password, email, verified, class_id, auth)
|
||||
VALUES (?, ?, ?, 1, 1, 4)`
|
||||
|
||||
if err := db.Exec(stmt, "demo", hashedPassword, "demo@demo.com"); err != nil {
|
||||
if err := database.Exec(stmt, "demo", hashedPassword, "demo@demo.com"); err != nil {
|
||||
return fmt.Errorf("failed to create demo user: %w", err)
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,12 @@ import (
|
||||
// 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 {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
item: &Item{db: db},
|
||||
db: db,
|
||||
item: &Item{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +53,7 @@ func (b *Builder) WithSpecial(special string) *Builder {
|
||||
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 {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO items (type, name, value, att, special)
|
||||
VALUES (?, ?, ?, ?, ?)`
|
||||
|
||||
@ -81,7 +79,6 @@ func (b *Builder) Create() (*Item, error) {
|
||||
Value: b.item.Value,
|
||||
Att: b.item.Att,
|
||||
Special: b.item.Special,
|
||||
db: b.db,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -16,8 +16,6 @@ type Item struct {
|
||||
Value int `json:"value"`
|
||||
Att int `json:"att"`
|
||||
Special string `json:"special"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// ItemType constants for item types
|
||||
@ -28,11 +26,11 @@ const (
|
||||
)
|
||||
|
||||
// Find retrieves an item by ID
|
||||
func Find(db *database.DB, id int) (*Item, error) {
|
||||
item := &Item{db: db}
|
||||
func Find(id int) (*Item, error) {
|
||||
item := &Item{}
|
||||
|
||||
query := "SELECT id, type, name, value, att, special FROM items WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
item.ID = stmt.ColumnInt(0)
|
||||
item.Type = stmt.ColumnInt(1)
|
||||
item.Name = stmt.ColumnText(2)
|
||||
@ -54,11 +52,11 @@ func Find(db *database.DB, id int) (*Item, error) {
|
||||
}
|
||||
|
||||
// All retrieves all items
|
||||
func All(db *database.DB) ([]*Item, error) {
|
||||
func All() ([]*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 {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
item := &Item{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Type: stmt.ColumnInt(1),
|
||||
@ -66,7 +64,6 @@ func All(db *database.DB) ([]*Item, error) {
|
||||
Value: stmt.ColumnInt(3),
|
||||
Att: stmt.ColumnInt(4),
|
||||
Special: stmt.ColumnText(5),
|
||||
db: db,
|
||||
}
|
||||
items = append(items, item)
|
||||
return nil
|
||||
@ -80,11 +77,11 @@ func All(db *database.DB) ([]*Item, error) {
|
||||
}
|
||||
|
||||
// ByType retrieves items by type
|
||||
func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
||||
func ByType(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 {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
item := &Item{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Type: stmt.ColumnInt(1),
|
||||
@ -92,7 +89,6 @@ func ByType(db *database.DB, itemType int) ([]*Item, error) {
|
||||
Value: stmt.ColumnInt(3),
|
||||
Att: stmt.ColumnInt(4),
|
||||
Special: stmt.ColumnText(5),
|
||||
db: db,
|
||||
}
|
||||
items = append(items, item)
|
||||
return nil
|
||||
@ -112,7 +108,7 @@ func (i *Item) Save() error {
|
||||
}
|
||||
|
||||
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)
|
||||
return database.Exec(query, i.Type, i.Name, i.Value, i.Att, i.Special, i.ID)
|
||||
}
|
||||
|
||||
// Delete removes the item from the database
|
||||
@ -122,7 +118,7 @@ func (i *Item) Delete() error {
|
||||
}
|
||||
|
||||
query := "DELETE FROM items WHERE id = ?"
|
||||
return i.db.Exec(query, i.ID)
|
||||
return database.Exec(query, i.ID)
|
||||
}
|
||||
|
||||
// IsWeapon returns true if the item is a weapon
|
||||
|
@ -10,14 +10,12 @@ import (
|
||||
// Builder provides a fluent interface for creating monsters
|
||||
type Builder struct {
|
||||
monster *Monster
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new monster builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
monster: &Monster{db: db},
|
||||
db: db,
|
||||
monster: &Monster{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +71,7 @@ func (b *Builder) WithImmunity(immunity int) *Builder {
|
||||
func (b *Builder) Create() (*Monster, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var monster *Monster
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO monsters (name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
|
||||
@ -103,7 +101,6 @@ func (b *Builder) Create() (*Monster, error) {
|
||||
MaxExp: b.monster.MaxExp,
|
||||
MaxGold: b.monster.MaxGold,
|
||||
Immune: b.monster.Immune,
|
||||
db: b.db,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -19,8 +19,6 @@ type Monster struct {
|
||||
MaxExp int `json:"max_exp"`
|
||||
MaxGold int `json:"max_gold"`
|
||||
Immune int `json:"immune"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// Immunity constants for monster immunity types
|
||||
@ -31,11 +29,11 @@ const (
|
||||
)
|
||||
|
||||
// Find retrieves a monster by ID
|
||||
func Find(db *database.DB, id int) (*Monster, error) {
|
||||
monster := &Monster{db: db}
|
||||
func Find(id int) (*Monster, error) {
|
||||
monster := &Monster{}
|
||||
|
||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
monster.ID = stmt.ColumnInt(0)
|
||||
monster.Name = stmt.ColumnText(1)
|
||||
monster.MaxHP = stmt.ColumnInt(2)
|
||||
@ -60,11 +58,11 @@ func Find(db *database.DB, id int) (*Monster, error) {
|
||||
}
|
||||
|
||||
// All retrieves all monsters
|
||||
func All(db *database.DB) ([]*Monster, error) {
|
||||
func All() ([]*Monster, error) {
|
||||
var monsters []*Monster
|
||||
|
||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters ORDER BY level, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
monster := &Monster{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -75,7 +73,6 @@ func All(db *database.DB) ([]*Monster, error) {
|
||||
MaxExp: stmt.ColumnInt(6),
|
||||
MaxGold: stmt.ColumnInt(7),
|
||||
Immune: stmt.ColumnInt(8),
|
||||
db: db,
|
||||
}
|
||||
monsters = append(monsters, monster)
|
||||
return nil
|
||||
@ -89,11 +86,11 @@ func All(db *database.DB) ([]*Monster, error) {
|
||||
}
|
||||
|
||||
// ByLevel retrieves monsters by level
|
||||
func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
||||
func ByLevel(level int) ([]*Monster, error) {
|
||||
var monsters []*Monster
|
||||
|
||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level = ? ORDER BY id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
monster := &Monster{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -104,7 +101,6 @@ func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
||||
MaxExp: stmt.ColumnInt(6),
|
||||
MaxGold: stmt.ColumnInt(7),
|
||||
Immune: stmt.ColumnInt(8),
|
||||
db: db,
|
||||
}
|
||||
monsters = append(monsters, monster)
|
||||
return nil
|
||||
@ -118,11 +114,11 @@ func ByLevel(db *database.DB, level int) ([]*Monster, error) {
|
||||
}
|
||||
|
||||
// ByLevelRange retrieves monsters within a level range (inclusive)
|
||||
func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
||||
func ByLevelRange(minLevel, maxLevel int) ([]*Monster, error) {
|
||||
var monsters []*Monster
|
||||
|
||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE level BETWEEN ? AND ? ORDER BY level, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
monster := &Monster{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -133,7 +129,6 @@ func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
||||
MaxExp: stmt.ColumnInt(6),
|
||||
MaxGold: stmt.ColumnInt(7),
|
||||
Immune: stmt.ColumnInt(8),
|
||||
db: db,
|
||||
}
|
||||
monsters = append(monsters, monster)
|
||||
return nil
|
||||
@ -147,11 +142,11 @@ func ByLevelRange(db *database.DB, minLevel, maxLevel int) ([]*Monster, error) {
|
||||
}
|
||||
|
||||
// ByImmunity retrieves monsters by immunity type
|
||||
func ByImmunity(db *database.DB, immunityType int) ([]*Monster, error) {
|
||||
func ByImmunity(immunityType int) ([]*Monster, error) {
|
||||
var monsters []*Monster
|
||||
|
||||
query := "SELECT id, name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune FROM monsters WHERE immune = ? ORDER BY level, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
monster := &Monster{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -162,7 +157,6 @@ func ByImmunity(db *database.DB, immunityType int) ([]*Monster, error) {
|
||||
MaxExp: stmt.ColumnInt(6),
|
||||
MaxGold: stmt.ColumnInt(7),
|
||||
Immune: stmt.ColumnInt(8),
|
||||
db: db,
|
||||
}
|
||||
monsters = append(monsters, monster)
|
||||
return nil
|
||||
@ -182,7 +176,7 @@ func (m *Monster) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE monsters SET name = ?, max_hp = ?, max_dmg = ?, armor = ?, level = ?, max_exp = ?, max_gold = ?, immune = ? WHERE id = ?`
|
||||
return m.db.Exec(query, m.Name, m.MaxHP, m.MaxDmg, m.Armor, m.Level, m.MaxExp, m.MaxGold, m.Immune, m.ID)
|
||||
return database.Exec(query, m.Name, m.MaxHP, m.MaxDmg, m.Armor, m.Level, m.MaxExp, m.MaxGold, m.Immune, m.ID)
|
||||
}
|
||||
|
||||
// Delete removes the monster from the database
|
||||
@ -192,7 +186,7 @@ func (m *Monster) Delete() error {
|
||||
}
|
||||
|
||||
query := "DELETE FROM monsters WHERE id = ?"
|
||||
return m.db.Exec(query, m.ID)
|
||||
return database.Exec(query, m.ID)
|
||||
}
|
||||
|
||||
// IsHurtImmune returns true if the monster is immune to Hurt spells
|
||||
|
@ -12,17 +12,14 @@ import (
|
||||
// Builder provides a fluent interface for creating news posts
|
||||
type Builder struct {
|
||||
news *News
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new news builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
news: &News{
|
||||
db: db,
|
||||
Posted: time.Now().Unix(), // Default to current time
|
||||
},
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,7 +51,7 @@ func (b *Builder) WithPostedTime(t time.Time) *Builder {
|
||||
func (b *Builder) Create() (*News, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var news *News
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO news (author, posted, content)
|
||||
VALUES (?, ?, ?)`
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
package news
|
||||
|
||||
import (
|
||||
"dk/internal/database"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"dk/internal/database"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
)
|
||||
|
||||
@ -15,16 +14,14 @@ type News struct {
|
||||
Author int `json:"author"`
|
||||
Posted int64 `json:"posted"`
|
||||
Content string `json:"content"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// Find retrieves a news post by ID
|
||||
func Find(db *database.DB, id int) (*News, error) {
|
||||
news := &News{db: db}
|
||||
func Find(id int) (*News, error) {
|
||||
news := &News{}
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news.ID = stmt.ColumnInt(0)
|
||||
news.Author = stmt.ColumnInt(1)
|
||||
news.Posted = stmt.ColumnInt64(2)
|
||||
@ -44,17 +41,16 @@ func Find(db *database.DB, id int) (*News, error) {
|
||||
}
|
||||
|
||||
// All retrieves all news posts ordered by posted date (newest first)
|
||||
func All(db *database.DB) ([]*News, error) {
|
||||
func All() ([]*News, error) {
|
||||
var newsPosts []*News
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news := &News{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Author: stmt.ColumnInt(1),
|
||||
Posted: stmt.ColumnInt64(2),
|
||||
Content: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
newsPosts = append(newsPosts, news)
|
||||
return nil
|
||||
@ -68,17 +64,16 @@ func All(db *database.DB) ([]*News, error) {
|
||||
}
|
||||
|
||||
// ByAuthor retrieves news posts by a specific author
|
||||
func ByAuthor(db *database.DB, authorID int) ([]*News, error) {
|
||||
func ByAuthor(authorID int) ([]*News, error) {
|
||||
var newsPosts []*News
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news WHERE author = ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news := &News{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Author: stmt.ColumnInt(1),
|
||||
Posted: stmt.ColumnInt64(2),
|
||||
Content: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
newsPosts = append(newsPosts, news)
|
||||
return nil
|
||||
@ -92,17 +87,16 @@ func ByAuthor(db *database.DB, authorID int) ([]*News, error) {
|
||||
}
|
||||
|
||||
// Recent retrieves the most recent news posts (limited by count)
|
||||
func Recent(db *database.DB, limit int) ([]*News, error) {
|
||||
func Recent(limit int) ([]*News, error) {
|
||||
var newsPosts []*News
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news ORDER BY posted DESC, id DESC LIMIT ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news := &News{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Author: stmt.ColumnInt(1),
|
||||
Posted: stmt.ColumnInt64(2),
|
||||
Content: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
newsPosts = append(newsPosts, news)
|
||||
return nil
|
||||
@ -116,17 +110,16 @@ func Recent(db *database.DB, limit int) ([]*News, error) {
|
||||
}
|
||||
|
||||
// Since retrieves news posts since a specific timestamp
|
||||
func Since(db *database.DB, since int64) ([]*News, error) {
|
||||
func Since(since int64) ([]*News, error) {
|
||||
var newsPosts []*News
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news WHERE posted >= ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news := &News{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Author: stmt.ColumnInt(1),
|
||||
Posted: stmt.ColumnInt64(2),
|
||||
Content: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
newsPosts = append(newsPosts, news)
|
||||
return nil
|
||||
@ -140,17 +133,16 @@ func Since(db *database.DB, since int64) ([]*News, error) {
|
||||
}
|
||||
|
||||
// Between retrieves news posts between two timestamps (inclusive)
|
||||
func Between(db *database.DB, start, end int64) ([]*News, error) {
|
||||
func Between(start, end int64) ([]*News, error) {
|
||||
var newsPosts []*News
|
||||
|
||||
query := "SELECT id, author, posted, content FROM news WHERE posted >= ? AND posted <= ? ORDER BY posted DESC, id DESC"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
news := &News{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Author: stmt.ColumnInt(1),
|
||||
Posted: stmt.ColumnInt64(2),
|
||||
Content: stmt.ColumnText(3),
|
||||
db: db,
|
||||
}
|
||||
newsPosts = append(newsPosts, news)
|
||||
return nil
|
||||
@ -170,7 +162,7 @@ func (n *News) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE news SET author = ?, posted = ?, content = ? WHERE id = ?`
|
||||
return n.db.Exec(query, n.Author, n.Posted, n.Content, n.ID)
|
||||
return database.Exec(query, n.Author, n.Posted, n.Content, n.ID)
|
||||
}
|
||||
|
||||
// Delete removes the news post from the database
|
||||
@ -180,7 +172,7 @@ func (n *News) Delete() error {
|
||||
}
|
||||
|
||||
query := "DELETE FROM news WHERE id = ?"
|
||||
return n.db.Exec(query, n.ID)
|
||||
return database.Exec(query, n.ID)
|
||||
}
|
||||
|
||||
// PostedTime returns the posted timestamp as a time.Time
|
||||
|
@ -28,7 +28,7 @@ func Start(port string) error {
|
||||
template.InitializeCache(cwd)
|
||||
|
||||
// Initialize database singleton
|
||||
if err := database.InitializeDB("dk.db"); err != nil {
|
||||
if err := database.Init("dk.db"); err != nil {
|
||||
return fmt.Errorf("failed to initialize database: %w", err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
@ -10,14 +10,12 @@ import (
|
||||
// Builder provides a fluent interface for creating spells
|
||||
type Builder struct {
|
||||
spell *Spell
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new spell builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
spell: &Spell{db: db},
|
||||
db: db,
|
||||
spell: &Spell{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +47,7 @@ func (b *Builder) WithType(spellType int) *Builder {
|
||||
func (b *Builder) Create() (*Spell, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var spell *Spell
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO spells (name, mp, attribute, type)
|
||||
VALUES (?, ?, ?, ?)`
|
||||
|
||||
@ -74,7 +72,6 @@ func (b *Builder) Create() (*Spell, error) {
|
||||
MP: b.spell.MP,
|
||||
Attribute: b.spell.Attribute,
|
||||
Type: b.spell.Type,
|
||||
db: b.db,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -15,8 +15,6 @@ type Spell struct {
|
||||
MP int `json:"mp"`
|
||||
Attribute int `json:"attribute"`
|
||||
Type int `json:"type"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// SpellType constants for spell types
|
||||
@ -29,11 +27,11 @@ const (
|
||||
)
|
||||
|
||||
// Find retrieves a spell by ID
|
||||
func Find(db *database.DB, id int) (*Spell, error) {
|
||||
spell := &Spell{db: db}
|
||||
func Find(id int) (*Spell, error) {
|
||||
spell := &Spell{}
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell.ID = stmt.ColumnInt(0)
|
||||
spell.Name = stmt.ColumnText(1)
|
||||
spell.MP = stmt.ColumnInt(2)
|
||||
@ -54,18 +52,17 @@ func Find(db *database.DB, id int) (*Spell, error) {
|
||||
}
|
||||
|
||||
// All retrieves all spells
|
||||
func All(db *database.DB) ([]*Spell, error) {
|
||||
func All() ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells ORDER BY type, mp, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell := &Spell{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
MP: stmt.ColumnInt(2),
|
||||
Attribute: stmt.ColumnInt(3),
|
||||
Type: stmt.ColumnInt(4),
|
||||
db: db,
|
||||
}
|
||||
spells = append(spells, spell)
|
||||
return nil
|
||||
@ -79,18 +76,17 @@ func All(db *database.DB) ([]*Spell, error) {
|
||||
}
|
||||
|
||||
// ByType retrieves spells by type
|
||||
func ByType(db *database.DB, spellType int) ([]*Spell, error) {
|
||||
func ByType(spellType int) ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells WHERE type = ? ORDER BY mp, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell := &Spell{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
MP: stmt.ColumnInt(2),
|
||||
Attribute: stmt.ColumnInt(3),
|
||||
Type: stmt.ColumnInt(4),
|
||||
db: db,
|
||||
}
|
||||
spells = append(spells, spell)
|
||||
return nil
|
||||
@ -104,18 +100,17 @@ func ByType(db *database.DB, spellType int) ([]*Spell, error) {
|
||||
}
|
||||
|
||||
// ByMaxMP retrieves spells that cost at most the specified MP
|
||||
func ByMaxMP(db *database.DB, maxMP int) ([]*Spell, error) {
|
||||
func ByMaxMP(maxMP int) ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells WHERE mp <= ? ORDER BY type, mp, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell := &Spell{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
MP: stmt.ColumnInt(2),
|
||||
Attribute: stmt.ColumnInt(3),
|
||||
Type: stmt.ColumnInt(4),
|
||||
db: db,
|
||||
}
|
||||
spells = append(spells, spell)
|
||||
return nil
|
||||
@ -129,18 +124,17 @@ func ByMaxMP(db *database.DB, maxMP int) ([]*Spell, error) {
|
||||
}
|
||||
|
||||
// ByTypeAndMaxMP retrieves spells of a specific type that cost at most the specified MP
|
||||
func ByTypeAndMaxMP(db *database.DB, spellType, maxMP int) ([]*Spell, error) {
|
||||
func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) {
|
||||
var spells []*Spell
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells WHERE type = ? AND mp <= ? ORDER BY mp, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell := &Spell{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
MP: stmt.ColumnInt(2),
|
||||
Attribute: stmt.ColumnInt(3),
|
||||
Type: stmt.ColumnInt(4),
|
||||
db: db,
|
||||
}
|
||||
spells = append(spells, spell)
|
||||
return nil
|
||||
@ -154,11 +148,11 @@ func ByTypeAndMaxMP(db *database.DB, spellType, maxMP int) ([]*Spell, error) {
|
||||
}
|
||||
|
||||
// ByName retrieves a spell by name (case-insensitive)
|
||||
func ByName(db *database.DB, name string) (*Spell, error) {
|
||||
spell := &Spell{db: db}
|
||||
func ByName(name string) (*Spell, error) {
|
||||
spell := &Spell{}
|
||||
|
||||
query := "SELECT id, name, mp, attribute, type FROM spells WHERE LOWER(name) = LOWER(?) LIMIT 1"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
spell.ID = stmt.ColumnInt(0)
|
||||
spell.Name = stmt.ColumnText(1)
|
||||
spell.MP = stmt.ColumnInt(2)
|
||||
@ -185,7 +179,7 @@ func (s *Spell) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE spells SET name = ?, mp = ?, attribute = ?, type = ? WHERE id = ?`
|
||||
return s.db.Exec(query, s.Name, s.MP, s.Attribute, s.Type, s.ID)
|
||||
return database.Exec(query, s.Name, s.MP, s.Attribute, s.Type, s.ID)
|
||||
}
|
||||
|
||||
// Delete removes the spell from the database
|
||||
@ -195,7 +189,7 @@ func (s *Spell) Delete() error {
|
||||
}
|
||||
|
||||
query := "DELETE FROM spells WHERE id = ?"
|
||||
return s.db.Exec(query, s.ID)
|
||||
return database.Exec(query, s.ID)
|
||||
}
|
||||
|
||||
// IsHealing returns true if the spell is a healing spell
|
||||
|
@ -11,16 +11,12 @@ import (
|
||||
// Builder provides a fluent interface for creating towns
|
||||
type Builder struct {
|
||||
town *Town
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// NewBuilder creates a new town builder
|
||||
func NewBuilder(db *database.DB) *Builder {
|
||||
func NewBuilder() *Builder {
|
||||
return &Builder{
|
||||
town: &Town{
|
||||
db: db,
|
||||
},
|
||||
db: db,
|
||||
town: &Town{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +79,7 @@ func (b *Builder) WithShopItems(items []string) *Builder {
|
||||
func (b *Builder) Create() (*Town, error) {
|
||||
// Use a transaction to ensure we can get the ID
|
||||
var town *Town
|
||||
err := b.db.Transaction(func(tx *database.Tx) error {
|
||||
err := database.Transaction(func(tx *database.Tx) error {
|
||||
query := `INSERT INTO towns (name, x, y, inn_cost, map_cost, tp_cost, shop_list)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
||||
|
||||
|
@ -19,16 +19,14 @@ type Town struct {
|
||||
MapCost int `json:"map_cost"`
|
||||
TPCost int `json:"tp_cost"`
|
||||
ShopList string `json:"shop_list"`
|
||||
|
||||
db *database.DB
|
||||
}
|
||||
|
||||
// Find retrieves a town by ID
|
||||
func Find(db *database.DB, id int) (*Town, error) {
|
||||
town := &Town{db: db}
|
||||
func Find(id int) (*Town, error) {
|
||||
town := &Town{}
|
||||
|
||||
query := "SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list FROM towns WHERE id = ?"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town.ID = stmt.ColumnInt(0)
|
||||
town.Name = stmt.ColumnText(1)
|
||||
town.X = stmt.ColumnInt(2)
|
||||
@ -52,11 +50,11 @@ func Find(db *database.DB, id int) (*Town, error) {
|
||||
}
|
||||
|
||||
// All retrieves all towns
|
||||
func All(db *database.DB) ([]*Town, error) {
|
||||
func All() ([]*Town, error) {
|
||||
var towns []*Town
|
||||
|
||||
query := "SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list FROM towns ORDER BY id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town := &Town{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -66,7 +64,6 @@ func All(db *database.DB) ([]*Town, error) {
|
||||
MapCost: stmt.ColumnInt(5),
|
||||
TPCost: stmt.ColumnInt(6),
|
||||
ShopList: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
towns = append(towns, town)
|
||||
return nil
|
||||
@ -80,11 +77,11 @@ func All(db *database.DB) ([]*Town, error) {
|
||||
}
|
||||
|
||||
// ByName retrieves a town by name (case-insensitive)
|
||||
func ByName(db *database.DB, name string) (*Town, error) {
|
||||
town := &Town{db: db}
|
||||
func ByName(name string) (*Town, error) {
|
||||
town := &Town{}
|
||||
|
||||
query := "SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list FROM towns WHERE LOWER(name) = LOWER(?) LIMIT 1"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town.ID = stmt.ColumnInt(0)
|
||||
town.Name = stmt.ColumnText(1)
|
||||
town.X = stmt.ColumnInt(2)
|
||||
@ -108,11 +105,11 @@ func ByName(db *database.DB, name string) (*Town, error) {
|
||||
}
|
||||
|
||||
// ByMaxInnCost retrieves towns with inn cost at most the specified amount
|
||||
func ByMaxInnCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
func ByMaxInnCost(maxCost int) ([]*Town, error) {
|
||||
var towns []*Town
|
||||
|
||||
query := "SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list FROM towns WHERE inn_cost <= ? ORDER BY inn_cost, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town := &Town{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -122,7 +119,6 @@ func ByMaxInnCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
MapCost: stmt.ColumnInt(5),
|
||||
TPCost: stmt.ColumnInt(6),
|
||||
ShopList: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
towns = append(towns, town)
|
||||
return nil
|
||||
@ -136,11 +132,11 @@ func ByMaxInnCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
}
|
||||
|
||||
// ByMaxTPCost retrieves towns with teleport cost at most the specified amount
|
||||
func ByMaxTPCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
func ByMaxTPCost(maxCost int) ([]*Town, error) {
|
||||
var towns []*Town
|
||||
|
||||
query := "SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list FROM towns WHERE tp_cost <= ? ORDER BY tp_cost, id"
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town := &Town{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -150,7 +146,6 @@ func ByMaxTPCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
MapCost: stmt.ColumnInt(5),
|
||||
TPCost: stmt.ColumnInt(6),
|
||||
ShopList: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
towns = append(towns, town)
|
||||
return nil
|
||||
@ -164,7 +159,7 @@ func ByMaxTPCost(db *database.DB, maxCost int) ([]*Town, error) {
|
||||
}
|
||||
|
||||
// ByDistance retrieves towns within a certain distance from a point
|
||||
func ByDistance(db *database.DB, fromX, fromY, maxDistance int) ([]*Town, error) {
|
||||
func ByDistance(fromX, fromY, maxDistance int) ([]*Town, error) {
|
||||
var towns []*Town
|
||||
|
||||
query := `SELECT id, name, x, y, inn_cost, map_cost, tp_cost, shop_list
|
||||
@ -173,7 +168,7 @@ func ByDistance(db *database.DB, fromX, fromY, maxDistance int) ([]*Town, error)
|
||||
ORDER BY ((x - ?) * (x - ?) + (y - ?) * (y - ?)), id`
|
||||
|
||||
maxDistance2 := maxDistance * maxDistance
|
||||
err := db.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
err := database.Query(query, func(stmt *sqlite.Stmt) error {
|
||||
town := &Town{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
@ -183,7 +178,6 @@ func ByDistance(db *database.DB, fromX, fromY, maxDistance int) ([]*Town, error)
|
||||
MapCost: stmt.ColumnInt(5),
|
||||
TPCost: stmt.ColumnInt(6),
|
||||
ShopList: stmt.ColumnText(7),
|
||||
db: db,
|
||||
}
|
||||
towns = append(towns, town)
|
||||
return nil
|
||||
@ -203,7 +197,7 @@ func (t *Town) Save() error {
|
||||
}
|
||||
|
||||
query := `UPDATE towns SET name = ?, x = ?, y = ?, inn_cost = ?, map_cost = ?, tp_cost = ?, shop_list = ? WHERE id = ?`
|
||||
return t.db.Exec(query, t.Name, t.X, t.Y, t.InnCost, t.MapCost, t.TPCost, t.ShopList, t.ID)
|
||||
return database.Exec(query, t.Name, t.X, t.Y, t.InnCost, t.MapCost, t.TPCost, t.ShopList, t.ID)
|
||||
}
|
||||
|
||||
// Delete removes the town from the database
|
||||
@ -213,7 +207,7 @@ func (t *Town) Delete() error {
|
||||
}
|
||||
|
||||
query := "DELETE FROM towns WHERE id = ?"
|
||||
return t.db.Exec(query, t.ID)
|
||||
return database.Exec(query, t.ID)
|
||||
}
|
||||
|
||||
// GetShopItems returns the shop items as a slice of item IDs
|
||||
|
Loading…
x
Reference in New Issue
Block a user