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:
parent
478f309108
commit
c1feac0812
7 changed files with 62 additions and 30 deletions
|
|
@ -20,16 +20,18 @@ func main() {
|
||||||
server := server.NewServer()
|
server := server.NewServer()
|
||||||
|
|
||||||
uow := repositories.NewUnitOfWork();
|
uow := repositories.NewUnitOfWork();
|
||||||
indexRepo := repositories.NewIndexRepository()
|
|
||||||
|
indexRepo := repositories.NewIndexRepository(*persistence.NewReadContext())
|
||||||
linkRepo := repositories.NewLinkRepository(*persistence.NewReadContext())
|
linkRepo := repositories.NewLinkRepository(*persistence.NewReadContext())
|
||||||
tagRepo := repositories.NewTagRepository()
|
tagRepo := repositories.NewTagRepository()
|
||||||
noteRepo := repositories.NewNoteRepository(*persistence.NewReadContext())
|
noteRepo := repositories.NewNoteRepository(*persistence.NewReadContext())
|
||||||
|
|
||||||
tagService := services.NewTagService(tagRepo)
|
tagService := services.NewTagService(tagRepo)
|
||||||
linkService := services.NewLinkService(linkRepo)
|
linkService := services.NewLinkService(linkRepo)
|
||||||
noteService := services.NewNoteService(tagRepo, linkRepo, noteRepo)
|
noteService := services.NewNoteService(tagRepo, linkRepo, noteRepo)
|
||||||
idxr := services.NewIndexRebuilder(uow, noteRepo, linkRepo, tagRepo, indexRepo )
|
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/create", note.NewCreateNoteHandler(uow, tagService, noteRepo))
|
||||||
server.RegisterHandler("note/save", note.NewSaveNoteHandler(uow, noteRepo, tagService, noteService, linkService))
|
server.RegisterHandler("note/save", note.NewSaveNoteHandler(uow, noteRepo, tagService, noteService, linkService))
|
||||||
server.RegisterHandler("note/goto", note.NewGotoNoteHandler(noteRepo))
|
server.RegisterHandler("note/goto", note.NewGotoNoteHandler(noteRepo))
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package vault
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/KristianJBorgwarth/dendrite.daemon/core/services"
|
"github.com/KristianJBorgwarth/dendrite.daemon/core/services"
|
||||||
"github.com/KristianJBorgwarth/dendrite.daemon/persistence"
|
"github.com/KristianJBorgwarth/dendrite.daemon/persistence"
|
||||||
|
|
@ -17,10 +18,11 @@ type initializeCommand struct {
|
||||||
|
|
||||||
type InitializeHandler struct {
|
type InitializeHandler struct {
|
||||||
idxRebuilder services.IIndexRebuilder
|
idxRebuilder services.IIndexRebuilder
|
||||||
|
noteService services.INoteService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInitializeHandler(idxR services.IIndexRebuilder) *InitializeHandler {
|
func NewInitializeHandler(idxR services.IIndexRebuilder, nsv services.INoteService) *InitializeHandler {
|
||||||
return &InitializeHandler{idxRebuilder: idxR}
|
return &InitializeHandler{idxRebuilder: idxR, noteService: nsv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h InitializeHandler) Handle(ctx context.Context, raw json.RawMessage) (any, error) {
|
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
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,30 +43,27 @@ func NewIndexRebuilder(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexRebuilder) RebuildIndex(ctx context.Context, vaultRoot string) error {
|
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()
|
dbctx, err := r.uow.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = r.buildIndex(ctx, dbctx, notes, links, tags, noteTags); err != nil {
|
if err = r.buildIndex(ctx, dbctx, notes, links, tags, noteTags); err != nil {
|
||||||
r.uow.Rollback()
|
return err
|
||||||
slog.Debug("Failed to build index, rolling back transaction", "error", err)
|
}
|
||||||
|
|
||||||
|
if err = r.uow.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,7 +107,7 @@ func (r *indexRebuilder) readFiles(vault string) ([]*filehandling.File, error) {
|
||||||
slog.Debug("Processing file during index rebuild", "path", path)
|
slog.Debug("Processing file during index rebuild", "path", path)
|
||||||
|
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
if !r.shouldIndexDirectory(path) {
|
if !r.IsValidDirectory(path) {
|
||||||
slog.Debug("Skipping directory during index rebuild", "path", path)
|
slog.Debug("Skipping directory during index rebuild", "path", path)
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +135,7 @@ func (r *indexRebuilder) readFiles(vault string) ([]*filehandling.File, error) {
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexRebuilder) shouldIndexDirectory(path string) bool {
|
func (r *indexRebuilder) IsValidDirectory(path string) bool {
|
||||||
ignoredDirs := []string{".git", ".templates", "temp", "issues"}
|
ignoredDirs := []string{".git", ".templates", "temp", "issues"}
|
||||||
for part := range strings.SplitSeq(path, string(filepath.Separator)) {
|
for part := range strings.SplitSeq(path, string(filepath.Separator)) {
|
||||||
if slices.Contains(ignoredDirs, part) {
|
if slices.Contains(ignoredDirs, part) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ type INoteService interface {
|
||||||
CreateNote(ctx context.Context, dbCtx persistence.IDbContext, path, title, slug string) (*models.Note, error)
|
CreateNote(ctx context.Context, dbCtx persistence.IDbContext, path, title, slug string) (*models.Note, error)
|
||||||
DeleteNoteMetaData(ctx context.Context, dbCtx persistence.IDbContext, noteID string) error
|
DeleteNoteMetaData(ctx context.Context, dbCtx persistence.IDbContext, noteID string) error
|
||||||
UpdateNote(ctx context.Context, dbCtx persistence.IDbContext, noteID, path, title, slug string) error
|
UpdateNote(ctx context.Context, dbCtx persistence.IDbContext, noteID, path, title, slug string) error
|
||||||
|
GetNoteCount(ctx context.Context) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type noteService struct {
|
type noteService struct {
|
||||||
|
|
@ -55,3 +56,7 @@ func (s *noteService) DeleteNoteMetaData(ctx context.Context, dbCtx persistence.
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *noteService) GetNoteCount(ctx context.Context) (int, error) {
|
||||||
|
return s.noteRepo.GetNoteCount(ctx)
|
||||||
|
}
|
||||||
|
|
|
||||||
BIN
dendrite
BIN
dendrite
Binary file not shown.
|
|
@ -10,11 +10,12 @@ type IIndexRepository interface {
|
||||||
WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error
|
WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexRepository struct{
|
type indexRepository struct {
|
||||||
|
readDBContext persistence.ReadContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIndexRepository() IIndexRepository {
|
func NewIndexRepository(rdb persistence.ReadContext) IIndexRepository {
|
||||||
return &indexRepository{}
|
return &indexRepository{readDBContext: rdb}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *indexRepository) WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error {
|
func (r *indexRepository) WipeIndex(ctx context.Context, dbContext persistence.IDbContext) error {
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,15 @@ type INoteRepository interface {
|
||||||
InsertRange(ctx context.Context, dbContext persistence.IDbContext, note []*models.Note) error
|
InsertRange(ctx context.Context, dbContext persistence.IDbContext, note []*models.Note) error
|
||||||
Update(ctx context.Context, dbContext persistence.IDbContext, noteID, path, title, slug string) error
|
Update(ctx context.Context, dbContext persistence.IDbContext, noteID, path, title, slug string) error
|
||||||
GetBySlug(ctx context.Context, slug string) (*models.Note, error)
|
GetBySlug(ctx context.Context, slug string) (*models.Note, error)
|
||||||
|
GetNoteCount(ctx context.Context) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type noteRepository struct {
|
type noteRepository struct {
|
||||||
readDBContext persistence.ReadContext
|
readDBContext persistence.ReadContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNoteRepository(persistence.ReadContext) INoteRepository {
|
func NewNoteRepository(rdb persistence.ReadContext) INoteRepository {
|
||||||
return ¬eRepository{}
|
return ¬eRepository{readDBContext: rdb}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *noteRepository) Insert(ctx context.Context, dbContext persistence.IDbContext, note *models.Note) error {
|
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
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue