MCPcopy Create free account
hub / github.com/OctopusDeploy/cli / MapCollectionWithLookups

Function MapCollectionWithLookups

pkg/util/util.go:131–205  ·  view source on GitHub ↗

MapCollectionWithLookups does a 'map' operation over the collection, transforming each input row into an output row according to `mapper`, however it also provides the ability to collect ID's of related items as it iterates the collection, and call out to lambdas to look those values up. See the uni

(
	cacheContainer *MapCollectionCacheContainer, // cache for keys (typically this will store a mapping of ID->[Name, Name]).
	collection []T, // input (e.g. list of Releases)
	keySelector func(T) []string, // fetches the keys (e.g given a Release, returns the [ChannelID, ProjectID]
	mapper func(T, []string) TResult, // fetches the value to lookup (e.g given a Release and the [ChannelName,ProjectName], does the mapping to return the output struct)
	runLookups ...func([]string) ([]string, error), // callbacks to go fetch values for the keys (given a list of Channel IDs, it should return the list of associated Channel Names)
)

Source from the content-addressed store, hash-verified

129// items as it iterates the collection, and call out to lambdas to look those values up.
130// See the unit tests for examples which should clarify the use-cases for this.
131func MapCollectionWithLookups[T any, TResult any](
132 cacheContainer *MapCollectionCacheContainer, // cache for keys (typically this will store a mapping of ID->[Name, Name]).
133 collection []T, // input (e.g. list of Releases)
134 keySelector func(T) []string, // fetches the keys (e.g given a Release, returns the [ChannelID, ProjectID]
135 mapper func(T, []string) TResult, // fetches the value to lookup (e.g given a Release and the [ChannelName,ProjectName], does the mapping to return the output struct)
136 runLookups ...func([]string) ([]string, error), // callbacks to go fetch values for the keys (given a list of Channel IDs, it should return the list of associated Channel Names)
137) ([]TResult, error) {
138 // if the caller didn't specify an external cache, create an internal one.
139 // it'll work, but we lose the ability to cache across multiple lookups
140 // (e.g. when fetching more than one page of results from the server)
141 if cacheContainer == nil {
142 cacheContainer = &MapCollectionCacheContainer{}
143 }
144
145 if len(cacheContainer.Caches) < len(runLookups) {
146 // caches aren't allocated, we need to do that
147 cacheContainer.Caches = nil
148 for i := 0; i < len(runLookups); i++ {
149 cacheContainer.Caches = append(cacheContainer.Caches, map[string]string{})
150 }
151 }
152
153 caches := cacheContainer.Caches
154
155 // first pass: walk the collection and see if there's anything we need to look up.
156 // if we detect a situation where all the lookups are already satisfied by the cache,
157 // then we may not need to do any lookups at all.
158 var allKeysToLookup = make([][]string, len(caches)) // preallocate the right number of nils
159 for _, item := range collection {
160 keys := keySelector(item)
161 for i, key := range keys {
162 _, ok := caches[i][key]
163 if !ok { // we haven't seen this value in the cache, we need to go and look something up
164 if allKeysToLookup[i] == nil {
165 allKeysToLookup[i] = []string{key}
166 } else {
167 if !SliceContains(allKeysToLookup[i], key) {
168 allKeysToLookup[i] = append(allKeysToLookup[i], key)
169 } // else we've already seen this key
170 }
171 }
172 }
173 }
174
175 // if we have things we need to look up, go and look them up and insert them into the cache.
176 for lookupIdx, keysToLookup := range allKeysToLookup {
177 if keysToLookup != nil {
178 lookedUpValues, err := runLookups[lookupIdx](keysToLookup)
179 if err != nil {
180 return nil, err
181 }
182 for valueIdx, value := range lookedUpValues {
183 caches[lookupIdx][keysToLookup[valueIdx]] = value
184 }
185 }
186 }
187
188 // Now we do a second pass over the array in order to produce the output (incorporating the looked-up values from cache)

Callers 2

listRunFunction · 0.92

Calls 1

SliceContainsFunction · 0.85

Tested by 1