diff options
Diffstat (limited to 'cache/cached.go')
-rw-r--r-- | cache/cached.go | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/cache/cached.go b/cache/cached.go new file mode 100644 index 00000000..5e24e732 --- /dev/null +++ b/cache/cached.go @@ -0,0 +1,133 @@ +package cache + +import ( + "sync" + + "github.com/MichaelMure/git-bug/entities/bug" + "github.com/MichaelMure/git-bug/entities/identity" + "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/entity/dag" + "github.com/MichaelMure/git-bug/repository" +) + +// type withSnapshot[SnapT dag.Snapshot, OpT dag.OperationWithApply[SnapT]] struct { +// dag.Interface[SnapT, OpT] +// snap dag.Snapshot +// } +// +// +// func (ws *withSnapshot[SnapT, OpT]) Compile() dag.Snapshot { +// if ws.snap == nil { +// snap := ws.Interface.Compile() +// ws.snap = snap +// } +// return ws.snap +// } +// +// // Append intercept Bug.Append() to update the snapshot efficiently +// func (ws *withSnapshot[SnapT, OpT]) Append(op OpT) { +// ws.Interface.Append(op) +// +// if ws.snap == nil { +// return +// } +// +// op.Apply(ws.snap) +// ws.snap. = append(ws.snap.Operations, op) +// } +// +// // Commit intercept Bug.Commit() to update the snapshot efficiently +// func (ws *withSnapshot[SnapT, OpT]) Commit(repo repository.ClockedRepo) error { +// err := ws.Interface.Commit(repo) +// +// if err != nil { +// ws.snap = nil +// return err +// } +// +// // Commit() shouldn't change anything of the bug state apart from the +// // initial ID set +// +// if ws.snap == nil { +// return nil +// } +// +// ws.snap.id = ws.Interface.Id() +// return nil +// } + +type CachedEntityBase[SnapT dag.Snapshot, OpT dag.Operation] struct { + entityUpdated func(id entity.Id) error + getUserIdentity func() (identity.Interface, error) + repo repository.ClockedRepo + + mu sync.RWMutex + entity dag.Interface[SnapT, OpT] +} + +func (e *CachedEntityBase[SnapT, OpT]) Id() entity.Id { + return e.entity.Id() +} + +func (e *CachedEntityBase[SnapT, OpT]) Snapshot() SnapT { + e.mu.RLock() + defer e.mu.RUnlock() + return e.entity.Compile() +} + +func (e *CachedEntityBase[SnapT, OpT]) notifyUpdated() error { + return e.entityUpdated(e.entity.Id()) +} + +// ResolveOperationWithMetadata will find an operation that has the matching metadata +func (e *CachedEntityBase[SnapT, OpT]) ResolveOperationWithMetadata(key string, value string) (entity.Id, error) { + e.mu.RLock() + defer e.mu.RUnlock() + // preallocate but empty + matching := make([]entity.Id, 0, 5) + + for _, op := range e.entity.Operations() { + opValue, ok := op.GetMetadata(key) + if ok && value == opValue { + matching = append(matching, op.Id()) + } + } + + if len(matching) == 0 { + return "", ErrNoMatchingOp + } + + if len(matching) > 1 { + return "", bug.NewErrMultipleMatchOp(matching) + } + + return matching[0], nil +} + +func (e *CachedEntityBase[SnapT, OpT]) Commit() error { + e.mu.Lock() + err := e.entity.Commit(e.repo) + if err != nil { + e.mu.Unlock() + return err + } + e.mu.Unlock() + return e.notifyUpdated() +} + +func (e *CachedEntityBase[SnapT, OpT]) CommitAsNeeded() error { + e.mu.Lock() + err := e.entity.CommitAsNeeded(e.repo) + if err != nil { + e.mu.Unlock() + return err + } + e.mu.Unlock() + return e.notifyUpdated() +} + +func (e *CachedEntityBase[SnapT, OpT]) NeedCommit() bool { + e.mu.RLock() + defer e.mu.RUnlock() + return e.entity.NeedCommit() +} |