rum-goggles/v1/internal/models/chatbot.go

314 lines
5.7 KiB
Go
Raw Normal View History

2024-05-02 19:30:25 +00:00
package models
import (
"database/sql"
"fmt"
)
const (
chatbotColumns = "id, name, url"
chatbotTable = "chatbot"
)
type Chatbot struct {
ID *int64 `json:"id"`
Name *string `json:"name"`
Url *string `json:"url"`
}
func (c *Chatbot) values() []any {
return []any{c.ID, c.Name, c.Url}
}
func (c *Chatbot) valuesNoID() []any {
return c.values()[1:]
}
func (c *Chatbot) valuesEndID() []any {
vals := c.values()
return append(vals[1:], vals[0])
}
type sqlChatbot struct {
id sql.NullInt64
name sql.NullString
url sql.NullString
}
func (sc *sqlChatbot) scan(r Row) error {
return r.Scan(&sc.id, &sc.name, &sc.url)
}
func (sc sqlChatbot) toChatbot() *Chatbot {
var c Chatbot
c.ID = toInt64(sc.id)
c.Name = toString(sc.name)
c.Url = toString(sc.url)
return &c
}
type ChatbotService interface {
All() ([]Chatbot, error)
AutoMigrate() error
ByID(id int64) (*Chatbot, error)
ByName(name string) (*Chatbot, error)
Create(c *Chatbot) (int64, error)
Delete(c *Chatbot) error
DestructiveReset() error
Update(c *Chatbot) error
}
func NewChatbotService(db *sql.DB) ChatbotService {
return &chatbotService{
Database: db,
}
}
var _ ChatbotService = &chatbotService{}
type chatbotService struct {
Database *sql.DB
}
func (cs *chatbotService) All() ([]Chatbot, error) {
selectQ := fmt.Sprintf(`
SELECT %s
FROM "%s"
`, chatbotColumns, chatbotTable)
rows, err := cs.Database.Query(selectQ)
if err != nil {
return nil, pkgErr("error executing select query", err)
}
defer rows.Close()
chatbots := []Chatbot{}
for rows.Next() {
sc := &sqlChatbot{}
err = sc.scan(rows)
if err != nil {
return nil, pkgErr("error scanning row", err)
}
chatbots = append(chatbots, *sc.toChatbot())
}
err = rows.Err()
if err != nil && err != sql.ErrNoRows {
return nil, pkgErr("error iterating over rows", err)
}
return chatbots, nil
}
func (cs *chatbotService) AutoMigrate() error {
err := cs.createChatbotTable()
if err != nil {
return pkgErr(fmt.Sprintf("error creating %s table", chatbotTable), err)
}
return nil
}
func (cs *chatbotService) createChatbotTable() error {
createQ := fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS "%s" (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
url TEXT
)
`, chatbotTable)
_, err := cs.Database.Exec(createQ)
if err != nil {
return fmt.Errorf("error executing create query: %v", err)
}
return nil
}
func (cs *chatbotService) ByID(id int64) (*Chatbot, error) {
err := runChatbotValFuncs(
&Chatbot{ID: &id},
chatbotRequireID,
)
if err != nil {
return nil, pkgErr("", err)
}
selectQ := fmt.Sprintf(`
SELECT %s
FROM "%s"
WHERE id=?
`, chatbotColumns, chatbotTable)
var sc sqlChatbot
row := cs.Database.QueryRow(selectQ, id)
err = sc.scan(row)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, pkgErr("error executing select query", err)
}
return sc.toChatbot(), nil
}
func (cs *chatbotService) ByName(name string) (*Chatbot, error) {
err := runChatbotValFuncs(
&Chatbot{Name: &name},
chatbotRequireName,
)
if err != nil {
return nil, pkgErr("", err)
}
selectQ := fmt.Sprintf(`
SELECT %s
FROM "%s"
WHERE name=?
`, chatbotColumns, chatbotTable)
var sc sqlChatbot
row := cs.Database.QueryRow(selectQ, name)
err = sc.scan(row)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, pkgErr("error executing select query", err)
}
return sc.toChatbot(), nil
}
func (cs *chatbotService) Create(c *Chatbot) (int64, error) {
err := runChatbotValFuncs(
c,
chatbotRequireName,
)
if err != nil {
return -1, pkgErr("invalid chatbot", err)
}
columns := columnsNoID(chatbotColumns)
insertQ := fmt.Sprintf(`
INSERT INTO "%s" (%s)
VALUES (%s)
RETURNING id
`, chatbotTable, columns, values(columns))
var id int64
row := cs.Database.QueryRow(insertQ, c.valuesNoID()...)
err = row.Scan(&id)
if err != nil {
return -1, pkgErr("error executing insert query", err)
}
return id, nil
}
func (cs *chatbotService) Delete(c *Chatbot) error {
err := runChatbotValFuncs(
c,
chatbotRequireID,
)
if err != nil {
return pkgErr("invalid chatbot", err)
}
deleteQ := fmt.Sprintf(`
DELETE FROM "%s"
WHERE id=?
`, chatbotTable)
_, err = cs.Database.Exec(deleteQ, c.ID)
if err != nil {
return pkgErr("error executing delete query", err)
}
return nil
}
func (cs *chatbotService) DestructiveReset() error {
err := cs.dropChatbotTable()
if err != nil {
return pkgErr(fmt.Sprintf("error dropping %s table", chatbotTable), err)
}
return nil
}
func (cs *chatbotService) dropChatbotTable() error {
dropQ := fmt.Sprintf(`
DROP TABLE IF EXISTS "%s"
`, chatbotTable)
_, err := cs.Database.Exec(dropQ)
if err != nil {
return fmt.Errorf("error executing drop query: %v", err)
}
return nil
}
func (cs *chatbotService) Update(c *Chatbot) error {
err := runChatbotValFuncs(
c,
chatbotRequireID,
chatbotRequireName,
)
if err != nil {
return pkgErr("invalid chatbot", err)
}
columns := columnsNoID(chatbotColumns)
updateQ := fmt.Sprintf(`
UPDATE "%s"
SET %s
WHERE id=?
`, chatbotTable, set(columns))
_, err = cs.Database.Exec(updateQ, c.valuesEndID()...)
if err != nil {
return pkgErr("error executing update query", err)
}
return nil
}
type chatbotValFunc func(*Chatbot) error
func runChatbotValFuncs(c *Chatbot, fns ...chatbotValFunc) error {
if c == nil {
return fmt.Errorf("chatbot is nil")
}
for _, fn := range fns {
err := fn(c)
if err != nil {
return err
}
}
return nil
}
func chatbotRequireID(c *Chatbot) error {
if c.ID == nil || *c.ID < 1 {
return ErrChatbotInvalidID
}
return nil
}
func chatbotRequireName(c *Chatbot) error {
if c.Name == nil || *c.Name == "" {
return ErrChatbotInvalidName
}
return nil
}