feat(completion/tag): support for tag completion (#32)

* setup tag complete handler

* feat(completion/tag): added tag complete query

* improved return

* fix test
This commit is contained in:
Kristian 2026-04-25 12:37:33 +02:00 committed by GitHub
parent 2275d4bae4
commit 594764344d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 79 additions and 13 deletions

View file

@ -21,10 +21,10 @@ func main() {
uow := repositories.NewUnitOfWork();
indexRepo := repositories.NewIndexRepository(*persistence.NewReadContext())
linkRepo := repositories.NewLinkRepository(*persistence.NewReadContext())
tagRepo := repositories.NewTagRepository()
noteRepo := repositories.NewNoteRepository(*persistence.NewReadContext())
indexRepo := repositories.NewIndexRepository(persistence.NewReadContext())
linkRepo := repositories.NewLinkRepository(persistence.NewReadContext())
tagRepo := repositories.NewTagRepository(persistence.NewReadContext())
noteRepo := repositories.NewNoteRepository(persistence.NewReadContext())
tagService := services.NewTagService(tagRepo)
linkService := services.NewLinkService(linkRepo)
@ -33,10 +33,13 @@ func main() {
server.RegisterHandler("vault/init", vault.NewInitializeHandler(idxr, noteService))
server.RegisterHandler("vault/rebuild", vault.NewRebuildIndexHandler(idxr))
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))
server.RegisterHandler("completion/link", completion.NewCompleteLinkHandler(linkRepo))
server.RegisterHandler("completion/tag", completion.NewCompleteTagHandler(tagRepo))
if err := server.Run(os.Stdin, os.Stdout); err != nil {
slog.Error("server error", "error", err)

View file

@ -0,0 +1,41 @@
package completion
import (
"context"
"encoding/json"
"log/slog"
"github.com/KristianJBorgwarth/dendrite.daemon/persistence/repositories"
)
type completeTagCommand struct {
Query string `json:"query"`
}
type CompleteTagHandler struct {
tagRepo repositories.ITagRepository
}
func NewCompleteTagHandler(tr repositories.ITagRepository) *CompleteTagHandler {
return &CompleteTagHandler{tagRepo: tr}
}
func (h *CompleteTagHandler) Handle(ctx context.Context, raw json.RawMessage) (any, error) {
var cmd completeTagCommand
if err := json.Unmarshal(raw, &cmd); err != nil {
return nil, err
}
tags, err := h.tagRepo.GetByName(ctx, cmd.Query)
slog.Debug("Got tags", "query", cmd.Query, "count", len(tags))
if err != nil {
return nil, err
}
results := make([]string, len(tags))
for i, tag := range tags {
results[i] = tag.Name()
}
return results, nil
}

BIN
dendrite

Binary file not shown.

View file

@ -7,8 +7,8 @@ import (
type ReadContext struct{}
func NewReadContext() *ReadContext {
return &ReadContext{}
func NewReadContext() ReadContext {
return ReadContext{}
}
func (r *ReadContext) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {

View file

@ -14,12 +14,15 @@ type ITagRepository interface {
InsertNoteTags(ctx context.Context, dbCtx persistence.IDbContext, noteTags []*models.NoteTag) error
GetByNames(ctx context.Context, dbCtx persistence.IDbContext, names []string) ([]*models.Tag, error)
DeleteNoteTags(ctx context.Context, dbCtx persistence.IDbContext, noteID string) error
GetByName(ctx context.Context, tagName string) ([]*models.Tag, error)
}
type tagRepository struct{}
type tagRepository struct {
readDBContext persistence.ReadContext
}
func NewTagRepository() ITagRepository {
return &tagRepository{}
func NewTagRepository(rdb persistence.ReadContext) ITagRepository {
return &tagRepository{readDBContext: rdb}
}
func (r *tagRepository) Insert(ctx context.Context, dbCtx persistence.IDbContext, tags []*models.Tag) error {
@ -56,9 +59,9 @@ func (r *tagRepository) InsertRange(ctx context.Context, dbCtx persistence.IDbCo
return err
}
}
return nil
}
}
func (r *tagRepository) InsertNoteTags(ctx context.Context, dbCtx persistence.IDbContext, noteTags []*models.NoteTag) error {
noteTagStmt, err := dbCtx.Prepare(`INSERT INTO note_tag (note_id, tag_id) VALUES (?, ?)`)
@ -108,6 +111,25 @@ func (r *tagRepository) GetByNames(ctx context.Context, dbCtx persistence.IDbCon
return tags, nil
}
func (r *tagRepository) GetByName(ctx context.Context, tagName string) ([]*models.Tag, error) {
rows, err := r.readDBContext.QueryContext(ctx, `SELECT * FROM tag WHERE name LIKE ?`, "%"+tagName+"%")
if err != nil {
return nil, err
}
defer rows.Close()
var tags []*models.Tag
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
tags = append(tags, models.NewTag(name))
}
return tags, nil
}
func (r *tagRepository) DeleteNoteTags(ctx context.Context, dbCtx persistence.IDbContext, noteID string) error {
query := "DELETE FROM note_tag WHERE note_id = ?"
_, err := dbCtx.ExecContext(ctx, query, noteID)

View file

@ -17,8 +17,8 @@ import (
func newCreateNoteHandler() *note.CreateNoteHandler {
return note.NewCreateNoteHandler(
repositories.NewUnitOfWork(),
services.NewTagService(repositories.NewTagRepository()),
repositories.NewNoteRepository(*persistence.NewReadContext()),
services.NewTagService(repositories.NewTagRepository(persistence.NewReadContext())),
repositories.NewNoteRepository(persistence.NewReadContext()),
)
}