feat: filter and search by tag
This commit is contained in:
@ -155,7 +155,13 @@ func (s *SQLiteStorage) Search(query string) []*note.Note {
|
||||
SELECT id, path, title, content, updated_at, size, published
|
||||
FROM notes
|
||||
WHERE lower(content) LIKE lower(?)
|
||||
`, pattern)
|
||||
OR id IN (
|
||||
SELECT nt.note_id
|
||||
FROM note_tags nt
|
||||
JOIN tags t ON t.id = nt.tag_id
|
||||
WHERE lower(t.name) LIKE lower(?)
|
||||
)
|
||||
`, pattern, pattern)
|
||||
if err != nil {
|
||||
return []*note.Note{}
|
||||
}
|
||||
|
||||
@ -187,3 +187,27 @@ func TestSQLiteStorage_Tags(t *testing.T) {
|
||||
t.Fatalf("expected remaining tag rust, got %+v", tags)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSQLiteStorage_SearchByTag(t *testing.T) {
|
||||
st := newSQLiteStorage(t)
|
||||
|
||||
ts := time.Date(2026, 2, 3, 12, 0, 0, 0, time.UTC)
|
||||
if err := st.Create(sampleNote("n1", "notes/alpha.md", "Alpha", "no match", ts)); err != nil {
|
||||
t.Fatalf("create note: %v", err)
|
||||
}
|
||||
if err := st.Create(sampleNote("n2", "notes/beta.md", "Beta", "content", ts)); err != nil {
|
||||
t.Fatalf("create note: %v", err)
|
||||
}
|
||||
|
||||
if err := st.AddTag("n2", "Go"); err != nil {
|
||||
t.Fatalf("add tag: %v", err)
|
||||
}
|
||||
|
||||
results := st.Search("go")
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("expected 1 result, got %d", len(results))
|
||||
}
|
||||
if results[0].ID != "n2" {
|
||||
t.Fatalf("expected tag match to be n2")
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,13 +67,25 @@ func (ns *NoteStorage) Search(query string) []*note.Note {
|
||||
for _, note := range ns.Index {
|
||||
lowContent := strings.ToLower(string(note.Content))
|
||||
lowQuery := strings.ToLower(query)
|
||||
if strings.Contains(lowContent, lowQuery) {
|
||||
if strings.Contains(lowContent, lowQuery) || tagsContain(note.Tags, lowQuery) {
|
||||
results = append(results, note)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func tagsContain(tags []string, query string) bool {
|
||||
if query == "" {
|
||||
return false
|
||||
}
|
||||
for _, tag := range tags {
|
||||
if strings.Contains(strings.ToLower(tag), query) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ns *NoteStorage) AddTag(noteID, tag string) error {
|
||||
n, ok := ns.Index[noteID]
|
||||
if !ok {
|
||||
|
||||
@ -51,3 +51,20 @@ func TestNoteStorageGetUpdate(t *testing.T) {
|
||||
t.Errorf("Updating a note should reflect it in storage. Wanted '%s', got '%s'\n", n1.Content, nn2.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoteStorageSearch_Tags(t *testing.T) {
|
||||
ns = NewNoteStorage()
|
||||
|
||||
n := note.NewNote()
|
||||
n.Path = "note3.md"
|
||||
n.ID = note.GenerateNoteID(n.Path)
|
||||
n.Content = "no tag here"
|
||||
n.Tags = []string{"devops", "go"}
|
||||
|
||||
ns.Create(n)
|
||||
|
||||
results := ns.Search("go")
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("expected 1 result, got %d", len(results))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user