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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/KristianJBorgwarth/dendrite.daemon/core/frontmatter"
|
"github.com/KristianJBorgwarth/dendrite.daemon/core/frontmatter"
|
||||||
|
"github.com/KristianJBorgwarth/dendrite.daemon/core/template"
|
||||||
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
|
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -17,55 +16,56 @@ type createNoteCommand struct {
|
||||||
Vars map[string]string `json:"vars"`
|
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
|
var cmd createNoteCommand
|
||||||
|
|
||||||
if err := json.Unmarshal(raw, &cmd); err != nil {
|
if err := json.Unmarshal(raw, &cmd); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := h.getTemplate(cmd.TemplatePath)
|
data, err := template.GenerateTemplate(cmd.TemplatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if data == nil {
|
||||||
|
data = []byte("---\ntitle: " + cmd.Title + "\ntags: []\n---\n")
|
||||||
|
}
|
||||||
|
|
||||||
tags, err := frontmatter.ParseTags(data)
|
tags, err := frontmatter.ParseTags(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.uow.Execute(ctx, func(tx *sql.Tx) error {
|
tx, err := h.uow.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer h.uow.Rollback()
|
||||||
|
|
||||||
tagRepo := repositories.NewTagRepository(tx)
|
tagRepo := repositories.NewTagRepository(tx)
|
||||||
noteRepo := repositories.NewNoteRepository(tx)
|
noteRepo := repositories.NewNoteRepository(tx)
|
||||||
|
|
||||||
if err = tagRepo.Upsert(ctx, tags); err != nil {
|
if err = tagRepo.Upsert(ctx, tags); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = noteRepo.Upsert(ctx, cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title)); err != nil {
|
if err = noteRepo.Upsert(ctx, cmd.Title, cmd.Path, frontmatter.Slugify(cmd.Title)); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
h.uow.FileStore.Stage(cmd.Path, data)
|
||||||
})
|
|
||||||
if err != nil {
|
if err = h.uow.Commit(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd.Path, nil
|
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
|
package repositories
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UnitOfWork struct {
|
type UnitOfWork struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
Transaction *sql.Tx
|
Transaction *sql.Tx
|
||||||
|
FileStore *store.FileStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUnitOfWork(db *sql.DB) *UnitOfWork {
|
func NewUnitOfWork(db *sql.DB) *UnitOfWork {
|
||||||
|
|
@ -30,10 +32,10 @@ func (u *UnitOfWork) Commit() error {
|
||||||
return u.Transaction.Commit()
|
return u.Transaction.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UnitOfWork) Rollback() error {
|
func (u *UnitOfWork) Rollback() {
|
||||||
if u.Transaction == nil {
|
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