github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/example/dataloader/addressloader_gen.go (about)

     1  // Code generated by github.com/vektah/dataloaden, DO NOT EDIT.
     2  
     3  package dataloader
     4  
     5  import (
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  // AddressLoaderConfig captures the config to create a new AddressLoader
    11  type AddressLoaderConfig struct {
    12  	// Fetch is a method that provides the data for the loader
    13  	Fetch func(keys []int) ([]*Address, []error)
    14  
    15  	// Wait is how long wait before sending a batch
    16  	Wait time.Duration
    17  
    18  	// MaxBatch will limit the maximum number of keys to send in one batch, 0 = not limit
    19  	MaxBatch int
    20  }
    21  
    22  // NewAddressLoader creates a new AddressLoader given a fetch, wait, and maxBatch
    23  func NewAddressLoader(config AddressLoaderConfig) *AddressLoader {
    24  	return &AddressLoader{
    25  		fetch:    config.Fetch,
    26  		wait:     config.Wait,
    27  		maxBatch: config.MaxBatch,
    28  	}
    29  }
    30  
    31  // AddressLoader batches and caches requests
    32  type AddressLoader struct {
    33  	// this method provides the data for the loader
    34  	fetch func(keys []int) ([]*Address, []error)
    35  
    36  	// how long to done before sending a batch
    37  	wait time.Duration
    38  
    39  	// this will limit the maximum number of keys to send in one batch, 0 = no limit
    40  	maxBatch int
    41  
    42  	// INTERNAL
    43  
    44  	// lazily created cache
    45  	cache map[int]*Address
    46  
    47  	// the current batch. keys will continue to be collected until timeout is hit,
    48  	// then everything will be sent to the fetch method and out to the listeners
    49  	batch *addressLoaderBatch
    50  
    51  	// mutex to prevent races
    52  	mu sync.Mutex
    53  }
    54  
    55  type addressLoaderBatch struct {
    56  	keys    []int
    57  	data    []*Address
    58  	error   []error
    59  	closing bool
    60  	done    chan struct{}
    61  }
    62  
    63  // Load a Address by key, batching and caching will be applied automatically
    64  func (l *AddressLoader) Load(key int) (*Address, error) {
    65  	return l.LoadThunk(key)()
    66  }
    67  
    68  // LoadThunk returns a function that when called will block waiting for a Address.
    69  // This method should be used if you want one goroutine to make requests to many
    70  // different data loaders without blocking until the thunk is called.
    71  func (l *AddressLoader) LoadThunk(key int) func() (*Address, error) {
    72  	l.mu.Lock()
    73  	if it, ok := l.cache[key]; ok {
    74  		l.mu.Unlock()
    75  		return func() (*Address, error) {
    76  			return it, nil
    77  		}
    78  	}
    79  	if l.batch == nil {
    80  		l.batch = &addressLoaderBatch{done: make(chan struct{})}
    81  	}
    82  	batch := l.batch
    83  	pos := batch.keyIndex(l, key)
    84  	l.mu.Unlock()
    85  
    86  	return func() (*Address, error) {
    87  		<-batch.done
    88  
    89  		var data *Address
    90  		if pos < len(batch.data) {
    91  			data = batch.data[pos]
    92  		}
    93  
    94  		var err error
    95  		// its convenient to be able to return a single error for everything
    96  		if len(batch.error) == 1 {
    97  			err = batch.error[0]
    98  		} else if batch.error != nil {
    99  			err = batch.error[pos]
   100  		}
   101  
   102  		if err == nil {
   103  			l.mu.Lock()
   104  			l.unsafeSet(key, data)
   105  			l.mu.Unlock()
   106  		}
   107  
   108  		return data, err
   109  	}
   110  }
   111  
   112  // LoadAll fetches many keys at once. It will be broken into appropriate sized
   113  // sub batches depending on how the loader is configured
   114  func (l *AddressLoader) LoadAll(keys []int) ([]*Address, []error) {
   115  	results := make([]func() (*Address, error), len(keys))
   116  
   117  	for i, key := range keys {
   118  		results[i] = l.LoadThunk(key)
   119  	}
   120  
   121  	addresss := make([]*Address, len(keys))
   122  	errors := make([]error, len(keys))
   123  	for i, thunk := range results {
   124  		addresss[i], errors[i] = thunk()
   125  	}
   126  	return addresss, errors
   127  }
   128  
   129  // LoadAllThunk returns a function that when called will block waiting for a Addresss.
   130  // This method should be used if you want one goroutine to make requests to many
   131  // different data loaders without blocking until the thunk is called.
   132  func (l *AddressLoader) LoadAllThunk(keys []int) func() ([]*Address, []error) {
   133  	results := make([]func() (*Address, error), len(keys))
   134  	for i, key := range keys {
   135  		results[i] = l.LoadThunk(key)
   136  	}
   137  	return func() ([]*Address, []error) {
   138  		addresss := make([]*Address, len(keys))
   139  		errors := make([]error, len(keys))
   140  		for i, thunk := range results {
   141  			addresss[i], errors[i] = thunk()
   142  		}
   143  		return addresss, errors
   144  	}
   145  }
   146  
   147  // Prime the cache with the provided key and value. If the key already exists, no change is made
   148  // and false is returned.
   149  // (To forcefully prime the cache, clear the key first with loader.clear(key).prime(key, value).)
   150  func (l *AddressLoader) Prime(key int, value *Address) bool {
   151  	l.mu.Lock()
   152  	var found bool
   153  	if _, found = l.cache[key]; !found {
   154  		// make a copy when writing to the cache, its easy to pass a pointer in from a loop var
   155  		// and end up with the whole cache pointing to the same value.
   156  		cpy := *value
   157  		l.unsafeSet(key, &cpy)
   158  	}
   159  	l.mu.Unlock()
   160  	return !found
   161  }
   162  
   163  // Clear the value at key from the cache, if it exists
   164  func (l *AddressLoader) Clear(key int) {
   165  	l.mu.Lock()
   166  	delete(l.cache, key)
   167  	l.mu.Unlock()
   168  }
   169  
   170  func (l *AddressLoader) unsafeSet(key int, value *Address) {
   171  	if l.cache == nil {
   172  		l.cache = map[int]*Address{}
   173  	}
   174  	l.cache[key] = value
   175  }
   176  
   177  // keyIndex will return the location of the key in the batch, if its not found
   178  // it will add the key to the batch
   179  func (b *addressLoaderBatch) keyIndex(l *AddressLoader, key int) int {
   180  	for i, existingKey := range b.keys {
   181  		if key == existingKey {
   182  			return i
   183  		}
   184  	}
   185  
   186  	pos := len(b.keys)
   187  	b.keys = append(b.keys, key)
   188  	if pos == 0 {
   189  		go b.startTimer(l)
   190  	}
   191  
   192  	if l.maxBatch != 0 && pos >= l.maxBatch-1 {
   193  		if !b.closing {
   194  			b.closing = true
   195  			l.batch = nil
   196  			go b.end(l)
   197  		}
   198  	}
   199  
   200  	return pos
   201  }
   202  
   203  func (b *addressLoaderBatch) startTimer(l *AddressLoader) {
   204  	time.Sleep(l.wait)
   205  	l.mu.Lock()
   206  
   207  	// we must have hit a batch limit and are already finalizing this batch
   208  	if b.closing {
   209  		l.mu.Unlock()
   210  		return
   211  	}
   212  
   213  	l.batch = nil
   214  	l.mu.Unlock()
   215  
   216  	b.end(l)
   217  }
   218  
   219  func (b *addressLoaderBatch) end(l *AddressLoader) {
   220  	b.data, b.error = l.fetch(b.keys)
   221  	close(b.done)
   222  }