https://github.com/pricelessrabbit/flatr
Golang util to easily flatten a nested map into a 1-level deep one.
https://github.com/pricelessrabbit/flatr
flat go golang map
Last synced: 3 months ago
JSON representation
Golang util to easily flatten a nested map into a 1-level deep one.
- Host: GitHub
- URL: https://github.com/pricelessrabbit/flatr
- Owner: pricelessrabbit
- License: unlicense
- Created: 2023-03-07T16:59:06.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2025-01-26T22:34:40.000Z (about 1 year ago)
- Last Synced: 2026-01-12T14:44:59.731Z (4 months ago)
- Topics: flat, go, golang, map
- Language: Go
- Homepage:
- Size: 43 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

The Flat Rabbit, Barour Oskarsson
# FLATR
Golang util to easily flat a nested map into a 1-level deep one.
## Features
- Prefix selection
- Separator selection
- Transformers to preprocess each node for advanced use cases
## Get it
`go get github.com/pricelessrabbit/flatr`
## Use it
### Basic usage
```go
toFlat := map[string]any{
"foo": "bar",
"nest": map[string]any{
"bar": "baz",
},
"list": []any{
map[string]any{
"id": 1,
"data": "data1",
},
map[string]any{
"id": 2,
"data": "data2",
},
},
}
f := flatr.New()
flatten, err := f.Flat(toFlat)
/* result
map[
foo: bar
list.0.data: data1
list.0.id: 1
list.1.data: data2
list.1.id: 2
nest.bar: baz
]
*/
```
### Options
Add options to the constructor to use them: `flatr.New(Option1(),Option2()...)`
#### Prefix option
Adds a prefix to all the flatted keys
```go
f := New(flatr.WithPrefix("namespace"))
flatten, _ := f.Flat(toFlat)
/* result
map[
namespace.foo: bar
namespace.list.0.data: data1
namespace.list.0.id: 1
namespace.list.1.data: data2
namespace.list.1.id: 2
namespace.nest.bar: baz
]
*/
```
#### Separator option
Choose path separator (default `.`)
```go
f := New(flatr.WithSeparator("_"))
flatten, _ := f.Flat(toFlat)
/* result
map[
foo: bar
list_0_data: data1
list_0_id: 1
list_1_data: data2
list_1_id: 2
nest_bar: baz
]
*/
```
### Transformers
Transformers:
- Have access to the entry related to node being flatted
- Can read and update node key, value, and set a stop flag to block children processing
#### Default transformers
##### `flatr.Transformers.MaxDeep`
define a max deep for the flattening process.
after reaching the max deep, the children of the current will be left untouched.
```go
toFlat := map[string]any{
"foo": []any{
map[string]any{"id": "a", "data": 10},
map[string]any{"id": "b", "data": 20},
},
"bar": []any{
map[string]any{"id": 1, "data": 30},
map[string]any{"id": 2, "data": 40},
},
}
f := New(
AddTransformer(MaxDeep(2)),
)
flatted, _ := f.Flat(toFlat)
/*
map[
foo.0: {"id": "a", "data": 10}
foo.1: {"id": 1, "data": 30}
bar.0: {"id": 1, "data": 30}
bar.1: {"id": 2, "data": 40}
]
*/
```
##### `flatr.Transformers.UseFieldAsIndex`
if the current node is a slice, use the value of the given field (eg `id`) as index instead
of the array index.
```go
toFlat := map[string]any{
"foo": []any{
map[string]any{"id": "a", "data": 10},
map[string]any{"id": "b", "data": 20},
},
"bar": []any{
map[string]any{"id": 1, "data": 30},
map[string]any{"id": 2, "data": 40},
},
}
f := New(
AddScopedTransformer("foo", UseFieldAsIndex("id")),
AddScopedTransformer("bar", UseFieldAsIndex("id")),
)
flatten, _ := f.Flat(toFlat)
/*
map[
foo.a.id: a
foo.a.data: 10
foo.b.id: b
foo.b.data: 20
bar.1.id: 1
bar.1: data: 30
bar.2.id: 2
bar.2.data: 40
]
*/
```
#### Custom transfomers
It is possible to implement custom transformers. A trasformer is valid if:
- takes an Entry
- returns the transformed Entry and an optional error
The entry field that can be transformed are:
- K the key of the node
- V the value related to the key
- H deep of the node
- Stop stops processing of the children of the current node
##### Example
the transformer in the example adds the suffix "_transformed" to all the string values
that are found in the structure. other value types are left untouched.
```go
customTransformer := func (e Entry) (Entry, error) {
//check if the current entry value is a string
// and in that case add the suffix "transformed"
if s, ok := e.V.(string); ok {
e.V = s + "_transformed"
}
return e, nil
}
f := New(AddTransformer(customTransformer))
flatten, _ := f.Flat(toFlat)
/*
map[
foo: bar_transformed
list_0_data: data1_transformed
list_0_id: 1
list_1_data: data2_transformed
list_1_id: 2
nest_bar: baz_transformed
]
*/
```