From d797b94845941816aa8f8b52779f16214c6d942c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mickae=CC=88l=20Menu?= Date: Tue, 12 Jan 2021 19:58:14 +0100 Subject: [PATCH] Filter by creation date --- adapter/sqlite/note_dao.go | 36 +++++++++++++++++++++++++ cmd/list.go | 54 +++++++++++++++++++++++++++++++++++--- core/note/list.go | 23 ++++++++++++++++ go.mod | 1 + go.sum | 3 +++ 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/adapter/sqlite/note_dao.go b/adapter/sqlite/note_dao.go index db0ea22..341995b 100644 --- a/adapter/sqlite/note_dao.go +++ b/adapter/sqlite/note_dao.go @@ -173,6 +173,18 @@ func (d *NoteDAO) Find(opts note.FinderOpts, callback func(note.Match) error) (i } whereExprs = append(whereExprs, strings.Join(globs, " OR ")) + case note.DateFilter: + value := "?" + field := "n." + dateField(filter) + op, ignoreTime := dateDirection(filter) + if ignoreTime { + field = "date(" + field + ")" + value = "date(?)" + } + + whereExprs = append(whereExprs, fmt.Sprintf("%s %s %s", field, op, value)) + args = append(args, filter.Date) + default: panic("unknown filter type") } @@ -236,3 +248,27 @@ ON n.id = notes_fts.rowid` return count, nil } + +func dateField(filter note.DateFilter) string { + switch filter.Field { + case note.DateCreated: + return "created" + case note.DateModified: + return "modified" + default: + panic("unknown DateFilter field") + } +} + +func dateDirection(filter note.DateFilter) (op string, ignoreTime bool) { + switch filter.Direction { + case note.DateOn: + return "=", true + case note.DateBefore: + return "<=", false + case note.DateAfter: + return ">=", false + default: + panic("unknown DateFilter direction") + } +} diff --git a/cmd/list.go b/cmd/list.go index 85b42cb..5c83563 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -2,19 +2,24 @@ package cmd import ( "fmt" + "time" "github.com/mickael-menu/zk/adapter/sqlite" "github.com/mickael-menu/zk/core/note" "github.com/mickael-menu/zk/core/zk" "github.com/mickael-menu/zk/util/opt" + "github.com/tj/go-naturaldate" ) // List displays notes matching a set of criteria. type List struct { - Paths []string `arg optional placeholder:"PATHS"` - Format string `help:"Pretty prints the list using the given format" placeholder:"TEMPLATE"` - Match string `help:"Terms to search for in the notes" placeholder:"TERMS"` - Limit int `help:"Limit the number of results" placeholder:"MAX"` + Paths []string `arg optional placeholder:"PATHS"` + Format string `help:"Pretty prints the list using the given format" placeholder:"TEMPLATE"` + Match string `help:"Terms to search for in the notes" placeholder:"TERMS"` + Limit int `help:"Limit the number of results" placeholder:"MAX"` + Created string `help:"Show only the notes created on the given date" placeholder:"DATE"` + CreatedBefore string `help:"Show only the notes created before the given date" placeholder:"DATE"` + CreatedAfter string `help:"Show only the notes created after the given date" placeholder:"DATE"` } func (cmd *List) Run(container *Container) error { @@ -48,6 +53,42 @@ func (cmd *List) Run(container *Container) error { filters = append(filters, note.MatchFilter(cmd.Match)) } + if cmd.Created != "" { + date, err := parseDate(cmd.Created) + if err != nil { + return err + } + filters = append(filters, note.DateFilter{ + Date: date, + Field: note.DateCreated, + Direction: note.DateOn, + }) + } + + if cmd.CreatedBefore != "" { + date, err := parseDate(cmd.CreatedBefore) + if err != nil { + return err + } + filters = append(filters, note.DateFilter{ + Date: date, + Field: note.DateCreated, + Direction: note.DateBefore, + }) + } + + if cmd.CreatedAfter != "" { + date, err := parseDate(cmd.CreatedAfter) + if err != nil { + return err + } + filters = append(filters, note.DateFilter{ + Date: date, + Field: note.DateCreated, + Direction: note.DateAfter, + }) + } + count, err := note.List( note.ListOpts{ Format: opt.NewNotEmptyString(cmd.Format), @@ -76,3 +117,8 @@ func printNote(note string) error { _, err := fmt.Println(note) return err } + +func parseDate(date string) (time.Time, error) { + // FIXME: support years + return naturaldate.Parse(date, time.Now().UTC(), naturaldate.WithDirection(naturaldate.Past)) +} diff --git a/core/note/list.go b/core/note/list.go index 808ea04..90bd652 100644 --- a/core/note/list.go +++ b/core/note/list.go @@ -18,6 +18,28 @@ type MatchFilter string // PathFilter is a note filter using path globs to match notes. type PathFilter []string +// DateFilter can be used to filter notes created or modified before, after or on a given date. +type DateFilter struct { + Date time.Time + Direction DateDirection + Field DateField +} + +type DateDirection int + +const ( + DateOn DateDirection = iota + 1 + DateBefore + DateAfter +) + +type DateField int + +const ( + DateCreated DateField = iota + 1 + DateModified +) + // Match holds information about a note matching the list filters. type Match struct { // Snippet is an excerpt of the note. @@ -166,3 +188,4 @@ type Filter interface{ sealed() } func (f MatchFilter) sealed() {} func (f PathFilter) sealed() {} +func (f DateFilter) sealed() {} diff --git a/go.mod b/go.mod index 2654beb..ef50a14 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/rogpeppe/go-internal v1.6.2 // indirect github.com/rvflash/elapsed v0.2.0 github.com/tebeka/strftime v0.1.5 // indirect + github.com/tj/go-naturaldate v1.3.0 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad // indirect gopkg.in/djherbis/times.v1 v1.2.0 gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 2d95130..bc91b39 100644 --- a/go.sum +++ b/go.sum @@ -147,6 +147,9 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg= github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= +github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/go-naturaldate v1.3.0 h1:OgJIPkR/Jk4bFMBLbxZ8w+QUxwjqSvzd9x+yXocY4RI= +github.com/tj/go-naturaldate v1.3.0/go.mod h1:rpUbjivDKiS1BlfMGc2qUKNZ/yxgthOfmytQs8d8hKk= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI= github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=