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 }