filter.go

  1package cache
  2
  3import (
  4	"strings"
  5
  6	"github.com/MichaelMure/git-bug/bug"
  7)
  8
  9// Filter is a predicate that match a subset of bugs
 10type Filter func(repoCache *RepoCache, excerpt *BugExcerpt) bool
 11
 12// StatusFilter return a Filter that match a bug status
 13func StatusFilter(query string) (Filter, error) {
 14	status, err := bug.StatusFromString(query)
 15	if err != nil {
 16		return nil, err
 17	}
 18
 19	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 20		return excerpt.Status == status
 21	}, nil
 22}
 23
 24// AuthorFilter return a Filter that match a bug author
 25func AuthorFilter(query string) Filter {
 26	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 27		query = strings.ToLower(query)
 28
 29		// Normal identity
 30		if excerpt.AuthorId != "" {
 31			author, ok := repoCache.identitiesExcerpts[excerpt.AuthorId]
 32			if !ok {
 33				panic("missing identity in the cache")
 34			}
 35
 36			return author.Match(query)
 37		}
 38
 39		// Legacy identity support
 40		return strings.Contains(strings.ToLower(excerpt.LegacyAuthor.Name), query) ||
 41			strings.Contains(strings.ToLower(excerpt.LegacyAuthor.Login), query)
 42	}
 43}
 44
 45// LabelFilter return a Filter that match a label
 46func LabelFilter(label string) Filter {
 47	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 48		for _, l := range excerpt.Labels {
 49			if string(l) == label {
 50				return true
 51			}
 52		}
 53		return false
 54	}
 55}
 56
 57// ActorFilter return a Filter that match a bug actor
 58func ActorFilter(query string) Filter {
 59	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 60		query = strings.ToLower(query)
 61
 62		for _, id := range excerpt.Actors {
 63			identityExcerpt, ok := repoCache.identitiesExcerpts[id]
 64			if !ok {
 65				panic("missing identity in the cache")
 66			}
 67
 68			if identityExcerpt.Match(query) {
 69				return true
 70			}
 71		}
 72		return false
 73	}
 74}
 75
 76// ParticipantFilter return a Filter that match a bug participant
 77func ParticipantFilter(query string) Filter {
 78	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
 79		query = strings.ToLower(query)
 80
 81		for _, id := range excerpt.Participants {
 82			identityExcerpt, ok := repoCache.identitiesExcerpts[id]
 83			if !ok {
 84				panic("missing identity in the cache")
 85			}
 86
 87			if identityExcerpt.Match(query) {
 88				return true
 89			}
 90		}
 91		return false
 92	}
 93}
 94
 95// TitleFilter return a Filter that match if the title contains the given query
 96func TitleFilter(query string) Filter {
 97	return func(repo *RepoCache, excerpt *BugExcerpt) bool {
 98		return strings.Contains(
 99			strings.ToLower(excerpt.Title),
100			strings.ToLower(query),
101		)
102	}
103}
104
105// NoLabelFilter return a Filter that match the absence of labels
106func NoLabelFilter() Filter {
107	return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
108		return len(excerpt.Labels) == 0
109	}
110}
111
112// Filters is a collection of Filter that implement a complex filter
113type Filters struct {
114	Status      []Filter
115	Author      []Filter
116	Actor       []Filter
117	Participant []Filter
118	Label       []Filter
119	Title       []Filter
120	NoFilters   []Filter
121}
122
123// Match check if a bug match the set of filters
124func (f *Filters) Match(repoCache *RepoCache, excerpt *BugExcerpt) bool {
125	if match := f.orMatch(f.Status, repoCache, excerpt); !match {
126		return false
127	}
128
129	if match := f.orMatch(f.Author, repoCache, excerpt); !match {
130		return false
131	}
132
133	if match := f.orMatch(f.Participant, repoCache, excerpt); !match {
134		return false
135	}
136
137	if match := f.orMatch(f.Actor, repoCache, excerpt); !match {
138		return false
139	}
140
141	if match := f.andMatch(f.Label, repoCache, excerpt); !match {
142		return false
143	}
144
145	if match := f.andMatch(f.NoFilters, repoCache, excerpt); !match {
146		return false
147	}
148
149	if match := f.andMatch(f.Title, repoCache, excerpt); !match {
150		return false
151	}
152
153	return true
154}
155
156// Check if any of the filters provided match the bug
157func (*Filters) orMatch(filters []Filter, repoCache *RepoCache, excerpt *BugExcerpt) bool {
158	if len(filters) == 0 {
159		return true
160	}
161
162	match := false
163	for _, f := range filters {
164		match = match || f(repoCache, excerpt)
165	}
166
167	return match
168}
169
170// Check if all of the filters provided match the bug
171func (*Filters) andMatch(filters []Filter, repoCache *RepoCache, excerpt *BugExcerpt) bool {
172	if len(filters) == 0 {
173		return true
174	}
175
176	match := true
177	for _, f := range filters {
178		match = match && f(repoCache, excerpt)
179	}
180
181	return match
182}