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