feat(uow): added filestore for cross boundary tx
This commit is contained in:
parent
f070674cdb
commit
884e9cd207
6 changed files with 87 additions and 58 deletions
|
|
@ -1,2 +0,0 @@
|
|||
// Package files provides utilities for working with files and directories.
|
||||
package files
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package files
|
||||
|
||||
import "os"
|
||||
|
||||
func WriteToFile(path string, data []byte) (filePath string, err error) {
|
||||
if checkIfFileExists(path) {
|
||||
return path, nil
|
||||
}
|
||||
err = os.WriteFile(path, data, 0o644)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func checkIfFileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
|
@ -2,11 +2,10 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/KristianJBorgwarth/dendrite.daemon/core/frontmatter"
|
||||
"github.com/KristianJBorgwarth/dendrite.daemon/core/template"
|
||||
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
|
||||
)
|
||||
|
||||
|
|
@ -17,55 +16,56 @@ type createNoteCommand struct {
|
|||
Vars map[string]string `json:"vars"`
|
||||
}
|
||||
|
||||
type CreateNoteHandler struct {}
|
||||
type CreateNoteHandler struct {
|
||||
uow *repositories.UnitOfWork
|
||||
}
|
||||
|
||||
func NewCreateNoteHandler(uow *repositories.UnitOfWork) *CreateNoteHandler
|
||||
func NewCreateNoteHandler(uow *repositories.UnitOfWork) *CreateNoteHandler {
|
||||
return &CreateNoteHandler{uow: uow}
|
||||
}
|
||||
|
||||
func (h CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (any, error) {
|
||||
func (h *CreateNoteHandler) Handle(ctx context.Context, raw json.RawMessage) (any, error) {
|
||||
var cmd createNoteCommand
|
||||
|
||||
if err := json.Unmarshal(raw, &cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := h.getTemplate(cmd.TemplatePath)
|
||||
data, err := template.GenerateTemplate(cmd.TemplatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
data = []byte("---\ntitle: " + cmd.Title + "\ntags: []\n---\n")
|
||||
}
|
||||
|
||||
tags, err := frontmatter.ParseTags(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = h.uow.Execute(ctx, func(tx *sql.Tx) error {
|
||||
tagRepo := repositories.NewTagRepository(tx)
|
||||
noteRepo := repositories.NewNoteRepository(tx)
|
||||
|
||||
if err = tagRepo.Upsert(ctx, tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = noteRepo.Upsert(ctx, cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
tx, err := h.uow.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer h.uow.Rollback()
|
||||
|
||||
tagRepo := repositories.NewTagRepository(tx)
|
||||
noteRepo := repositories.NewNoteRepository(tx)
|
||||
|
||||
if err = tagRepo.Upsert(ctx, tags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = noteRepo.Upsert(ctx, cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h.uow.FileStore.Stage(cmd.Path, data)
|
||||
|
||||
if err = h.uow.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cmd.Path, nil
|
||||
}
|
||||
|
||||
func (h *CreateNoteHandler) getTemplate(templatePath string) ([]byte, error) {
|
||||
if templatePath == "" {
|
||||
return nil, nil
|
||||
}
|
||||
data, err := os.ReadFile(templatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/store"
|
||||
)
|
||||
|
||||
type UnitOfWork struct {
|
||||
db *sql.DB
|
||||
Transaction *sql.Tx
|
||||
FileStore *store.FileStore
|
||||
}
|
||||
|
||||
func NewUnitOfWork(db *sql.DB) *UnitOfWork {
|
||||
|
|
@ -30,10 +32,10 @@ func (u *UnitOfWork) Commit() error {
|
|||
return u.Transaction.Commit()
|
||||
}
|
||||
|
||||
func (u *UnitOfWork) Rollback() error {
|
||||
func (u *UnitOfWork) Rollback() {
|
||||
if u.Transaction == nil {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
return u.Transaction.Rollback()
|
||||
u.Transaction.Rollback()
|
||||
u.FileStore.Rollback()
|
||||
}
|
||||
|
||||
|
|
|
|||
2
persistence/store/doc.go
Normal file
2
persistence/store/doc.go
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Package store provides access to any in memory stores related to files and index
|
||||
package store
|
||||
46
persistence/store/file_store.go
Normal file
46
persistence/store/file_store.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package store
|
||||
|
||||
import "os"
|
||||
|
||||
type FileStore struct {
|
||||
staged []stagedFile
|
||||
commited []string
|
||||
}
|
||||
|
||||
type stagedFile struct {
|
||||
path string
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (fs *FileStore) Stage(path string, data []byte) {
|
||||
fs.staged = append(fs.staged, stagedFile{path: path, data: data})
|
||||
}
|
||||
|
||||
func (fs *FileStore) Flush() error {
|
||||
for _, file := range fs.staged {
|
||||
if fs.fileExists(file.path) {
|
||||
continue
|
||||
}
|
||||
if err := os.WriteFile(file.path, file.data, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
fs.commited = append(fs.commited, file.path)
|
||||
}
|
||||
fs.staged = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *FileStore) Rollback() error {
|
||||
for _, path := range fs.commited {
|
||||
if err := os.Remove(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fs.commited = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *FileStore) fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue