feat
- sqlite adapter
This commit is contained in:
1 parent
0e0a4d34ac
commit
3673d318a1
2 files changed
+142
-3
No files matched your search
@@ -0,0 +1,136 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"spellbook/internal/models"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const schema = `
|
||||
CREATE TABLE IF NOT EXISTS spells (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
spell TEXT NOT NULL,
|
||||
short_desc TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
tags TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
`
|
||||
|
||||
type scanner interface {
|
||||
Scan(dst ...any) error
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewRepo(db *sql.DB) *Repo {
|
||||
return &Repo{db: db}
|
||||
}
|
||||
|
||||
func (r *Repo) Init(ctx context.Context) error {
|
||||
if r.db == nil {
|
||||
return fmt.Errorf("no db provided")
|
||||
}
|
||||
|
||||
if _, err := r.db.ExecContext(ctx, schema); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) Add(ctx context.Context, spell models.Spell) error {
|
||||
const query = `INSERT INTO spells (name, spell, short_desc, description, tags) VALUES (?, ?, ?, ?, ?)`
|
||||
tags := strings.Join(spell.Tags, ",")
|
||||
|
||||
_, err := r.db.ExecContext(
|
||||
ctx, query,
|
||||
spell.Name, spell.Spell,
|
||||
spell.ShortDesc, spell.Description,
|
||||
tags,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) Delete(ctx context.Context, spellName string) error {
|
||||
const query = `DELETE FROM spells WHERE name = ?`
|
||||
|
||||
if _, err := r.db.ExecContext(ctx, query, spellName); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) Get(ctx context.Context, spellName string) (models.Spell, error) {
|
||||
const query = `SELECT id, name, spell, short_desc, description, tags FROM spells WHERE name = ?`
|
||||
|
||||
row := r.db.QueryRowContext(ctx, query, spellName)
|
||||
if err := row.Err(); err != nil {
|
||||
return models.Spell{}, err
|
||||
}
|
||||
|
||||
return scanSpell(row)
|
||||
}
|
||||
|
||||
func (r *Repo) GetMany(ctx context.Context, query models.SearchQuery) ([]models.Spell, error) {
|
||||
sqlQuery := `
|
||||
SELECT id, name, spell, short_desc, description, tags
|
||||
FROM spells
|
||||
WHERE id > ?`
|
||||
|
||||
args := []any{query.Cursor}
|
||||
|
||||
for _, tag := range query.Tags {
|
||||
if trimmed := strings.TrimSpace(tag); trimmed != "" {
|
||||
sqlQuery += " AND tags LIKE ?"
|
||||
args = append(args, "%"+trimmed+"%")
|
||||
}
|
||||
}
|
||||
|
||||
sqlQuery += " ORDER BY id ASC LIMIT ?"
|
||||
limit := query.Limit
|
||||
if limit <= 0 {
|
||||
limit = 20
|
||||
}
|
||||
args = append(args, limit)
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, sqlQuery, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spells := make([]models.Spell, 0)
|
||||
for rows.Next() {
|
||||
spell, err := scanSpell(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spells = append(spells, spell)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return spells, nil
|
||||
}
|
||||
|
||||
func scanSpell(row scanner) (models.Spell, error) {
|
||||
spell := models.Spell{}
|
||||
tagsString := ""
|
||||
|
||||
if err := row.Scan(&spell.Id, &spell.Name, &spell.Spell, &spell.ShortDesc, &spell.Description, &tagsString); err != nil {
|
||||
return models.Spell{}, err
|
||||
}
|
||||
|
||||
if tagsString != "" {
|
||||
spell.Tags = strings.Split(tagsString, ",")
|
||||
}
|
||||
|
||||
return spell, nil
|
||||
}
|
||||
Reference in new issue
Block a user