-
Notifications
You must be signed in to change notification settings - Fork 1
/
event_equality.go
175 lines (144 loc) · 5.09 KB
/
event_equality.go
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package log
import (
"errors"
"reflect"
"github.com/echocat/slf4g/fields"
)
// AreEventsEqual is comparing two given Events using DefaultEventEquality.
func AreEventsEqual(left, right Event) (bool, error) {
if v := DefaultEventEquality; v != nil {
return v.AreEventsEqual(left, right)
}
return false, nil
}
// DefaultEventEquality is the default instance of a Equality. The initial
// initialization of this global variable should be able to deal with the
// majority of the cases. There is also a shortcut function:
// AreEventsEqual(left,right)
var DefaultEventEquality EventEquality = &privateEventEqualityImpl{&EventEqualityImpl{
CompareLevel: true,
CompareValuesUsing: fields.NewValueEqualityFacade(func() fields.ValueEquality {
return fields.DefaultValueEquality
}),
}}
// EventEquality is comparing two Fields with each other and check if both are
// equal.
type EventEquality interface {
// AreEventsEqual compares the two given Events for their equality.
AreEventsEqual(left, right Event) (bool, error)
// WithIgnoringKeys creates a new instance of this EventEquality which will
// ignore the given keys while the equality check run.
WithIgnoringKeys(keys ...string) EventEquality
}
// EventEqualityFunc is wrapping a given func into EventEquality.
type EventEqualityFunc func(left, right Event) (bool, error)
// AreEventsEqual implements EventEquality.AreEventsEqual().
func (instance EventEqualityFunc) AreEventsEqual(left, right Event) (bool, error) {
return instance(left, right)
}
// WithIgnoringKeys implements EventEquality.WithIgnoringKeys().
func (instance EventEqualityFunc) WithIgnoringKeys(keys ...string) EventEquality {
return &ignoringKeysEventEquality{instance, keys}
}
type EventEqualityImpl struct {
// CompareLevel will configure to compare the Event.GetLevel() of both
// events to be the same.
CompareLevel bool
// CompareValuesUsing is used to compare the fields of the given events. If
// nil the values will not be compared.
CompareValuesUsing fields.ValueEquality
}
// AreEventsEqual implements EventEquality.AreEventsEqual().
func (instance *EventEqualityImpl) AreEventsEqual(left, right Event) (bool, error) {
if instance == nil {
return false, nil
}
if left == nil && right == nil {
return true, nil
}
if left == nil || right == nil {
return false, nil
}
if instance.CompareLevel && left.GetLevel() != right.GetLevel() {
return false, nil
}
if ve := instance.CompareValuesUsing; ve != nil {
if left.Len() != right.Len() {
return false, nil
}
if err := left.ForEach(func(key string, lValue interface{}) error {
rValue, rExists := right.Get(key)
if !rExists {
return entriesNotEqualV
}
if equal, err := ve.AreValuesEqual(key, lValue, rValue); err != nil {
return err
} else if !equal {
return entriesNotEqualV
} else {
return nil
}
}); err == entriesNotEqualV {
return false, nil
} else if err != nil {
return false, err
}
}
return true, nil
}
// WithIgnoringKeys implements EventEquality.WithIgnoringKeys().
func (instance *EventEqualityImpl) WithIgnoringKeys(keys ...string) EventEquality {
return &ignoringKeysEventEquality{instance, keys}
}
// NewEventEqualityFacade creates a re-implementation of EventEquality which
// uses the given provider to retrieve the actual instance of EventEquality in
// the moment when it is used. This is useful especially in cases where you want
// to deal with concurrency while creation of objects that need to hold a
// reference to a EventEquality.
func NewEventEqualityFacade(provider func() EventEquality) EventEquality {
return eventEqualityFacade(provider)
}
type eventEqualityFacade func() EventEquality
func (instance eventEqualityFacade) AreEventsEqual(left, right Event) (bool, error) {
return instance.Unwrap().AreEventsEqual(left, right)
}
func (instance eventEqualityFacade) WithIgnoringKeys(keys ...string) EventEquality {
return &ignoringKeysEventEquality{instance, keys}
}
func (instance eventEqualityFacade) Unwrap() EventEquality {
return instance()
}
type privateEventEqualityImpl struct {
inner *EventEqualityImpl
}
func (instance *privateEventEqualityImpl) AreEventsEqual(left, right Event) (bool, error) {
return instance.inner.AreEventsEqual(left, right)
}
func (instance *privateEventEqualityImpl) WithIgnoringKeys(keys ...string) EventEquality {
return &ignoringKeysEventEquality{instance, keys}
}
type ignoringKeysEventEquality struct {
parent EventEquality
keysToIgnore []string
}
func (instance *ignoringKeysEventEquality) AreEventsEqual(left, right Event) (bool, error) {
if left == nil && right == nil {
return true, nil
}
if left == nil || right == nil {
return false, nil
}
return instance.parent.AreEventsEqual(
left.Without(instance.keysToIgnore...),
right.Without(instance.keysToIgnore...),
)
}
func (instance *ignoringKeysEventEquality) WithIgnoringKeys(keys ...string) EventEquality {
return &ignoringKeysEventEquality{
parent: instance.parent,
keysToIgnore: append(instance.keysToIgnore, keys...),
}
}
var (
entriesNotEqualV = errors.New(reflect.TypeOf((*EventEquality)(nil)).PkgPath() + "/both entries are not equal")
)