mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-15 02:01:43 +03:00
add a cache to support the graphql API and the future interactive CLI UI
This commit is contained in:
parent
6706fa2beb
commit
074156634b
160
cache/cache.go
vendored
Normal file
160
cache/cache.go
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/repository"
|
||||
)
|
||||
|
||||
type Cache interface {
|
||||
RegisterRepository(ref string, repo repository.Repo)
|
||||
RegisterDefaultRepository(repo repository.Repo)
|
||||
ResolveRepo(ref string) (CachedRepo, error)
|
||||
DefaultRepo() (CachedRepo, error)
|
||||
}
|
||||
|
||||
type CachedRepo interface {
|
||||
ResolveBug(id string) (CachedBug, error)
|
||||
ResolveBugPrefix(prefix string) (CachedBug, error)
|
||||
ClearAllBugs()
|
||||
}
|
||||
|
||||
type CachedBug interface {
|
||||
Snapshot() bug.Snapshot
|
||||
ClearSnapshot()
|
||||
}
|
||||
|
||||
// Cache ------------------------
|
||||
|
||||
type DefaultCache struct {
|
||||
repos map[string]CachedRepo
|
||||
}
|
||||
|
||||
func NewDefaultCache() Cache {
|
||||
return &DefaultCache{
|
||||
repos: make(map[string]CachedRepo),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DefaultCache) RegisterRepository(ref string, repo repository.Repo) {
|
||||
c.repos[ref] = NewCachedRepo(repo)
|
||||
}
|
||||
|
||||
func (c *DefaultCache) RegisterDefaultRepository(repo repository.Repo) {
|
||||
c.repos[""] = NewCachedRepo(repo)
|
||||
}
|
||||
|
||||
func (c *DefaultCache) DefaultRepo() (CachedRepo, error) {
|
||||
if len(c.repos) != 1 {
|
||||
return nil, fmt.Errorf("repository is not unique")
|
||||
}
|
||||
|
||||
for _, r := range c.repos {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (c *DefaultCache) ResolveRepo(ref string) (CachedRepo, error) {
|
||||
r, ok := c.repos[ref]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown repo")
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Repo ------------------------
|
||||
|
||||
type CachedRepoImpl struct {
|
||||
repo repository.Repo
|
||||
bugs map[string]CachedBug
|
||||
}
|
||||
|
||||
func NewCachedRepo(r repository.Repo) CachedRepo {
|
||||
return &CachedRepoImpl{
|
||||
repo: r,
|
||||
bugs: make(map[string]CachedBug),
|
||||
}
|
||||
}
|
||||
|
||||
func (c CachedRepoImpl) ResolveBug(id string) (CachedBug, error) {
|
||||
cached, ok := c.bugs[id]
|
||||
if ok {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
b, err := bug.ReadLocalBug(c.repo, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cached = NewCachedBug(b)
|
||||
c.bugs[id] = cached
|
||||
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
func (c CachedRepoImpl) ResolveBugPrefix(prefix string) (CachedBug, error) {
|
||||
// preallocate but empty
|
||||
matching := make([]string, 0, 5)
|
||||
|
||||
for id := range c.bugs {
|
||||
if strings.HasPrefix(id, prefix) {
|
||||
matching = append(matching, id)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should check matching bug in the repo as well
|
||||
|
||||
if len(matching) > 1 {
|
||||
return nil, fmt.Errorf("Multiple matching bug found:\n%s", strings.Join(matching, "\n"))
|
||||
}
|
||||
|
||||
if len(matching) == 1 {
|
||||
b := c.bugs[matching[0]]
|
||||
return b, nil
|
||||
}
|
||||
|
||||
b, err := bug.FindLocalBug(c.repo, prefix)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cached := NewCachedBug(b)
|
||||
c.bugs[b.Id()] = cached
|
||||
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
func (c CachedRepoImpl) ClearAllBugs() {
|
||||
c.bugs = make(map[string]CachedBug)
|
||||
}
|
||||
|
||||
// Bug ------------------------
|
||||
|
||||
type CachedBugImpl struct {
|
||||
bug *bug.Bug
|
||||
snap *bug.Snapshot
|
||||
}
|
||||
|
||||
func NewCachedBug(b *bug.Bug) CachedBug {
|
||||
return &CachedBugImpl{
|
||||
bug: b,
|
||||
}
|
||||
}
|
||||
|
||||
func (c CachedBugImpl) Snapshot() bug.Snapshot {
|
||||
if c.snap == nil {
|
||||
snap := c.bug.Compile()
|
||||
c.snap = &snap
|
||||
}
|
||||
return *c.snap
|
||||
}
|
||||
|
||||
func (c CachedBugImpl) ClearSnapshot() {
|
||||
c.snap = nil
|
||||
}
|
@ -4,18 +4,19 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/MichaelMure/git-bug/cache"
|
||||
"github.com/MichaelMure/git-bug/repository"
|
||||
"github.com/graphql-go/handler"
|
||||
graphqlHandler "github.com/graphql-go/handler"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
Handler *handler.Handler
|
||||
Repo repository.Repo
|
||||
handler *graphqlHandler.Handler
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "repo", h.Repo)
|
||||
h.Handler.ContextHandler(ctx, w, r)
|
||||
ctx := context.WithValue(r.Context(), "cache", h.cache)
|
||||
h.handler.ContextHandler(ctx, w, r)
|
||||
}
|
||||
|
||||
func NewHandler(repo repository.Repo) (*Handler, error) {
|
||||
@ -25,12 +26,17 @@ func NewHandler(repo repository.Repo) (*Handler, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := graphqlHandler.New(&graphqlHandler.Config{
|
||||
Schema: &schema,
|
||||
Pretty: true,
|
||||
GraphiQL: true,
|
||||
})
|
||||
|
||||
c := cache.NewDefaultCache()
|
||||
c.RegisterDefaultRepository(repo)
|
||||
|
||||
return &Handler{
|
||||
Handler: handler.New(&handler.Config{
|
||||
Schema: &schema,
|
||||
Pretty: true,
|
||||
GraphiQL: true,
|
||||
}),
|
||||
Repo: repo,
|
||||
handler: h,
|
||||
cache: c,
|
||||
}, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user