owl-blogs/infra/entry_repository.go

162 lines
4.0 KiB
Go
Raw Permalink Normal View History

2023-06-25 18:04:06 +00:00
package infra
import (
"encoding/json"
"errors"
2023-06-25 19:54:04 +00:00
"owl-blogs/app"
2023-06-25 18:04:06 +00:00
"owl-blogs/app/repository"
"owl-blogs/domain/model"
"reflect"
"strings"
"time"
2023-07-06 17:36:24 +00:00
"github.com/google/uuid"
2023-06-25 18:04:06 +00:00
"github.com/jmoiron/sqlx"
_ "github.com/mattn/go-sqlite3"
)
type sqlEntry struct {
Id string `db:"id"`
Type string `db:"type"`
PublishedAt *time.Time `db:"published_at"`
MetaData *string `db:"meta_data"`
2023-07-13 19:55:08 +00:00
AuthorId string `db:"author_id"`
2023-06-25 18:04:06 +00:00
}
type DefaultEntryRepo struct {
2023-06-25 19:54:04 +00:00
typeRegistry *app.EntryTypeRegistry
db *sqlx.DB
2023-06-25 18:04:06 +00:00
}
2023-08-08 18:17:04 +00:00
func NewEntryRepository(db Database, register *app.EntryTypeRegistry) repository.EntryRepository {
sqlxdb := db.Get()
// Create tables if not exists
sqlxdb.MustExec(`
CREATE TABLE IF NOT EXISTS entries (
id TEXT PRIMARY KEY,
type TEXT NOT NULL,
published_at DATETIME,
author_id TEXT NOT NULL,
meta_data TEXT NOT NULL
);
`)
return &DefaultEntryRepo{
db: sqlxdb,
typeRegistry: register,
}
}
2023-06-25 18:04:06 +00:00
// Create implements repository.EntryRepository.
2023-07-09 20:12:06 +00:00
func (r *DefaultEntryRepo) Create(entry model.Entry) error {
2023-06-25 19:54:04 +00:00
t, err := r.typeRegistry.TypeName(entry)
if err != nil {
2023-06-25 18:04:06 +00:00
return errors.New("entry type not registered")
}
var metaDataJson []byte
if entry.MetaData() != nil {
2023-07-09 20:12:06 +00:00
metaDataJson, _ = json.Marshal(entry.MetaData())
2023-06-25 18:04:06 +00:00
}
2023-07-09 20:12:06 +00:00
if entry.ID() == "" {
entry.SetID(uuid.New().String())
}
2023-07-13 19:55:08 +00:00
_, err = r.db.Exec("INSERT INTO entries (id, type, published_at, author_id, meta_data) VALUES (?, ?, ?, ?, ?)", entry.ID(), t, entry.PublishedAt(), entry.AuthorId(), metaDataJson)
2023-06-25 18:04:06 +00:00
return err
}
// Delete implements repository.EntryRepository.
func (r *DefaultEntryRepo) Delete(entry model.Entry) error {
2023-08-09 18:48:16 +00:00
if entry.ID() == "" {
return errors.New("entry not found")
}
2023-06-25 18:04:06 +00:00
_, err := r.db.Exec("DELETE FROM entries WHERE id = ?", entry.ID())
return err
}
// FindAll implements repository.EntryRepository.
func (r *DefaultEntryRepo) FindAll(types *[]string) ([]model.Entry, error) {
filterStr := ""
if types != nil {
filters := []string{}
for _, t := range *types {
filters = append(filters, "type = '"+t+"'")
}
filterStr = strings.Join(filters, " OR ")
}
var entries []sqlEntry
if filterStr != "" {
err := r.db.Select(&entries, "SELECT * FROM entries WHERE "+filterStr)
if err != nil {
return nil, err
}
} else {
err := r.db.Select(&entries, "SELECT * FROM entries")
if err != nil {
return nil, err
}
}
result := []model.Entry{}
for _, entry := range entries {
e, err := r.sqlEntryToEntry(entry)
if err != nil {
return nil, err
}
result = append(result, e)
}
return result, nil
}
// FindById implements repository.EntryRepository.
func (r *DefaultEntryRepo) FindById(id string) (model.Entry, error) {
data := sqlEntry{}
err := r.db.Get(&data, "SELECT * FROM entries WHERE id = ?", id)
if err != nil {
return nil, err
}
if data.Id == "" {
2023-08-08 17:41:07 +00:00
return nil, errors.New("entry not found")
2023-06-25 18:04:06 +00:00
}
return r.sqlEntryToEntry(data)
}
// Update implements repository.EntryRepository.
func (r *DefaultEntryRepo) Update(entry model.Entry) error {
exEntry, _ := r.FindById(entry.ID())
if exEntry == nil {
return errors.New("entry not found")
}
2023-06-25 19:54:04 +00:00
_, err := r.typeRegistry.TypeName(entry)
if err != nil {
2023-06-25 18:04:06 +00:00
return errors.New("entry type not registered")
}
var metaDataJson []byte
if entry.MetaData() != nil {
metaDataJson, _ = json.Marshal(entry.MetaData())
}
2023-07-13 19:55:08 +00:00
_, err = r.db.Exec("UPDATE entries SET published_at = ?, author_id = ?, meta_data = ? WHERE id = ?", entry.PublishedAt(), entry.AuthorId(), metaDataJson, entry.ID())
2023-06-25 18:04:06 +00:00
return err
}
func (r *DefaultEntryRepo) sqlEntryToEntry(entry sqlEntry) (model.Entry, error) {
2023-06-25 19:54:04 +00:00
e, err := r.typeRegistry.Type(entry.Type)
if err != nil {
2023-06-25 18:04:06 +00:00
return nil, errors.New("entry type not registered")
}
metaData := reflect.New(reflect.TypeOf(e.MetaData()).Elem()).Interface().(model.EntryMetaData)
2023-06-25 18:04:06 +00:00
json.Unmarshal([]byte(*entry.MetaData), metaData)
2023-07-08 13:56:42 +00:00
e.SetID(entry.Id)
e.SetPublishedAt(entry.PublishedAt)
e.SetMetaData(metaData)
2023-07-13 19:55:08 +00:00
e.SetAuthorId(entry.AuthorId)
2023-06-25 18:04:06 +00:00
return e, nil
}