Documentation ¶
Overview ¶
Package data provides utilities to query, merge and patch data of map[string]any.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CamelCase ¶
CamelCase converts field name from snake case to camel case.
For example, "field_name" will be converted to "fieldName".
func Capitalize ¶
Capitalize converts field name to capitalized name.
For example, "fieldName" will be converted to "FieldName".
func MergeTo ¶
MergeTo merges multiple data from left to right to the target, and if there are same keys, they will be merged deeply. If target is nil, it will be ignored and no data will be merged.
More details about merging strategy, please refer to `Merge`'s document.
func SnakeCase ¶
SnakeCase converts field name from camel case to snake case.
For example, "FieldName" will be converted to "field_name".
func Uncapitalize ¶
Uncapitalize converts field name to uncapitalized name.
For example, "FieldName" will be converted to "fieldName".
Types ¶
type Data ¶
type Data struct {
// contains filtered or unexported fields
}
Data is a general data storage structure that can be used to express data in various formats such as JSON, TOML, YAML, etc. It can also be used to serialize/deserialize Go struct.
Data is not editable directly. It can only be modified by MergeTo, Patch#ApplyTo, etc.
func Make ¶
Make creates a new Data from the m. It filters out illegal data and converts struct inside the m to Data format.
Make is suitable to convert map[string]any data generated by JSON/YAML deserialization tools. For general purpose, you should use Encoder instead.
func Merge ¶
Merge merges multiple data from left to right to d, and if there are same keys, they will be merged deeply.
Merging strategy:
- For Data type value, merge same key deeply.
- If same key exists and value types are the same, both are Data or slice, merge value deeply.
- If same key exists and value types are different, later value overwrites previous value.
- For slice type value, if two slices are the same type, later slice values will be appended.
func (Data) Get ¶
Get returns value through the fields. It returns nil if the value is not found.
The fields is an array of map indices. For example, []string{"a", "b", "c"} represents d["a"]["b"]["c"]. If you want to access array elements, you can write the array index directly, such as []string{"a", "0", "c"} represents d["a"][0]["c"].
func (Data) JSON ¶
JSON returns a JSON string representing d. If the pretty is true, it will return a pretty-print JSON.
func (Data) MarshalJSON ¶
MarshalJSON marshals d into JSON.
func (Data) Query ¶
Query parses query and returns the value matching the query. If the value is not found, nil is returned.
The syntax of query is a list of map keys separated by ".". For example, "a.b.c" represents d["a"]["b"]["c"]. If you want to access array elements, you can write the array index directly, such as "a.0.c" represents d["a"][0]["c"].
If map key contains ".", you can use "\" to escape it.
func (*Data) UnmarshalJSON ¶
UnmarshalJSON parses JSON string and sets d's value.
We don't use `json.Unmarshal` to deserialize directly because `Data` requires all data types to be unified internally, but `json.Unmarshal` cannot meet this requirement.
type Decoder ¶
type Decoder struct { TagName string // The field tag used in decoder. The default value is "data". NameConverter NameConverter // The function used to convert field name to another name. The default value is nil. }
Decoder decodes a Data and updates the value of target struct in depth.
func (*Decoder) DecodeField ¶
DecodeField decodes the part of d matching the fields and updates v in depth. See `Data#Get` for the rule using the fields.
type Encoder ¶
type Encoder struct { TagName string // The field tag used in encoder. The default value is "data". OmitEmpty bool // If true, empty value will be omitted. The default value is false. NameConverter NameConverter // The function used to convert field name to another name. The default value is nil. }
Encoder encodes any data to Data
type FieldTag ¶
type FieldTag struct { Alias string // The alias set in tag. Skipped bool // Skipped if the alias is "-". OmitEmpty bool // Ignore empty value. Squash bool // Squash this field. }
FieldTag is a parsed field tag. The format is:
data:"alias,opt1,opt2,..."
Current supported options are:
- omitempty: ignore empty value.
- squash: squash this field.
When alias is "-", current field will be skipped.
func ParseFieldTag ¶
ParseFieldTag parses alias and options from field tag. See doc in FieldTag for more details.
type NameConverter ¶
NameConverter is a function that converts field name to another name.
type Patch ¶
type Patch struct {
// contains filtered or unexported fields
}
Patch represents a series of modifications to Data.
Example ¶
patch := NewPatch() // Delete d["v2"]、d["v3"][1]、d["v4"]["v4-4"]。 patch.Add([]string{"v2", "v3.1", "v4.v4-1"}, nil) // Add data. patch.Add(nil, map[string]Data{ // Add data at root. "": Make(RawData{ "v1": []int{2, 3}, "v2": 456, }), // Add data in d["v4"]. "v4": Make(RawData{ "v4-1": "new", }), }) // Delete and add data at the same time. patch.Add([]string{"v4.v4-2"}, map[string]Data{ "v4": Make(RawData{ "v4-2": RawData{ "new": true, }, }), }) d := Make(RawData{ "v1": []int{1}, "v2": 123, "v3": []string{"first", "second", "third"}, "v4": RawData{ "v4-1": "old", "v4-2": RawData{ "old": true, }, }, }) patch.ApplyTo(&d) fmt.Println(d)
Output: {"v1":[1,2,3],"v2":456,"v3":["first","third"],"v4":{"v4-1":"new","v4-2":{"new":true}}}
func (*Patch) Add ¶
Add adds a new patch action. Every patch action is composed of deletes and updates. When applying, deletes will be deleted first, then updates will be merged into Data. The key of updates is a query of Data. When applying, updates will be merged into Data
Note that `Patch#Apply`/`Patch#ApplyTo` uses `Merge`/`MergeTo` to update Data. The merge series functions will traverse map/slice deeply, which means that the new value cannot simply overwrite the old value. If you want the new value to overwrite the old value instead of merging, use deletes to delete the old value first and then merge.
type PatchAction ¶
type PatchAction struct { Deletes []string `data:"deletes"` Updates map[string]Data `data:"updates"` }
PatchAction presents a patch action.
func (*PatchAction) ApplyTo ¶
func (action *PatchAction) ApplyTo(target *Data) error
ApplyTo applies an action to target.
type RawData ¶
RawData represents raw data in Data.
func (*RawData) Delete ¶
Delete deletes the key matching any one of the queries. If one of the queries is an empty string, d is cleared completedly.
func (RawData) Get ¶
Get returns value through the fields. It returns nil if the value is not found.
The fields is an array of map indices. For example, []string{"a", "b", "c"} represents d["a"]["b"]["c"]. If you want to access array elements, you can write the array index directly, such as []string{"a", "0", "c"} represents d["a"][0]["c"].
func (RawData) Query ¶
Query parses query and returns the value matching the query. If the value is not found, nil is returned.
The syntax of query is a list of map keys separated by ".". For example, "a.b.c" represents d["a"]["b"]["c"]. If you want to access array elements, you can write the array index directly, such as "a.0.c" represents d["a"][0]["c"].
If map key contains ".", you can use "\" to escape it.