1package models
2
3import (
4 "sync"
5 "time"
6
7 "github.com/git-bug/git-bug/cache"
8 "github.com/git-bug/git-bug/entities/board"
9 "github.com/git-bug/git-bug/entity"
10 "github.com/git-bug/git-bug/entity/dag"
11)
12
13// BoardWrapper is an interface used by the GraphQL resolvers to handle a board.
14// Depending on the situation, a Board can already be fully loaded in memory or not.
15// This interface is used to wrap either a lazyBoard or a loadedBoard depending on the situation.
16type BoardWrapper interface {
17 Id() entity.Id
18 LastEdit() time.Time
19 CreatedAt() time.Time
20
21 Title() string
22 Description() string
23 Columns() ([]*board.Column, error)
24
25 Actors() ([]IdentityWrapper, error)
26 Operations() ([]dag.Operation, error)
27}
28
29var _ BoardWrapper = &lazyBoard{}
30
31type lazyBoard struct {
32 cache *cache.RepoCache
33 excerpt *cache.BoardExcerpt
34
35 mu sync.Mutex
36 snap *board.Snapshot
37}
38
39func NewLazyBoard(cache *cache.RepoCache, excerpt *cache.BoardExcerpt) *lazyBoard {
40 return &lazyBoard{
41 cache: cache,
42 excerpt: excerpt,
43 }
44}
45
46func (lb *lazyBoard) load() error {
47 lb.mu.Lock()
48 defer lb.mu.Unlock()
49
50 if lb.snap != nil {
51 return nil
52 }
53
54 b, err := lb.cache.Boards().Resolve(lb.excerpt.Id())
55 if err != nil {
56 return err
57 }
58
59 lb.snap = b.Snapshot()
60 return nil
61}
62
63func (lb *lazyBoard) identity(id entity.Id) (IdentityWrapper, error) {
64 i, err := lb.cache.Identities().ResolveExcerpt(id)
65 if err != nil {
66 return nil, err
67 }
68 return &lazyIdentity{cache: lb.cache, excerpt: i}, nil
69}
70
71func (lb *lazyBoard) Id() entity.Id {
72 return lb.excerpt.Id()
73}
74
75func (lb *lazyBoard) LastEdit() time.Time {
76 return lb.excerpt.EditTime()
77}
78
79func (lb *lazyBoard) CreatedAt() time.Time {
80 return lb.excerpt.CreateTime()
81}
82
83func (lb *lazyBoard) Title() string {
84 return lb.excerpt.Title
85}
86
87func (lb *lazyBoard) Description() string {
88 return lb.excerpt.Description
89}
90
91func (lb *lazyBoard) Columns() ([]*board.Column, error) {
92 err := lb.load()
93 if err != nil {
94 return nil, err
95 }
96 return lb.snap.Columns, nil
97}
98
99func (lb *lazyBoard) Actors() ([]IdentityWrapper, error) {
100 result := make([]IdentityWrapper, len(lb.excerpt.Actors))
101 for i, actorId := range lb.excerpt.Actors {
102 actor, err := lb.identity(actorId)
103 if err != nil {
104 return nil, err
105 }
106 result[i] = actor
107 }
108 return result, nil
109}
110
111func (lb *lazyBoard) Operations() ([]dag.Operation, error) {
112 err := lb.load()
113 if err != nil {
114 return nil, err
115 }
116 return lb.snap.Operations, nil
117}
118
119var _ BoardWrapper = &loadedBoard{}
120
121type loadedBoard struct {
122 *board.Snapshot
123}
124
125func NewLoadedBoard(snap *board.Snapshot) *loadedBoard {
126 return &loadedBoard{Snapshot: snap}
127}
128
129func (l *loadedBoard) LastEdit() time.Time {
130 return l.Snapshot.EditTime()
131}
132
133func (l *loadedBoard) CreatedAt() time.Time {
134 return l.Snapshot.CreateTime
135}
136
137func (l *loadedBoard) Title() string {
138 return l.Snapshot.Title
139}
140
141func (l *loadedBoard) Description() string {
142 return l.Snapshot.Description
143}
144
145func (l *loadedBoard) Columns() ([]*board.Column, error) {
146 return l.Snapshot.Columns, nil
147}
148
149func (l *loadedBoard) Actors() ([]IdentityWrapper, error) {
150 res := make([]IdentityWrapper, len(l.Snapshot.Actors))
151 for i, actor := range l.Snapshot.Actors {
152 res[i] = NewLoadedIdentity(actor)
153 }
154 return res, nil
155}
156
157func (l *loadedBoard) Operations() ([]dag.Operation, error) {
158 return l.Snapshot.Operations, nil
159}