ls.go:`git bug ls` should be faster

Sladyn created

Added `Title` to BugExcerpt
Added `TitleFilter` to `filter.go`
Used BugExcerpt in `ls` command to improve performance.

Closes https://github.com/MichaelMure/git-bug/issues/98

Change summary

cache/bug_excerpt.go |  8 ++++++--
cache/filter.go      | 16 ++++++++++++++++
cache/repo_cache.go  |  9 +++++++++
commands/ls.go       | 31 +++++++++++++++----------------
4 files changed, 46 insertions(+), 18 deletions(-)

Detailed changes

cache/bug_excerpt.go 🔗

@@ -23,8 +23,10 @@ type BugExcerpt struct {
 	CreateUnixTime    int64
 	EditUnixTime      int64
 
-	Status bug.Status
-	Labels []bug.Label
+	Title        string
+	Status       bug.Status
+	NoOfComments int
+	Labels       []bug.Label
 
 	// If author is identity.Bare, LegacyAuthor is set
 	// If author is identity.Identity, AuthorId is set and data is deported
@@ -48,8 +50,10 @@ func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
 		EditLamportTime:   b.EditLamportTime(),
 		CreateUnixTime:    b.FirstOp().GetUnixTime(),
 		EditUnixTime:      snap.LastEditUnix(),
+		Title:             snap.Title,
 		Status:            snap.Status,
 		Labels:            snap.Labels,
+		NoOfComments:      len(snap.Comments),
 		CreateMetadata:    b.FirstOp().AllMetadata(),
 	}
 

cache/filter.go 🔗

@@ -55,6 +55,17 @@ func LabelFilter(label string) Filter {
 	}
 }
 
+// TitleFilter return a Filter that match a title
+func TitleFilter(title string) Filter {
+	return func(excerpt *BugExcerpt) bool {
+		if strings.Contains(excerpt.Title, title) {
+			return true
+		}
+		return false
+	}
+
+}
+
 // NoLabelFilter return a Filter that match the absence of labels
 func NoLabelFilter() Filter {
 	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
@@ -67,6 +78,7 @@ type Filters struct {
 	Status    []Filter
 	Author    []Filter
 	Label     []Filter
+	Title     []Filter
 	NoFilters []Filter
 }
 
@@ -88,6 +100,10 @@ func (f *Filters) Match(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 		return false
 	}
 
+	if match := f.andMatch(f.Title, excerpt); !match {
+		return false
+	}
+
 	return true
 }
 

cache/repo_cache.go 🔗

@@ -386,6 +386,15 @@ func (c *RepoCache) ResolveBug(id string) (*BugCache, error) {
 
 	return cached, nil
 }
+// ResolveBugExcerpt retrieve a BugExcerpt matching the exact given id
+func (c *RepoCache) ResolveBugExcerpt(id string) (*BugExcerpt, error) {
+	e, ok := c.excerpts[id]
+	if !ok {
+		return nil, bug.ErrBugNotExist
+	}
+
+ 	return e, nil
+}
 
 // ResolveBugExcerpt retrieve a BugExcerpt matching the exact given id
 func (c *RepoCache) ResolveBugExcerpt(id string) (*BugExcerpt, error) {

commands/ls.go 🔗

@@ -5,7 +5,6 @@ import (
 	"strings"
 
 	"github.com/MichaelMure/git-bug/cache"
-	"github.com/MichaelMure/git-bug/identity"
 	"github.com/MichaelMure/git-bug/util/colors"
 	"github.com/MichaelMure/git-bug/util/interrupt"
 	"github.com/spf13/cobra"
@@ -14,6 +13,7 @@ import (
 var (
 	lsStatusQuery   []string
 	lsAuthorQuery   []string
+	lsTitleQuery    []string
 	lsLabelQuery    []string
 	lsNoQuery       []string
 	lsSortBy        string
@@ -45,30 +45,22 @@ func runLsBug(cmd *cobra.Command, args []string) error {
 	allIds := backend.QueryBugs(query)
 
 	for _, id := range allIds {
-		b, err := backend.ResolveBug(id)
+		b, err := backend.ResolveBugExcerpt(id)
 		if err != nil {
 			return err
 		}
 
-		snapshot := b.Snapshot()
-
-		var author identity.Interface
-
-		if len(snapshot.Comments) > 0 {
-			create := snapshot.Comments[0]
-			author = create.Author
-		}
-
 		// truncate + pad if needed
-		titleFmt := fmt.Sprintf("%-50.50s", snapshot.Title)
-		authorFmt := fmt.Sprintf("%-15.15s", author.DisplayName())
+		titleFmt := fmt.Sprintf("%-50.50s", b.Title)
+		authorFmt := fmt.Sprintf("%-15.15s", b.Author.Name)
 
-		fmt.Printf("%s %s\t%s\t%s\t%s\n",
+		fmt.Printf("%s %s\t%s\t%s\tC:%d L:%d\n",
 			colors.Cyan(b.HumanId()),
-			colors.Yellow(snapshot.Status),
+			colors.Yellow(b.Status),
 			titleFmt,
 			colors.Magenta(authorFmt),
-			snapshot.Summary(),
+			b.NoOfComments,
+			len(b.Labels),
 		)
 	}
 
@@ -87,6 +79,11 @@ func lsQueryFromFlags() (*cache.Query, error) {
 		query.Status = append(query.Status, f)
 	}
 
+	for _, title := range lsTitleQuery {
+		f := cache.TitleFilter(title)
+		query.Title = append(query.Title, f)
+	}
+
 	for _, author := range lsAuthorQuery {
 		f := cache.AuthorFilter(author)
 		query.Author = append(query.Author, f)
@@ -156,6 +153,8 @@ func init() {
 		"Filter by author")
 	lsCmd.Flags().StringSliceVarP(&lsLabelQuery, "label", "l", nil,
 		"Filter by label")
+	lsCmd.Flags().StringSliceVarP(&lsTitleQuery, "title", "t", nil,
+		"Filter by title")
 	lsCmd.Flags().StringSliceVarP(&lsNoQuery, "no", "n", nil,
 		"Filter by absence of something. Valid values are [label]")
 	lsCmd.Flags().StringVarP(&lsSortBy, "by", "b", "creation",