From 884e9cd207f026d96526c04fa1195d4b50966389 Mon Sep 17 00:00:00 2001 From: Kristian Borgwarth <10348902@pm.me> Date: Thu, 2 Apr 2026 17:56:35 +0200 Subject: [PATCH] feat(uow): added filestore for cross boundary tx --- core/files/doc.go | 2 - core/files/file_handler.go | 19 --------- core/handlers/create_note_handler.go | 64 ++++++++++++++-------------- persistence/repositories/uow.go | 12 +++--- persistence/store/doc.go | 2 + persistence/store/file_store.go | 46 ++++++++++++++++++++ 6 files changed, 87 insertions(+), 58 deletions(-) delete mode 100644 core/files/doc.go delete mode 100644 core/files/file_handler.go create mode 100644 persistence/store/doc.go create mode 100644 persistence/store/file_store.go diff --git a/core/files/doc.go b/core/files/doc.go deleted file mode 100644 index a4727ba..0000000 --- a/core/files/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package files provides utilities for working with files and directories. -package files diff --git a/core/files/file_handler.go b/core/files/file_handler.go deleted file mode 100644 index 3ba059b..0000000 --- a/core/files/file_handler.go +++ /dev/null @@ -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 -} diff --git a/core/handlers/create_note_handler.go b/core/handlers/create_note_handler.go index 81a443d..4225430 100644 --- a/core/handlers/create_note_handler.go +++ b/core/handlers/create_note_handler.go @@ -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 -} diff --git a/persistence/repositories/uow.go b/persistence/repositories/uow.go index cbec578..ff98c6b 100644 --- a/persistence/repositories/uow.go +++ b/persistence/repositories/uow.go @@ -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() } - diff --git a/persistence/store/doc.go b/persistence/store/doc.go new file mode 100644 index 0000000..a60b605 --- /dev/null +++ b/persistence/store/doc.go @@ -0,0 +1,2 @@ +// Package store provides access to any in memory stores related to files and index +package store diff --git a/persistence/store/file_store.go b/persistence/store/file_store.go new file mode 100644 index 0000000..9f77bc3 --- /dev/null +++ b/persistence/store/file_store.go @@ -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 +}