Exclude a tag with the --tag filtering option

This commit is contained in:
Mickaël Menu 2021-03-07 17:36:54 +01:00
parent f1391b5a63
commit bae1fab567
No known key found for this signature in database
GPG Key ID: 53D73664CD359895
3 changed files with 33 additions and 5 deletions

View File

@ -7,7 +7,9 @@ All notable changes to this project will be documented in this file.
### Added
* Support for tags.
* Filter notes by their tags using `--tag "history, europe"`. To match notes associated with either tags, use a pipe `|` or `OR` (all caps), e.g. `--tag "inbox OR todo"`.
* Filter notes by their tags using `--tag "history, europe"`.
* To match notes associated with either tags, use a pipe `|` or `OR` (all caps), e.g. `--tag "inbox OR todo"`.
* If you want to exclude notes having a particular tag, prefix it with `-` or `NOT` (all caps), e.g. `--tag "NOT done"`
* Many tag flavors are supported: `#hashtags`, `:colon:separated:tags:` and even Bear's [`#multi-word tags#`](https://blog.bear.app/2017/11/bear-tips-how-to-create-multi-word-tags/). If you prefer to use a YAML frontmatter, list your tags with the key `tags` or `keywords`.
### Changed

View File

@ -442,11 +442,22 @@ func (d *NoteDAO) findRows(opts note.FinderOpts) (*sql.Rows, error) {
break
}
separatorRegex := regexp.MustCompile(`(\ OR\ )|\|`)
for _, tags := range filter {
tags := separatorRegex.Split(tags, -1)
for _, tagsArg := range filter {
tags := separatorRegex.Split(tagsArg, -1)
negate := false
globs := make([]string, 0)
for _, tag := range tags {
tag = strings.TrimSpace(tag)
if strings.HasPrefix(tag, "-") {
negate = true
tag = strings.TrimPrefix(tag, "-")
} else if strings.HasPrefix(tag, "NOT") {
negate = true
tag = strings.TrimPrefix(tag, "NOT")
}
tag = strings.TrimSpace(tag)
if len(tag) == 0 {
continue
@ -455,13 +466,25 @@ func (d *NoteDAO) findRows(opts note.FinderOpts) (*sql.Rows, error) {
args = append(args, tag)
}
whereExprs = append(whereExprs, fmt.Sprintf(`n.id IN (
if len(globs) == 0 {
continue
}
if negate && len(globs) > 1 {
return nil, fmt.Errorf("cannot negate a tag in a OR group: %s", tagsArg)
}
expr := "n.id"
if negate {
expr += " NOT"
}
expr += fmt.Sprintf(` IN (
SELECT note_id FROM notes_collections
WHERE collection_id IN (SELECT id FROM collections t WHERE kind = '%s' AND (%s))
)`,
note.CollectionKindTag,
strings.Join(globs, " OR "),
))
)
whereExprs = append(whereExprs, expr)
}
case note.ExcludePathFilter:

View File

@ -418,6 +418,9 @@ func TestNoteDAOFindTag(t *testing.T) {
test([]string{"fiction | adventure | fantasy"}, []string{"ref/test/b.md", "f39c8.md", "log/2021-01-03.md"})
test([]string{"fiction | history", "adventure"}, []string{"ref/test/b.md", "log/2021-01-03.md"})
test([]string{"fiction", "unknown"}, []string{})
test([]string{"-fiction"}, []string{"ref/test/b.md", "f39c8.md", "ref/test/a.md", "log/2021-02-04.md", "index.md", "log/2021-01-04.md"})
test([]string{"NOT fiction"}, []string{"ref/test/b.md", "f39c8.md", "ref/test/a.md", "log/2021-02-04.md", "index.md", "log/2021-01-04.md"})
test([]string{"NOTfiction"}, []string{"ref/test/b.md", "f39c8.md", "ref/test/a.md", "log/2021-02-04.md", "index.md", "log/2021-01-04.md"})
}
func TestNoteDAOFindMatch(t *testing.T) {