mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-15 10:12:06 +03:00
Merge pull request #316 from MichaelMure/lazy-graphql
graphql: use the cache in priority for fast browsing in the WebUI
This commit is contained in:
commit
3caffeef4d
@ -677,6 +677,3 @@ func (bug *Bug) Compile() Snapshot {
|
||||
|
||||
return snap
|
||||
}
|
||||
|
||||
// Sign post method for gqlgen
|
||||
func (bug *Bug) IsAuthored() {}
|
||||
|
@ -21,6 +21,9 @@ type AddCommentOperation struct {
|
||||
Files []git.Hash `json:"files"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *AddCommentOperation) IsOperation() {}
|
||||
|
||||
func (op *AddCommentOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ type CreateOperation struct {
|
||||
Files []git.Hash `json:"files"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *CreateOperation) IsOperation() {}
|
||||
|
||||
func (op *CreateOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -24,6 +24,9 @@ type EditCommentOperation struct {
|
||||
Files []git.Hash `json:"files"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *EditCommentOperation) IsOperation() {}
|
||||
|
||||
func (op *EditCommentOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ type LabelChangeOperation struct {
|
||||
Removed []Label `json:"removed"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *LabelChangeOperation) IsOperation() {}
|
||||
|
||||
func (op *LabelChangeOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ type NoOpOperation struct {
|
||||
OpBase
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *NoOpOperation) IsOperation() {}
|
||||
|
||||
func (op *NoOpOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ type SetMetadataOperation struct {
|
||||
NewMetadata map[string]string `json:"new_metadata"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *SetMetadataOperation) IsOperation() {}
|
||||
|
||||
func (op *SetMetadataOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ type SetStatusOperation struct {
|
||||
Status Status `json:"status"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *SetStatusOperation) IsOperation() {}
|
||||
|
||||
func (op *SetStatusOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ type SetTitleOperation struct {
|
||||
Was string `json:"was"`
|
||||
}
|
||||
|
||||
// Sign-post method for gqlgen
|
||||
func (op *SetTitleOperation) IsOperation() {}
|
||||
|
||||
func (op *SetTitleOperation) base() *OpBase {
|
||||
return &op.OpBase
|
||||
}
|
||||
|
@ -52,6 +52,9 @@ type Operation interface {
|
||||
AllMetadata() map[string]string
|
||||
// GetAuthor return the author identity
|
||||
GetAuthor() identity.Interface
|
||||
|
||||
// sign-post method for gqlgen
|
||||
IsOperation()
|
||||
}
|
||||
|
||||
func deriveId(data []byte) entity.Id {
|
||||
|
65
cache/filter.go
vendored
65
cache/filter.go
vendored
@ -4,10 +4,17 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/entity"
|
||||
)
|
||||
|
||||
// resolver has the resolving functions needed by filters.
|
||||
// This exist mainly to go through the functions of the cache with proper locking.
|
||||
type resolver interface {
|
||||
ResolveIdentityExcerpt(id entity.Id) (*IdentityExcerpt, error)
|
||||
}
|
||||
|
||||
// Filter is a predicate that match a subset of bugs
|
||||
type Filter func(repoCache *RepoCache, excerpt *BugExcerpt) bool
|
||||
type Filter func(excerpt *BugExcerpt, resolver resolver) bool
|
||||
|
||||
// StatusFilter return a Filter that match a bug status
|
||||
func StatusFilter(query string) (Filter, error) {
|
||||
@ -16,21 +23,21 @@ func StatusFilter(query string) (Filter, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
return excerpt.Status == status
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AuthorFilter return a Filter that match a bug author
|
||||
func AuthorFilter(query string) Filter {
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
query = strings.ToLower(query)
|
||||
|
||||
// Normal identity
|
||||
if excerpt.AuthorId != "" {
|
||||
author, ok := repoCache.identitiesExcerpts[excerpt.AuthorId]
|
||||
if !ok {
|
||||
panic("missing identity in the cache")
|
||||
author, err := resolver.ResolveIdentityExcerpt(excerpt.AuthorId)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return author.Match(query)
|
||||
@ -43,7 +50,7 @@ func AuthorFilter(query string) Filter {
|
||||
|
||||
// LabelFilter return a Filter that match a label
|
||||
func LabelFilter(label string) Filter {
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
for _, l := range excerpt.Labels {
|
||||
if string(l) == label {
|
||||
return true
|
||||
@ -55,13 +62,13 @@ func LabelFilter(label string) Filter {
|
||||
|
||||
// ActorFilter return a Filter that match a bug actor
|
||||
func ActorFilter(query string) Filter {
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
query = strings.ToLower(query)
|
||||
|
||||
for _, id := range excerpt.Actors {
|
||||
identityExcerpt, ok := repoCache.identitiesExcerpts[id]
|
||||
if !ok {
|
||||
panic("missing identity in the cache")
|
||||
identityExcerpt, err := resolver.ResolveIdentityExcerpt(id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if identityExcerpt.Match(query) {
|
||||
@ -74,13 +81,13 @@ func ActorFilter(query string) Filter {
|
||||
|
||||
// ParticipantFilter return a Filter that match a bug participant
|
||||
func ParticipantFilter(query string) Filter {
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
query = strings.ToLower(query)
|
||||
|
||||
for _, id := range excerpt.Participants {
|
||||
identityExcerpt, ok := repoCache.identitiesExcerpts[id]
|
||||
if !ok {
|
||||
panic("missing identity in the cache")
|
||||
identityExcerpt, err := resolver.ResolveIdentityExcerpt(id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if identityExcerpt.Match(query) {
|
||||
@ -93,7 +100,7 @@ func ParticipantFilter(query string) Filter {
|
||||
|
||||
// TitleFilter return a Filter that match if the title contains the given query
|
||||
func TitleFilter(query string) Filter {
|
||||
return func(repo *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
return strings.Contains(
|
||||
strings.ToLower(excerpt.Title),
|
||||
strings.ToLower(query),
|
||||
@ -103,7 +110,7 @@ func TitleFilter(query string) Filter {
|
||||
|
||||
// NoLabelFilter return a Filter that match the absence of labels
|
||||
func NoLabelFilter() Filter {
|
||||
return func(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
return func(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
return len(excerpt.Labels) == 0
|
||||
}
|
||||
}
|
||||
@ -120,32 +127,32 @@ type Filters struct {
|
||||
}
|
||||
|
||||
// Match check if a bug match the set of filters
|
||||
func (f *Filters) Match(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
if match := f.orMatch(f.Status, repoCache, excerpt); !match {
|
||||
func (f *Filters) Match(excerpt *BugExcerpt, resolver resolver) bool {
|
||||
if match := f.orMatch(f.Status, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.orMatch(f.Author, repoCache, excerpt); !match {
|
||||
if match := f.orMatch(f.Author, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.orMatch(f.Participant, repoCache, excerpt); !match {
|
||||
if match := f.orMatch(f.Participant, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.orMatch(f.Actor, repoCache, excerpt); !match {
|
||||
if match := f.orMatch(f.Actor, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.andMatch(f.Label, repoCache, excerpt); !match {
|
||||
if match := f.andMatch(f.Label, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.andMatch(f.NoFilters, repoCache, excerpt); !match {
|
||||
if match := f.andMatch(f.NoFilters, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
if match := f.andMatch(f.Title, repoCache, excerpt); !match {
|
||||
if match := f.andMatch(f.Title, excerpt, resolver); !match {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -153,28 +160,28 @@ func (f *Filters) Match(repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
}
|
||||
|
||||
// Check if any of the filters provided match the bug
|
||||
func (*Filters) orMatch(filters []Filter, repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
func (*Filters) orMatch(filters []Filter, excerpt *BugExcerpt, resolver resolver) bool {
|
||||
if len(filters) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
match := false
|
||||
for _, f := range filters {
|
||||
match = match || f(repoCache, excerpt)
|
||||
match = match || f(excerpt, resolver)
|
||||
}
|
||||
|
||||
return match
|
||||
}
|
||||
|
||||
// Check if all of the filters provided match the bug
|
||||
func (*Filters) andMatch(filters []Filter, repoCache *RepoCache, excerpt *BugExcerpt) bool {
|
||||
func (*Filters) andMatch(filters []Filter, excerpt *BugExcerpt, resolver resolver) bool {
|
||||
if len(filters) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
match := true
|
||||
for _, f := range filters {
|
||||
match = match && f(repoCache, excerpt)
|
||||
match = match && f(excerpt, resolver)
|
||||
}
|
||||
|
||||
return match
|
||||
|
2
cache/filter_test.go
vendored
2
cache/filter_test.go
vendored
@ -28,7 +28,7 @@ func TestTitleFilter(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
filter := TitleFilter(tt.query)
|
||||
excerpt := &BugExcerpt{Title: tt.title}
|
||||
assert.Equal(t, tt.match, filter(nil, excerpt))
|
||||
assert.Equal(t, tt.match, filter(excerpt, nil))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
195
cache/repo_cache.go
vendored
195
cache/repo_cache.go
vendored
@ -10,6 +10,7 @@ import (
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@ -57,11 +58,13 @@ type RepoCache struct {
|
||||
// the underlying repo
|
||||
repo repository.ClockedRepo
|
||||
|
||||
muBug sync.RWMutex
|
||||
// excerpt of bugs data for all bugs
|
||||
bugExcerpts map[entity.Id]*BugExcerpt
|
||||
// bug loaded in memory
|
||||
bugs map[entity.Id]*BugCache
|
||||
|
||||
muIdentity sync.RWMutex
|
||||
// excerpt of identities data for all identities
|
||||
identitiesExcerpts map[entity.Id]*IdentityExcerpt
|
||||
// identities loaded in memory
|
||||
@ -157,6 +160,11 @@ func (c *RepoCache) lock() error {
|
||||
}
|
||||
|
||||
func (c *RepoCache) Close() error {
|
||||
c.muBug.Lock()
|
||||
defer c.muBug.Unlock()
|
||||
c.muIdentity.Lock()
|
||||
defer c.muIdentity.Unlock()
|
||||
|
||||
c.identities = make(map[entity.Id]*IdentityCache)
|
||||
c.identitiesExcerpts = nil
|
||||
c.bugs = make(map[entity.Id]*BugCache)
|
||||
@ -169,12 +177,16 @@ func (c *RepoCache) Close() error {
|
||||
// bugUpdated is a callback to trigger when the excerpt of a bug changed,
|
||||
// that is each time a bug is updated
|
||||
func (c *RepoCache) bugUpdated(id entity.Id) error {
|
||||
c.muBug.Lock()
|
||||
|
||||
b, ok := c.bugs[id]
|
||||
if !ok {
|
||||
c.muBug.Unlock()
|
||||
panic("missing bug in the cache")
|
||||
}
|
||||
|
||||
c.bugExcerpts[id] = NewBugExcerpt(b.bug, b.Snapshot())
|
||||
c.muBug.Unlock()
|
||||
|
||||
// we only need to write the bug cache
|
||||
return c.writeBugCache()
|
||||
@ -183,12 +195,16 @@ func (c *RepoCache) bugUpdated(id entity.Id) error {
|
||||
// identityUpdated is a callback to trigger when the excerpt of an identity
|
||||
// changed, that is each time an identity is updated
|
||||
func (c *RepoCache) identityUpdated(id entity.Id) error {
|
||||
c.muIdentity.Lock()
|
||||
|
||||
i, ok := c.identities[id]
|
||||
if !ok {
|
||||
c.muIdentity.Unlock()
|
||||
panic("missing identity in the cache")
|
||||
}
|
||||
|
||||
c.identitiesExcerpts[id] = NewIdentityExcerpt(i.Identity)
|
||||
c.muIdentity.Unlock()
|
||||
|
||||
// we only need to write the identity cache
|
||||
return c.writeIdentityCache()
|
||||
@ -205,6 +221,9 @@ func (c *RepoCache) load() error {
|
||||
|
||||
// load will try to read from the disk the bug cache file
|
||||
func (c *RepoCache) loadBugCache() error {
|
||||
c.muBug.Lock()
|
||||
defer c.muBug.Unlock()
|
||||
|
||||
f, err := os.Open(bugCacheFilePath(c.repo))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -234,6 +253,9 @@ func (c *RepoCache) loadBugCache() error {
|
||||
|
||||
// load will try to read from the disk the identity cache file
|
||||
func (c *RepoCache) loadIdentityCache() error {
|
||||
c.muIdentity.Lock()
|
||||
defer c.muIdentity.Unlock()
|
||||
|
||||
f, err := os.Open(identityCacheFilePath(c.repo))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -272,6 +294,9 @@ func (c *RepoCache) write() error {
|
||||
|
||||
// write will serialize on disk the bug cache file
|
||||
func (c *RepoCache) writeBugCache() error {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
var data bytes.Buffer
|
||||
|
||||
aux := struct {
|
||||
@ -304,6 +329,9 @@ func (c *RepoCache) writeBugCache() error {
|
||||
|
||||
// write will serialize on disk the identity cache file
|
||||
func (c *RepoCache) writeIdentityCache() error {
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
var data bytes.Buffer
|
||||
|
||||
aux := struct {
|
||||
@ -343,6 +371,11 @@ func identityCacheFilePath(repo repository.Repo) string {
|
||||
}
|
||||
|
||||
func (c *RepoCache) buildCache() error {
|
||||
c.muBug.Lock()
|
||||
defer c.muBug.Unlock()
|
||||
c.muIdentity.Lock()
|
||||
defer c.muIdentity.Unlock()
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Building identity cache... ")
|
||||
|
||||
c.identitiesExcerpts = make(map[entity.Id]*IdentityExcerpt)
|
||||
@ -378,9 +411,24 @@ func (c *RepoCache) buildCache() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveBugExcerpt retrieve a BugExcerpt matching the exact given id
|
||||
func (c *RepoCache) ResolveBugExcerpt(id entity.Id) (*BugExcerpt, error) {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
e, ok := c.bugExcerpts[id]
|
||||
if !ok {
|
||||
return nil, bug.ErrBugNotExist
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// ResolveBug retrieve a bug matching the exact given id
|
||||
func (c *RepoCache) ResolveBug(id entity.Id) (*BugCache, error) {
|
||||
c.muBug.RLock()
|
||||
cached, ok := c.bugs[id]
|
||||
c.muBug.RUnlock()
|
||||
if ok {
|
||||
return cached, nil
|
||||
}
|
||||
@ -391,19 +439,20 @@ func (c *RepoCache) ResolveBug(id entity.Id) (*BugCache, error) {
|
||||
}
|
||||
|
||||
cached = NewBugCache(c, b)
|
||||
|
||||
c.muBug.Lock()
|
||||
c.bugs[id] = cached
|
||||
c.muBug.Unlock()
|
||||
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
// ResolveBugExcerpt retrieve a BugExcerpt matching the exact given id
|
||||
func (c *RepoCache) ResolveBugExcerpt(id entity.Id) (*BugExcerpt, error) {
|
||||
e, ok := c.bugExcerpts[id]
|
||||
if !ok {
|
||||
return nil, bug.ErrBugNotExist
|
||||
}
|
||||
|
||||
return e, nil
|
||||
// ResolveBugExcerptPrefix retrieve a BugExcerpt matching an id prefix. It fails if multiple
|
||||
// bugs match.
|
||||
func (c *RepoCache) ResolveBugExcerptPrefix(prefix string) (*BugExcerpt, error) {
|
||||
return c.ResolveBugExcerptMatcher(func(excerpt *BugExcerpt) bool {
|
||||
return excerpt.Id.HasPrefix(prefix)
|
||||
})
|
||||
}
|
||||
|
||||
// ResolveBugPrefix retrieve a bug matching an id prefix. It fails if multiple
|
||||
@ -423,7 +472,26 @@ func (c *RepoCache) ResolveBugCreateMetadata(key string, value string) (*BugCach
|
||||
})
|
||||
}
|
||||
|
||||
func (c *RepoCache) ResolveBugExcerptMatcher(f func(*BugExcerpt) bool) (*BugExcerpt, error) {
|
||||
id, err := c.resolveBugMatcher(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.ResolveBugExcerpt(id)
|
||||
}
|
||||
|
||||
func (c *RepoCache) ResolveBugMatcher(f func(*BugExcerpt) bool) (*BugCache, error) {
|
||||
id, err := c.resolveBugMatcher(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.ResolveBug(id)
|
||||
}
|
||||
|
||||
func (c *RepoCache) resolveBugMatcher(f func(*BugExcerpt) bool) (entity.Id, error) {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
// preallocate but empty
|
||||
matching := make([]entity.Id, 0, 5)
|
||||
|
||||
@ -434,18 +502,21 @@ func (c *RepoCache) ResolveBugMatcher(f func(*BugExcerpt) bool) (*BugCache, erro
|
||||
}
|
||||
|
||||
if len(matching) > 1 {
|
||||
return nil, bug.NewErrMultipleMatchBug(matching)
|
||||
return entity.UnsetId, bug.NewErrMultipleMatchBug(matching)
|
||||
}
|
||||
|
||||
if len(matching) == 0 {
|
||||
return nil, bug.ErrBugNotExist
|
||||
return entity.UnsetId, bug.ErrBugNotExist
|
||||
}
|
||||
|
||||
return c.ResolveBug(matching[0])
|
||||
return matching[0], nil
|
||||
}
|
||||
|
||||
// QueryBugs return the id of all Bug matching the given Query
|
||||
func (c *RepoCache) QueryBugs(query *Query) []entity.Id {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
if query == nil {
|
||||
return c.AllBugsIds()
|
||||
}
|
||||
@ -453,7 +524,7 @@ func (c *RepoCache) QueryBugs(query *Query) []entity.Id {
|
||||
var filtered []*BugExcerpt
|
||||
|
||||
for _, excerpt := range c.bugExcerpts {
|
||||
if query.Match(c, excerpt) {
|
||||
if query.Match(excerpt, c) {
|
||||
filtered = append(filtered, excerpt)
|
||||
}
|
||||
}
|
||||
@ -488,6 +559,9 @@ func (c *RepoCache) QueryBugs(query *Query) []entity.Id {
|
||||
|
||||
// AllBugsIds return all known bug ids
|
||||
func (c *RepoCache) AllBugsIds() []entity.Id {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
result := make([]entity.Id, len(c.bugExcerpts))
|
||||
|
||||
i := 0
|
||||
@ -505,6 +579,9 @@ func (c *RepoCache) AllBugsIds() []entity.Id {
|
||||
// labels are defined in a configuration file. Until that, the default behavior
|
||||
// is to return the list of labels already used.
|
||||
func (c *RepoCache) ValidLabels() []bug.Label {
|
||||
c.muBug.RLock()
|
||||
defer c.muBug.RUnlock()
|
||||
|
||||
set := map[bug.Label]interface{}{}
|
||||
|
||||
for _, excerpt := range c.bugExcerpts {
|
||||
@ -564,12 +641,15 @@ func (c *RepoCache) NewBugRaw(author *IdentityCache, unixTime int64, title strin
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
c.muBug.Lock()
|
||||
if _, has := c.bugs[b.Id()]; has {
|
||||
c.muBug.Unlock()
|
||||
return nil, nil, fmt.Errorf("bug %s already exist in the cache", b.Id())
|
||||
}
|
||||
|
||||
cached := NewBugCache(c, b)
|
||||
c.bugs[b.Id()] = cached
|
||||
c.muBug.Unlock()
|
||||
|
||||
// force the write of the excerpt
|
||||
err = c.bugUpdated(b.Id())
|
||||
@ -615,7 +695,9 @@ func (c *RepoCache) MergeAll(remote string) <-chan entity.MergeResult {
|
||||
switch result.Status {
|
||||
case entity.MergeStatusNew, entity.MergeStatusUpdated:
|
||||
i := result.Entity.(*identity.Identity)
|
||||
c.muIdentity.Lock()
|
||||
c.identitiesExcerpts[result.Id] = NewIdentityExcerpt(i)
|
||||
c.muIdentity.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,7 +713,9 @@ func (c *RepoCache) MergeAll(remote string) <-chan entity.MergeResult {
|
||||
case entity.MergeStatusNew, entity.MergeStatusUpdated:
|
||||
b := result.Entity.(*bug.Bug)
|
||||
snap := b.Compile()
|
||||
c.muBug.Lock()
|
||||
c.bugExcerpts[result.Id] = NewBugExcerpt(b, &snap)
|
||||
c.muBug.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@ -745,9 +829,24 @@ func repoIsAvailable(repo repository.Repo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveIdentityExcerpt retrieve a IdentityExcerpt matching the exact given id
|
||||
func (c *RepoCache) ResolveIdentityExcerpt(id entity.Id) (*IdentityExcerpt, error) {
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
e, ok := c.identitiesExcerpts[id]
|
||||
if !ok {
|
||||
return nil, identity.ErrIdentityNotExist
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// ResolveIdentity retrieve an identity matching the exact given id
|
||||
func (c *RepoCache) ResolveIdentity(id entity.Id) (*IdentityCache, error) {
|
||||
c.muIdentity.RLock()
|
||||
cached, ok := c.identities[id]
|
||||
c.muIdentity.RUnlock()
|
||||
if ok {
|
||||
return cached, nil
|
||||
}
|
||||
@ -758,19 +857,20 @@ func (c *RepoCache) ResolveIdentity(id entity.Id) (*IdentityCache, error) {
|
||||
}
|
||||
|
||||
cached = NewIdentityCache(c, i)
|
||||
|
||||
c.muIdentity.Lock()
|
||||
c.identities[id] = cached
|
||||
c.muIdentity.Unlock()
|
||||
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
// ResolveIdentityExcerpt retrieve a IdentityExcerpt matching the exact given id
|
||||
func (c *RepoCache) ResolveIdentityExcerpt(id entity.Id) (*IdentityExcerpt, error) {
|
||||
e, ok := c.identitiesExcerpts[id]
|
||||
if !ok {
|
||||
return nil, identity.ErrIdentityNotExist
|
||||
}
|
||||
|
||||
return e, nil
|
||||
// ResolveIdentityExcerptPrefix retrieve a IdentityExcerpt matching an id prefix.
|
||||
// It fails if multiple identities match.
|
||||
func (c *RepoCache) ResolveIdentityExcerptPrefix(prefix string) (*IdentityExcerpt, error) {
|
||||
return c.ResolveIdentityExcerptMatcher(func(excerpt *IdentityExcerpt) bool {
|
||||
return excerpt.Id.HasPrefix(prefix)
|
||||
})
|
||||
}
|
||||
|
||||
// ResolveIdentityPrefix retrieve an Identity matching an id prefix.
|
||||
@ -789,7 +889,26 @@ func (c *RepoCache) ResolveIdentityImmutableMetadata(key string, value string) (
|
||||
})
|
||||
}
|
||||
|
||||
func (c *RepoCache) ResolveIdentityExcerptMatcher(f func(*IdentityExcerpt) bool) (*IdentityExcerpt, error) {
|
||||
id, err := c.resolveIdentityMatcher(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.ResolveIdentityExcerpt(id)
|
||||
}
|
||||
|
||||
func (c *RepoCache) ResolveIdentityMatcher(f func(*IdentityExcerpt) bool) (*IdentityCache, error) {
|
||||
id, err := c.resolveIdentityMatcher(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.ResolveIdentity(id)
|
||||
}
|
||||
|
||||
func (c *RepoCache) resolveIdentityMatcher(f func(*IdentityExcerpt) bool) (entity.Id, error) {
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
// preallocate but empty
|
||||
matching := make([]entity.Id, 0, 5)
|
||||
|
||||
@ -800,18 +919,21 @@ func (c *RepoCache) ResolveIdentityMatcher(f func(*IdentityExcerpt) bool) (*Iden
|
||||
}
|
||||
|
||||
if len(matching) > 1 {
|
||||
return nil, identity.NewErrMultipleMatch(matching)
|
||||
return entity.UnsetId, identity.NewErrMultipleMatch(matching)
|
||||
}
|
||||
|
||||
if len(matching) == 0 {
|
||||
return nil, identity.ErrIdentityNotExist
|
||||
return entity.UnsetId, identity.ErrIdentityNotExist
|
||||
}
|
||||
|
||||
return c.ResolveIdentity(matching[0])
|
||||
return matching[0], nil
|
||||
}
|
||||
|
||||
// AllIdentityIds return all known identity ids
|
||||
func (c *RepoCache) AllIdentityIds() []entity.Id {
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
result := make([]entity.Id, len(c.identitiesExcerpts))
|
||||
|
||||
i := 0
|
||||
@ -829,6 +951,9 @@ func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
|
||||
return err
|
||||
}
|
||||
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
// Make sure that everything is fine
|
||||
if _, ok := c.identities[i.Id()]; !ok {
|
||||
panic("SetUserIdentity while the identity is not from the cache, something is wrong")
|
||||
@ -847,6 +972,9 @@ func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
|
||||
}
|
||||
}
|
||||
|
||||
c.muIdentity.Lock()
|
||||
defer c.muIdentity.Unlock()
|
||||
|
||||
i, err := identity.GetUserIdentity(c.repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -859,6 +987,25 @@ func (c *RepoCache) GetUserIdentity() (*IdentityCache, error) {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
func (c *RepoCache) GetUserIdentityExcerpt() (*IdentityExcerpt, error) {
|
||||
if c.userIdentityId == "" {
|
||||
id, err := identity.GetUserIdentityId(c.repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.userIdentityId = id
|
||||
}
|
||||
|
||||
c.muIdentity.RLock()
|
||||
defer c.muIdentity.RUnlock()
|
||||
|
||||
excerpt, ok := c.identitiesExcerpts[c.userIdentityId]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cache: missing identity excerpt %v", c.userIdentityId)
|
||||
}
|
||||
return excerpt, nil
|
||||
}
|
||||
|
||||
func (c *RepoCache) IsUserIdentitySet() (bool, error) {
|
||||
return identity.IsUserIdentitySet(c.repo)
|
||||
}
|
||||
@ -902,12 +1049,14 @@ func (c *RepoCache) finishIdentity(i *identity.Identity, metadata map[string]str
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.muIdentity.Lock()
|
||||
if _, has := c.identities[i.Id()]; has {
|
||||
return nil, fmt.Errorf("identity %s already exist in the cache", i.Id())
|
||||
}
|
||||
|
||||
cached := NewIdentityCache(c, i)
|
||||
c.identities[i.Id()] = cached
|
||||
c.muIdentity.Unlock()
|
||||
|
||||
// force the write of the excerpt
|
||||
err = c.identityUpdated(i.Id())
|
||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/MichaelMure/git-bug
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200205113530-b941b970f0b6
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b
|
||||
github.com/MichaelMure/go-term-text v0.2.6
|
||||
github.com/araddon/dateparse v0.0.0-20190622164848-0fb0a474d195
|
||||
github.com/awesome-gocui/gocui v0.6.1-0.20191115151952-a34ffb055986
|
||||
|
13
go.sum
13
go.sum
@ -1,11 +1,11 @@
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200205113530-b941b970f0b6 h1:WU+9Z7AoCyl+HlB2kE0O+4/3BaVqLQfnX5dHigV5p8A=
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200205113530-b941b970f0b6/go.mod h1:28v/ATDVwPUriwNtAIrQEhRHXJjdi5dVGqxSqPna1I8=
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200208093655-ab8d62b67dd0 h1:ADy3XJwhOYg6Pb90XeXazWvO+9gpOsgLuaM1buZUZOY=
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200208093655-ab8d62b67dd0/go.mod h1:dfBhwZKMcSYiYRMTs8qWF+Oha6782e1xPfgRmVal9I8=
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b h1:510xa84qGbDemwTHNio4cLWkdKFxxJgVtsIOH+Ku8bo=
|
||||
github.com/99designs/gqlgen v0.10.3-0.20200209012558-b7a58a1c0e4b/go.mod h1:dfBhwZKMcSYiYRMTs8qWF+Oha6782e1xPfgRmVal9I8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/MichaelMure/go-term-text v0.2.4 h1:h+lAsjG5o3oNvaJeh7OzE8zdSiB/VyJo9JzSnncrZv4=
|
||||
github.com/MichaelMure/go-term-text v0.2.4/go.mod h1:o2Z5T3b28F4kwAojGvvNdbzjHf9t18vbQ7E2pmTe2Ww=
|
||||
github.com/MichaelMure/go-term-text v0.2.6 h1:dSmJSzk2iI5xWymSMrMbdVM1bxYWu3DjDFhdcJvAuqA=
|
||||
github.com/MichaelMure/go-term-text v0.2.6/go.mod h1:o2Z5T3b28F4kwAojGvvNdbzjHf9t18vbQ7E2pmTe2Ww=
|
||||
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
||||
@ -36,8 +36,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@ -69,6 +67,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
@ -132,6 +131,8 @@ github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUd
|
||||
github.com/vektah/gqlparser v1.2.1 h1:C+L7Go/eUbN0w6Y0kaiq2W6p2wN5j8wU82EdDXxDivc=
|
||||
github.com/vektah/gqlparser v1.2.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||
github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU=
|
||||
github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU=
|
||||
github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||
github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||
github.com/xanzy/go-gitlab v0.22.1 h1:TVxgHmoa35jQL+9FCkG0nwPDxU9dQZXknBTDtGaSFno=
|
||||
github.com/xanzy/go-gitlab v0.22.1/go.mod h1:t4Bmvnxj7k37S4Y17lfLx+nLqkf/oQwT2HagfWKv5Og=
|
||||
|
@ -1,6 +1,6 @@
|
||||
//go:generate genny -in=connection_template.go -out=gen_lazy_bug.go gen "Name=LazyBug NodeType=entity.Id EdgeType=LazyBugEdge ConnectionType=models.BugConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_lazy_identity.go gen "Name=LazyIdentity NodeType=entity.Id EdgeType=LazyIdentityEdge ConnectionType=models.IdentityConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_identity.go gen "Name=Identity NodeType=identity.Interface EdgeType=models.IdentityEdge ConnectionType=models.IdentityConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_identity.go gen "Name=Identity NodeType=models.IdentityWrapper EdgeType=models.IdentityEdge ConnectionType=models.IdentityConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_operation.go gen "Name=Operation NodeType=bug.Operation EdgeType=models.OperationEdge ConnectionType=models.OperationConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_comment.go gen "Name=Comment NodeType=bug.Comment EdgeType=models.CommentEdge ConnectionType=models.CommentConnection"
|
||||
//go:generate genny -in=connection_template.go -out=gen_timeline.go gen "Name=TimelineItem NodeType=bug.TimelineItem EdgeType=models.TimelineItemEdge ConnectionType=models.TimelineItemConnection"
|
||||
|
@ -2,6 +2,17 @@ package connections
|
||||
|
||||
import "github.com/MichaelMure/git-bug/entity"
|
||||
|
||||
// LazyBugEdge is a special relay edge used to implement a lazy loading connection
|
||||
type LazyBugEdge struct {
|
||||
Id entity.Id
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// GetCursor return the cursor of a LazyBugEdge
|
||||
func (lbe LazyBugEdge) GetCursor() string {
|
||||
return lbe.Cursor
|
||||
}
|
||||
|
||||
// LazyIdentityEdge is a special relay edge used to implement a lazy loading connection
|
||||
type LazyIdentityEdge struct {
|
||||
Id entity.Id
|
@ -8,23 +8,22 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/MichaelMure/git-bug/graphql/models"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
)
|
||||
|
||||
// IdentityInterfaceEdgeMaker define a function that take a identity.Interface and an offset and
|
||||
// ModelsIdentityWrapperEdgeMaker define a function that take a models.IdentityWrapper and an offset and
|
||||
// create an Edge.
|
||||
type IdentityEdgeMaker func(value identity.Interface, offset int) Edge
|
||||
type IdentityEdgeMaker func(value models.IdentityWrapper, offset int) Edge
|
||||
|
||||
// IdentityConMaker define a function that create a models.IdentityConnection
|
||||
type IdentityConMaker func(
|
||||
edges []*models.IdentityEdge,
|
||||
nodes []identity.Interface,
|
||||
nodes []models.IdentityWrapper,
|
||||
info *models.PageInfo,
|
||||
totalCount int) (*models.IdentityConnection, error)
|
||||
|
||||
// IdentityCon will paginate a source according to the input of a relay connection
|
||||
func IdentityCon(source []identity.Interface, edgeMaker IdentityEdgeMaker, conMaker IdentityConMaker, input models.ConnectionInput) (*models.IdentityConnection, error) {
|
||||
var nodes []identity.Interface
|
||||
func IdentityCon(source []models.IdentityWrapper, edgeMaker IdentityEdgeMaker, conMaker IdentityConMaker, input models.ConnectionInput) (*models.IdentityConnection, error) {
|
||||
var nodes []models.IdentityWrapper
|
||||
var edges []*models.IdentityEdge
|
||||
var cursors []string
|
||||
var pageInfo = &models.PageInfo{}
|
||||
|
@ -1,14 +0,0 @@
|
||||
package connections
|
||||
|
||||
import "github.com/MichaelMure/git-bug/entity"
|
||||
|
||||
// LazyBugEdge is a special relay edge used to implement a lazy loading connection
|
||||
type LazyBugEdge struct {
|
||||
Id entity.Id
|
||||
Cursor string
|
||||
}
|
||||
|
||||
// GetCursor return the cursor of a LazyBugEdge
|
||||
func (lbe LazyBugEdge) GetCursor() string {
|
||||
return lbe.Cursor
|
||||
}
|
@ -10,13 +10,24 @@ models:
|
||||
RepositoryMutation:
|
||||
model: github.com/MichaelMure/git-bug/graphql/models.RepositoryMutation
|
||||
Bug:
|
||||
model: github.com/MichaelMure/git-bug/bug.Snapshot
|
||||
model: github.com/MichaelMure/git-bug/graphql/models.BugWrapper
|
||||
fields:
|
||||
actors:
|
||||
resolver: true
|
||||
participants:
|
||||
resolver: true
|
||||
comments:
|
||||
resolver: true
|
||||
timeline:
|
||||
resolver: true
|
||||
operations:
|
||||
resolver: true
|
||||
Color:
|
||||
model: image/color.RGBA
|
||||
Comment:
|
||||
model: github.com/MichaelMure/git-bug/bug.Comment
|
||||
Identity:
|
||||
model: github.com/MichaelMure/git-bug/identity.Interface
|
||||
model: github.com/MichaelMure/git-bug/graphql/models.IdentityWrapper
|
||||
Label:
|
||||
model: github.com/MichaelMure/git-bug/bug.Label
|
||||
Hash:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,6 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
"github.com/MichaelMure/git-bug/util/git"
|
||||
)
|
||||
|
||||
@ -34,7 +33,7 @@ type AddCommentPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation.
|
||||
Operation *bug.AddCommentOperation `json:"operation"`
|
||||
}
|
||||
@ -42,8 +41,8 @@ type AddCommentPayload struct {
|
||||
// The connection type for Bug.
|
||||
type BugConnection struct {
|
||||
// A list of edges.
|
||||
Edges []*BugEdge `json:"edges"`
|
||||
Nodes []*bug.Snapshot `json:"nodes"`
|
||||
Edges []*BugEdge `json:"edges"`
|
||||
Nodes []BugWrapper `json:"nodes"`
|
||||
// Information to aid in pagination.
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
// Identifies the total count of items in the connection.
|
||||
@ -55,7 +54,7 @@ type BugEdge struct {
|
||||
// A cursor for use in pagination.
|
||||
Cursor string `json:"cursor"`
|
||||
// The item at the end of the edge.
|
||||
Node *bug.Snapshot `json:"node"`
|
||||
Node BugWrapper `json:"node"`
|
||||
}
|
||||
|
||||
type ChangeLabelInput struct {
|
||||
@ -75,7 +74,7 @@ type ChangeLabelPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation.
|
||||
Operation *bug.LabelChangeOperation `json:"operation"`
|
||||
// The effect each source label had.
|
||||
@ -95,7 +94,7 @@ type CloseBugPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation.
|
||||
Operation *bug.SetStatusOperation `json:"operation"`
|
||||
}
|
||||
@ -125,7 +124,7 @@ type CommitAsNeededPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
}
|
||||
|
||||
type CommitInput struct {
|
||||
@ -141,19 +140,19 @@ type CommitPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
}
|
||||
|
||||
type IdentityConnection struct {
|
||||
Edges []*IdentityEdge `json:"edges"`
|
||||
Nodes []identity.Interface `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
Edges []*IdentityEdge `json:"edges"`
|
||||
Nodes []IdentityWrapper `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
type IdentityEdge struct {
|
||||
Cursor string `json:"cursor"`
|
||||
Node identity.Interface `json:"node"`
|
||||
Cursor string `json:"cursor"`
|
||||
Node IdentityWrapper `json:"node"`
|
||||
}
|
||||
|
||||
type LabelConnection struct {
|
||||
@ -185,7 +184,7 @@ type NewBugPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The created bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation.
|
||||
Operation *bug.CreateOperation `json:"operation"`
|
||||
}
|
||||
@ -203,7 +202,7 @@ type OpenBugPayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation.
|
||||
Operation *bug.SetStatusOperation `json:"operation"`
|
||||
}
|
||||
@ -249,7 +248,7 @@ type SetTitlePayload struct {
|
||||
// A unique identifier for the client performing the mutation.
|
||||
ClientMutationID *string `json:"clientMutationId"`
|
||||
// The affected bug.
|
||||
Bug *bug.Snapshot `json:"bug"`
|
||||
Bug BugWrapper `json:"bug"`
|
||||
// The resulting operation
|
||||
Operation *bug.SetTitleOperation `json:"operation"`
|
||||
}
|
||||
|
215
graphql/models/lazy_bug.go
Normal file
215
graphql/models/lazy_bug.go
Normal file
@ -0,0 +1,215 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/cache"
|
||||
"github.com/MichaelMure/git-bug/entity"
|
||||
)
|
||||
|
||||
// BugWrapper is an interface used by the GraphQL resolvers to handle a bug.
|
||||
// Depending on the situation, a Bug can already be fully loaded in memory or not.
|
||||
// This interface is used to wrap either a lazyBug or a loadedBug depending on the situation.
|
||||
type BugWrapper interface {
|
||||
Id() entity.Id
|
||||
LastEdit() time.Time
|
||||
Status() bug.Status
|
||||
Title() string
|
||||
Comments() ([]bug.Comment, error)
|
||||
Labels() []bug.Label
|
||||
Author() (IdentityWrapper, error)
|
||||
Actors() ([]IdentityWrapper, error)
|
||||
Participants() ([]IdentityWrapper, error)
|
||||
CreatedAt() time.Time
|
||||
Timeline() ([]bug.TimelineItem, error)
|
||||
Operations() ([]bug.Operation, error)
|
||||
|
||||
IsAuthored()
|
||||
}
|
||||
|
||||
var _ BugWrapper = &lazyBug{}
|
||||
|
||||
// lazyBug is a lazy-loading wrapper that fetch data from the cache (BugExcerpt) in priority,
|
||||
// and load the complete bug and snapshot only when necessary.
|
||||
type lazyBug struct {
|
||||
cache *cache.RepoCache
|
||||
excerpt *cache.BugExcerpt
|
||||
|
||||
mu sync.Mutex
|
||||
snap *bug.Snapshot
|
||||
}
|
||||
|
||||
func NewLazyBug(cache *cache.RepoCache, excerpt *cache.BugExcerpt) *lazyBug {
|
||||
return &lazyBug{
|
||||
cache: cache,
|
||||
excerpt: excerpt,
|
||||
}
|
||||
}
|
||||
|
||||
func (lb *lazyBug) load() error {
|
||||
if lb.snap != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
lb.mu.Lock()
|
||||
defer lb.mu.Unlock()
|
||||
|
||||
b, err := lb.cache.ResolveBug(lb.excerpt.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb.snap = b.Snapshot()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lb *lazyBug) identity(id entity.Id) (IdentityWrapper, error) {
|
||||
i, err := lb.cache.ResolveIdentityExcerpt(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &lazyIdentity{cache: lb.cache, excerpt: i}, nil
|
||||
}
|
||||
|
||||
// Sign post method for gqlgen
|
||||
func (lb *lazyBug) IsAuthored() {}
|
||||
|
||||
func (lb *lazyBug) Id() entity.Id {
|
||||
return lb.excerpt.Id
|
||||
}
|
||||
|
||||
func (lb *lazyBug) LastEdit() time.Time {
|
||||
return time.Unix(lb.excerpt.EditUnixTime, 0)
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Status() bug.Status {
|
||||
return lb.excerpt.Status
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Title() string {
|
||||
return lb.excerpt.Title
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Comments() ([]bug.Comment, error) {
|
||||
err := lb.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lb.snap.Comments, nil
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Labels() []bug.Label {
|
||||
return lb.excerpt.Labels
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Author() (IdentityWrapper, error) {
|
||||
return lb.identity(lb.excerpt.AuthorId)
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Actors() ([]IdentityWrapper, error) {
|
||||
result := make([]IdentityWrapper, len(lb.excerpt.Actors))
|
||||
for i, actorId := range lb.excerpt.Actors {
|
||||
actor, err := lb.identity(actorId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[i] = actor
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Participants() ([]IdentityWrapper, error) {
|
||||
result := make([]IdentityWrapper, len(lb.excerpt.Participants))
|
||||
for i, participantId := range lb.excerpt.Participants {
|
||||
participant, err := lb.identity(participantId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[i] = participant
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (lb *lazyBug) CreatedAt() time.Time {
|
||||
return time.Unix(lb.excerpt.CreateUnixTime, 0)
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Timeline() ([]bug.TimelineItem, error) {
|
||||
err := lb.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lb.snap.Timeline, nil
|
||||
}
|
||||
|
||||
func (lb *lazyBug) Operations() ([]bug.Operation, error) {
|
||||
err := lb.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lb.snap.Operations, nil
|
||||
}
|
||||
|
||||
var _ BugWrapper = &loadedBug{}
|
||||
|
||||
type loadedBug struct {
|
||||
*bug.Snapshot
|
||||
}
|
||||
|
||||
func NewLoadedBug(snap *bug.Snapshot) *loadedBug {
|
||||
return &loadedBug{Snapshot: snap}
|
||||
}
|
||||
|
||||
func (l *loadedBug) LastEdit() time.Time {
|
||||
return l.Snapshot.LastEditTime()
|
||||
}
|
||||
|
||||
func (l *loadedBug) Status() bug.Status {
|
||||
return l.Snapshot.Status
|
||||
}
|
||||
|
||||
func (l *loadedBug) Title() string {
|
||||
return l.Snapshot.Title
|
||||
}
|
||||
|
||||
func (l *loadedBug) Comments() ([]bug.Comment, error) {
|
||||
return l.Snapshot.Comments, nil
|
||||
}
|
||||
|
||||
func (l *loadedBug) Labels() []bug.Label {
|
||||
return l.Snapshot.Labels
|
||||
}
|
||||
|
||||
func (l *loadedBug) Author() (IdentityWrapper, error) {
|
||||
return NewLoadedIdentity(l.Snapshot.Author), nil
|
||||
}
|
||||
|
||||
func (l *loadedBug) Actors() ([]IdentityWrapper, error) {
|
||||
res := make([]IdentityWrapper, len(l.Snapshot.Actors))
|
||||
for i, actor := range l.Snapshot.Actors {
|
||||
res[i] = NewLoadedIdentity(actor)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (l *loadedBug) Participants() ([]IdentityWrapper, error) {
|
||||
res := make([]IdentityWrapper, len(l.Snapshot.Participants))
|
||||
for i, participant := range l.Snapshot.Participants {
|
||||
res[i] = NewLoadedIdentity(participant)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (l *loadedBug) CreatedAt() time.Time {
|
||||
return l.Snapshot.CreatedAt
|
||||
}
|
||||
|
||||
func (l *loadedBug) Timeline() ([]bug.TimelineItem, error) {
|
||||
return l.Snapshot.Timeline, nil
|
||||
}
|
||||
|
||||
func (l *loadedBug) Operations() ([]bug.Operation, error) {
|
||||
return l.Snapshot.Operations, nil
|
||||
}
|
167
graphql/models/lazy_identity.go
Normal file
167
graphql/models/lazy_identity.go
Normal file
@ -0,0 +1,167 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/MichaelMure/git-bug/cache"
|
||||
"github.com/MichaelMure/git-bug/entity"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
"github.com/MichaelMure/git-bug/util/lamport"
|
||||
"github.com/MichaelMure/git-bug/util/timestamp"
|
||||
)
|
||||
|
||||
// IdentityWrapper is an interface used by the GraphQL resolvers to handle an identity.
|
||||
// Depending on the situation, an Identity can already be fully loaded in memory or not.
|
||||
// This interface is used to wrap either a lazyIdentity or a loadedIdentity depending on the situation.
|
||||
type IdentityWrapper interface {
|
||||
Id() entity.Id
|
||||
Name() string
|
||||
Email() (string, error)
|
||||
AvatarUrl() (string, error)
|
||||
Keys() ([]*identity.Key, error)
|
||||
ValidKeysAtTime(time lamport.Time) ([]*identity.Key, error)
|
||||
DisplayName() string
|
||||
IsProtected() (bool, error)
|
||||
LastModificationLamport() (lamport.Time, error)
|
||||
LastModification() (timestamp.Timestamp, error)
|
||||
}
|
||||
|
||||
var _ IdentityWrapper = &lazyIdentity{}
|
||||
|
||||
type lazyIdentity struct {
|
||||
cache *cache.RepoCache
|
||||
excerpt *cache.IdentityExcerpt
|
||||
|
||||
mu sync.Mutex
|
||||
id *cache.IdentityCache
|
||||
}
|
||||
|
||||
func NewLazyIdentity(cache *cache.RepoCache, excerpt *cache.IdentityExcerpt) *lazyIdentity {
|
||||
return &lazyIdentity{
|
||||
cache: cache,
|
||||
excerpt: excerpt,
|
||||
}
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) load() (*cache.IdentityCache, error) {
|
||||
if li.id != nil {
|
||||
return li.id, nil
|
||||
}
|
||||
|
||||
li.mu.Lock()
|
||||
defer li.mu.Unlock()
|
||||
|
||||
id, err := li.cache.ResolveIdentity(li.excerpt.Id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cache: missing identity %v", li.excerpt.Id)
|
||||
}
|
||||
li.id = id
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) Id() entity.Id {
|
||||
return li.excerpt.Id
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) Name() string {
|
||||
return li.excerpt.Name
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) Email() (string, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id.Email(), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) AvatarUrl() (string, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return id.AvatarUrl(), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) Keys() ([]*identity.Key, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return id.Keys(), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) ValidKeysAtTime(time lamport.Time) ([]*identity.Key, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return id.ValidKeysAtTime(time), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) DisplayName() string {
|
||||
return li.excerpt.DisplayName()
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) IsProtected() (bool, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return id.IsProtected(), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) LastModificationLamport() (lamport.Time, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id.LastModificationLamport(), nil
|
||||
}
|
||||
|
||||
func (li *lazyIdentity) LastModification() (timestamp.Timestamp, error) {
|
||||
id, err := li.load()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id.LastModification(), nil
|
||||
}
|
||||
|
||||
var _ IdentityWrapper = &loadedIdentity{}
|
||||
|
||||
type loadedIdentity struct {
|
||||
identity.Interface
|
||||
}
|
||||
|
||||
func NewLoadedIdentity(id identity.Interface) *loadedIdentity {
|
||||
return &loadedIdentity{Interface: id}
|
||||
}
|
||||
|
||||
func (l loadedIdentity) Email() (string, error) {
|
||||
return l.Interface.Email(), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) AvatarUrl() (string, error) {
|
||||
return l.Interface.AvatarUrl(), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) Keys() ([]*identity.Key, error) {
|
||||
return l.Interface.Keys(), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) ValidKeysAtTime(time lamport.Time) ([]*identity.Key, error) {
|
||||
return l.Interface.ValidKeysAtTime(time), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) IsProtected() (bool, error) {
|
||||
return l.Interface.IsProtected(), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) LastModificationLamport() (lamport.Time, error) {
|
||||
return l.Interface.LastModificationLamport(), nil
|
||||
}
|
||||
|
||||
func (l loadedIdentity) LastModification() (timestamp.Timestamp, error) {
|
||||
return l.Interface.LastModification(), nil
|
||||
}
|
@ -2,32 +2,30 @@ package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/graphql/connections"
|
||||
"github.com/MichaelMure/git-bug/graphql/graph"
|
||||
"github.com/MichaelMure/git-bug/graphql/models"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
)
|
||||
|
||||
var _ graph.BugResolver = &bugResolver{}
|
||||
|
||||
type bugResolver struct{}
|
||||
|
||||
func (bugResolver) ID(ctx context.Context, obj *bug.Snapshot) (string, error) {
|
||||
func (bugResolver) ID(_ context.Context, obj models.BugWrapper) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (bugResolver) HumanID(ctx context.Context, obj *bug.Snapshot) (string, error) {
|
||||
func (bugResolver) HumanID(_ context.Context, obj models.BugWrapper) (string, error) {
|
||||
return obj.Id().Human(), nil
|
||||
}
|
||||
|
||||
func (bugResolver) Status(ctx context.Context, obj *bug.Snapshot) (models.Status, error) {
|
||||
return convertStatus(obj.Status)
|
||||
func (bugResolver) Status(_ context.Context, obj models.BugWrapper) (models.Status, error) {
|
||||
return convertStatus(obj.Status())
|
||||
}
|
||||
|
||||
func (bugResolver) Comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (*models.CommentConnection, error) {
|
||||
func (bugResolver) Comments(_ context.Context, obj models.BugWrapper, after *string, before *string, first *int, last *int) (*models.CommentConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -55,10 +53,15 @@ func (bugResolver) Comments(ctx context.Context, obj *bug.Snapshot, after *strin
|
||||
}, nil
|
||||
}
|
||||
|
||||
return connections.CommentCon(obj.Comments, edger, conMaker, input)
|
||||
comments, err := obj.Comments()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connections.CommentCon(comments, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (bugResolver) Operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (*models.OperationConnection, error) {
|
||||
func (bugResolver) Operations(_ context.Context, obj models.BugWrapper, after *string, before *string, first *int, last *int) (*models.OperationConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -82,10 +85,15 @@ func (bugResolver) Operations(ctx context.Context, obj *bug.Snapshot, after *str
|
||||
}, nil
|
||||
}
|
||||
|
||||
return connections.OperationCon(obj.Operations, edger, conMaker, input)
|
||||
ops, err := obj.Operations()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connections.OperationCon(ops, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (bugResolver) Timeline(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (*models.TimelineItemConnection, error) {
|
||||
func (bugResolver) Timeline(_ context.Context, obj models.BugWrapper, after *string, before *string, first *int, last *int) (*models.TimelineItemConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -109,15 +117,15 @@ func (bugResolver) Timeline(ctx context.Context, obj *bug.Snapshot, after *strin
|
||||
}, nil
|
||||
}
|
||||
|
||||
return connections.TimelineItemCon(obj.Timeline, edger, conMaker, input)
|
||||
timeline, err := obj.Timeline()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connections.TimelineItemCon(timeline, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (bugResolver) LastEdit(ctx context.Context, obj *bug.Snapshot) (*time.Time, error) {
|
||||
t := obj.LastEditTime()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (bugResolver) Actors(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
func (bugResolver) Actors(_ context.Context, obj models.BugWrapper, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -125,14 +133,14 @@ func (bugResolver) Actors(ctx context.Context, obj *bug.Snapshot, after *string,
|
||||
Last: last,
|
||||
}
|
||||
|
||||
edger := func(actor identity.Interface, offset int) connections.Edge {
|
||||
edger := func(actor models.IdentityWrapper, offset int) connections.Edge {
|
||||
return models.IdentityEdge{
|
||||
Node: actor,
|
||||
Cursor: connections.OffsetToCursor(offset),
|
||||
}
|
||||
}
|
||||
|
||||
conMaker := func(edges []*models.IdentityEdge, nodes []identity.Interface, info *models.PageInfo, totalCount int) (*models.IdentityConnection, error) {
|
||||
conMaker := func(edges []*models.IdentityEdge, nodes []models.IdentityWrapper, info *models.PageInfo, totalCount int) (*models.IdentityConnection, error) {
|
||||
return &models.IdentityConnection{
|
||||
Edges: edges,
|
||||
Nodes: nodes,
|
||||
@ -141,10 +149,15 @@ func (bugResolver) Actors(ctx context.Context, obj *bug.Snapshot, after *string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return connections.IdentityCon(obj.Actors, edger, conMaker, input)
|
||||
actors, err := obj.Actors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connections.IdentityCon(actors, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (bugResolver) Participants(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
func (bugResolver) Participants(_ context.Context, obj models.BugWrapper, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -152,14 +165,14 @@ func (bugResolver) Participants(ctx context.Context, obj *bug.Snapshot, after *s
|
||||
Last: last,
|
||||
}
|
||||
|
||||
edger := func(participant identity.Interface, offset int) connections.Edge {
|
||||
edger := func(participant models.IdentityWrapper, offset int) connections.Edge {
|
||||
return models.IdentityEdge{
|
||||
Node: participant,
|
||||
Cursor: connections.OffsetToCursor(offset),
|
||||
}
|
||||
}
|
||||
|
||||
conMaker := func(edges []*models.IdentityEdge, nodes []identity.Interface, info *models.PageInfo, totalCount int) (*models.IdentityConnection, error) {
|
||||
conMaker := func(edges []*models.IdentityEdge, nodes []models.IdentityWrapper, info *models.PageInfo, totalCount int) (*models.IdentityConnection, error) {
|
||||
return &models.IdentityConnection{
|
||||
Edges: edges,
|
||||
Nodes: nodes,
|
||||
@ -168,5 +181,10 @@ func (bugResolver) Participants(ctx context.Context, obj *bug.Snapshot, after *s
|
||||
}, nil
|
||||
}
|
||||
|
||||
return connections.IdentityCon(obj.Participants, edger, conMaker, input)
|
||||
participants, err := obj.Participants()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return connections.IdentityCon(participants, edger, conMaker, input)
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ var _ graph.ColorResolver = &colorResolver{}
|
||||
|
||||
type colorResolver struct{}
|
||||
|
||||
func (colorResolver) R(ctx context.Context, obj *color.RGBA) (int, error) {
|
||||
func (colorResolver) R(_ context.Context, obj *color.RGBA) (int, error) {
|
||||
return int(obj.R), nil
|
||||
}
|
||||
|
||||
func (colorResolver) G(ctx context.Context, obj *color.RGBA) (int, error) {
|
||||
func (colorResolver) G(_ context.Context, obj *color.RGBA) (int, error) {
|
||||
return int(obj.G), nil
|
||||
}
|
||||
|
||||
func (colorResolver) B(ctx context.Context, obj *color.RGBA) (int, error) {
|
||||
func (colorResolver) B(_ context.Context, obj *color.RGBA) (int, error) {
|
||||
return int(obj.B), nil
|
||||
}
|
||||
|
17
graphql/resolvers/comment.go
Normal file
17
graphql/resolvers/comment.go
Normal file
@ -0,0 +1,17 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/graphql/graph"
|
||||
"github.com/MichaelMure/git-bug/graphql/models"
|
||||
)
|
||||
|
||||
var _ graph.CommentResolver = &commentResolver{}
|
||||
|
||||
type commentResolver struct{}
|
||||
|
||||
func (c commentResolver) Author(_ context.Context, obj *bug.Comment) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
@ -4,18 +4,18 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/MichaelMure/git-bug/graphql/graph"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
"github.com/MichaelMure/git-bug/graphql/models"
|
||||
)
|
||||
|
||||
var _ graph.IdentityResolver = &identityResolver{}
|
||||
|
||||
type identityResolver struct{}
|
||||
|
||||
func (identityResolver) ID(ctx context.Context, obj identity.Interface) (string, error) {
|
||||
func (identityResolver) ID(ctx context.Context, obj models.IdentityWrapper) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (r identityResolver) HumanID(ctx context.Context, obj identity.Interface) (string, error) {
|
||||
func (r identityResolver) HumanID(ctx context.Context, obj models.IdentityWrapper) (string, error) {
|
||||
return obj.Id().Human(), nil
|
||||
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ func (r mutationResolver) getRepo(ref *string) (*cache.RepoCache, error) {
|
||||
return r.cache.DefaultRepo()
|
||||
}
|
||||
|
||||
func (r mutationResolver) NewBug(ctx context.Context, input models.NewBugInput) (*models.NewBugPayload, error) {
|
||||
func (r mutationResolver) NewBug(_ context.Context, input models.NewBugInput) (*models.NewBugPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -36,12 +36,12 @@ func (r mutationResolver) NewBug(ctx context.Context, input models.NewBugInput)
|
||||
|
||||
return &models.NewBugPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) AddComment(ctx context.Context, input models.AddCommentInput) (*models.AddCommentPayload, error) {
|
||||
func (r mutationResolver) AddComment(_ context.Context, input models.AddCommentInput) (*models.AddCommentPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -59,12 +59,12 @@ func (r mutationResolver) AddComment(ctx context.Context, input models.AddCommen
|
||||
|
||||
return &models.AddCommentPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) ChangeLabels(ctx context.Context, input *models.ChangeLabelInput) (*models.ChangeLabelPayload, error) {
|
||||
func (r mutationResolver) ChangeLabels(_ context.Context, input *models.ChangeLabelInput) (*models.ChangeLabelPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -87,13 +87,13 @@ func (r mutationResolver) ChangeLabels(ctx context.Context, input *models.Change
|
||||
|
||||
return &models.ChangeLabelPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
Results: resultsPtr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) OpenBug(ctx context.Context, input models.OpenBugInput) (*models.OpenBugPayload, error) {
|
||||
func (r mutationResolver) OpenBug(_ context.Context, input models.OpenBugInput) (*models.OpenBugPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -111,12 +111,12 @@ func (r mutationResolver) OpenBug(ctx context.Context, input models.OpenBugInput
|
||||
|
||||
return &models.OpenBugPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) CloseBug(ctx context.Context, input models.CloseBugInput) (*models.CloseBugPayload, error) {
|
||||
func (r mutationResolver) CloseBug(_ context.Context, input models.CloseBugInput) (*models.CloseBugPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -134,12 +134,12 @@ func (r mutationResolver) CloseBug(ctx context.Context, input models.CloseBugInp
|
||||
|
||||
return &models.CloseBugPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) SetTitle(ctx context.Context, input models.SetTitleInput) (*models.SetTitlePayload, error) {
|
||||
func (r mutationResolver) SetTitle(_ context.Context, input models.SetTitleInput) (*models.SetTitlePayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -157,12 +157,12 @@ func (r mutationResolver) SetTitle(ctx context.Context, input models.SetTitleInp
|
||||
|
||||
return &models.SetTitlePayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
Operation: op,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) Commit(ctx context.Context, input models.CommitInput) (*models.CommitPayload, error) {
|
||||
func (r mutationResolver) Commit(_ context.Context, input models.CommitInput) (*models.CommitPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -180,11 +180,11 @@ func (r mutationResolver) Commit(ctx context.Context, input models.CommitInput)
|
||||
|
||||
return &models.CommitPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r mutationResolver) CommitAsNeeded(ctx context.Context, input models.CommitAsNeededInput) (*models.CommitAsNeededPayload, error) {
|
||||
func (r mutationResolver) CommitAsNeeded(_ context.Context, input models.CommitAsNeededInput) (*models.CommitAsNeededPayload, error) {
|
||||
repo, err := r.getRepo(input.RepoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -202,6 +202,6 @@ func (r mutationResolver) CommitAsNeeded(ctx context.Context, input models.Commi
|
||||
|
||||
return &models.CommitAsNeededPayload{
|
||||
ClientMutationID: input.ClientMutationID,
|
||||
Bug: b.Snapshot(),
|
||||
Bug: models.NewLoadedBug(b.Snapshot()),
|
||||
}, nil
|
||||
}
|
||||
|
@ -14,11 +14,15 @@ var _ graph.CreateOperationResolver = createOperationResolver{}
|
||||
|
||||
type createOperationResolver struct{}
|
||||
|
||||
func (createOperationResolver) ID(ctx context.Context, obj *bug.CreateOperation) (string, error) {
|
||||
func (createOperationResolver) ID(_ context.Context, obj *bug.CreateOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (createOperationResolver) Date(ctx context.Context, obj *bug.CreateOperation) (*time.Time, error) {
|
||||
func (createOperationResolver) Author(_ context.Context, obj *bug.CreateOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (createOperationResolver) Date(_ context.Context, obj *bug.CreateOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -27,11 +31,15 @@ var _ graph.AddCommentOperationResolver = addCommentOperationResolver{}
|
||||
|
||||
type addCommentOperationResolver struct{}
|
||||
|
||||
func (addCommentOperationResolver) ID(ctx context.Context, obj *bug.AddCommentOperation) (string, error) {
|
||||
func (addCommentOperationResolver) ID(_ context.Context, obj *bug.AddCommentOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (addCommentOperationResolver) Date(ctx context.Context, obj *bug.AddCommentOperation) (*time.Time, error) {
|
||||
func (addCommentOperationResolver) Author(_ context.Context, obj *bug.AddCommentOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (addCommentOperationResolver) Date(_ context.Context, obj *bug.AddCommentOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -40,15 +48,19 @@ var _ graph.EditCommentOperationResolver = editCommentOperationResolver{}
|
||||
|
||||
type editCommentOperationResolver struct{}
|
||||
|
||||
func (editCommentOperationResolver) ID(ctx context.Context, obj *bug.EditCommentOperation) (string, error) {
|
||||
func (editCommentOperationResolver) ID(_ context.Context, obj *bug.EditCommentOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (editCommentOperationResolver) Target(ctx context.Context, obj *bug.EditCommentOperation) (string, error) {
|
||||
func (editCommentOperationResolver) Target(_ context.Context, obj *bug.EditCommentOperation) (string, error) {
|
||||
return obj.Target.String(), nil
|
||||
}
|
||||
|
||||
func (editCommentOperationResolver) Date(ctx context.Context, obj *bug.EditCommentOperation) (*time.Time, error) {
|
||||
func (editCommentOperationResolver) Author(_ context.Context, obj *bug.EditCommentOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (editCommentOperationResolver) Date(_ context.Context, obj *bug.EditCommentOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -57,11 +69,15 @@ var _ graph.LabelChangeOperationResolver = labelChangeOperationResolver{}
|
||||
|
||||
type labelChangeOperationResolver struct{}
|
||||
|
||||
func (labelChangeOperationResolver) ID(ctx context.Context, obj *bug.LabelChangeOperation) (string, error) {
|
||||
func (labelChangeOperationResolver) ID(_ context.Context, obj *bug.LabelChangeOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (labelChangeOperationResolver) Date(ctx context.Context, obj *bug.LabelChangeOperation) (*time.Time, error) {
|
||||
func (labelChangeOperationResolver) Author(_ context.Context, obj *bug.LabelChangeOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (labelChangeOperationResolver) Date(_ context.Context, obj *bug.LabelChangeOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -70,16 +86,20 @@ var _ graph.SetStatusOperationResolver = setStatusOperationResolver{}
|
||||
|
||||
type setStatusOperationResolver struct{}
|
||||
|
||||
func (setStatusOperationResolver) ID(ctx context.Context, obj *bug.SetStatusOperation) (string, error) {
|
||||
func (setStatusOperationResolver) ID(_ context.Context, obj *bug.SetStatusOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (setStatusOperationResolver) Date(ctx context.Context, obj *bug.SetStatusOperation) (*time.Time, error) {
|
||||
func (setStatusOperationResolver) Author(_ context.Context, obj *bug.SetStatusOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (setStatusOperationResolver) Date(_ context.Context, obj *bug.SetStatusOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (setStatusOperationResolver) Status(ctx context.Context, obj *bug.SetStatusOperation) (models.Status, error) {
|
||||
func (setStatusOperationResolver) Status(_ context.Context, obj *bug.SetStatusOperation) (models.Status, error) {
|
||||
return convertStatus(obj.Status)
|
||||
}
|
||||
|
||||
@ -87,11 +107,15 @@ var _ graph.SetTitleOperationResolver = setTitleOperationResolver{}
|
||||
|
||||
type setTitleOperationResolver struct{}
|
||||
|
||||
func (setTitleOperationResolver) ID(ctx context.Context, obj *bug.SetTitleOperation) (string, error) {
|
||||
func (setTitleOperationResolver) ID(_ context.Context, obj *bug.SetTitleOperation) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (setTitleOperationResolver) Date(ctx context.Context, obj *bug.SetTitleOperation) (*time.Time, error) {
|
||||
func (setTitleOperationResolver) Author(_ context.Context, obj *bug.SetTitleOperation) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (setTitleOperationResolver) Date(_ context.Context, obj *bug.SetTitleOperation) (*time.Time, error) {
|
||||
t := obj.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ type rootQueryResolver struct {
|
||||
cache *cache.MultiRepoCache
|
||||
}
|
||||
|
||||
func (r rootQueryResolver) DefaultRepository(ctx context.Context) (*models.Repository, error) {
|
||||
func (r rootQueryResolver) DefaultRepository(_ context.Context) (*models.Repository, error) {
|
||||
repo, err := r.cache.DefaultRepo()
|
||||
|
||||
if err != nil {
|
||||
@ -27,7 +27,7 @@ func (r rootQueryResolver) DefaultRepository(ctx context.Context) (*models.Repos
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r rootQueryResolver) Repository(ctx context.Context, ref string) (*models.Repository, error) {
|
||||
func (r rootQueryResolver) Repository(_ context.Context, ref string) (*models.Repository, error) {
|
||||
repo, err := r.cache.ResolveRepo(ref)
|
||||
|
||||
if err != nil {
|
||||
|
@ -9,14 +9,13 @@ import (
|
||||
"github.com/MichaelMure/git-bug/graphql/connections"
|
||||
"github.com/MichaelMure/git-bug/graphql/graph"
|
||||
"github.com/MichaelMure/git-bug/graphql/models"
|
||||
"github.com/MichaelMure/git-bug/identity"
|
||||
)
|
||||
|
||||
var _ graph.RepositoryResolver = &repoResolver{}
|
||||
|
||||
type repoResolver struct{}
|
||||
|
||||
func (repoResolver) AllBugs(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int, queryStr *string) (*models.BugConnection, error) {
|
||||
func (repoResolver) AllBugs(_ context.Context, obj *models.Repository, after *string, before *string, first *int, last *int, queryStr *string) (*models.BugConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -49,22 +48,21 @@ func (repoResolver) AllBugs(ctx context.Context, obj *models.Repository, after *
|
||||
// The conMaker will finally load and compile bugs from git to replace the selected edges
|
||||
conMaker := func(lazyBugEdges []*connections.LazyBugEdge, lazyNode []entity.Id, info *models.PageInfo, totalCount int) (*models.BugConnection, error) {
|
||||
edges := make([]*models.BugEdge, len(lazyBugEdges))
|
||||
nodes := make([]*bug.Snapshot, len(lazyBugEdges))
|
||||
nodes := make([]models.BugWrapper, len(lazyBugEdges))
|
||||
|
||||
for i, lazyBugEdge := range lazyBugEdges {
|
||||
b, err := obj.Repo.ResolveBug(lazyBugEdge.Id)
|
||||
|
||||
excerpt, err := obj.Repo.ResolveBugExcerpt(lazyBugEdge.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snap := b.Snapshot()
|
||||
b := models.NewLazyBug(obj.Repo, excerpt)
|
||||
|
||||
edges[i] = &models.BugEdge{
|
||||
Cursor: lazyBugEdge.Cursor,
|
||||
Node: snap,
|
||||
Node: b,
|
||||
}
|
||||
nodes[i] = snap
|
||||
nodes[i] = b
|
||||
}
|
||||
|
||||
return &models.BugConnection{
|
||||
@ -78,17 +76,16 @@ func (repoResolver) AllBugs(ctx context.Context, obj *models.Repository, after *
|
||||
return connections.LazyBugCon(source, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (repoResolver) Bug(ctx context.Context, obj *models.Repository, prefix string) (*bug.Snapshot, error) {
|
||||
b, err := obj.Repo.ResolveBugPrefix(prefix)
|
||||
|
||||
func (repoResolver) Bug(_ context.Context, obj *models.Repository, prefix string) (models.BugWrapper, error) {
|
||||
excerpt, err := obj.Repo.ResolveBugExcerptPrefix(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.Snapshot(), nil
|
||||
return models.NewLazyBug(obj.Repo, excerpt), nil
|
||||
}
|
||||
|
||||
func (repoResolver) AllIdentities(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
func (repoResolver) AllIdentities(_ context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.IdentityConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
@ -110,22 +107,21 @@ func (repoResolver) AllIdentities(ctx context.Context, obj *models.Repository, a
|
||||
// The conMaker will finally load and compile identities from git to replace the selected edges
|
||||
conMaker := func(lazyIdentityEdges []*connections.LazyIdentityEdge, lazyNode []entity.Id, info *models.PageInfo, totalCount int) (*models.IdentityConnection, error) {
|
||||
edges := make([]*models.IdentityEdge, len(lazyIdentityEdges))
|
||||
nodes := make([]identity.Interface, len(lazyIdentityEdges))
|
||||
nodes := make([]models.IdentityWrapper, len(lazyIdentityEdges))
|
||||
|
||||
for k, lazyIdentityEdge := range lazyIdentityEdges {
|
||||
i, err := obj.Repo.ResolveIdentity(lazyIdentityEdge.Id)
|
||||
|
||||
excerpt, err := obj.Repo.ResolveIdentityExcerpt(lazyIdentityEdge.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ii := identity.Interface(i.Identity)
|
||||
i := models.NewLazyIdentity(obj.Repo, excerpt)
|
||||
|
||||
edges[k] = &models.IdentityEdge{
|
||||
Cursor: lazyIdentityEdge.Cursor,
|
||||
Node: i.Identity,
|
||||
Node: i,
|
||||
}
|
||||
nodes[k] = ii
|
||||
nodes[k] = i
|
||||
}
|
||||
|
||||
return &models.IdentityConnection{
|
||||
@ -139,27 +135,25 @@ func (repoResolver) AllIdentities(ctx context.Context, obj *models.Repository, a
|
||||
return connections.LazyIdentityCon(source, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (repoResolver) Identity(ctx context.Context, obj *models.Repository, prefix string) (identity.Interface, error) {
|
||||
i, err := obj.Repo.ResolveIdentityPrefix(prefix)
|
||||
|
||||
func (repoResolver) Identity(_ context.Context, obj *models.Repository, prefix string) (models.IdentityWrapper, error) {
|
||||
excerpt, err := obj.Repo.ResolveIdentityExcerptPrefix(prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.Identity, nil
|
||||
return models.NewLazyIdentity(obj.Repo, excerpt), nil
|
||||
}
|
||||
|
||||
func (repoResolver) UserIdentity(ctx context.Context, obj *models.Repository) (identity.Interface, error) {
|
||||
i, err := obj.Repo.GetUserIdentity()
|
||||
|
||||
func (repoResolver) UserIdentity(_ context.Context, obj *models.Repository) (models.IdentityWrapper, error) {
|
||||
excerpt, err := obj.Repo.GetUserIdentityExcerpt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i.Identity, nil
|
||||
return models.NewLazyIdentity(obj.Repo, excerpt), nil
|
||||
}
|
||||
|
||||
func (resolver repoResolver) ValidLabels(ctx context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.LabelConnection, error) {
|
||||
func (resolver repoResolver) ValidLabels(_ context.Context, obj *models.Repository, after *string, before *string, first *int, last *int) (*models.LabelConnection, error) {
|
||||
input := models.ConnectionInput{
|
||||
Before: before,
|
||||
After: after,
|
||||
|
@ -42,6 +42,10 @@ func (RootResolver) Color() graph.ColorResolver {
|
||||
return &colorResolver{}
|
||||
}
|
||||
|
||||
func (r RootResolver) Comment() graph.CommentResolver {
|
||||
return &commentResolver{}
|
||||
}
|
||||
|
||||
func (RootResolver) Label() graph.LabelResolver {
|
||||
return &labelResolver{}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ var _ graph.CommentHistoryStepResolver = commentHistoryStepResolver{}
|
||||
|
||||
type commentHistoryStepResolver struct{}
|
||||
|
||||
func (commentHistoryStepResolver) Date(ctx context.Context, obj *bug.CommentHistoryStep) (*time.Time, error) {
|
||||
func (commentHistoryStepResolver) Date(_ context.Context, obj *bug.CommentHistoryStep) (*time.Time, error) {
|
||||
t := obj.UnixTime.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -22,16 +22,20 @@ var _ graph.AddCommentTimelineItemResolver = addCommentTimelineItemResolver{}
|
||||
|
||||
type addCommentTimelineItemResolver struct{}
|
||||
|
||||
func (addCommentTimelineItemResolver) ID(ctx context.Context, obj *bug.AddCommentTimelineItem) (string, error) {
|
||||
func (addCommentTimelineItemResolver) ID(_ context.Context, obj *bug.AddCommentTimelineItem) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (addCommentTimelineItemResolver) CreatedAt(ctx context.Context, obj *bug.AddCommentTimelineItem) (*time.Time, error) {
|
||||
func (addCommentTimelineItemResolver) Author(_ context.Context, obj *bug.AddCommentTimelineItem) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (addCommentTimelineItemResolver) CreatedAt(_ context.Context, obj *bug.AddCommentTimelineItem) (*time.Time, error) {
|
||||
t := obj.CreatedAt.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (addCommentTimelineItemResolver) LastEdit(ctx context.Context, obj *bug.AddCommentTimelineItem) (*time.Time, error) {
|
||||
func (addCommentTimelineItemResolver) LastEdit(_ context.Context, obj *bug.AddCommentTimelineItem) (*time.Time, error) {
|
||||
t := obj.LastEdit.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -40,16 +44,20 @@ var _ graph.CreateTimelineItemResolver = createTimelineItemResolver{}
|
||||
|
||||
type createTimelineItemResolver struct{}
|
||||
|
||||
func (createTimelineItemResolver) ID(ctx context.Context, obj *bug.CreateTimelineItem) (string, error) {
|
||||
func (createTimelineItemResolver) ID(_ context.Context, obj *bug.CreateTimelineItem) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (createTimelineItemResolver) CreatedAt(ctx context.Context, obj *bug.CreateTimelineItem) (*time.Time, error) {
|
||||
func (r createTimelineItemResolver) Author(_ context.Context, obj *bug.CreateTimelineItem) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (createTimelineItemResolver) CreatedAt(_ context.Context, obj *bug.CreateTimelineItem) (*time.Time, error) {
|
||||
t := obj.CreatedAt.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (createTimelineItemResolver) LastEdit(ctx context.Context, obj *bug.CreateTimelineItem) (*time.Time, error) {
|
||||
func (createTimelineItemResolver) LastEdit(_ context.Context, obj *bug.CreateTimelineItem) (*time.Time, error) {
|
||||
t := obj.LastEdit.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -58,11 +66,15 @@ var _ graph.LabelChangeTimelineItemResolver = labelChangeTimelineItem{}
|
||||
|
||||
type labelChangeTimelineItem struct{}
|
||||
|
||||
func (labelChangeTimelineItem) ID(ctx context.Context, obj *bug.LabelChangeTimelineItem) (string, error) {
|
||||
func (labelChangeTimelineItem) ID(_ context.Context, obj *bug.LabelChangeTimelineItem) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (labelChangeTimelineItem) Date(ctx context.Context, obj *bug.LabelChangeTimelineItem) (*time.Time, error) {
|
||||
func (i labelChangeTimelineItem) Author(_ context.Context, obj *bug.LabelChangeTimelineItem) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (labelChangeTimelineItem) Date(_ context.Context, obj *bug.LabelChangeTimelineItem) (*time.Time, error) {
|
||||
t := obj.UnixTime.Time()
|
||||
return &t, nil
|
||||
}
|
||||
@ -71,16 +83,20 @@ var _ graph.SetStatusTimelineItemResolver = setStatusTimelineItem{}
|
||||
|
||||
type setStatusTimelineItem struct{}
|
||||
|
||||
func (setStatusTimelineItem) ID(ctx context.Context, obj *bug.SetStatusTimelineItem) (string, error) {
|
||||
func (setStatusTimelineItem) ID(_ context.Context, obj *bug.SetStatusTimelineItem) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (setStatusTimelineItem) Date(ctx context.Context, obj *bug.SetStatusTimelineItem) (*time.Time, error) {
|
||||
func (i setStatusTimelineItem) Author(_ context.Context, obj *bug.SetStatusTimelineItem) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (setStatusTimelineItem) Date(_ context.Context, obj *bug.SetStatusTimelineItem) (*time.Time, error) {
|
||||
t := obj.UnixTime.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
func (setStatusTimelineItem) Status(ctx context.Context, obj *bug.SetStatusTimelineItem) (models.Status, error) {
|
||||
func (setStatusTimelineItem) Status(_ context.Context, obj *bug.SetStatusTimelineItem) (models.Status, error) {
|
||||
return convertStatus(obj.Status)
|
||||
}
|
||||
|
||||
@ -88,11 +104,15 @@ var _ graph.SetTitleTimelineItemResolver = setTitleTimelineItem{}
|
||||
|
||||
type setTitleTimelineItem struct{}
|
||||
|
||||
func (setTitleTimelineItem) ID(ctx context.Context, obj *bug.SetTitleTimelineItem) (string, error) {
|
||||
func (setTitleTimelineItem) ID(_ context.Context, obj *bug.SetTitleTimelineItem) (string, error) {
|
||||
return obj.Id().String(), nil
|
||||
}
|
||||
|
||||
func (setTitleTimelineItem) Date(ctx context.Context, obj *bug.SetTitleTimelineItem) (*time.Time, error) {
|
||||
func (i setTitleTimelineItem) Author(_ context.Context, obj *bug.SetTitleTimelineItem) (models.IdentityWrapper, error) {
|
||||
return models.NewLoadedIdentity(obj.Author), nil
|
||||
}
|
||||
|
||||
func (setTitleTimelineItem) Date(_ context.Context, obj *bug.SetTitleTimelineItem) (*time.Time, error) {
|
||||
t := obj.UnixTime.Time()
|
||||
return &t, nil
|
||||
}
|
||||
|
@ -227,28 +227,11 @@ func SetUserIdentity(repo repository.RepoConfig, identity *Identity) error {
|
||||
|
||||
// GetUserIdentity read the current user identity, set with a git config entry
|
||||
func GetUserIdentity(repo repository.Repo) (*Identity, error) {
|
||||
configs, err := repo.LocalConfig().ReadAll(identityConfigKey)
|
||||
id, err := GetUserIdentityId(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(configs) == 0 {
|
||||
return nil, ErrNoIdentitySet
|
||||
}
|
||||
|
||||
if len(configs) > 1 {
|
||||
return nil, ErrMultipleIdentitiesSet
|
||||
}
|
||||
|
||||
var id entity.Id
|
||||
for _, val := range configs {
|
||||
id = entity.Id(val)
|
||||
}
|
||||
|
||||
if err := id.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i, err := ReadLocal(repo, id)
|
||||
if err == ErrIdentityNotExist {
|
||||
innerErr := repo.LocalConfig().RemoveAll(identityConfigKey)
|
||||
@ -261,6 +244,32 @@ func GetUserIdentity(repo repository.Repo) (*Identity, error) {
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func GetUserIdentityId(repo repository.Repo) (entity.Id, error) {
|
||||
configs, err := repo.LocalConfig().ReadAll(identityConfigKey)
|
||||
if err != nil {
|
||||
return entity.UnsetId, err
|
||||
}
|
||||
|
||||
if len(configs) == 0 {
|
||||
return entity.UnsetId, ErrNoIdentitySet
|
||||
}
|
||||
|
||||
if len(configs) > 1 {
|
||||
return entity.UnsetId, ErrMultipleIdentitiesSet
|
||||
}
|
||||
|
||||
var id entity.Id
|
||||
for _, val := range configs {
|
||||
id = entity.Id(val)
|
||||
}
|
||||
|
||||
if err := id.Validate(); err != nil {
|
||||
return entity.UnsetId, err
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// IsUserIdentitySet say if the user has set his identity
|
||||
func IsUserIdentitySet(repo repository.Repo) (bool, error) {
|
||||
configs, err := repo.LocalConfig().ReadAll(identityConfigKey)
|
||||
|
Loading…
Reference in New Issue
Block a user