1package cache
2
3import (
4 "errors"
5 "time"
6
7 "github.com/git-bug/git-bug/entities/board"
8 "github.com/git-bug/git-bug/entities/identity"
9 "github.com/git-bug/git-bug/entity"
10 "github.com/git-bug/git-bug/repository"
11)
12
13type RepoCacheBoard struct {
14 *SubCache[*board.Board, *BoardExcerpt, *BoardCache]
15}
16
17func NewRepoCacheBoard(repo repository.ClockedRepo,
18 resolvers func() entity.Resolvers,
19 getUserIdentity getUserIdentityFunc) *RepoCacheBoard {
20
21 makeCached := func(b *board.Board, entityUpdated func(id entity.Id) error) *BoardCache {
22 return NewBoardCache(b, repo, getUserIdentity, entityUpdated)
23 }
24
25 makeIndexData := func(b *BoardCache) []string {
26 // no indexing
27 return nil
28 }
29
30 actions := Actions[*board.Board]{
31 ReadWithResolver: board.ReadWithResolver,
32 ReadAllWithResolver: board.ReadAllWithResolver,
33 Remove: board.Remove,
34 RemoveAll: board.RemoveAll,
35 MergeAll: board.MergeAll,
36 }
37
38 sc := NewSubCache[*board.Board, *BoardExcerpt, *BoardCache](
39 repo, resolvers, getUserIdentity,
40 makeCached, NewBoardExcerpt, makeIndexData, actions,
41 board.Typename, board.Namespace,
42 formatVersion, defaultMaxLoadedBugs,
43 )
44
45 return &RepoCacheBoard{SubCache: sc}
46}
47
48// ResolveBoardCreateMetadata retrieve a board that has the exact given metadata on its Create operation, that is, the first operation.
49// It fails if multiple bugs match.
50func (c *RepoCacheBoard) ResolveBoardCreateMetadata(key string, value string) (*BoardCache, error) {
51 return c.ResolveMatcher(func(excerpt *BoardExcerpt) bool {
52 return excerpt.CreateMetadata[key] == value
53 })
54}
55
56// ResolveColumn finds the board and column id that matches the given prefix.
57func (c *RepoCacheBoard) ResolveColumn(prefix string) (*BoardCache, entity.CombinedId, error) {
58 boardPrefix, _ := entity.SeparateIds(prefix)
59 boardCandidate := make([]entity.Id, 0, 5)
60
61 // build a list of possible matching boards
62 c.mu.RLock()
63 for _, excerpt := range c.excerpts {
64 if excerpt.Id().HasPrefix(boardPrefix) {
65 boardCandidate = append(boardCandidate, excerpt.Id())
66 }
67 }
68 c.mu.RUnlock()
69
70 matchingBoardIds := make([]entity.Id, 0, 5)
71 matchingColumnId := entity.UnsetCombinedId
72 var matchingBoard *BoardCache
73
74 // search for matching columns
75 // searching every board candidate allow for some collision with the board prefix only,
76 // before being refined with the full column prefix
77 for _, boardId := range boardCandidate {
78 b, err := c.Resolve(boardId)
79 if err != nil {
80 return nil, entity.UnsetCombinedId, err
81 }
82
83 for _, column := range b.Snapshot().Columns {
84 if column.CombinedId.HasPrefix(prefix) {
85 matchingBoardIds = append(matchingBoardIds, boardId)
86 matchingBoard = b
87 matchingColumnId = column.CombinedId
88 }
89 }
90 }
91
92 if len(matchingBoardIds) > 1 {
93 return nil, entity.UnsetCombinedId, entity.NewErrMultipleMatch("board/column", matchingBoardIds)
94 } else if len(matchingBoardIds) == 0 {
95 return nil, entity.UnsetCombinedId, errors.New("column doesn't exist")
96 }
97
98 return matchingBoard, matchingColumnId, nil
99}
100
101// TODO: resolve item?
102
103// New creates a new board.
104// The new board is written in the repository (commit)
105func (c *RepoCacheBoard) New(title, description string, columns []string) (*BoardCache, *board.CreateOperation, error) {
106 author, err := c.getUserIdentity()
107 if err != nil {
108 return nil, nil, err
109 }
110
111 return c.NewRaw(author, time.Now().Unix(), title, description, columns, nil)
112}
113
114// NewDefaultColumns creates a new board with the default columns.
115// The new board is written in the repository (commit)
116func (c *RepoCacheBoard) NewDefaultColumns(title, description string) (*BoardCache, *board.CreateOperation, error) {
117 return c.New(title, description, board.DefaultColumns)
118}
119
120// NewRaw create a new board with the given title, description, and columns.
121// The new board is written in the repository (commit).
122func (c *RepoCacheBoard) NewRaw(author identity.Interface, unixTime int64, title, description string, columns []string, metadata map[string]string) (*BoardCache, *board.CreateOperation, error) {
123 b, op, err := board.Create(author, unixTime, title, description, columns, metadata)
124 if err != nil {
125 return nil, nil, err
126 }
127
128 err = b.Commit(c.repo)
129 if err != nil {
130 return nil, nil, err
131 }
132
133 cached, err := c.add(b)
134 if err != nil {
135 return nil, nil, err
136 }
137
138 return cached, op, nil
139}