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

     1  //go:generate go run github.com/vektah/dataloaden AddressLoader int *github.com/99designs/gqlgen/example/dataloader.Address
     2  //go:generate go run github.com/vektah/dataloaden OrderSliceLoader int []*github.com/99designs/gqlgen/example/dataloader.Order
     3  //go:generate go run github.com/vektah/dataloaden ItemSliceLoader int []*github.com/99designs/gqlgen/example/dataloader.Item
     4  
     5  package dataloader
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"math/rand"
    11  	"net/http"
    12  	"strconv"
    13  	"strings"
    14  	"time"
    15  )
    16  
    17  type ctxKeyType struct{ name string }
    18  
    19  var ctxKey = ctxKeyType{"userCtx"}
    20  
    21  type loaders struct {
    22  	addressByID      *AddressLoader
    23  	ordersByCustomer *OrderSliceLoader
    24  	itemsByOrder     *ItemSliceLoader
    25  }
    26  
    27  // nolint: gosec
    28  func LoaderMiddleware(next http.Handler) http.Handler {
    29  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    30  		ldrs := loaders{}
    31  
    32  		// set this to zero what happens without dataloading
    33  		wait := 250 * time.Microsecond
    34  
    35  		// simple 1:1 loader, fetch an address by its primary key
    36  		ldrs.addressByID = &AddressLoader{
    37  			wait:     wait,
    38  			maxBatch: 100,
    39  			fetch: func(keys []int) ([]*Address, []error) {
    40  				var keySql []string
    41  				for _, key := range keys {
    42  					keySql = append(keySql, strconv.Itoa(key))
    43  				}
    44  
    45  				fmt.Printf("SELECT * FROM address WHERE id IN (%s)\n", strings.Join(keySql, ","))
    46  				time.Sleep(5 * time.Millisecond)
    47  
    48  				addresses := make([]*Address, len(keys))
    49  				errors := make([]error, len(keys))
    50  				for i, key := range keys {
    51  					addresses[i] = &Address{Street: "home street", Country: "hometon " + strconv.Itoa(key)}
    52  				}
    53  				return addresses, errors
    54  			},
    55  		}
    56  
    57  		// 1:M loader
    58  		ldrs.ordersByCustomer = &OrderSliceLoader{
    59  			wait:     wait,
    60  			maxBatch: 100,
    61  			fetch: func(keys []int) ([][]*Order, []error) {
    62  				var keySql []string
    63  				for _, key := range keys {
    64  					keySql = append(keySql, strconv.Itoa(key))
    65  				}
    66  
    67  				fmt.Printf("SELECT * FROM orders WHERE customer_id IN (%s)\n", strings.Join(keySql, ","))
    68  				time.Sleep(5 * time.Millisecond)
    69  
    70  				orders := make([][]*Order, len(keys))
    71  				errors := make([]error, len(keys))
    72  				for i, key := range keys {
    73  					id := 10 + rand.Int()%3
    74  					orders[i] = []*Order{
    75  						{ID: id, Amount: rand.Float64(), Date: time.Now().Add(-time.Duration(key) * time.Hour)},
    76  						{ID: id + 1, Amount: rand.Float64(), Date: time.Now().Add(-time.Duration(key) * time.Hour)},
    77  					}
    78  
    79  					// if you had another customer loader you would prime its cache here
    80  					// by calling `ldrs.ordersByID.Prime(id, orders[i])`
    81  				}
    82  
    83  				return orders, errors
    84  			},
    85  		}
    86  
    87  		// M:M loader
    88  		ldrs.itemsByOrder = &ItemSliceLoader{
    89  			wait:     wait,
    90  			maxBatch: 100,
    91  			fetch: func(keys []int) ([][]*Item, []error) {
    92  				var keySql []string
    93  				for _, key := range keys {
    94  					keySql = append(keySql, strconv.Itoa(key))
    95  				}
    96  
    97  				fmt.Printf("SELECT * FROM items JOIN item_order WHERE item_order.order_id IN (%s)\n", strings.Join(keySql, ","))
    98  				time.Sleep(5 * time.Millisecond)
    99  
   100  				items := make([][]*Item, len(keys))
   101  				errors := make([]error, len(keys))
   102  				for i := range keys {
   103  					items[i] = []*Item{
   104  						{Name: "item " + strconv.Itoa(rand.Int()%20+20)},
   105  						{Name: "item " + strconv.Itoa(rand.Int()%20+20)},
   106  					}
   107  				}
   108  
   109  				return items, errors
   110  			},
   111  		}
   112  
   113  		dlCtx := context.WithValue(r.Context(), ctxKey, ldrs)
   114  		next.ServeHTTP(w, r.WithContext(dlCtx))
   115  	})
   116  }
   117  
   118  func ctxLoaders(ctx context.Context) loaders {
   119  	return ctx.Value(ctxKey).(loaders)
   120  }