mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-14 17:51:44 +03:00
bug: add a new BugExerpt that hold a subset of a bug state for efficient sorting and retrieval
This commit is contained in:
parent
16f55e3f4d
commit
e7648996c8
10
bug/bug.go
10
bug/bug.go
@ -579,6 +579,16 @@ func formatHumanId(id string) string {
|
||||
return fmt.Sprintf(format, id)
|
||||
}
|
||||
|
||||
// CreateLamportTime return the Lamport time of creation
|
||||
func (bug *Bug) CreateLamportTime() util.LamportTime {
|
||||
return bug.createTime
|
||||
}
|
||||
|
||||
// EditLamportTime return the Lamport time of the last edit
|
||||
func (bug *Bug) EditLamportTime() util.LamportTime {
|
||||
return bug.editTime
|
||||
}
|
||||
|
||||
// Lookup for the very first operation of the bug.
|
||||
// For a valid Bug, this operation should be a CreateOp
|
||||
func (bug *Bug) FirstOp() Operation {
|
||||
|
@ -2,6 +2,7 @@ package bug
|
||||
|
||||
import (
|
||||
"github.com/MichaelMure/git-bug/repository"
|
||||
"github.com/MichaelMure/git-bug/util"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
@ -38,6 +39,12 @@ type Interface interface {
|
||||
|
||||
// Compile a bug in a easily usable snapshot
|
||||
Compile() Snapshot
|
||||
|
||||
// CreateLamportTime return the Lamport time of creation
|
||||
CreateLamportTime() util.LamportTime
|
||||
|
||||
// EditLamportTime return the Lamport time of the last edit
|
||||
EditLamportTime() util.LamportTime
|
||||
}
|
||||
|
||||
func bugFromInterface(bug Interface) *Bug {
|
||||
|
@ -23,6 +23,8 @@ type Operation interface {
|
||||
OpType() OperationType
|
||||
// Time return the time when the operation was added
|
||||
Time() time.Time
|
||||
// unixTime return the unix timestamp when the operation was added
|
||||
UnixTime() int64
|
||||
// Apply the operation to a Snapshot to create the final state
|
||||
Apply(snapshot Snapshot) Snapshot
|
||||
// Files return the files needed by this operation
|
||||
@ -36,7 +38,7 @@ type Operation interface {
|
||||
type OpBase struct {
|
||||
OperationType OperationType
|
||||
Author Person
|
||||
UnixTime int64
|
||||
unixTime int64
|
||||
}
|
||||
|
||||
// NewOpBase is the constructor for an OpBase
|
||||
@ -44,7 +46,7 @@ func NewOpBase(opType OperationType, author Person) OpBase {
|
||||
return OpBase{
|
||||
OperationType: opType,
|
||||
Author: author,
|
||||
UnixTime: time.Now().Unix(),
|
||||
unixTime: time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +57,12 @@ func (op OpBase) OpType() OperationType {
|
||||
|
||||
// Time return the time when the operation was added
|
||||
func (op OpBase) Time() time.Time {
|
||||
return time.Unix(op.UnixTime, 0)
|
||||
return time.Unix(op.unixTime, 0)
|
||||
}
|
||||
|
||||
// unixTime return the unix timestamp when the operation was added
|
||||
func (op OpBase) UnixTime() int64 {
|
||||
return op.unixTime
|
||||
}
|
||||
|
||||
// Files return the files needed by this operation
|
||||
|
@ -21,7 +21,7 @@ func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
|
||||
Message: op.Message,
|
||||
Author: op.Author,
|
||||
Files: op.files,
|
||||
UnixTime: op.UnixTime,
|
||||
UnixTime: op.UnixTime(),
|
||||
}
|
||||
|
||||
snapshot.Comments = append(snapshot.Comments, comment)
|
||||
|
@ -22,7 +22,7 @@ func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
|
||||
{
|
||||
Message: op.Message,
|
||||
Author: op.Author,
|
||||
UnixTime: op.UnixTime,
|
||||
UnixTime: op.UnixTime(),
|
||||
},
|
||||
}
|
||||
snapshot.Author = op.Author
|
||||
|
@ -21,7 +21,7 @@ func TestCreate(t *testing.T) {
|
||||
expected := bug.Snapshot{
|
||||
Title: "title",
|
||||
Comments: []bug.Comment{
|
||||
{Author: rene, Message: "message", UnixTime: create.UnixTime},
|
||||
{Author: rene, Message: "message", UnixTime: create.UnixTime()},
|
||||
},
|
||||
Author: rene,
|
||||
CreatedAt: create.Time(),
|
||||
|
@ -37,10 +37,19 @@ func (snap Snapshot) Summary() string {
|
||||
}
|
||||
|
||||
// Return the last time a bug was modified
|
||||
func (snap Snapshot) LastEdit() time.Time {
|
||||
func (snap Snapshot) LastEditTime() time.Time {
|
||||
if len(snap.Operations) == 0 {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
|
||||
return snap.Operations[len(snap.Operations)-1].Time()
|
||||
}
|
||||
|
||||
// Return the last timestamp a bug was modified
|
||||
func (snap Snapshot) LastEditUnix() int64 {
|
||||
if len(snap.Operations) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return snap.Operations[len(snap.Operations)-1].UnixTime()
|
||||
}
|
||||
|
92
cache/bug_excerpt.go
vendored
Normal file
92
cache/bug_excerpt.go
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/util"
|
||||
)
|
||||
|
||||
// BugExcerpt hold a subset of the bug values to be able to sort and filter bugs
|
||||
// efficiently without having to read and compile each raw bugs.
|
||||
type BugExcerpt struct {
|
||||
Id string
|
||||
|
||||
CreateLamportTime util.LamportTime
|
||||
EditLamportTime util.LamportTime
|
||||
CreateUnixTime int64
|
||||
EditUnixTime int64
|
||||
|
||||
Status bug.Status
|
||||
Author bug.Person
|
||||
}
|
||||
|
||||
func NewBugExcerpt(b *bug.Bug, snap bug.Snapshot) BugExcerpt {
|
||||
return BugExcerpt{
|
||||
Id: b.Id(),
|
||||
CreateLamportTime: b.CreateLamportTime(),
|
||||
EditLamportTime: b.EditLamportTime(),
|
||||
CreateUnixTime: b.FirstOp().UnixTime(),
|
||||
EditUnixTime: snap.LastEditUnix(),
|
||||
Status: snap.Status,
|
||||
Author: snap.Author,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
type BugsByCreationTime []*BugExcerpt
|
||||
|
||||
func (b BugsByCreationTime) Len() int {
|
||||
return len(b)
|
||||
}
|
||||
|
||||
func (b BugsByCreationTime) Less(i, j int) bool {
|
||||
if b[i].CreateLamportTime < b[j].CreateLamportTime {
|
||||
return true
|
||||
}
|
||||
|
||||
if b[i].CreateLamportTime > b[j].CreateLamportTime {
|
||||
return false
|
||||
}
|
||||
|
||||
// When the logical clocks are identical, that means we had a concurrent
|
||||
// edition. In this case we rely on the timestamp. While the timestamp might
|
||||
// be incorrect due to a badly set clock, the drift in sorting is bounded
|
||||
// by the first sorting using the logical clock. That means that if users
|
||||
// synchronize their bugs regularly, the timestamp will rarely be used, and
|
||||
// should still provide a kinda accurate sorting when needed.
|
||||
return b[i].CreateUnixTime < b[j].CreateUnixTime
|
||||
}
|
||||
|
||||
func (b BugsByCreationTime) Swap(i, j int) {
|
||||
b[i], b[j] = b[j], b[i]
|
||||
}
|
||||
|
||||
type BugsByEditTime []*BugExcerpt
|
||||
|
||||
func (b BugsByEditTime) Len() int {
|
||||
return len(b)
|
||||
}
|
||||
|
||||
func (b BugsByEditTime) Less(i, j int) bool {
|
||||
if b[i].EditLamportTime < b[j].EditLamportTime {
|
||||
return true
|
||||
}
|
||||
|
||||
if b[i].EditLamportTime > b[j].EditLamportTime {
|
||||
return false
|
||||
}
|
||||
|
||||
// When the logical clocks are identical, that means we had a concurrent
|
||||
// edition. In this case we rely on the timestamp. While the timestamp might
|
||||
// be incorrect due to a badly set clock, the drift in sorting is bounded
|
||||
// by the first sorting using the logical clock. That means that if users
|
||||
// synchronize their bugs regularly, the timestamp will rarely be used, and
|
||||
// should still provide a kinda accurate sorting when needed.
|
||||
return b[i].EditUnixTime < b[j].EditUnixTime
|
||||
}
|
||||
|
||||
func (b BugsByEditTime) Swap(i, j int) {
|
||||
b[i], b[j] = b[j], b[i]
|
||||
}
|
@ -34,6 +34,7 @@ type Resolvers interface {
|
||||
|
||||
Bug_status(ctx context.Context, obj *bug.Snapshot) (models.Status, error)
|
||||
|
||||
Bug_lastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error)
|
||||
Bug_comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.CommentConnection, error)
|
||||
Bug_operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.OperationConnection, error)
|
||||
|
||||
@ -78,6 +79,7 @@ type AddCommentOperationResolver interface {
|
||||
type BugResolver interface {
|
||||
Status(ctx context.Context, obj *bug.Snapshot) (models.Status, error)
|
||||
|
||||
LastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error)
|
||||
Comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.CommentConnection, error)
|
||||
Operations(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.OperationConnection, error)
|
||||
}
|
||||
@ -124,6 +126,10 @@ func (s shortMapper) Bug_status(ctx context.Context, obj *bug.Snapshot) (models.
|
||||
return s.r.Bug().Status(ctx, obj)
|
||||
}
|
||||
|
||||
func (s shortMapper) Bug_lastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error) {
|
||||
return s.r.Bug().LastEdit(ctx, obj)
|
||||
}
|
||||
|
||||
func (s shortMapper) Bug_comments(ctx context.Context, obj *bug.Snapshot, after *string, before *string, first *int, last *int) (models.CommentConnection, error) {
|
||||
return s.r.Bug().Comments(ctx, obj, after, before, first, last)
|
||||
}
|
||||
@ -494,14 +500,33 @@ func (ec *executionContext) _Bug_createdAt(ctx context.Context, field graphql.Co
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bug_lastEdit(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler {
|
||||
rctx := graphql.GetResolverContext(ctx)
|
||||
rctx.Object = "Bug"
|
||||
rctx.Args = nil
|
||||
rctx.Field = field
|
||||
rctx.PushField(field.Alias)
|
||||
defer rctx.Pop()
|
||||
res := obj.LastEdit()
|
||||
return graphql.MarshalTime(res)
|
||||
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
|
||||
Object: "Bug",
|
||||
Args: nil,
|
||||
Field: field,
|
||||
})
|
||||
return graphql.Defer(func() (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
userErr := ec.Recover(ctx, r)
|
||||
ec.Error(ctx, userErr)
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(ctx context.Context) (interface{}, error) {
|
||||
return ec.resolvers.Bug_lastEdit(ctx, obj)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(time.Time)
|
||||
return graphql.MarshalTime(res)
|
||||
})
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bug_comments(ctx context.Context, field graphql.CollectedField, obj *bug.Snapshot) graphql.Marshaler {
|
||||
|
@ -2,6 +2,7 @@ package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/MichaelMure/git-bug/bug"
|
||||
"github.com/MichaelMure/git-bug/graphql/connections"
|
||||
@ -67,3 +68,7 @@ func (bugResolver) Operations(ctx context.Context, obj *bug.Snapshot, after *str
|
||||
|
||||
return connections.BugOperationCon(obj.Operations, edger, conMaker, input)
|
||||
}
|
||||
|
||||
func (bugResolver) LastEdit(ctx context.Context, obj *bug.Snapshot) (time.Time, error) {
|
||||
return obj.LastEditTime(), nil
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ func (bt *bugTable) render(v *gocui.View, maxX int) {
|
||||
title := util.LeftPaddedString(snap.Title, columnWidths["title"], 2)
|
||||
author := util.LeftPaddedString(person.Name, columnWidths["author"], 2)
|
||||
summary := util.LeftPaddedString(snap.Summary(), columnWidths["summary"], 2)
|
||||
lastEdit := util.LeftPaddedString(humanize.Time(snap.LastEdit()), columnWidths["lastEdit"], 2)
|
||||
lastEdit := util.LeftPaddedString(humanize.Time(snap.LastEditTime()), columnWidths["lastEdit"], 2)
|
||||
|
||||
fmt.Fprintf(v, "%s %s %s %s %s %s\n",
|
||||
util.Cyan(id),
|
||||
|
Loading…
Reference in New Issue
Block a user