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}