data

package
v0.0.0-...-d36796e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 27, 2023 License: MIT Imports: 14 Imported by: 0

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

func CamelCase(name string) string

CamelCase converts field name from snake case to camel case.

For example, "field_name" will be converted to "fieldName".

func Capitalize

func Capitalize(name string) string

Capitalize converts field name to capitalized name.

For example, "fieldName" will be converted to "FieldName".

func MergeTo

func MergeTo(target *Data, data ...Data)

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

func SnakeCase(name string) string

SnakeCase converts field name from camel case to snake case.

For example, "FieldName" will be converted to "field_name".

func Uncapitalize

func Uncapitalize(name string) string

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

func Make(m map[string]any) Data

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

func Merge(data ...Data) (d Data)

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) Clone

func (d Data) Clone() Data

Clone creates a deep-copy of d.

func (Data) Get

func (d Data) Get(fields ...string) any

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

func (d Data) JSON(pretty bool) string

JSON returns a JSON string representing d. If the pretty is true, it will return a pretty-print JSON.

func (Data) Len

func (d Data) Len() int

Len returns the length of internal map data.

func (Data) MarshalJSON

func (d Data) MarshalJSON() ([]byte, error)

MarshalJSON marshals d into JSON.

func (Data) Query

func (d Data) Query(query string) any

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) String

func (d Data) String() string

String returns a JSON string representing d.

func (*Data) UnmarshalJSON

func (d *Data) UnmarshalJSON(src []byte) error

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) Decode

func (dec *Decoder) Decode(d Data, v any) error

Decode decodes d and updates v in depth.

func (*Decoder) DecodeField

func (dec *Decoder) DecodeField(d Data, fields []string, v any) error

DecodeField decodes the part of d matching the fields and updates v in depth. See `Data#Get` for the rule using the fields.

func (*Decoder) DecodeQuery

func (dec *Decoder) DecodeQuery(d Data, query string, v any) error

DecodeQuery decodes the part of d matching the query and updates v in depth. See `Data#Query` for the syntax of the query.

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

func (*Encoder) Encode

func (enc *Encoder) Encode(v any) Data

Encode encodes any data to Data.

Only the following types can be encoded successfully. If v is not one of them, Encode may return nil.

  • Go struct and struct pointer.
  • Any map[string]T, T can be any type.

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

func ParseFieldTag(tag string) *FieldTag

ParseFieldTag parses alias and options from field tag. See doc in FieldTag for more details.

type NameConverter

type NameConverter func(name string) string

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 NewPatch

func NewPatch() *Patch

NewPatch creates a new Patch.

func (*Patch) Actions

func (patch *Patch) Actions() []*PatchAction

Actions returns all actions.

func (*Patch) Add

func (patch *Patch) Add(deletes []string, updates map[string]Data)

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.

func (*Patch) Apply

func (patch *Patch) Apply(d Data) (applied Data, err error)

Apply copies d and applies all changes to the copy of d.

Apply returns error when:

  • If a query in updates cannot find the corresponding element.
  • If a query in updates finds a result that is not a RawData.

func (*Patch) ApplyTo

func (patch *Patch) ApplyTo(target *Data) error

ApplyTo applies all changes to target.

ApplyTo returns error in the same conditions as Apply.

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

type RawData map[string]any

RawData represents raw data in Data.

func (*RawData) Delete

func (d *RawData) Delete(queries ...string)

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

func (d RawData) Get(fields ...string) any

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

func (d RawData) Query(query string) any

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL