aboutsummaryrefslogtreecommitdiffstats
path: root/entity/resolver.go
diff options
context:
space:
mode:
Diffstat (limited to 'entity/resolver.go')
-rw-r--r--entity/resolver.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/entity/resolver.go b/entity/resolver.go
new file mode 100644
index 00000000..d4fe5d3e
--- /dev/null
+++ b/entity/resolver.go
@@ -0,0 +1,74 @@
+package entity
+
+import (
+ "fmt"
+ "sync"
+)
+
+// Resolver is an interface to find an Entity from its Id
+type Resolver interface {
+ Resolve(id Id) (Interface, error)
+}
+
+// Resolvers is a collection of Resolver, for different type of Entity
+type Resolvers map[Interface]Resolver
+
+// Resolve use the appropriate sub-resolver for the given type and find the Entity matching the Id.
+func Resolve[T Interface](rs Resolvers, id Id) (T, error) {
+ var zero T
+ for t, resolver := range rs {
+ switch t.(type) {
+ case T:
+ val, err := resolver.(Resolver).Resolve(id)
+ if err != nil {
+ return zero, err
+ }
+ return val.(T), nil
+ }
+ }
+ return zero, fmt.Errorf("unknown type to resolve")
+}
+
+var _ Resolver = &CachedResolver{}
+
+// CachedResolver is a resolver ensuring that loading is done only once through another Resolver.
+type CachedResolver struct {
+ resolver Resolver
+ mu sync.RWMutex
+ entities map[Id]Interface
+}
+
+func NewCachedResolver(resolver Resolver) *CachedResolver {
+ return &CachedResolver{
+ resolver: resolver,
+ entities: make(map[Id]Interface),
+ }
+}
+
+func (c *CachedResolver) Resolve(id Id) (Interface, error) {
+ c.mu.RLock()
+ if i, ok := c.entities[id]; ok {
+ c.mu.RUnlock()
+ return i, nil
+ }
+ c.mu.RUnlock()
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ i, err := c.resolver.Resolve(id)
+ if err != nil {
+ return nil, err
+ }
+ c.entities[id] = i
+ return i, nil
+}
+
+var _ Resolver = ResolverFunc(nil)
+
+// ResolverFunc is a helper to morph a function resolver into a Resolver
+type ResolverFunc func(id Id) (Interface, error)
+
+func (fn ResolverFunc) Resolve(id Id) (Interface, error) {
+ return fn(id)
+}