Pick converts data into a []any, map[string]any, etc. (using json marshal->unmarshal) containing only the fields from the parsed rawFields expression. rawFields is a comma separated string of the fields to include. Nested fields should be listed with dot-notation. Fields value modifiers are also su
(data any, rawFields string)
| 20 | // data := map[string]any{"a": 1, "b": 2, "c": map[string]any{"c1": 11, "c2": 22}} |
| 21 | // Pick(data, "a,c.c1") // map[string]any{"a": 1, "c": map[string]any{"c1": 11}} |
| 22 | func Pick(data any, rawFields string) (any, error) { |
| 23 | parsedFields, err := parseFields(rawFields) |
| 24 | if err != nil { |
| 25 | return nil, err |
| 26 | } |
| 27 | |
| 28 | // marshalize the provided data to ensure that the related json.Marshaler |
| 29 | // implementations are invoked, and then convert it back to a plain |
| 30 | // json value that we can further operate on. |
| 31 | // |
| 32 | // @todo research other approaches to avoid the double serialization |
| 33 | // --- |
| 34 | encoded, err := json.Marshal(data) |
| 35 | if err != nil { |
| 36 | return nil, err |
| 37 | } |
| 38 | |
| 39 | var decoded any |
| 40 | if err := json.Unmarshal(encoded, &decoded); err != nil { |
| 41 | return nil, err |
| 42 | } |
| 43 | // --- |
| 44 | |
| 45 | // special cases to preserve the same fields format when used with single item or search results data. |
| 46 | var isSearchResult bool |
| 47 | switch data.(type) { |
| 48 | case search.Result, *search.Result: |
| 49 | isSearchResult = true |
| 50 | } |
| 51 | |
| 52 | if isSearchResult { |
| 53 | if decodedMap, ok := decoded.(map[string]any); ok { |
| 54 | pickParsedFields(decodedMap["items"], parsedFields) |
| 55 | } |
| 56 | } else { |
| 57 | pickParsedFields(decoded, parsedFields) |
| 58 | } |
| 59 | |
| 60 | return decoded, nil |
| 61 | } |
| 62 | |
| 63 | func parseFields(rawFields string) (map[string]Modifier, error) { |
| 64 | t := tokenizer.NewFromString(rawFields) |
searching dependent graphs…