board_subcache.go

  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}