Documentation ¶
Index ¶
Examples ¶
Constants ¶
const ( OperationAdd = "add" OperationReplace = "replace" OperationRemove = "remove" OperationMove = "move" OperationCopy = "copy" OperationTest = "test" )
JSON Patch operation types. These are defined in RFC 6902 section 4. https://datatracker.ietf.org/doc/html/rfc6902#section-4
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Differ ¶
type Differ struct {
// contains filtered or unexported fields
}
A Differ is a JSON Patch generator. The zero value is an empty generator ready to use.
func (*Differ) Compare ¶
func (d *Differ) Compare(src, tgt interface{})
Compare computes the differences between src and tgt as a series of JSON Patch operations.
func (*Differ) Patch ¶
Patch returns the list of JSON patch operations generated by the Differ. The patch is valid for usage until the next comparison or reset.
type Operation ¶
type Operation struct { Type string `json:"op"` Name string `json:"name"` From pointer `json:"from,omitempty"` Path pointer `json:"path"` OldValue interface{} `json:"-"` Value interface{} `json:"value,omitempty"` }
Operation represents a single RFC6902 JSON Patch operation.
func (Operation) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface.
type Option ¶
type Option func(*Differ)
An Option changes the default behavior of a Differ.
func Equivalent ¶
func Equivalent() Option
Equivalent disables the generation of operations for arrays of equal length and content that are not ordered.
func Factorize ¶
func Factorize() Option
Factorize enables factorization of operations.
Example ¶
package main import ( "fmt" "log" "github.com/highercomve/jsondiff" ) func main() { source := `{"a":[1,2,3],"b":{"foo":"bar"}}` target := `{"a":[1,2,3],"c":[1,2,3],"d":{"foo":"bar"}}` patch, err := jsondiff.CompareJSONOpts( []byte(source), []byte(target), jsondiff.Factorize(), ) if err != nil { log.Fatal(err) } for _, op := range patch { fmt.Printf("%s\n", op) } }
Output: {"op":"copy","from":"/a","path":"/c"} {"op":"move","from":"/b","path":"/d"}
func Invertible ¶
func Invertible() Option
Invertible enables the generation of an invertible patch, by preceding each remove and replace operation by a test operation that verifies the value at the path that is being removed/replaced. Note that copy operations are not invertible, and as such, using this option disable the usage of copy operation in favor of add operations.
Example ¶
package main import ( "fmt" "log" "github.com/highercomve/jsondiff" ) func main() { source := `{"a":"1","b":"2"}` target := `{"a":"3","c":"4"}` patch, err := jsondiff.CompareJSONOpts( []byte(source), []byte(target), jsondiff.Invertible(), ) if err != nil { log.Fatal(err) } for _, op := range patch { fmt.Printf("%s\n", op) } }
Output: {"op":"test","path":"/a","value":"1"} {"op":"replace","path":"/a","value":"3"} {"op":"test","path":"/b","value":"2"} {"op":"remove","path":"/b"} {"op":"add","path":"/c","value":"4"}
type Patch ¶
type Patch []Operation
Patch represents a series of JSON Patch operations.
func Compare ¶
Compare compares the JSON representations of the given values and returns the differences relative to the former as a list of JSON Patch operations.
Example ¶
package main import ( "fmt" "log" "github.com/highercomve/jsondiff" ) type ( Pod struct { Spec PodSpec `json:"spec,omitempty"` } PodSpec struct { Containers []Container `json:"containers,omitempty"` Volumes []Volume `json:"volumes,omitempty"` } Container struct { Name string `json:"name"` Image string `json:"image,omitempty"` VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"` } Volume struct { Name string `json:"name"` VolumeSource `json:",inline"` } VolumeSource struct { EmptyDir *EmptyDirVolumeSource `json:"emptyDir,omitempty"` } VolumeMount struct { Name string `json:"name"` MountPath string `json:"mountPath"` } EmptyDirVolumeSource struct { Medium StorageMedium `json:"medium,omitempty"` } StorageMedium string ) const ( StorageMediumDefault StorageMedium = "" StorageMediumMemory StorageMedium = "Memory" ) func createPod() Pod { return Pod{ Spec: PodSpec{ Containers: []Container{{ Name: "webserver", Image: "nginx:latest", VolumeMounts: []VolumeMount{{ Name: "shared-data", MountPath: "/usr/share/nginx/html", }}, }}, Volumes: []Volume{{ Name: "shared-data", VolumeSource: VolumeSource{ EmptyDir: &EmptyDirVolumeSource{ Medium: StorageMediumMemory, }, }, }}, }, } } func main() { oldPod := createPod() newPod := createPod() newPod.Spec.Containers[0].Image = "nginx:1.19.5-alpine" newPod.Spec.Volumes[0].EmptyDir.Medium = StorageMediumDefault patch, err := jsondiff.Compare(oldPod, newPod) if err != nil { log.Fatal(err) } for _, op := range patch { fmt.Printf("%s\n", op) } }
Output: {"op":"replace","path":"/spec/containers/0/image","value":"nginx:1.19.5-alpine"} {"op":"remove","path":"/spec/volumes/0/emptyDir/medium"}
func CompareJSON ¶
CompareJSON compares the given JSON documents and returns the differences relative to the former as a list of JSON Patch operations.
Example ¶
type Phone struct { Type string `json:"type"` Number string `json:"number"` } type Person struct { Firstname string `json:"firstName"` Lastname string `json:"lastName"` Gender string `json:"gender"` Age int `json:"age"` Phones []Phone `json:"phoneNumbers"` } source, err := ioutil.ReadFile("testdata/examples/john.json") if err != nil { log.Fatal(err) } var john Person if err := unmarshal(source, &john); err != nil { log.Fatal(err) } john.Age = 30 john.Phones = append(john.Phones, Phone{ Type: "mobile", Number: "209-212-0015", }) target, err := json.Marshal(john) if err != nil { log.Fatal(err) } patch, err := jsondiff.CompareJSON(source, target) if err != nil { log.Fatal(err) } for _, op := range patch { fmt.Printf("%s\n", op) }
Output: {"op":"replace","path":"/age","value":30} {"op":"add","path":"/phoneNumbers/-","value":{"number":"209-212-0015","type":"mobile"}}
func CompareJSONOpts ¶
CompareJSONOpts is similar to CompareJSON, but also accepts a list of options to configure the behavior.
func CompareOpts ¶
CompareOpts is similar to Compare, but also accepts a list of options to configure the behavior.
Example ¶
package main import ( "fmt" "log" "github.com/highercomve/jsondiff" ) type ( Pod struct { Spec PodSpec `json:"spec,omitempty"` } PodSpec struct { Containers []Container `json:"containers,omitempty"` Volumes []Volume `json:"volumes,omitempty"` } Container struct { Name string `json:"name"` Image string `json:"image,omitempty"` VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"` } Volume struct { Name string `json:"name"` VolumeSource `json:",inline"` } VolumeSource struct { EmptyDir *EmptyDirVolumeSource `json:"emptyDir,omitempty"` } VolumeMount struct { Name string `json:"name"` MountPath string `json:"mountPath"` } EmptyDirVolumeSource struct { Medium StorageMedium `json:"medium,omitempty"` } StorageMedium string ) const StorageMediumMemory StorageMedium = "Memory" func createPod() Pod { return Pod{ Spec: PodSpec{ Containers: []Container{{ Name: "webserver", Image: "nginx:latest", VolumeMounts: []VolumeMount{{ Name: "shared-data", MountPath: "/usr/share/nginx/html", }}, }}, Volumes: []Volume{{ Name: "shared-data", VolumeSource: VolumeSource{ EmptyDir: &EmptyDirVolumeSource{ Medium: StorageMediumMemory, }, }, }}, }, } } func main() { oldPod := createPod() newPod := createPod() newPod.Spec.Volumes = append(newPod.Spec.Volumes, oldPod.Spec.Volumes[0]) patch, err := jsondiff.CompareOpts( oldPod, newPod, jsondiff.Factorize(), jsondiff.Rationalize(), ) if err != nil { log.Fatal(err) } for _, op := range patch { fmt.Printf("%s\n", op) } }
Output: {"op":"copy","from":"/spec/volumes/0","path":"/spec/volumes/-"}