func (l *Loader) Prime(ctx context.Context, key Key, value interface{}) Interface {
	if _, ok := l.cache.Get(ctx, key); !ok {
		thunk := func() (interface{}, error) {
			return value, nil
		}
		l.cache.Set(ctx, key, thunk)
	}
	return l
}
Prime adds the provided key and value to the cache. If the key already exists, no change is made.
Returns self for method chaining
package dataloader
import (
	"context"
	"fmt"
	"log"
	"runtime"
	"sync"
	"time"
)
type Interface interface {
	Load(context.Context, Key) Thunk
	LoadMany(context.Context, Keys) ThunkMany
	Clear(context.Context, Key) Interface
	ClearAll() Interface
	Prime(ctx context.Context, key Key, value interface{}) Interface
}
type BatchFunc func(context.Context, Keys) []*Result
type Result struct {
	Data  interface{}
	Error error
}
type ResultMany struct {
	Data  []interface{}
	Error []error
}
type Loader struct {
	batchFn BatchFunc
	batchCap int
	cacheLock sync.Mutex
	cache     Cache
	clearCacheOnBatch bool
	count int
	inputCap int
	wait time.Duration
	batchLock sync.Mutex
	curBatcher *batcher
	endSleeper chan bool
	silent bool
	tracer Tracer
}
type Thunk func() (interface{}, error)
type ThunkMany func() ([]interface{}, []error)
type batchRequest struct {
	key     Key
	channel chan *Result
}
type Option func(*Loader)
func WithCache(c Cache) Option {
	return func(l *Loader) {
		l.cache = c
	}
}
func WithBatchCapacity(c int) Option {
	return func(l *Loader) {
		l.batchCap = c
	}
}
func WithInputCapacity(c int) Option {
	return func(l *Loader) {
		l.inputCap = c
	}
}
func WithWait(d time.Duration) Option {
	return func(l *Loader) {
		l.wait = d
	}
}
func WithClearCacheOnBatch() Option {
	return func(l *Loader) {
		l.cacheLock.Lock()
		l.clearCacheOnBatch = true
		l.cacheLock.Unlock()
	}
}
func withSilentLogger() Option {
	return func(l *Loader) {
		l.silent = true
	}
}
func WithTracer(tracer Tracer) Option {
	return func(l *Loader) {
		l.tracer = tracer
	}
}
func WithOpenTracingTracer() Option {
	return WithTracer(&OpenTracingTracer{})
}
func NewBatchedLoader(batchFn BatchFunc, opts ...Option) *Loader {
	loader := &Loader{
		batchFn:  batchFn,
		inputCap: 1000,
		wait:     16 * time.Millisecond,
	}
	for _, apply := range opts {
		apply(loader)
	}
	if loader.cache == nil {
		loader.cache = NewCache()
	}
	if loader.tracer == nil {
		loader.tracer = &NoopTracer{}
	}
	return loader
}
func (l *Loader) Load(originalContext context.Context, key Key) Thunk {
	ctx, finish := l.tracer.TraceLoad(originalContext, key)
	c := make(chan *Result, 1)
	var result struct {
		mu    sync.RWMutex
		value *Result
	}
	l.cacheLock.Lock()
	if v, ok := l.cache.Get(ctx, key); ok {
		defer finish(v)
		defer l.cacheLock.Unlock()
		return v
	}
	thunk := func() (interface{}, error) {
		result.mu.RLock()
		resultNotSet := result.value == nil
		result.mu.RUnlock()
		if resultNotSet {
			result.mu.Lock()
			if v, ok := <-c; ok {
				result.value = v
			}
			result.mu.Unlock()
		}
		result.mu.RLock()
		defer result.mu.RUnlock()
		return result.value.Data, result.value.Error
	}
	defer finish(thunk)
	l.cache.Set(ctx, key, thunk)
	l.cacheLock.Unlock()
	req := &batchRequest{key, c}
	l.batchLock.Lock()
	if l.curBatcher == nil {
		l.curBatcher = l.newBatcher(l.silent, l.tracer)
		go l.curBatcher.batch(originalContext)
		l.endSleeper = make(chan bool)
		go l.sleeper(l.curBatcher, l.endSleeper)
	}
	l.curBatcher.input <- req
	if l.batchCap > 0 {
		l.count++
		if l.count == l.batchCap {
			l.curBatcher.end()
			close(l.endSleeper)
			l.reset()
		}
	}
	l.batchLock.Unlock()
	return thunk
}
func (l *Loader) LoadMany(originalContext context.Context, keys Keys) ThunkMany {
	ctx, finish := l.tracer.TraceLoadMany(originalContext, keys)
	var (
		length = len(keys)
		data   = make([]interface{}, length)
		errors = make([]error, length)
		c      = make(chan *ResultMany, 1)
		wg     sync.WaitGroup
	)
	resolve := func(ctx context.Context, i int) {
		defer wg.Done()
		thunk := l.Load(ctx, keys[i])
		result, err := thunk()
		data[i] = result
		errors[i] = err
	}
	wg.Add(length)
	for i := range keys {
		go resolve(ctx, i)
	}
	go func() {
		wg.Wait()
		var errs []error
		for _, e := range errors {
			if e != nil {
				errs = errors
				break
			}
		}
		c <- &ResultMany{Data: data, Error: errs}
		close(c)
	}()
	var result struct {
		mu    sync.RWMutex
		value *ResultMany
	}
	thunkMany := func() ([]interface{}, []error) {
		result.mu.RLock()
		resultNotSet := result.value == nil
		result.mu.RUnlock()
		if resultNotSet {
			result.mu.Lock()
			if v, ok := <-c; ok {
				result.value = v
			}
			result.mu.Unlock()
		}
		result.mu.RLock()
		defer result.mu.RUnlock()
		return result.value.Data, result.value.Error
	}
	defer finish(thunkMany)
	return thunkMany
}
func (l *Loader) Clear(ctx context.Context, key Key) Interface {
	l.cacheLock.Lock()
	l.cache.Delete(ctx, key)
	l.cacheLock.Unlock()
	return l
}
func (l *Loader) ClearAll() Interface {
	l.cacheLock.Lock()
	l.cache.Clear()
	l.cacheLock.Unlock()
	return l
}