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