1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// Tideland Go Library - Generic JSON Processor - Difference
//
// Copyright (C) 2017 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.
package gjp
//--------------------
// IMPORTS
//--------------------
import "github.com/tideland/golib/errors"
//--------------------
// DIFFERENCE
//--------------------
// Diff manages the two parsed documents and their differences.
type Diff interface {
// FirstDocument returns the first document passed to Diff().
FirstDocument() Document
// SecondDocument returns the second document passed to Diff().
SecondDocument() Document
// Differences returns a list of paths where the documents
// have different content.
Differences() []string
// DifferenceAt returns the differences at the given path by
// returning the first and the second value.
DifferenceAt(path string) (Value, Value)
}
// diff implements Diff.
type diff struct {
first Document
second Document
paths []string
}
// Compare parses and compares the documents and returns their differences.
func Compare(first, second []byte, separator string) (Diff, error) {
fd, err := Parse(first, separator)
if err != nil {
return nil, err
}
sd, err := Parse(second, separator)
if err != nil {
return nil, err
}
d := &diff{
first: fd,
second: sd,
}
err = d.compare()
if err != nil {
return nil, err
}
return d, nil
}
// CompareDocuments compares the documents and returns their differences.
func CompareDocuments(first, second Document, separator string) (Diff, error) {
fd, ok := first.(*document)
if !ok {
return nil, errors.New(ErrInvalidDocument, errorMessages, "first")
}
fd.separator = separator
sd, ok := second.(*document)
if !ok {
return nil, errors.New(ErrInvalidDocument, errorMessages, "second")
}
sd.separator = separator
d := &diff{
first: fd,
second: sd,
}
err := d.compare()
if err != nil {
return nil, err
}
return d, nil
}
func (d *diff) FirstDocument() Document {
return d.first
}
func (d *diff) SecondDocument() Document {
return d.second
}
func (d *diff) Differences() []string {
return d.paths
}
func (d *diff) DifferenceAt(path string) (Value, Value) {
firstValue := d.first.ValueAt(path)
secondValue := d.second.ValueAt(path)
return firstValue, secondValue
}
func (d *diff) compare() error {
firstPaths := map[string]struct{}{}
firstProcessor := func(path string, value Value) error {
firstPaths[path] = struct{}{}
if !value.Equals(d.second.ValueAt(path)) {
d.paths = append(d.paths, path)
}
return nil
}
err := d.first.Process(firstProcessor)
if err != nil {
return err
}
secondProcessor := func(path string, value Value) error {
_, ok := firstPaths[path]
if ok {
// Been there, done that.
return nil
}
d.paths = append(d.paths, path)
return nil
}
return d.second.Process(secondProcessor)
}
// EOF
|