Documentation
¶
Index ¶
- Constants
- Variables
- func AllowTypeMismatch(enabled bool) func(d *Differ) error
- func AreType(a, b reflect.Value, types ...reflect.Type) bool
- func Changed(a, b interface{}) bool
- func CustomValueDiffers(vd ...ValueDiffer) func(d *Differ) error
- func DisableStructValues() func(d *Differ) error
- func Filter(f FilterFunc) func(d *Differ) error
- func SliceOrdering(enabled bool) func(d *Differ) error
- func TagName(tag string) func(d *Differ) error
- type Change
- type ChangeValue
- func (c *ChangeValue) AddError(err error) *ChangeValue
- func (c ChangeValue) CanSet() bool
- func (c *ChangeValue) ClearFlags()
- func (c *ChangeValue) HasFlag(flag PatchFlags) bool
- func (c ChangeValue) Index(i int) reflect.Value
- func (c ChangeValue) Interface() interface{}
- func (c ChangeValue) IsNil() bool
- func (c *ChangeValue) IsValid() bool
- func (c ChangeValue) KeyType() reflect.Type
- func (c ChangeValue) Kind() reflect.Kind
- func (c ChangeValue) Len() int
- func (c *ChangeValue) Set(value reflect.Value)
- func (c *ChangeValue) SetFlag(flag PatchFlags)
- func (c *ChangeValue) SetMapValue(key reflect.Value, value reflect.Value)
- func (c ChangeValue) Type() reflect.Type
- type Changelog
- type Comparative
- type ComparativeList
- type DiffError
- type Differ
- type FilterFunc
- type PatchFlags
- type PatchLog
- type PatchLogEntry
- type ValueDiffer
Examples ¶
Constants ¶
const ( // CREATE represents when an element has been added CREATE = "create" // UPDATE represents when an element has been updated UPDATE = "update" // DELETE represents when an element has been removed DELETE = "delete" )
Variables ¶
var ( // ErrTypeMismatch Compared types do not match ErrTypeMismatch = NewError("types do not match") // ErrInvalidChangeType The specified change values are not unsupported ErrInvalidChangeType = NewError("change type must be one of 'create' or 'delete'") )
Functions ¶
func AllowTypeMismatch ¶
AllowTypeMismatch changed behaviour to report value as "updated" when its type has changed instead of error
func CustomValueDiffers ¶
func CustomValueDiffers(vd ...ValueDiffer) func(d *Differ) error
CustomValueDiffers allows you to register custom differs for specific types
func DisableStructValues ¶
DisableStructValues disables populating a separate change for each item in a struct, where the struct is being compared to a nil value
func Filter ¶
func Filter(f FilterFunc) func(d *Differ) error
Filter allows you to determine which fields the differ descends into
Example ¶
type Tag struct {
Name string `diff:"name,identifier"`
Value string `diff:"value"`
}
type Fruit struct {
ID int `diff:"id"`
Name string `diff:"name"`
Healthy bool `diff:"healthy"`
Nutrients []string `diff:"nutrients"`
Tags []Tag `diff:"tags"`
}
a := Fruit{
ID: 1,
Name: "Green Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
},
}
b := Fruit{
ID: 2,
Name: "Red Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
"vitamin e",
},
}
d, err := NewDiffer(Filter(func(path []string, parent reflect.Type, field reflect.StructField) bool {
return field.Name != "Name"
}))
if err != nil {
panic(err)
}
changelog, err := d.Diff(a, b)
if err != nil {
panic(err)
}
fmt.Printf("%#v", changelog)
Output: diff.Changelog{diff.Change{Type:"update", Path:[]string{"id"}, From:1, To:2}, diff.Change{Type:"create", Path:[]string{"nutrients", "2"}, From:interface {}(nil), To:"vitamin e"}}
func SliceOrdering ¶
SliceOrdering determines whether the ordering of items in a slice results in a change
Types ¶
type Change ¶
type Change struct {
Type string `json:"type"`
Path []string `json:"path"`
From interface{} `json:"from"`
To interface{} `json:"to"`
}
Change stores information about a changed item
type ChangeValue ¶
type ChangeValue struct {
// contains filtered or unexported fields
}
ChangeValue is a specialized struct for monitoring patching
func NewChangeValue ¶
func NewChangeValue(c Change, target interface{}) *ChangeValue
NewChangeValue idiomatic constructor
func (*ChangeValue) AddError ¶
func (c *ChangeValue) AddError(err error) *ChangeValue
AddError appends errors to this change value
func (*ChangeValue) ClearFlags ¶
func (c *ChangeValue) ClearFlags()
ClearFlag Clears a flag on the node and saves the change
func (*ChangeValue) HasFlag ¶
func (c *ChangeValue) HasFlag(flag PatchFlags) bool
HasFlag indicates if a flag is set on the node. returns false if node is bad
func (ChangeValue) Interface ¶
func (c ChangeValue) Interface() interface{}
Interface gets the interface for the value
func (ChangeValue) KeyType ¶
func (c ChangeValue) KeyType() reflect.Type
KeyType returns the key type of a map if it is one
func (*ChangeValue) SetFlag ¶
func (c *ChangeValue) SetFlag(flag PatchFlags)
Sets a flag on the node and saves the change
func (*ChangeValue) SetMapValue ¶
func (c *ChangeValue) SetMapValue(key reflect.Value, value reflect.Value)
SetMapValue is used to set a map value
type Changelog ¶
type Changelog []Change
Changelog stores a list of changed items
func Diff ¶
Diff returns a changelog of all mutated values from both
Example ¶
type Tag struct {
Name string `diff:"name,identifier"`
Value string `diff:"value"`
}
type Fruit struct {
ID int `diff:"id"`
Name string `diff:"name"`
Healthy bool `diff:"healthy"`
Nutrients []string `diff:"nutrients"`
Tags []Tag `diff:"tags"`
}
a := Fruit{
ID: 1,
Name: "Green Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
},
Tags: []Tag{
{
Name: "kind",
Value: "fruit",
},
},
}
b := Fruit{
ID: 2,
Name: "Red Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
"vitamin e",
},
Tags: []Tag{
{
Name: "popularity",
Value: "high",
},
{
Name: "kind",
Value: "fruit",
},
},
}
changelog, err := Diff(a, b)
if err != nil {
panic(err)
}
fmt.Printf("%#v", changelog)
// Produces: diff.Changelog{diff.Change{Type:"update", Path:[]string{"id"}, From:1, To:2}, diff.Change{Type:"update", Path:[]string{"name"}, From:"Green Apple", To:"Red Apple"}, diff.Change{Type:"create", Path:[]string{"nutrients", "2"}, From:interface {}(nil), To:"vitamin e"}, diff.Change{Type:"create", Path:[]string{"tags", "popularity"}, From:interface {}(nil), To:main.Tag{Name:"popularity", Value:"high"}}}
func StructValues ¶
StructValues gets all values from a struct values are stored as "created" or "deleted" entries in the changelog, depending on the change type specified
type ComparativeList ¶
type ComparativeList struct {
// contains filtered or unexported fields
}
ComparativeList : stores indexed comparative
func NewComparativeList ¶
func NewComparativeList() *ComparativeList
NewComparativeList : returns a new comparative list
type DiffError ¶
type DiffError struct {
// contains filtered or unexported fields
}
our own version of an error, which can wrap others
type Differ ¶
type Differ struct {
TagName string
SliceOrdering bool
DisableStructValues bool
AllowTypeMismatch bool
Filter FilterFunc
// contains filtered or unexported fields
}
Differ a configurable diff instance
type FilterFunc ¶
FilterFunc is a function that determines whether to descend into a struct field. parent is the struct being examined and field is a field on that struct. path is the path to the field from the root of the diff.
type PatchFlags ¶
type PatchFlags uint32
Not strictly necessary but migh be nice in some cases
const ( OptionCreate PatchFlags = 1 << iota OptionOmitUnequal FlagInvalidTarget FlagApplied FlagFailed FlagCreated FlagIgnored FlagDeleted FlagUpdated )
type PatchLog ¶
type PatchLog []PatchLogEntry
func Merge ¶
Merge is a convenience function that diffs, the original and changed items and merges said changes with target all in one call.
Example ¶
ExampleMerge demonstrates how to use the Merge function
type Fruit struct {
ID int `diff:"ID" json:"Identifier"`
Name string `diff:"name"`
Healthy bool `diff:"healthy"`
Nutrients []string `diff:"nutrients,create,omitunequal"`
Labels map[string]int `diff:"labs,create"`
}
a := Fruit{
ID: 1,
Name: "Green Apple",
Healthy: true,
Nutrients: []string{
"vitamin a",
"vitamin b",
"vitamin c",
"vitamin d",
},
Labels: make(map[string]int),
}
a.Labels["likes"] = 10
a.Labels["colors"] = 2
b := Fruit{
ID: 2,
Name: "Red Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
"vitamin e",
},
Labels: make(map[string]int),
}
b.Labels["forests"] = 1223
b.Labels["colors"] = 1222
c := Fruit{
Labels: make(map[string]int),
Nutrients: []string{
"vitamin a",
"vitamin c",
"vitamin d",
},
}
c.Labels["likes"] = 21
c.Labels["colors"] = 42
//the only error that can happen here comes from the diff step
patchLog, _ := Merge(a, b, &c)
//Note that unlike our patch version we've not included 'create' in the
//tag for nutrients. This will omit "vitamin e" from ending up in c
fmt.Printf("%#v", len(patchLog))
Output: 8
func Patch ¶
Patch... the missing feature.
Example ¶
ExamplePatch demonstrates how to use the Patch function
type Fruit struct {
ID int `diff:"ID" json:"Identifier"`
Name string `diff:"name"`
Healthy bool `diff:"healthy"`
Nutrients []string `diff:"nutrients,create,omitunequal"`
Labels map[string]int `diff:"labs,create"`
}
a := Fruit{
ID: 1,
Name: "Green Apple",
Healthy: true,
Nutrients: []string{
"vitamin a",
"vitamin b",
"vitamin c",
"vitamin d",
},
Labels: make(map[string]int),
}
a.Labels["likes"] = 10
a.Labels["colors"] = 2
b := Fruit{
ID: 2,
Name: "Red Apple",
Healthy: true,
Nutrients: []string{
"vitamin c",
"vitamin d",
"vitamin e",
},
Labels: make(map[string]int),
}
b.Labels["forests"] = 1223
b.Labels["colors"] = 1222
c := Fruit{
Labels: make(map[string]int),
Nutrients: []string{
"vitamin a",
"vitamin c",
"vitamin d",
},
}
c.Labels["likes"] = 21
changelog, err := Diff(a, b)
if err != nil {
panic(err)
}
patchLog := Patch(changelog, &c)
fmt.Printf("%#v", len(patchLog))
Output: 8
type PatchLogEntry ¶
type PatchLogEntry struct {
Path []string `json:"path"`
From interface{} `json:"from"`
To interface{} `json:"to"`
Flags PatchFlags `json:"flags"`
Errors error `json:"errors"`
}
PatchLogEntry defines how a DiffLog entry was applied
func NewPatchLogEntry ¶
func NewPatchLogEntry(change *ChangeValue) PatchLogEntry
NewPatchLogEntry converts our complicated reflection based struct to a simpler format for the consumer