File: diff.go

package info (click to toggle)
golang-github-tideland-golib 4.24.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,144 kB
  • sloc: makefile: 4
file content (131 lines) | stat: -rw-r--r-- 2,926 bytes parent folder | download | duplicates (2)
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