1
0
justguestbook/internal/database/sqlite/database.go

289 lines
5.2 KiB
Go

package sqlite
import (
"database/sql"
_ "embed"
"fmt"
"justguestbook/internal/guestbook"
_ "github.com/mattn/go-sqlite3"
)
var (
//go:embed queries/schema.sql
queryCreateDatabase string
//go:embed queries/entryGetAll.sql
queryGetEntries string
//go:embed queries/entryCount.sql
queryCount string
//go:embed queries/entryNew.sql
queryNewEntry string
//go:embed queries/entryUpdate.sql
queryUpdateEntry string
//go:embed queries/entryDelete.sql
queryDeleteEntry string
//go:embed queries/replyNew.sql
queryNewReply string
//go:embed queries/replyUpdate.sql
queryUpdateReply string
//go:embed queries/replyDelete.sql
queryDeleteReply string
)
var (
stmtGetEntries *sql.Stmt
stmtCount *sql.Stmt
stmtNewEntry *sql.Stmt
stmtUpdateEntry *sql.Stmt
stmtDeleteEntry *sql.Stmt
stmtNewReply *sql.Stmt
stmtUpdateReply *sql.Stmt
stmtDeleteReply *sql.Stmt
)
func initDBStatements(db *sql.DB) error {
_, err := db.Exec(queryCreateDatabase)
if err != nil {
return err
}
stmtGetEntries, err = db.Prepare(queryGetEntries)
if err != nil {
return err
}
stmtCount, err = db.Prepare(queryCount)
if err != nil {
return err
}
stmtNewEntry, err = db.Prepare(queryNewEntry)
if err != nil {
return err
}
stmtUpdateEntry, err = db.Prepare(queryUpdateEntry)
if err != nil {
return err
}
stmtDeleteEntry, err = db.Prepare(queryDeleteEntry)
if err != nil {
return err
}
stmtNewReply, err = db.Prepare(queryNewReply)
if err != nil {
return err
}
stmtUpdateReply, err = db.Prepare(queryUpdateReply)
if err != nil {
return err
}
stmtDeleteReply, err = db.Prepare(queryDeleteReply)
if err != nil {
return err
}
return nil
}
type SQLiteDatabase struct {
db *sql.DB
}
func New(filePath string) (*SQLiteDatabase, error) {
db, err := sql.Open("sqlite3", dsn(filePath))
if err != nil {
return nil, err
}
if err := initDBStatements(db); err != nil {
return nil, err
}
return &SQLiteDatabase{db: db}, nil
}
func (d *SQLiteDatabase) Entries(page, pageSize int64) (entries []*guestbook.Entry, err error) {
tx, err := d.db.Begin()
if err != nil {
return
}
defer tx.Rollback()
rows, err := tx.Stmt(stmtGetEntries).Query(pageSize, (page-1)*pageSize)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
var entry guestbook.Entry
var reply_created sql.NullString
var reply_message sql.NullString
if err = rows.Scan(
&entry.ID, &entry.Created, &entry.Name,
&entry.Website, &entry.Message,
&reply_created, &reply_message); err != nil {
return
}
if reply_message.Valid /* reply_created is also valid if reply is */ {
entry.Reply = &guestbook.Reply{
Created: reply_created.String,
Message: reply_message.String}
}
entries = append(entries, &entry)
}
tx.Commit()
return
}
func (d *SQLiteDatabase) Count() (int64, error) {
tx, err := d.db.Begin()
if err != nil {
return -1, err
}
defer tx.Rollback()
var count int64
err = tx.Stmt(stmtCount).QueryRow().Scan(&count)
if err != nil {
return -1, err
}
return count, nil
}
func (d *SQLiteDatabase) NewEntry(entry *guestbook.Entry) error {
tx, err := d.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
_, err = tx.Stmt(stmtNewEntry).Exec(entry.Created, entry.Name, entry.Message,
entry.Website, entry.HideWebsite)
if err != nil {
return err
}
tx.Commit()
return nil
}
func (d *SQLiteDatabase) UpdateEntry(entryID int64, entry *guestbook.Entry) (bool, error) {
tx, err := d.db.Begin()
if err != nil {
return false, err
}
defer tx.Rollback()
res, err := tx.Stmt(stmtUpdateEntry).Exec(entry.ID, entry.Name, entry.Message, entry.Website, entry.HideWebsite, entryID)
if err != nil {
return false, err
}
ra, err := res.RowsAffected()
if err != nil {
return false, err
}
return ra > 0, nil
}
func (d *SQLiteDatabase) DeleteEntry(entryID int64) error {
tx, err := d.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
res, err := tx.Stmt(stmtDeleteEntry).Exec(entryID)
if err != nil {
return err
}
_, err = res.RowsAffected()
if err != nil {
return err
}
return nil
}
func (d *SQLiteDatabase) NewReply(reply *guestbook.Reply) (err error) {
tx, err := d.db.Begin()
if err != nil {
return
}
defer tx.Rollback()
_, err = tx.Stmt(stmtNewReply).Exec(reply.ID, reply.Created, reply.Message)
if err != nil {
return
}
tx.Commit()
return
}
// UpdateEntry
func (d *SQLiteDatabase) UpdateReply(entryID int64, reply *guestbook.Reply) (bool, error) {
tx, err := d.db.Begin()
if err != nil {
return false, err
}
defer tx.Rollback()
res, err := tx.Stmt(stmtUpdateReply).Exec(reply.ID, reply.Created, reply.Message, entryID)
if err != nil {
return false, err
}
ra, err := res.RowsAffected()
if err != nil {
return false, err
}
return ra > 0, nil
}
func (d *SQLiteDatabase) DeleteReply(entryID int64) error {
tx, err := d.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
res, err := tx.Stmt(stmtDeleteReply).Exec(entryID)
if err != nil {
return err
}
_, err = res.RowsAffected()
if err != nil {
return err
}
return nil
}
func (d *SQLiteDatabase) Close() error {
return d.db.Close()
}
func dsn(filePath string) string {
return fmt.Sprintf("file:%s?_journal=WAL&_mutex=full", filePath)
}