jsondiff

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2021 License: MIT Imports: 8 Imported by: 0

README

JSONDIFF

FORK OF: [jsondiff][1] [1]: https://github.com/wI2L/jsondiff

CHANGES FROM jsondiff:

  • GREATER FOCUS ON GENERIC USE
  • FOREACH PATCH HELPERS
    • MUTABLE & IMMUTABLE
  • OPERATION PATH -> FIELD
  • MUTABLE FIELD SEPARATORS
    • nested fields follow mutable separator paradigm
  • generic differ append changes
    • differ append will truncate prepended separator

Documentation

Index

Examples

Constants

View Source
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.

Variables

This section is empty.

Functions

func UpdateSeparator

func UpdateSeparator(newSeparator string)

Types

type Operation

type Operation struct {
	Type     string      `json:"op"`
	From     pointer     `json:"from,omitempty"`
	Field    pointer     `json:"field"`
	OldValue interface{} `json:"-"`
	Value    interface{} `json:"value,omitempty"`
}

Operation represents a RFC6902 JSON Patch operation.

func (Operation) MarshalJSON

func (o Operation) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (Operation) String

func (o Operation) String() string

String implements the fmt.Stringer interface.

type Option

type Option func(*differ)

An Option overrides the default diff behavior of the CompareOpts and CompareJSONOpts function.

func Factorize

func Factorize() Option

Factorize enables factorization of operations.

Example
package main

import (
	"fmt"
	"log"

	"github.com/revzim/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/revzim/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"}

func Rationalize

func Rationalize() Option

Rationalize enables rationalization of operations.

type Patch

type Patch []Operation

Patch represents a series of JSON Patch operations.

func Compare

func Compare(source, target interface{}) (Patch, error)

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/revzim/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 main() {
	createPod := func() 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,
						},
					},
				}},
			},
		}
	}
	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

func CompareJSON(source, target []byte) (Patch, error)

CompareJSON compares the given JSON documents and returns the differences relative to the former as a list of JSON Patch operations.

Example
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"

	"github.com/revzim/jsondiff"
)

func main() {
	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 := json.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

func CompareJSONOpts(source, target []byte, opts ...Option) (Patch, error)

CompareJSONOpts is similar to CompareJSON, but also accepts a list of options to configure the diff behavior.

func CompareOpts

func CompareOpts(source, target interface{}, opts ...Option) (Patch, error)

CompareOpts is similar to Compare, but also accepts a list of options to configure the diff behavior.

func (Patch) ForEach

func (p Patch) ForEach(cb func(op Operation))

ForEach -- Loop - immutable

func (Patch) MutableForEach

func (p Patch) MutableForEach(cb func(op *Operation))

MutableForEach -- Loop - manipulate by *

func (Patch) String

func (p Patch) String() string

String implements the fmt.Stringer interface.

Jump to

Keyboard shortcuts

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