diff options
Diffstat (limited to 'entity/resolver.go')
-rw-r--r-- | entity/resolver.go | 74 |
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) +} |