Structure was simplified.
This commit is contained in:
parent
fe47f60581
commit
9a93ad9a3a
@ -1,4 +1,4 @@
|
|||||||
justguestbook ver. 1.2.1
|
justguestbook ver. 1.3.0
|
||||||
========================
|
========================
|
||||||
|
|
||||||
A library implementing simple guestbook with replies.
|
A library implementing simple guestbook with replies.
|
@ -1,305 +0,0 @@
|
|||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
_ "embed"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.arav.su/Arav/justguestbook/guestbook"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
//go:embed queries/schema.sql
|
|
||||||
querySchema string
|
|
||||||
|
|
||||||
//go:embed queries/entryGetAll.sql
|
|
||||||
queryGetAll 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 (
|
|
||||||
stmtGetAll *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 {
|
|
||||||
db.Exec("PRAGMA foreign_keys = ON;")
|
|
||||||
|
|
||||||
_, err := db.Exec(querySchema)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to init schema")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtGetAll, err = db.Prepare(queryGetAll)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryGetAll")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtCount, err = db.Prepare(queryCount)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryCount")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtNewEntry, err = db.Prepare(queryNewEntry)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryNewEntry")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtUpdateEntry, err = db.Prepare(queryUpdateEntry)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryUpdateEntry")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtDeleteEntry, err = db.Prepare(queryDeleteEntry)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryDeleteEntry")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtNewReply, err = db.Prepare(queryNewReply)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryNewReply")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtUpdateReply, err = db.Prepare(queryUpdateReply)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryUpdateReply")
|
|
||||||
}
|
|
||||||
|
|
||||||
stmtDeleteReply, err = db.Prepare(queryDeleteReply)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to prepare queryDeleteReply")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SQLiteDatabase struct {
|
|
||||||
db *sql.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(filePath string) (guestbook.Guestbook, 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(stmtGetAll).Query(pageSize, (page-1)*pageSize)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var entry guestbook.Entry
|
|
||||||
var entry_created int64
|
|
||||||
var reply_created int64
|
|
||||||
var reply_message string
|
|
||||||
if err = rows.Scan(
|
|
||||||
&entry.ID, &entry_created, &entry.Name,
|
|
||||||
&entry.Message, &entry.Website, &entry.HideWebsite,
|
|
||||||
&reply_created, &reply_message); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Created = time.Unix(entry_created, 0)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if reply_message != "" {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Reply = &guestbook.Reply{
|
|
||||||
ID: entry.ID,
|
|
||||||
// Created: date,
|
|
||||||
Created: time.Unix(reply_created, 0),
|
|
||||||
Message: reply_message}
|
|
||||||
}
|
|
||||||
|
|
||||||
entries = append(entries, &entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns how much entries are in an `entry` table.
|
|
||||||
func (d *SQLiteDatabase) Count() (count int64, err error) {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
err = tx.Stmt(stmtCount).QueryRow().Scan(&count)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEntry inserts a passed Entry struct and fills its ID field if successful.
|
|
||||||
func (d *SQLiteDatabase) NewEntry(entry *guestbook.Entry) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
r, err := tx.Stmt(stmtNewEntry).Exec(entry.Created.UTC().Unix(), entry.Name, entry.Message,
|
|
||||||
entry.Website, entry.HideWebsite)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.ID, err = r.LastInsertId()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) EditEntry(entry *guestbook.Entry) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
_, err = tx.Stmt(stmtUpdateEntry).Exec(entry.Name, entry.Message, entry.Website, entry.HideWebsite, entry.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) DeleteEntry(entryID int64) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
if _, err = tx.Stmt(stmtDeleteEntry).Exec(entryID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) NewReply(reply *guestbook.Reply) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
_, err = tx.Stmt(stmtNewReply).Exec(reply.ID, reply.Created.UTC().Unix(), reply.Message)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) EditReply(reply *guestbook.Reply) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
_, err = tx.Stmt(stmtUpdateReply).Exec(reply.Message, reply.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) DeleteReply(entryID int64) error {
|
|
||||||
tx, err := d.db.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
if _, err = tx.Stmt(stmtDeleteReply).Exec(entryID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *SQLiteDatabase) Close() error {
|
|
||||||
stmtCount.Close()
|
|
||||||
stmtDeleteEntry.Close()
|
|
||||||
stmtDeleteReply.Close()
|
|
||||||
stmtGetAll.Close()
|
|
||||||
stmtNewEntry.Close()
|
|
||||||
stmtNewReply.Close()
|
|
||||||
stmtUpdateEntry.Close()
|
|
||||||
stmtUpdateReply.Close()
|
|
||||||
|
|
||||||
return d.db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func dsn(filePath string) string {
|
|
||||||
return fmt.Sprintf("file:%s?_journal=WAL&_mutex=full", filePath)
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
INSERT INTO `entry`
|
|
||||||
(`created`, `name`, `message`, `website`, `hide_website`)
|
|
||||||
VALUES
|
|
||||||
(?, ?, ?, ?, ?);
|
|
@ -1,7 +0,0 @@
|
|||||||
UPDATE OR REPLACE `entry`
|
|
||||||
SET
|
|
||||||
`name` = ?,
|
|
||||||
`message` = ?,
|
|
||||||
`website` = ?,
|
|
||||||
`hide_website` = ?
|
|
||||||
WHERE `entry_id` = ?;
|
|
@ -1,4 +0,0 @@
|
|||||||
UPDATE OR REPLACE `reply`
|
|
||||||
SET
|
|
||||||
`message` = ?
|
|
||||||
WHERE `entry_id` = ?;
|
|
@ -1,22 +0,0 @@
|
|||||||
-- SQLite3
|
|
||||||
CREATE TABLE IF NOT EXISTS `entry` (
|
|
||||||
`entry_id` INTEGER NOT NULL,
|
|
||||||
`created` INTEGER NOT NULL,
|
|
||||||
`name` TEXT NOT NULL,
|
|
||||||
`message` TEXT NOT NULL,
|
|
||||||
`website` TEXT NOT NULL,
|
|
||||||
`hide_website` INTEGER NOT NULL DEFAULT TRUE,
|
|
||||||
PRIMARY KEY (`entry_id`) );
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS `entry_created_idx`
|
|
||||||
ON `entry` (`created`);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `reply` (
|
|
||||||
`entry_id` INTEGER NOT NULL,
|
|
||||||
`created` INTEGER NOT NULL,
|
|
||||||
`message` TEXT NOT NULL,
|
|
||||||
PRIMARY KEY (`entry_id`),
|
|
||||||
FOREIGN KEY (`entry_id`)
|
|
||||||
REFERENCES `entry` (`entry_id`)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
ON UPDATE CASCADE );
|
|
304
db_sqlite.go
Normal file
304
db_sqlite.go
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
package guestbook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed sqlite_queries/schema.sql
|
||||||
|
sqlQuerySchema string
|
||||||
|
|
||||||
|
//go:embed sqlite_queries/entryGetAll.sql
|
||||||
|
sqlQueryGetAll string
|
||||||
|
//go:embed sqlite_queries/entryCount.sql
|
||||||
|
sqlQueryCount string
|
||||||
|
|
||||||
|
//go:embed sqlite_queries/entryNew.sql
|
||||||
|
sqlQueryNewEntry string
|
||||||
|
//go:embed sqlite_queries/entryUpdate.sql
|
||||||
|
sqlQueryUpdateEntry string
|
||||||
|
//go:embed sqlite_queries/entryDelete.sql
|
||||||
|
sqlQueryDeleteEntry string
|
||||||
|
//go:embed sqlite_queries/replyNew.sql
|
||||||
|
sqlQueryNewReply string
|
||||||
|
//go:embed sqlite_queries/replyUpdate.sql
|
||||||
|
sqlQueryUpdateReply string
|
||||||
|
//go:embed sqlite_queries/replyDelete.sql
|
||||||
|
sqlQueryDeleteReply string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
sqlStmtGetAll *sql.Stmt
|
||||||
|
sqlStmtCount *sql.Stmt
|
||||||
|
sqlStmtNewEntry *sql.Stmt
|
||||||
|
sqlStmtUpdateEntry *sql.Stmt
|
||||||
|
sqlStmtDeleteEntry *sql.Stmt
|
||||||
|
sqlStmtNewReply *sql.Stmt
|
||||||
|
sqlStmtUpdateReply *sql.Stmt
|
||||||
|
sqlStmtDeleteReply *sql.Stmt
|
||||||
|
)
|
||||||
|
|
||||||
|
func initSQLiteStatements(db *sql.DB) error {
|
||||||
|
db.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
|
||||||
|
_, err := db.Exec(sqlQuerySchema)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to init schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtGetAll, err = db.Prepare(sqlQueryGetAll)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryGetAll")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtCount, err = db.Prepare(sqlQueryCount)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryCount")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtNewEntry, err = db.Prepare(sqlQueryNewEntry)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryNewEntry")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtUpdateEntry, err = db.Prepare(sqlQueryUpdateEntry)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryUpdateEntry")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtDeleteEntry, err = db.Prepare(sqlQueryDeleteEntry)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryDeleteEntry")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtNewReply, err = db.Prepare(sqlQueryNewReply)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryNewReply")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtUpdateReply, err = db.Prepare(sqlQueryUpdateReply)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryUpdateReply")
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlStmtDeleteReply, err = db.Prepare(sqlQueryDeleteReply)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to prepare sqlQueryDeleteReply")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SQLiteDatabase struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSQLiteDB(filePath string) (Guestbook, error) {
|
||||||
|
db, err := sql.Open("sqlite3", sqliteDSN(filePath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := initSQLiteStatements(db); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &SQLiteDatabase{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) Entries(page, pageSize int64) (entries []*Entry, err error) {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
rows, err := tx.Stmt(sqlStmtGetAll).Query(pageSize, (page-1)*pageSize)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var entry Entry
|
||||||
|
var entry_created int64
|
||||||
|
var reply_created int64
|
||||||
|
var reply_message string
|
||||||
|
if err = rows.Scan(
|
||||||
|
&entry.ID, &entry_created, &entry.Name,
|
||||||
|
&entry.Message, &entry.Website, &entry.HideWebsite,
|
||||||
|
&reply_created, &reply_message); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Created = time.Unix(entry_created, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply_message != "" {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Reply = &Reply{
|
||||||
|
ID: entry.ID,
|
||||||
|
// Created: date,
|
||||||
|
Created: time.Unix(reply_created, 0),
|
||||||
|
Message: reply_message}
|
||||||
|
}
|
||||||
|
|
||||||
|
entries = append(entries, &entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns how much entries are in an `entry` table.
|
||||||
|
func (d *SQLiteDatabase) Count() (count int64, err error) {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
err = tx.Stmt(sqlStmtCount).QueryRow().Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEntry inserts a passed Entry struct and fills its ID field if successful.
|
||||||
|
func (d *SQLiteDatabase) NewEntry(entry *Entry) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
r, err := tx.Stmt(sqlStmtNewEntry).Exec(entry.Created.UTC().Unix(), entry.Name, entry.Message,
|
||||||
|
entry.Website, entry.HideWebsite)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.ID, err = r.LastInsertId()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) EditEntry(entry *Entry) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
_, err = tx.Stmt(sqlStmtUpdateEntry).Exec(entry.Name, entry.Message, entry.Website, entry.HideWebsite, entry.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) DeleteEntry(entryID int64) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if _, err = tx.Stmt(sqlStmtDeleteEntry).Exec(entryID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) NewReply(reply *Reply) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
_, err = tx.Stmt(sqlStmtNewReply).Exec(reply.ID, reply.Created.UTC().Unix(), reply.Message)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) EditReply(reply *Reply) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
_, err = tx.Stmt(sqlStmtUpdateReply).Exec(reply.Message, reply.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) DeleteReply(entryID int64) error {
|
||||||
|
tx, err := d.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if _, err = tx.Stmt(sqlStmtDeleteReply).Exec(entryID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *SQLiteDatabase) Close() error {
|
||||||
|
sqlStmtCount.Close()
|
||||||
|
sqlStmtDeleteEntry.Close()
|
||||||
|
sqlStmtDeleteReply.Close()
|
||||||
|
sqlStmtGetAll.Close()
|
||||||
|
sqlStmtNewEntry.Close()
|
||||||
|
sqlStmtNewReply.Close()
|
||||||
|
sqlStmtUpdateEntry.Close()
|
||||||
|
sqlStmtUpdateReply.Close()
|
||||||
|
|
||||||
|
return d.db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sqliteDSN(filePath string) string {
|
||||||
|
return fmt.Sprintf("file:%s?_journal=WAL&_mutex=full", filePath)
|
||||||
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package sqlite_test
|
package guestbook_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.arav.su/Arav/justguestbook/database/sqlite"
|
guestbook "git.arav.su/Arav/justguestbook"
|
||||||
"git.arav.su/Arav/justguestbook/guestbook"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func genTestDB() (db guestbook.Guestbook, err error) {
|
func genTestDB() (db guestbook.Guestbook, err error) {
|
||||||
db, err = sqlite.New(":memory:")
|
db, err = guestbook.NewSQLiteDB(":memory:")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to init DB")
|
return nil, errors.Wrap(err, "failed to init DB")
|
||||||
}
|
}
|
@ -5,6 +5,25 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const DateFormat = "2006-01-02 15:04:05"
|
||||||
|
|
||||||
|
type Reply struct {
|
||||||
|
ID int64 `json:"-"`
|
||||||
|
Created time.Time `json:"created,omitempty"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReply(entryID int64, message string) (*Reply, error) {
|
||||||
|
if message == "" {
|
||||||
|
return nil, errors.New("empty message field")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Reply{
|
||||||
|
ID: entryID,
|
||||||
|
Created: time.Now().UTC(),
|
||||||
|
Message: message}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
ID int64 `json:"entry_id"`
|
ID int64 `json:"entry_id"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
@ -27,3 +46,15 @@ func NewEntry(name, message, website string, hideWebsite bool) (*Entry, error) {
|
|||||||
HideWebsite: hideWebsite,
|
HideWebsite: hideWebsite,
|
||||||
Message: message}, nil
|
Message: message}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Guestbook interface {
|
||||||
|
Entries(page, pageSize int64) ([]*Entry, error)
|
||||||
|
Count() (int64, error)
|
||||||
|
NewEntry(entry *Entry) error
|
||||||
|
EditEntry(entry *Entry) error
|
||||||
|
DeleteEntry(entryID int64) error
|
||||||
|
NewReply(reply *Reply) error
|
||||||
|
EditReply(reply *Reply) error
|
||||||
|
DeleteReply(entryID int64) error
|
||||||
|
Close() error
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
package guestbook
|
|
||||||
|
|
||||||
const DateFormat = "2006-01-02 15:04:05"
|
|
||||||
|
|
||||||
type Guestbook interface {
|
|
||||||
Entries(page, pageSize int64) ([]*Entry, error)
|
|
||||||
Count() (int64, error)
|
|
||||||
NewEntry(entry *Entry) error
|
|
||||||
EditEntry(entry *Entry) error
|
|
||||||
DeleteEntry(entryID int64) error
|
|
||||||
NewReply(reply *Reply) error
|
|
||||||
EditReply(reply *Reply) error
|
|
||||||
DeleteReply(entryID int64) error
|
|
||||||
Close() error
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package guestbook
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Reply struct {
|
|
||||||
ID int64 `json:"-"`
|
|
||||||
Created time.Time `json:"created,omitempty"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewReply(entryID int64, message string) (*Reply, error) {
|
|
||||||
if message == "" {
|
|
||||||
return nil, errors.New("empty reply field")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Reply{
|
|
||||||
ID: entryID,
|
|
||||||
Created: time.Now().UTC(),
|
|
||||||
Message: message}, nil
|
|
||||||
}
|
|
4
sqlite_queries/entryNew.sql
Normal file
4
sqlite_queries/entryNew.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
INSERT INTO `entry`
|
||||||
|
(`created`, `name`, `message`, `website`, `hide_website`)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?);
|
7
sqlite_queries/entryUpdate.sql
Normal file
7
sqlite_queries/entryUpdate.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
UPDATE OR REPLACE `entry`
|
||||||
|
SET
|
||||||
|
`name` = ?,
|
||||||
|
`message` = ?,
|
||||||
|
`website` = ?,
|
||||||
|
`hide_website` = ?
|
||||||
|
WHERE `entry_id` = ?;
|
4
sqlite_queries/replyUpdate.sql
Normal file
4
sqlite_queries/replyUpdate.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE OR REPLACE `reply`
|
||||||
|
SET
|
||||||
|
`message` = ?
|
||||||
|
WHERE `entry_id` = ?;
|
22
sqlite_queries/schema.sql
Normal file
22
sqlite_queries/schema.sql
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-- SQLite3
|
||||||
|
CREATE TABLE IF NOT EXISTS `entry` (
|
||||||
|
`entry_id` INTEGER NOT NULL,
|
||||||
|
`created` INTEGER NOT NULL,
|
||||||
|
`name` TEXT NOT NULL,
|
||||||
|
`message` TEXT NOT NULL,
|
||||||
|
`website` TEXT NOT NULL,
|
||||||
|
`hide_website` INTEGER NOT NULL DEFAULT TRUE,
|
||||||
|
PRIMARY KEY (`entry_id`) );
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS `entry_created_idx`
|
||||||
|
ON `entry` (`created`);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `reply` (
|
||||||
|
`entry_id` INTEGER NOT NULL,
|
||||||
|
`created` INTEGER NOT NULL,
|
||||||
|
`message` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (`entry_id`),
|
||||||
|
FOREIGN KEY (`entry_id`)
|
||||||
|
REFERENCES `entry` (`entry_id`)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
ON UPDATE CASCADE );
|
Loading…
Reference in New Issue
Block a user