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}