v2 #43
|
@ -0,0 +1,22 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"owl-blogs/app/repository"
|
||||
"owl-blogs/domain/model"
|
||||
)
|
||||
|
||||
type BinaryService struct {
|
||||
repo repository.BinaryRepository
|
||||
}
|
||||
|
||||
func NewBinaryFileService(repo repository.BinaryRepository) *BinaryService {
|
||||
return &BinaryService{repo: repo}
|
||||
}
|
||||
|
||||
func (s *BinaryService) Create(name string, file []byte) (*model.BinaryFile, error) {
|
||||
return s.repo.Create(name, file)
|
||||
}
|
||||
|
||||
func (s *BinaryService) FindById(id string) (*model.BinaryFile, error) {
|
||||
return s.repo.FindById(id)
|
||||
}
|
|
@ -47,5 +47,12 @@ func (r *EntryTypeRegistry) Type(name string) (model.Entry, error) {
|
|||
if _, ok := r.types[name]; !ok {
|
||||
return nil, errors.New("entry type not registered")
|
||||
}
|
||||
return r.types[name], nil
|
||||
|
||||
val := reflect.ValueOf(r.types[name])
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = reflect.Indirect(val)
|
||||
}
|
||||
newEntry := reflect.New(val.Type()).Interface().(model.Entry)
|
||||
|
||||
return newEntry, nil
|
||||
}
|
||||
|
|
|
@ -12,3 +12,8 @@ type EntryRepository interface {
|
|||
FindById(id string) (model.Entry, error)
|
||||
FindAll(types *[]string) ([]model.Entry, error)
|
||||
}
|
||||
|
||||
type BinaryRepository interface {
|
||||
Create(name string, data []byte) (*model.BinaryFile, error)
|
||||
FindById(id string) (*model.BinaryFile, error)
|
||||
}
|
||||
|
|
|
@ -14,9 +14,12 @@ func App(db infra.Database) *web.WebApp {
|
|||
|
||||
registry.Register(&model.ImageEntry{})
|
||||
|
||||
repo := infra.NewEntryRepository(db, registry)
|
||||
entryService := app.NewEntryService(repo)
|
||||
return web.NewWebApp(entryService, registry)
|
||||
entryRepo := infra.NewEntryRepository(db, registry)
|
||||
binRepo := infra.NewBinaryFileRepo(db)
|
||||
|
||||
entryService := app.NewEntryService(entryRepo)
|
||||
binaryService := app.NewBinaryFileService(binRepo)
|
||||
return web.NewWebApp(entryService, registry, binaryService)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package model
|
||||
|
||||
type BinaryFile struct {
|
||||
Id string
|
||||
Name string
|
||||
Data []byte
|
||||
}
|
|
@ -9,7 +9,7 @@ type ImageEntry struct {
|
|||
}
|
||||
|
||||
type ImageEntryMetaData struct {
|
||||
ImagePath string `owl:"inputType=file"`
|
||||
ImageId string `owl:"inputType=file"`
|
||||
Content string `owl:"inputType=text widget=textarea"`
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package infra
|
||||
|
||||
import (
|
||||
"owl-blogs/domain/model"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type sqlBinaryFile struct {
|
||||
Id string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Data []byte `db:"data"`
|
||||
}
|
||||
|
||||
type DefaultBinaryFileRepo struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func NewBinaryFileRepo(db Database) *DefaultBinaryFileRepo {
|
||||
sqlxdb := db.Get()
|
||||
|
||||
// Create table if not exists
|
||||
sqlxdb.MustExec(`
|
||||
CREATE TABLE IF NOT EXISTS binary_files (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
data BLOB NOT NULL
|
||||
);
|
||||
`)
|
||||
|
||||
return &DefaultBinaryFileRepo{db: sqlxdb}
|
||||
}
|
||||
|
||||
func (repo *DefaultBinaryFileRepo) Create(name string, data []byte) (*model.BinaryFile, error) {
|
||||
id := uuid.New().String()
|
||||
_, err := repo.db.Exec("INSERT INTO binary_files (id, name, data) VALUES (?, ?, ?)", id, name, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.BinaryFile{Id: id, Name: name, Data: data}, nil
|
||||
}
|
||||
|
||||
func (repo *DefaultBinaryFileRepo) FindById(id string) (*model.BinaryFile, error) {
|
||||
var sqlFile sqlBinaryFile
|
||||
err := repo.db.Get(&sqlFile, "SELECT * FROM binary_files WHERE id = ?", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.BinaryFile{Id: sqlFile.Id, Name: sqlFile.Name, Data: sqlFile.Data}, nil
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package infra_test
|
||||
|
||||
import (
|
||||
"owl-blogs/app/repository"
|
||||
"owl-blogs/infra"
|
||||
"owl-blogs/test"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func setupBinaryRepo() repository.BinaryRepository {
|
||||
db := test.NewMockDb()
|
||||
repo := infra.NewBinaryFileRepo(db)
|
||||
return repo
|
||||
}
|
||||
|
||||
func TestBinaryRepoCreate(t *testing.T) {
|
||||
repo := setupBinaryRepo()
|
||||
|
||||
file, err := repo.Create("name", []byte("😀 😃 😄 😁"))
|
||||
require.NoError(t, err)
|
||||
|
||||
file, err = repo.FindById(file.Id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, file.Name, "name")
|
||||
require.Equal(t, file.Data, []byte("😀 😃 😄 😁"))
|
||||
}
|
||||
|
||||
func TestBinaryRepoNoSideEffect(t *testing.T) {
|
||||
repo := setupBinaryRepo()
|
||||
|
||||
file, err := repo.Create("name1", []byte("111"))
|
||||
require.NoError(t, err)
|
||||
|
||||
file2, err := repo.Create("name2", []byte("222"))
|
||||
require.NoError(t, err)
|
||||
|
||||
file, err = repo.FindById(file.Id)
|
||||
require.NoError(t, err)
|
||||
file2, err = repo.FindById(file2.Id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, file.Name, "name1")
|
||||
require.Equal(t, file.Data, []byte("111"))
|
||||
require.Equal(t, file2.Name, "name2")
|
||||
require.Equal(t, file2.Data, []byte("222"))
|
||||
}
|
|
@ -131,3 +131,39 @@ func TestRepoUpdate(t *testing.T) {
|
|||
require.Equal(t, meta.Number, meta2.Number)
|
||||
require.Equal(t, meta.Date.Unix(), meta2.Date.Unix())
|
||||
}
|
||||
|
||||
func TestRepoNoSideEffect(t *testing.T) {
|
||||
repo := setupRepo()
|
||||
|
||||
entry1 := &test.MockEntry{}
|
||||
now1 := time.Now()
|
||||
err := repo.Create(entry1, &now1, &test.MockEntryMetaData{
|
||||
Str: "1",
|
||||
Number: 1,
|
||||
Date: now1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
entry2 := &test.MockEntry{}
|
||||
now2 := time.Now()
|
||||
err = repo.Create(entry2, &now2, &test.MockEntryMetaData{
|
||||
Str: "2",
|
||||
Number: 2,
|
||||
Date: now2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
r1, err := repo.FindById(entry1.ID())
|
||||
require.NoError(t, err)
|
||||
r2, err := repo.FindById(entry2.ID())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Str, "1")
|
||||
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Number, 1)
|
||||
require.Equal(t, r1.MetaData().(*test.MockEntryMetaData).Date.Unix(), now1.Unix())
|
||||
|
||||
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Str, "2")
|
||||
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Number, 2)
|
||||
require.Equal(t, r2.MetaData().(*test.MockEntryMetaData).Date.Unix(), now2.Unix())
|
||||
|
||||
}
|
||||
|
|
10
web/app.go
10
web/app.go
|
@ -9,10 +9,11 @@ import (
|
|||
type WebApp struct {
|
||||
FiberApp *fiber.App
|
||||
EntryService *app.EntryService
|
||||
BinaryService *app.BinaryService
|
||||
Registry *app.EntryTypeRegistry
|
||||
}
|
||||
|
||||
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry) *WebApp {
|
||||
func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegistry, binService *app.BinaryService) *WebApp {
|
||||
app := fiber.New()
|
||||
|
||||
indexHandler := NewIndexHandler(entryService)
|
||||
|
@ -51,7 +52,12 @@ func NewWebApp(entryService *app.EntryService, typeRegistry *app.EntryTypeRegist
|
|||
// app.Post("/auth/token/", userAuthTokenHandler(repo))
|
||||
// app.Get("/.well-known/oauth-authorization-server", userAuthMetadataHandler(repo))
|
||||
// app.NotFound = http.HandlerFunc(notFoundHandler(repo))
|
||||
return &WebApp{FiberApp: app, EntryService: entryService, Registry: typeRegistry}
|
||||
return &WebApp{
|
||||
FiberApp: app,
|
||||
EntryService: entryService,
|
||||
Registry: typeRegistry,
|
||||
BinaryService: binService,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebApp) Run() {
|
||||
|
|
Loading…
Reference in New Issue