Documentation
¶
Overview ¶
Package dataloader is an implementation of facebook's dataloader in go. See https://github.com/facebook/dataloader for more information
Index ¶
- Variables
- type BatchFunc
- type Cache
- type InMemoryCache
- type Interface
- type Loader
- func (l *Loader[K, V]) Clear(ctx context.Context, key K) Interface[K, V]
- func (l *Loader[K, V]) ClearAll() Interface[K, V]
- func (l *Loader[K, V]) Flush()
- func (l *Loader[K, V]) Load(originalContext context.Context, key K) Thunk[V]
- func (l *Loader[K, V]) LoadMany(originalContext context.Context, keys []K) ThunkMany[V]
- func (l *Loader[K, V]) Prime(ctx context.Context, key K, value V) Interface[K, V]
- type NoCache
- type NoopTracer
- func (NoopTracer[K, V]) TraceBatch(ctx context.Context, keys []K) (context.Context, TraceBatchFinishFunc[V])
- func (NoopTracer[K, V]) TraceLoad(ctx context.Context, key K) (context.Context, TraceLoadFinishFunc[V])
- func (NoopTracer[K, V]) TraceLoadMany(ctx context.Context, keys []K) (context.Context, TraceLoadManyFinishFunc[V])
- type Option
- func WithBatchCapacity[K comparable, V any](c int) Option[K, V]
- func WithCache[K comparable, V any](c Cache[K, V]) Option[K, V]
- func WithClearCacheOnBatch[K comparable, V any]() Option[K, V]
- func WithInputCapacity[K comparable, V any](c int) Option[K, V]
- func WithTracer[K comparable, V any](tracer Tracer[K, V]) Option[K, V]
- func WithWait[K comparable, V any](d time.Duration) Option[K, V]
- type PanicErrorWrapper
- type Result
- type ResultMany
- type SkipCacheError
- type Thunk
- type ThunkMany
- type TraceBatchFinishFunc
- type TraceLoadFinishFunc
- type TraceLoadManyFinishFunc
- type Tracer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNoResultProvided = errors.New("no result provided")
Functions ¶
This section is empty.
Types ¶
type BatchFunc ¶
type BatchFunc[K comparable, V any] func(context.Context, []K) []*Result[V]
BatchFunc is a function, which when given a slice of keys (string), returns a slice of `results`. It's important that the length of the input keys matches the length of the output results. Should the batch function return nil for a result, it will be treated as return an error of `ErrNoResultProvided` for that key.
The keys passed to this function are guaranteed to be unique
type Cache ¶
type Cache[K comparable, V any] interface { Get(context.Context, K) (Thunk[V], bool) Set(context.Context, K, Thunk[V]) Delete(context.Context, K) bool Clear() }
The Cache interface. If a custom cache is provided, it must implement this interface.
type InMemoryCache ¶
type InMemoryCache[K comparable, V any] struct { // contains filtered or unexported fields }
InMemoryCache is an in memory implementation of Cache interface. This simple implementation is well suited for a "per-request" dataloader (i.e. one that only lives for the life of an http request) but it's not well suited for long lived cached items.
func NewCache ¶
func NewCache[K comparable, V any]() *InMemoryCache[K, V]
NewCache constructs a new InMemoryCache
func (*InMemoryCache[K, V]) Clear ¶
func (c *InMemoryCache[K, V]) Clear()
Clear clears the entire cache
func (*InMemoryCache[K, V]) Delete ¶
func (c *InMemoryCache[K, V]) Delete(ctx context.Context, key K) bool
Delete deletes item at `key` from cache
type Interface ¶
type Interface[K comparable, V any] interface { Load(context.Context, K) Thunk[V] LoadMany(context.Context, []K) ThunkMany[V] Clear(context.Context, K) Interface[K, V] ClearAll() Interface[K, V] Prime(ctx context.Context, key K, value V) Interface[K, V] Flush() }
Interface is a `DataLoader` Interface which defines a public API for loading data from a particular data back-end with unique keys such as the `id` column of a SQL table or document name in a MongoDB database, given a batch loading function.
Each `DataLoader` instance should contain a unique memoized cache. Use caution when used in long-lived applications or those which serve many users with different access permissions and consider creating a new instance per web request.
type Loader ¶
type Loader[K comparable, V any] struct { // contains filtered or unexported fields }
Loader implements the dataloader.Interface.
func NewBatchedLoader ¶
func NewBatchedLoader[K comparable, V any](batchFn BatchFunc[K, V], opts ...Option[K, V]) *Loader[K, V]
NewBatchedLoader constructs a new Loader with given options.
Example (GoCache) ¶
package main
import (
"context"
"fmt"
"time"
dataloader "github.com/graph-gophers/dataloader/v7"
cache "github.com/patrickmn/go-cache"
)
type goCacheAdapter[K comparable, V any] struct {
c *cache.Cache
}
func (c *goCacheAdapter[K, V]) Get(_ context.Context, key K) (dataloader.Thunk[V], bool) {
k := fmt.Sprintf("%v", key)
v, ok := c.c.Get(k)
if ok {
return v.(dataloader.Thunk[V]), ok
}
return nil, ok
}
func (c *goCacheAdapter[K, V]) Set(_ context.Context, key K, value dataloader.Thunk[V]) {
k := fmt.Sprintf("%v", key)
c.c.Set(k, value, 0)
}
func (c *goCacheAdapter[K, V]) Delete(_ context.Context, key K) bool {
k := fmt.Sprintf("%v", key)
if _, found := c.c.Get(k); found {
c.c.Delete(k)
return true
}
return false
}
func (c *goCacheAdapter[K, V]) Clear() {
c.c.Flush()
}
func main() {
type User struct {
ID int
Email string
FirstName string
LastName string
}
m := map[int]*User{
5: {ID: 5, FirstName: "John", LastName: "Smith", Email: "john@example.com"},
}
batchFunc := func(_ context.Context, keys []int) []*dataloader.Result[*User] {
var results []*dataloader.Result[*User]
for _, k := range keys {
results = append(results, &dataloader.Result[*User]{Data: m[k]})
}
return results
}
c := cache.New(15*time.Minute, 15*time.Minute)
adapter := &goCacheAdapter[int, *User]{c}
loader := dataloader.NewBatchedLoader(batchFunc, dataloader.WithCache[int, *User](adapter))
result, err := loader.Load(context.Background(), 5)()
if err != nil {
// handle error
}
fmt.Printf("result: %+v", result)
}
Output: result: &{ID:5 Email:john@example.com FirstName:John LastName:Smith}
Example (GolangLRU) ¶
package main
import (
"context"
"fmt"
dataloader "github.com/graph-gophers/dataloader/v7"
lru "github.com/hashicorp/golang-lru"
)
type lruCacheAdapter[K comparable, V any] struct {
cache *lru.ARCCache
}
func (c *lruCacheAdapter[K, V]) Get(_ context.Context, key K) (dataloader.Thunk[V], bool) {
v, ok := c.cache.Get(key)
if ok {
return v.(dataloader.Thunk[V]), ok
}
return nil, ok
}
func (c *lruCacheAdapter[K, V]) Set(_ context.Context, key K, value dataloader.Thunk[V]) {
c.cache.Add(key, value)
}
func (c *lruCacheAdapter[K, V]) Delete(_ context.Context, key K) bool {
if c.cache.Contains(key) {
c.cache.Remove(key)
return true
}
return false
}
func (c *lruCacheAdapter[K, V]) Clear() {
c.cache.Purge()
}
func main() {
type User struct {
ID int
Email string
FirstName string
LastName string
}
m := map[int]*User{
5: {ID: 5, FirstName: "John", LastName: "Smith", Email: "john@example.com"},
}
batchFunc := func(_ context.Context, keys []int) []*dataloader.Result[*User] {
var results []*dataloader.Result[*User]
for _, k := range keys {
results = append(results, &dataloader.Result[*User]{Data: m[k]})
}
return results
}
c, _ := lru.NewARC(100)
adapter := &lruCacheAdapter[int, *User]{cache: c}
loader := dataloader.NewBatchedLoader(batchFunc, dataloader.WithCache[int, *User](adapter))
result, err := loader.Load(context.TODO(), 5)()
if err != nil {
// handle error
}
fmt.Printf("result: %+v", result)
}
Output: result: &{ID:5 Email:john@example.com FirstName:John LastName:Smith}
func (*Loader[K, V]) Clear ¶
Clear clears the value at `key` from the cache, it it exists. Returns self for method chaining
func (*Loader[K, V]) ClearAll ¶
ClearAll clears the entire cache. To be used when some event results in unknown invalidations. Returns self for method chaining.
func (*Loader[K, V]) Flush ¶ added in v7.1.2
func (l *Loader[K, V]) Flush()
Flush will load the items in the current batch immediately without waiting for the timer.
func (*Loader[K, V]) Load ¶
Load load/resolves the given key, returning a channel that will contain the value and error. The first context passed to this function within a given batch window will be provided to the registered BatchFunc.
type NoCache ¶
type NoCache[K comparable, V any] struct{}
NoCache implements Cache interface where all methods are noops. This is useful for when you don't want to cache items but still want to use a data loader
Example ¶
package main
import (
"context"
"fmt"
dataloader "github.com/graph-gophers/dataloader/v7"
)
func main() {
type User struct {
ID int
Email string
FirstName string
LastName string
}
m := map[int]*User{
5: {ID: 5, FirstName: "John", LastName: "Smith", Email: "john@example.com"},
}
batchFunc := func(_ context.Context, keys []int) []*dataloader.Result[*User] {
var results []*dataloader.Result[*User]
for _, k := range keys {
results = append(results, &dataloader.Result[*User]{Data: m[k]})
}
return results
}
cache := &dataloader.NoCache[int, *User]{}
loader := dataloader.NewBatchedLoader(batchFunc, dataloader.WithCache[int, *User](cache))
result, err := loader.Load(context.Background(), 5)()
if err != nil {
// handle error
}
fmt.Printf("result: %+v", result)
}
Output: result: &{ID:5 Email:john@example.com FirstName:John LastName:Smith}
type NoopTracer ¶
type NoopTracer[K comparable, V any] struct{}
NoopTracer is the default (noop) tracer
func (NoopTracer[K, V]) TraceBatch ¶
func (NoopTracer[K, V]) TraceBatch(ctx context.Context, keys []K) (context.Context, TraceBatchFinishFunc[V])
TraceBatch is a noop function
func (NoopTracer[K, V]) TraceLoad ¶
func (NoopTracer[K, V]) TraceLoad(ctx context.Context, key K) (context.Context, TraceLoadFinishFunc[V])
TraceLoad is a noop function
func (NoopTracer[K, V]) TraceLoadMany ¶
func (NoopTracer[K, V]) TraceLoadMany(ctx context.Context, keys []K) (context.Context, TraceLoadManyFinishFunc[V])
TraceLoadMany is a noop function
type Option ¶
type Option[K comparable, V any] func(*Loader[K, V])
Option allows for configuration of Loader fields.
func WithBatchCapacity ¶
func WithBatchCapacity[K comparable, V any](c int) Option[K, V]
WithBatchCapacity sets the batch capacity. Default is 0 (unbounded).
func WithCache ¶
func WithCache[K comparable, V any](c Cache[K, V]) Option[K, V]
WithCache sets the BatchedLoader cache. Defaults to InMemoryCache if a Cache is not set.
func WithClearCacheOnBatch ¶
func WithClearCacheOnBatch[K comparable, V any]() Option[K, V]
WithClearCacheOnBatch allows batching of items but no long term caching. It accomplishes this by clearing the cache after each batch operation.
func WithInputCapacity ¶
func WithInputCapacity[K comparable, V any](c int) Option[K, V]
WithInputCapacity sets the input capacity. Default is 1000.
func WithTracer ¶
func WithTracer[K comparable, V any](tracer Tracer[K, V]) Option[K, V]
WithTracer allows tracing of calls to Load and LoadMany
type PanicErrorWrapper ¶ added in v7.1.0
type PanicErrorWrapper struct {
// contains filtered or unexported fields
}
PanicErrorWrapper wraps the error interface. This is used to check if the error is a panic error. We should not cache panic errors.
func (*PanicErrorWrapper) Error ¶ added in v7.1.0
func (p *PanicErrorWrapper) Error() string
type Result ¶
Result is the data structure that a BatchFunc returns. It contains the resolved data, and any errors that may have occurred while fetching the data.
type ResultMany ¶
ResultMany is used by the LoadMany method. It contains a list of resolved data and a list of errors. The lengths of the data list and error list will match, and elements at each index correspond to each other.
type SkipCacheError ¶ added in v7.1.2
type SkipCacheError struct {
// contains filtered or unexported fields
}
SkipCacheError wraps the error interface. The cache should not store SkipCacheErrors.
func NewSkipCacheError ¶ added in v7.1.2
func NewSkipCacheError(err error) *SkipCacheError
func (*SkipCacheError) Error ¶ added in v7.1.2
func (s *SkipCacheError) Error() string
func (*SkipCacheError) Unwrap ¶ added in v7.1.2
func (s *SkipCacheError) Unwrap() error
type Thunk ¶
Thunk is a function that will block until the value (*Result) it contains is resolved. After the value it contains is resolved, this function will return the result. This function can be called many times, much like a Promise is other languages. The value will only need to be resolved once so subsequent calls will return immediately.
type TraceBatchFinishFunc ¶
type TraceLoadFinishFunc ¶
type TraceLoadManyFinishFunc ¶
type Tracer ¶
type Tracer[K comparable, V any] interface { // TraceLoad will trace the calls to Load. TraceLoad(ctx context.Context, key K) (context.Context, TraceLoadFinishFunc[V]) // TraceLoadMany will trace the calls to LoadMany. TraceLoadMany(ctx context.Context, keys []K) (context.Context, TraceLoadManyFinishFunc[V]) // TraceBatch will trace data loader batches. TraceBatch(ctx context.Context, keys []K) (context.Context, TraceBatchFinishFunc[V]) }
Tracer is an interface that may be used to implement tracing.