package merge import "github.com/databricks/cli/libs/dyn" type elementsByKey struct { key string keyFunc func(dyn.Value) string } func (e elementsByKey) Map(v dyn.Value) (dyn.Value, error) { // We know the type of this value is a sequence. // For additional defence, return self if it is not. elements, ok := v.AsSequence() if !ok { return v, nil } seen := make(map[string]dyn.Value, len(elements)) keys := make([]string, 0, len(elements)) // Iterate in natural order. For a given key, we first see the // base definition and merge instances that come after it. for i := range elements { kv := elements[i].Get(e.key) key := e.keyFunc(kv) // Register element with key if not yet seen before. ref, ok := seen[key] if !ok { keys = append(keys, key) seen[key] = elements[i] continue } // Merge this instance into the reference. nv, err := Merge(ref, elements[i]) if err != nil { return v, err } // Overwrite reference. seen[key] = nv } // Gather resulting elements in natural order. out := make([]dyn.Value, 0, len(keys)) for _, key := range keys { nv, err := dyn.Set(seen[key], e.key, dyn.V(key)) if err != nil { return dyn.InvalidValue, err } out = append(out, nv) } return dyn.NewValue(out, v.Location()), nil } // ElementsByKey returns a [dyn.MapFunc] that operates on a sequence // where each element is a map. It groups elements by a key and merges // elements with the same key. // // The function that extracts the key from an element is provided as // a parameter. The resulting elements get their key field overwritten // with the value as returned by the key function. func ElementsByKey(key string, keyFunc func(dyn.Value) string) dyn.MapFunc { return elementsByKey{key, keyFunc}.Map }