github.com/coveo/gotemplate@v2.7.7+incompatible/collections/implementation/dict_helper.go (about)

     1  package implementation
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/coveo/gotemplate/collections"
     7  )
     8  
     9  func (d baseDict) String() string {
    10  	// Unlike go maps, we render dictionary keys in order
    11  	keys := d.KeysAsString()
    12  	for i, k := range keys {
    13  		keys[i] = str(fmt.Sprintf("%s:%v", k, d.Get(k)))
    14  	}
    15  	return fmt.Sprintf("dict[%s]", keys.Join(" "))
    16  }
    17  
    18  func (d baseDict) PrettyPrint() string { return d.String() }
    19  
    20  // DictHelper implements basic functionalities required for IDictionary.
    21  type DictHelper struct {
    22  	BaseHelper
    23  }
    24  
    25  // AsDictionary returns the object casted as IDictionary.
    26  func (dh DictHelper) AsDictionary(object interface{}) baseIDict {
    27  	return must(dh.TryAsDictionary(object)).(baseIDict)
    28  }
    29  
    30  // Clone returns a distinct copy of the object with only supplied keys. If no keys are supplied, all keys from d are copied.
    31  func (dh DictHelper) Clone(dict baseIDict, keys []interface{}) baseIDict {
    32  	if len(keys) == 0 {
    33  		keys = dict.GetKeys().AsArray()
    34  	}
    35  	newDict := dh.CreateDictionary(dict.Len())
    36  	for i := range keys {
    37  		value := dict.Get(keys[i])
    38  		if value != nil {
    39  			if v, err := dh.TryAsDictionary(value); err == nil {
    40  				value = dh.Clone(v, nil)
    41  			} else if v, err := dh.TryAsList(value); err == nil {
    42  				value = dh.ConvertList(v.Clone())
    43  			}
    44  		}
    45  		newDict.Set(keys[i], value)
    46  	}
    47  	return newDict
    48  }
    49  
    50  // Default returns defVal if dictionary doesn't contain key, otherwise, simply returns entry corresponding to key.
    51  func (dh DictHelper) Default(dict baseIDict, key, defVal interface{}) interface{} {
    52  	if !dict.Has(key) {
    53  		return defVal
    54  	}
    55  	return dict.Get(key)
    56  }
    57  
    58  // Delete removes the entry value associated with key. The entry must exist.
    59  func (dh DictHelper) Delete(dict baseIDict, keys []interface{}) (baseIDict, error) {
    60  	return dh.delete(dict, keys, true)
    61  }
    62  
    63  // Flush removes all specified keys from the dictionary. If no key is specified, all keys are removed.
    64  func (dh DictHelper) Flush(dict baseIDict, keys []interface{}) baseIDict {
    65  	if len(keys) == 0 {
    66  		keys = dict.GetKeys().AsArray()
    67  	}
    68  	dh.delete(dict, keys, false)
    69  	return dict
    70  }
    71  
    72  // Get returns the value associated with key.
    73  func (dh DictHelper) Get(dict baseIDict, keys []interface{}) interface{} {
    74  	switch len(keys) {
    75  	case 0:
    76  		return nil
    77  	case 1:
    78  		return dict.AsMap()[fmt.Sprint(keys[0])]
    79  	}
    80  	result := dict.CreateList(len(keys))
    81  	for i := range result.AsArray() {
    82  		result.Set(i, dict.Get(keys[i]))
    83  	}
    84  	return result
    85  }
    86  
    87  // Has returns true if the dictionary object contains all the keys.
    88  func (dh DictHelper) Has(dict baseIDict, keys []interface{}) bool {
    89  	for _, key := range keys {
    90  		if _, ok := dict.AsMap()[fmt.Sprint(key)]; !ok {
    91  			return false
    92  		}
    93  	}
    94  	return dict.Len() > 0
    95  }
    96  
    97  // GetKeys returns the keys in the dictionary in alphabetical order.
    98  func (dh DictHelper) GetKeys(dict baseIDict) baseIList {
    99  	keys := dict.KeysAsString()
   100  	result := dh.CreateList(dict.Len())
   101  
   102  	for i := range keys {
   103  		result.Set(i, keys[i])
   104  	}
   105  	return result
   106  }
   107  
   108  // KeysAsString returns the keys in the dictionary in alphabetical order.
   109  func (dh DictHelper) KeysAsString(dict baseIDict) collections.StringArray {
   110  	keys := make(collections.StringArray, 0, dict.Len())
   111  	for key := range dict.AsMap() {
   112  		keys = append(keys, str(key))
   113  	}
   114  	return keys.Sorted()
   115  }
   116  
   117  // Merge merges the other dictionaries into the current dictionary.
   118  func (dh DictHelper) Merge(target baseIDict, sources []baseIDict) baseIDict {
   119  	for i := range sources {
   120  		if sources[i] == nil {
   121  			continue
   122  		}
   123  		target = dh.deepMerge(target, dh.ConvertDict(sources[i]))
   124  	}
   125  	return target
   126  }
   127  
   128  func (dh DictHelper) deepMerge(target baseIDict, source baseIDict) baseIDict {
   129  	targetMap := target.AsMap()
   130  	sourceMap := source.AsMap()
   131  	for key := range sourceMap {
   132  		sourceValue, sourceHasKey := sourceMap[key]
   133  		targetValue, targetHasKey := targetMap[key]
   134  
   135  		if sourceHasKey && !targetHasKey {
   136  			targetMap[key] = sourceValue
   137  			continue
   138  		}
   139  
   140  		targetValueDict, targetValueIsDict := targetValue.(baseIDict)
   141  		sourceValueDict, sourceValueIsDict := sourceValue.(baseIDict)
   142  
   143  		if sourceValueIsDict && targetValueIsDict {
   144  			targetMap[key] = dh.deepMerge(targetValueDict, sourceValueDict)
   145  		}
   146  	}
   147  
   148  	return target
   149  }
   150  
   151  // Omit returns a distinct copy of the object including all keys except specified ones.
   152  func (dh DictHelper) Omit(dict baseIDict, keys []interface{}) baseIDict {
   153  	omitKeys := make(map[string]bool, len(keys))
   154  	for i := range keys {
   155  		omitKeys[fmt.Sprint(keys[i])] = true
   156  	}
   157  	keep := make([]interface{}, 0, dict.Len())
   158  	for key := range dict.AsMap() {
   159  		if !omitKeys[key] {
   160  			keep = append(keep, key)
   161  		}
   162  	}
   163  	return dh.Clone(dict, keep)
   164  }
   165  
   166  // Pop returns and remove the objects with the specified keys.
   167  func (dh DictHelper) Pop(dict baseIDict, keys []interface{}) interface{} {
   168  	if len(keys) == 0 {
   169  		return nil
   170  	}
   171  	result := dh.Get(dict, keys)
   172  	dh.delete(dict, keys, false)
   173  	return result
   174  }
   175  
   176  // Set sets key to value in the dictionary.
   177  func (dh DictHelper) Set(dict baseIDict, key interface{}, value interface{}) baseIDict {
   178  	if dict.AsMap() == nil {
   179  		dict = dh.CreateDictionary()
   180  	}
   181  	dict.AsMap()[fmt.Sprint(key)] = dh.Convert(value)
   182  	return dict
   183  }
   184  
   185  // Add adds value to an existing key instead of replacing the value as done by set.
   186  func (dh DictHelper) Add(dict baseIDict, key interface{}, value interface{}) baseIDict {
   187  	if dict.AsMap() == nil {
   188  		dict = dh.CreateDictionary()
   189  	}
   190  	m := dict.AsMap()
   191  	k := fmt.Sprint(key)
   192  
   193  	if current, ok := m[k]; ok {
   194  		if list, err := collections.TryAsList(current); err == nil {
   195  			m[k] = list.Append(value)
   196  		} else {
   197  			// Convert the current value into a list
   198  			m[k] = dict.CreateList().Append(current, value)
   199  		}
   200  	} else {
   201  		m[k] = dh.Convert(value)
   202  	}
   203  	return dict
   204  }
   205  
   206  // GetValues returns the values in the dictionary in key alphabetical order.
   207  func (dh DictHelper) GetValues(dict baseIDict) baseIList {
   208  	result := dh.CreateList(dict.Len())
   209  	for i, key := range dict.KeysAsString() {
   210  		result.Set(i, dict.Get(key))
   211  	}
   212  	return result
   213  }
   214  
   215  // Transpose returns a dictionary with values as keys and keys as values. The resulting dictionary
   216  // is a dictionary where each key could contains single value or list of values if there are multiple matches.
   217  func (dh DictHelper) Transpose(dict baseIDict) baseIDict {
   218  	result := dh.CreateDictionary()
   219  	for _, key := range dict.GetKeys().AsArray() {
   220  		value := dict.Get(key)
   221  		if list, err := collections.TryAsList(value); err == nil {
   222  			// If the element is a list, we scan each element
   223  			for _, value := range list.AsArray() {
   224  				result.Add(value, key)
   225  			}
   226  		} else {
   227  			result.Add(value, key)
   228  		}
   229  	}
   230  	return result
   231  }
   232  
   233  func (dh DictHelper) delete(dict baseIDict, keys []interface{}, mustExist bool) (baseIDict, error) {
   234  	for i := range keys {
   235  		if mustExist && !dict.Has(keys[i]) {
   236  			return dict, fmt.Errorf("key %v not found", keys[i])
   237  		}
   238  		delete(dict.AsMap(), fmt.Sprint(keys[i]))
   239  	}
   240  	return dict, nil
   241  }
   242  
   243  // Register the default implementation of dictionary helper
   244  var _ = func() int {
   245  	collections.DictionaryHelper = baseDictHelper
   246  	return 0
   247  }()