cached.go

  1package cache
  2
  3import (
  4	"sync"
  5
  6	"github.com/MichaelMure/git-bug/entity"
  7	"github.com/MichaelMure/git-bug/entity/dag"
  8	"github.com/MichaelMure/git-bug/repository"
  9	"github.com/MichaelMure/git-bug/util/lamport"
 10)
 11
 12// CachedEntityBase provide the base function of an entity managed by the cache.
 13type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct {
 14	repo            repository.ClockedRepo
 15	entityUpdated   func(id entity.Id) error
 16	getUserIdentity getUserIdentityFunc
 17
 18	mu     sync.RWMutex
 19	entity dag.Interface[SnapT, OpT]
 20}
 21
 22func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id {
 23	return e.entity.Id()
 24}
 25
 26func (e *CachedEntityBase[SnapT, OpT]) Snapshot() SnapT {
 27	e.mu.RLock()
 28	defer e.mu.RUnlock()
 29	return e.entity.Compile()
 30}
 31
 32func (e *CachedEntityBase[SnapT, OpT]) notifyUpdated() error {
 33	return e.entityUpdated(e.entity.Id())
 34}
 35
 36// ResolveOperationWithMetadata will find an operation that has the matching metadata
 37func (e *CachedEntityBase[SnapT, OpT]) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) {
 38	e.mu.RLock()
 39	defer e.mu.RUnlock()
 40	// preallocate but empty
 41	matching := make([]entity.Id, 0, 5)
 42
 43	for _, op := range e.entity.Operations() {
 44		opValue, ok := op.GetMetadata(key)
 45		if ok && value == opValue {
 46			matching = append(matching, op.Id())
 47		}
 48	}
 49
 50	if len(matching) == 0 {
 51		return "", ErrNoMatchingOp
 52	}
 53
 54	if len(matching) > 1 {
 55		return "", entity.NewErrMultipleMatch("operation", matching)
 56	}
 57
 58	return matching[0], nil
 59}
 60
 61func (e *CachedEntityBase[SnapT, OpT]) Validate() error {
 62	e.mu.RLock()
 63	defer e.mu.RUnlock()
 64	return e.entity.Validate()
 65}
 66
 67func (e *CachedEntityBase[SnapT, OpT]) Commit() error {
 68	e.mu.Lock()
 69	err := e.entity.Commit(e.repo)
 70	if err != nil {
 71		e.mu.Unlock()
 72		return err
 73	}
 74	e.mu.Unlock()
 75	return e.notifyUpdated()
 76}
 77
 78func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error {
 79	e.mu.Lock()
 80	err := e.entity.CommitAsNeeded(e.repo)
 81	if err != nil {
 82		e.mu.Unlock()
 83		return err
 84	}
 85	e.mu.Unlock()
 86	return e.notifyUpdated()
 87}
 88
 89func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool {
 90	e.mu.RLock()
 91	defer e.mu.RUnlock()
 92	return e.entity.NeedCommit()
 93}
 94
 95func (e *CachedEntityBase[SnapT, OpT]) CreateLamportTime() lamport.Time {
 96	return e.entity.CreateLamportTime()
 97}
 98
 99func (e *CachedEntityBase[SnapT, OpT]) EditLamportTime() lamport.Time {
100	return e.entity.EditLamportTime()
101}
102
103func (e *CachedEntityBase[SnapT, OpT]) FirstOp() OpT {
104	return e.entity.FirstOp()
105}