package db import ( "database/sql" _ "embed" "fmt" _ "modernc.org/sqlite" "golang.org/x/crypto/bcrypt" "qbank/internal/config" ) //go:embed schema.sql var schema string func Open(path string) (*sql.DB, error) { db, err := sql.Open("sqlite", path) if err != nil { return nil, fmt.Errorf("open sqlite: %w", err) } db.SetMaxOpenConns(1) for _, stmt := range []string{ "PRAGMA journal_mode=WAL", "PRAGMA foreign_keys=ON", } { if _, err := db.Exec(stmt); err != nil { db.Close() return nil, fmt.Errorf("pragma %q: %w", stmt, err) } } if _, err := db.Exec(schema); err != nil { db.Close() return nil, fmt.Errorf("apply schema: %w", err) } return db, nil } func Seed(db *sql.DB, users []config.AdminUser) error { var count int if err := db.QueryRow("SELECT COUNT(*) FROM users").Scan(&count); err != nil { return fmt.Errorf("count users: %w", err) } if count > 0 { return nil } for _, u := range users { hash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost) if err != nil { return fmt.Errorf("hash password for %q: %w", u.Name, err) } if _, err := db.Exec("INSERT INTO users (name, password_hash) VALUES (?, ?)", u.Name, string(hash)); err != nil { return fmt.Errorf("insert user %q: %w", u.Name, err) } } return nil }