dict.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package sprig
  2. // get retrieves a value from a map by its key.
  3. // If the key exists, returns the corresponding value.
  4. // If the key doesn't exist, returns an empty string.
  5. //
  6. // Parameters:
  7. // - d: The map to retrieve the value from
  8. // - key: The key to look up
  9. //
  10. // Returns:
  11. // - any: The value associated with the key, or an empty string if not found
  12. func get(d map[string]any, key string) any {
  13. if val, ok := d[key]; ok {
  14. return val
  15. }
  16. return ""
  17. }
  18. // set adds or updates a key-value pair in a map.
  19. // Modifies the map in place and returns the modified map.
  20. //
  21. // Parameters:
  22. // - d: The map to modify
  23. // - key: The key to set
  24. // - value: The value to associate with the key
  25. //
  26. // Returns:
  27. // - map[string]any: The modified map (same instance as the input map)
  28. func set(d map[string]any, key string, value any) map[string]any {
  29. d[key] = value
  30. return d
  31. }
  32. // unset removes a key-value pair from a map.
  33. // If the key doesn't exist, the map remains unchanged.
  34. // Modifies the map in place and returns the modified map.
  35. //
  36. // Parameters:
  37. // - d: The map to modify
  38. // - key: The key to remove
  39. //
  40. // Returns:
  41. // - map[string]any: The modified map (same instance as the input map)
  42. func unset(d map[string]any, key string) map[string]any {
  43. delete(d, key)
  44. return d
  45. }
  46. // hasKey checks if a key exists in a map.
  47. //
  48. // Parameters:
  49. // - d: The map to check
  50. // - key: The key to look for
  51. //
  52. // Returns:
  53. // - bool: True if the key exists in the map, false otherwise
  54. func hasKey(d map[string]any, key string) bool {
  55. _, ok := d[key]
  56. return ok
  57. }
  58. // pluck extracts values for a specific key from multiple maps.
  59. // Only includes values from maps where the key exists.
  60. //
  61. // Parameters:
  62. // - key: The key to extract values for
  63. // - d: A variadic list of maps to extract values from
  64. //
  65. // Returns:
  66. // - []any: A slice containing all values associated with the key across all maps
  67. func pluck(key string, d ...map[string]any) []any {
  68. var res []any
  69. for _, dict := range d {
  70. if val, ok := dict[key]; ok {
  71. res = append(res, val)
  72. }
  73. }
  74. return res
  75. }
  76. // keys collects all keys from one or more maps.
  77. // The returned slice may contain duplicate keys if multiple maps contain the same key.
  78. //
  79. // Parameters:
  80. // - dicts: A variadic list of maps to collect keys from
  81. //
  82. // Returns:
  83. // - []string: A slice containing all keys from all provided maps
  84. func keys(dicts ...map[string]any) []string {
  85. var k []string
  86. for _, dict := range dicts {
  87. for key := range dict {
  88. k = append(k, key)
  89. }
  90. }
  91. return k
  92. }
  93. // pick creates a new map containing only the specified keys from the original map.
  94. // If a key doesn't exist in the original map, it won't be included in the result.
  95. //
  96. // Parameters:
  97. // - dict: The source map
  98. // - keys: A variadic list of keys to include in the result
  99. //
  100. // Returns:
  101. // - map[string]any: A new map containing only the specified keys and their values
  102. func pick(dict map[string]any, keys ...string) map[string]any {
  103. res := map[string]any{}
  104. for _, k := range keys {
  105. if v, ok := dict[k]; ok {
  106. res[k] = v
  107. }
  108. }
  109. return res
  110. }
  111. // omit creates a new map excluding the specified keys from the original map.
  112. // The original map remains unchanged.
  113. //
  114. // Parameters:
  115. // - dict: The source map
  116. // - keys: A variadic list of keys to exclude from the result
  117. //
  118. // Returns:
  119. // - map[string]any: A new map containing all key-value pairs except those specified
  120. func omit(dict map[string]any, keys ...string) map[string]any {
  121. res := map[string]any{}
  122. omit := make(map[string]bool, len(keys))
  123. for _, k := range keys {
  124. omit[k] = true
  125. }
  126. for k, v := range dict {
  127. if _, ok := omit[k]; !ok {
  128. res[k] = v
  129. }
  130. }
  131. return res
  132. }
  133. // dict creates a new map from a list of key-value pairs.
  134. // The arguments are treated as key-value pairs, where even-indexed arguments are keys
  135. // and odd-indexed arguments are values.
  136. // If there's an odd number of arguments, the last key will be assigned an empty string value.
  137. //
  138. // Parameters:
  139. // - v: A variadic list of alternating keys and values
  140. //
  141. // Returns:
  142. // - map[string]any: A new map containing the specified key-value pairs
  143. func dict(v ...any) map[string]any {
  144. dict := map[string]any{}
  145. lenv := len(v)
  146. for i := 0; i < lenv; i += 2 {
  147. key := strval(v[i])
  148. if i+1 >= lenv {
  149. dict[key] = ""
  150. continue
  151. }
  152. dict[key] = v[i+1]
  153. }
  154. return dict
  155. }
  156. // values collects all values from a map into a slice.
  157. // The order of values in the resulting slice is not guaranteed.
  158. //
  159. // Parameters:
  160. // - dict: The map to collect values from
  161. //
  162. // Returns:
  163. // - []any: A slice containing all values from the map
  164. func values(dict map[string]any) []any {
  165. var values []any
  166. for _, value := range dict {
  167. values = append(values, value)
  168. }
  169. return values
  170. }
  171. // dig safely accesses nested values in maps using a sequence of keys.
  172. // If any key in the path doesn't exist, it returns the default value.
  173. // The function expects at least 3 arguments: one or more keys, a default value, and a map.
  174. //
  175. // Parameters:
  176. // - ps: A variadic list where:
  177. // - The first N-2 arguments are string keys forming the path
  178. // - The second-to-last argument is the default value to return if the path doesn't exist
  179. // - The last argument is the map to traverse
  180. //
  181. // Returns:
  182. // - any: The value found at the specified path, or the default value if not found
  183. // - error: Any error that occurred during traversal
  184. //
  185. // Panics:
  186. // - If fewer than 3 arguments are provided
  187. func dig(ps ...any) (any, error) {
  188. if len(ps) < 3 {
  189. panic("dig needs at least three arguments")
  190. }
  191. dict := ps[len(ps)-1].(map[string]any)
  192. def := ps[len(ps)-2]
  193. ks := make([]string, len(ps)-2)
  194. for i := 0; i < len(ks); i++ {
  195. ks[i] = ps[i].(string)
  196. }
  197. return digFromDict(dict, def, ks)
  198. }
  199. // digFromDict is a helper function for dig that recursively traverses a map using a sequence of keys.
  200. // If any key in the path doesn't exist, it returns the default value.
  201. //
  202. // Parameters:
  203. // - dict: The map to traverse
  204. // - d: The default value to return if the path doesn't exist
  205. // - ks: A slice of string keys forming the path to traverse
  206. //
  207. // Returns:
  208. // - any: The value found at the specified path, or the default value if not found
  209. // - error: Any error that occurred during traversal
  210. func digFromDict(dict map[string]any, d any, ks []string) (any, error) {
  211. k, ns := ks[0], ks[1:]
  212. step, has := dict[k]
  213. if !has {
  214. return d, nil
  215. }
  216. if len(ns) == 0 {
  217. return step, nil
  218. }
  219. return digFromDict(step.(map[string]any), d, ns)
  220. }