feat(rebuild_guard): only build index on init if empty index (#30)

* feat(persistence): added build-flag and repo funcs

* feat(init_handler): note count check to avoid unnecessary rebuilds

* ref(build_flag): remove build flag is redundant

* build
This commit is contained in:
Kristian 2026-04-23 20:38:37 +02:00 committed by GitHub
parent 478f309108
commit c1feac0812
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 62 additions and 30 deletions

View file

@ -20,16 +20,18 @@ func main() {
server := server.NewServer()
uow := repositories.NewUnitOfWork();
indexRepo := repositories.NewIndexRepository()
indexRepo := repositories.NewIndexRepository(*persistence.NewReadContext())
linkRepo := repositories.NewLinkRepository(*persistence.NewReadContext())
tagRepo := repositories.NewTagRepository()
noteRepo := repositories.NewNoteRepository(*persistence.NewReadContext())
tagService := services.NewTagService(tagRepo)
linkService := services.NewLinkService(linkRepo)
noteService := services.NewNoteService(tagRepo, linkRepo, noteRepo)
idxr := services.NewIndexRebuilder(uow, noteRepo, linkRepo, tagRepo, indexRepo )
server.RegisterHandler("vault/init", vault.NewInitializeHandler(idxr))
server.RegisterHandler("vault/init", vault.NewInitializeHandler(idxr, noteService))
server.RegisterHandler("note/create", note.NewCreateNoteHandler(uow, tagService, noteRepo))
server.RegisterHandler("note/save", note.NewSaveNoteHandler(uow, noteRepo, tagService, noteService, linkService))
server.RegisterHandler("note/goto", note.NewGotoNoteHandler(noteRepo))

View file

@ -3,6 +3,7 @@ package vault
import (
"context"
"encoding/json"
"log/slog"
"github.com/KristianJBorgwarth/dendrite.daemon/core/services"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence"
@ -17,10 +18,11 @@ type initializeCommand struct {
type InitializeHandler struct {
idxRebuilder services.IIndexRebuilder
noteService services.INoteService
}
func NewInitializeHandler(idxR services.IIndexRebuilder) *InitializeHandler {
return &InitializeHandler{idxRebuilder: idxR}
func NewInitializeHandler(idxR services.IIndexRebuilder, nsv services.INoteService) *InitializeHandler {
return &InitializeHandler{idxRebuilder: idxR, noteService: nsv}
}
func (h InitializeHandler) Handle(ctx context.Context, raw json.RawMessage) (any, error) {
@ -37,7 +39,18 @@ func (h InitializeHandler) Handle(ctx context.Context, raw json.RawMessage) (any
return nil, err
}
if err = h.idxRebuilder.RebuildIndex(ctx, cmd.VaultPath); err != nil {
noteCount, err := h.noteService.GetNoteCount(ctx)
if err != nil {
return nil, err
}
if noteCount > 0 {
slog.Debug("Vault already initialized, skipping index rebuild")
return nil, nil
}
err = h.idxRebuilder.RebuildIndex(ctx, cmd.VaultPath)
if err != nil {
return nil, err
}

View file

@ -34,39 +34,36 @@ func NewIndexRebuilder(
indexRepo repositories.IIndexRepository,
) *indexRebuilder {
return &indexRebuilder{
uow: uow,
noteRepo: noteRepo,
linkRepo: linkRepo,
tagRepo: tagRepo,
uow: uow,
noteRepo: noteRepo,
linkRepo: linkRepo,
tagRepo: tagRepo,
indexRepo: indexRepo,
}
}
func (r *indexRebuilder) RebuildIndex(ctx context.Context, vaultRoot string) error {
files, err := r.readFiles(vaultRoot)
if err != nil {
slog.Debug("Failed to read files from vault", "vaultRoot", vaultRoot, "error", err)
return err
}
slog.Debug("Successfully read files from vault", "vaultRoot", vaultRoot, "fileCount", len(files))
notes, links, tags, noteTags := r.buildDBModels(files)
dbctx, err := r.uow.Begin()
if err != nil {
return err
}
files, err := r.readFiles(vaultRoot)
if err != nil {
return err
}
notes, links, tags, noteTags := r.buildDBModels(files)
if err = r.indexRepo.WipeIndex(ctx, dbctx); err != nil {
r.uow.Rollback()
slog.Debug("Failed to wipe index, rolling back transaction", "error", err)
return err
}
if err = r.buildIndex(ctx, dbctx, notes, links, tags, noteTags); err != nil {
r.uow.Rollback()
slog.Debug("Failed to build index, rolling back transaction", "error", err)
return err
}
if err = r.uow.Commit(); err != nil {
return err
}
@ -110,7 +107,7 @@ func (r *indexRebuilder) readFiles(vault string) ([]*filehandling.File, error) {
slog.Debug("Processing file during index rebuild", "path", path)
if d.IsDir() {
if !r.shouldIndexDirectory(path) {
if !r.IsValidDirectory(path) {
slog.Debug("Skipping directory during index rebuild", "path", path)
return filepath.SkipDir
}
@ -138,7 +135,7 @@ func (r *indexRebuilder) readFiles(vault string) ([]*filehandling.File, error) {
return files, nil
}
func (r *indexRebuilder) shouldIndexDirectory(path string) bool {
func (r *indexRebuilder) IsValidDirectory(path string) bool {
ignoredDirs := []string{".git", ".templates", "temp", "issues"}
for part := range strings.SplitSeq(path, string(filepath.Separator)) {
if slices.Contains(ignoredDirs, part) {

View file

@ -12,6 +12,7 @@ type INoteService interface {
CreateNote(ctx context.Context, dbCtx persistence.IDbContext, path, title, slug string) (*models.Note, error)
DeleteNoteMetaData(ctx context.Context, dbCtx persistence.IDbContext, noteID string) error
UpdateNote(ctx context.Context, dbCtx persistence.IDbContext, noteID, path, title, slug string) error
GetNoteCount(ctx context.Context) (int, error)
}
type noteService struct {
@ -55,3 +56,7 @@ func (s *noteService) DeleteNoteMetaData(ctx context.Context, dbCtx persistence.
return nil
}
func (s *noteService) GetNoteCount(ctx context.Context) (int, error) {
return s.noteRepo.GetNoteCount(ctx)
}

BIN
dendrite

Binary file not shown.

View file

@ -10,11 +10,12 @@ type IIndexRepository interface {
WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error
}
type indexRepository struct{
type indexRepository struct {
readDBContext persistence.ReadContext
}
func NewIndexRepository() IIndexRepository {
return &indexRepository{}
func NewIndexRepository(rdb persistence.ReadContext) IIndexRepository {
return &indexRepository{readDBContext: rdb}
}
func (r *indexRepository) WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error {

View file

@ -14,14 +14,15 @@ type INoteRepository interface {
InsertRange(ctx context.Context, dbContext persistence.IDbContext, note []*models.Note) error
Update(ctx context.Context, dbContext persistence.IDbContext, noteID, path, title, slug string) error
GetBySlug(ctx context.Context, slug string) (*models.Note, error)
GetNoteCount(ctx context.Context) (int, error)
}
type noteRepository struct {
readDBContext persistence.ReadContext
}
func NewNoteRepository(persistence.ReadContext) INoteRepository {
return &noteRepository{}
func NewNoteRepository(rdb persistence.ReadContext) INoteRepository {
return &noteRepository{readDBContext: rdb}
}
func (r *noteRepository) Insert(ctx context.Context, dbContext persistence.IDbContext, note *models.Note) error {
@ -82,3 +83,16 @@ func (r *noteRepository) GetBySlug(ctx context.Context, slug string) (*models.No
return models.NewNote(id, path, title, slug, createdAt, updatedAt), nil
}
func (r *noteRepository) GetNoteCount(ctx context.Context) (int, error) {
query := `SELECT COUNT(*) FROM note`
row := r.readDBContext.QueryRowContext(ctx, query)
var count int
err := row.Scan(&count)
if err != nil {
return 0, err
}
return count, nil
}