dynamodb.XConditions.Build   F
last analyzed

Complexity

Conditions 27

Size

Total Lines 98
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 59
nop 0
dl 0
loc 98
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like dynamodb.XConditions.Build often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package dynamodb
2
3
import (
4
	"errors"
5
	"fmt"
6
7
	"github.com/aws/aws-sdk-go-v2/service/dynamodb/expression"
8
)
9
10
// XConditions is to build Expression Condition for Query/Scan/Update operation.
11
type XConditions struct {
12
	KeyConditions []XCondition
13
	Conditions    []XCondition
14
	Filters       []XCondition
15
	Updates       []XUpdateCondition
16
	Projections   []string
17
}
18
19
func (x XConditions) hasValue() bool {
20
	switch {
21
	case len(x.KeyConditions) != 0,
22
		len(x.Conditions) != 0,
23
		len(x.Filters) != 0,
24
		len(x.Updates) != 0,
25
		len(x.Projections) != 0:
26
		return true
27
	}
28
	return false
29
}
30
31
func (x XConditions) Build() (expression.Expression, error) {
0 ignored issues
show
introduced by
exported method XConditions.Build should have comment or be unexported
Loading history...
32
	b := expression.NewBuilder()
33
34
	if len(x.KeyConditions) != 0 {
35
		kc, err := x.KeyConditions[0].KeyCondition()
36
		if err != nil {
37
			return expression.Expression{}, err
38
		}
39
		// for multiple key conditions
40
		if len(x.KeyConditions) > 1 {
41
			for _, v := range x.KeyConditions[1:] {
42
				kc2, err := v.KeyCondition()
43
				if err != nil {
44
					return expression.Expression{}, err
45
				}
46
				kc = kc.And(kc2)
47
			}
48
		}
49
		b = b.WithKeyCondition(kc)
50
	}
51
52
	if len(x.Conditions) != 0 {
53
		cond, err := x.Conditions[0].Condition()
54
		if err != nil {
55
			return expression.Expression{}, err
56
		}
57
58
		// for multiple conditions
59
		if len(x.Conditions) > 1 {
60
			for _, v := range x.Conditions[1:] {
61
				cond2, err := v.Condition()
62
				if err != nil {
63
					return expression.Expression{}, err
64
				}
65
				if v.IsNOT {
66
					cond2 = cond2.Not()
67
				}
68
69
				switch {
70
				case v.IsOR:
71
					cond = cond.Or(cond2)
72
				default:
73
					cond = cond.And(cond2)
74
				}
75
			}
76
		}
77
		b = b.WithCondition(cond)
78
	}
79
80
	if len(x.Filters) != 0 {
81
		filt, err := x.Filters[0].Condition()
82
		if err != nil {
83
			return expression.Expression{}, err
84
		}
85
86
		// for multiple conditions
87
		if len(x.Filters) > 1 {
88
			for _, v := range x.Filters[1:] {
89
				filt2, err := v.Condition()
90
				if err != nil {
91
					return expression.Expression{}, err
92
				}
93
				if v.IsNOT {
94
					filt2 = filt2.Not()
95
				}
96
97
				switch {
98
				case v.IsOR:
99
					filt = filt.Or(filt2)
100
				default:
101
					filt = filt.And(filt2)
102
				}
103
			}
104
		}
105
		b = b.WithFilter(filt)
106
	}
107
108
	if len(x.Updates) != 0 {
109
		cond := x.Updates[0].NewCondition()
110
111
		// for multiple conditions
112
		if len(x.Updates) > 1 {
113
			for _, v := range x.Updates[1:] {
114
				cond = v.updateCondition(cond)
115
			}
116
		}
117
		b = b.WithUpdate(cond)
118
	}
119
120
	if len(x.Projections) != 0 {
121
		list := make([]expression.NameBuilder, len(x.Projections))
122
		for i, v := range x.Projections {
123
			list[i] = expression.Name(v)
124
		}
125
		b = b.WithProjection(expression.ProjectionBuilder{}.AddNames(list...))
126
	}
127
128
	return b.Build()
129
}
130
131
// XCondition contains single condition parameters.
132
type XCondition struct {
133
	Name     string
134
	Value    interface{}
135
	Operator ComparisonOperator
136
137
	// optional
138
	IsOR  bool
139
	IsNOT bool
140
	// - 'BETWEEN': higher value.
141
	// - 'IN': all of values afre used besides XCondition.Value.
142
	OtherValues []string
143
}
144
145
func (x XCondition) KeyCondition() (expression.KeyConditionBuilder, error) {
0 ignored issues
show
introduced by
exported method XCondition.KeyCondition should have comment or be unexported
Loading history...
146
	e := expression.Key(x.Name)
147
	switch x.Operator {
148
	case ComparisonOperatorEq:
149
		return e.Equal(expression.Value(x.Value)), nil
150
	case ComparisonOperatorLe:
151
		return e.LessThanEqual(expression.Value(x.Value)), nil
152
	case ComparisonOperatorLt:
153
		return e.LessThan(expression.Value(x.Value)), nil
154
	case ComparisonOperatorGe:
155
		return e.GreaterThanEqual(expression.Value(x.Value)), nil
156
	case ComparisonOperatorGt:
157
		return e.GreaterThan(expression.Value(x.Value)), nil
158
	case ComparisonOperatorBeginsWith:
159
		return e.BeginsWith(fmt.Sprint(x.Value)), nil
160
	case ComparisonOperatorBetween:
161
		if len(x.OtherValues) == 0 {
162
			return expression.KeyConditionBuilder{}, errors.New("Condition 'BETWEEN' must set 'OtherValues[0]'")
163
		}
164
		return e.Between(expression.Value(x.Value), expression.Value(x.OtherValues[0])), nil
165
	default:
166
		return e.Equal(expression.Value(x.Value)), nil
167
	}
168
}
169
170
func (x XCondition) Condition() (expression.ConditionBuilder, error) {
0 ignored issues
show
introduced by
exported method XCondition.Condition should have comment or be unexported
Loading history...
171
	e := expression.Name(x.Name)
172
	switch x.Operator {
173
	case ComparisonOperatorEq:
174
		return e.Equal(expression.Value(x.Value)), nil
175
	case ComparisonOperatorLe:
176
		return e.LessThanEqual(expression.Value(x.Value)), nil
177
	case ComparisonOperatorLt:
178
		return e.LessThan(expression.Value(x.Value)), nil
179
	case ComparisonOperatorGe:
180
		return e.GreaterThanEqual(expression.Value(x.Value)), nil
181
	case ComparisonOperatorGt:
182
		return e.GreaterThan(expression.Value(x.Value)), nil
183
	case ComparisonOperatorBeginsWith:
184
		return e.BeginsWith(fmt.Sprint(x.Value)), nil
185
	case ComparisonOperatorBetween:
186
		if len(x.OtherValues) == 0 {
187
			return expression.ConditionBuilder{}, errors.New("Condition 'BETWEEN' must set 'OtherValues[0]'")
188
		}
189
		return e.Between(expression.Value(x.Value), expression.Value(x.OtherValues[0])), nil
190
	case ComparisonOperatorIn:
191
		list := make([]expression.OperandBuilder, len(x.OtherValues))
192
		for i, v := range x.OtherValues {
193
			list[i] = expression.Value(v)
194
		}
195
		return e.In(expression.Value(x.Value), list...), nil
196
	case ComparisonOperatorNe:
197
		return e.NotEqual(expression.Value(x.Value)), nil
198
	case ComparisonOperatorContains:
199
		return e.Contains(fmt.Sprint(x.Value)), nil
200
	case ComparisonOperatorAttrExists:
201
		return e.AttributeExists(), nil
202
	case ComparisonOperatorAttrNotExists:
203
		return e.AttributeNotExists(), nil
204
	case ComparisonOperatorAttrType:
205
		return e.AttributeType(expression.DynamoDBAttributeType(fmt.Sprint(x.Value))), nil
206
	default:
207
		return e.Equal(expression.Value(x.Value)), nil
208
	}
209
}
210
211
type XUpdateCondition struct {
0 ignored issues
show
introduced by
exported type XUpdateCondition should have comment or be unexported
Loading history...
212
	Name      string
213
	Value     interface{}
214
	Operation OperationMode
215
216
	SetType       SetType
217
	SetTypeKey    string
218
	SetTypeValue2 interface{}
219
}
220
221
func (x XUpdateCondition) NewCondition() expression.UpdateBuilder {
0 ignored issues
show
introduced by
exported method XUpdateCondition.NewCondition should have comment or be unexported
Loading history...
222
	return x.updateCondition(expression.UpdateBuilder{})
223
}
224
225
func (x XUpdateCondition) updateCondition(b expression.UpdateBuilder) expression.UpdateBuilder {
226
	switch x.Operation {
227
	case OperationModeSET:
228
		return x.updateConditionSet(b)
229
	case OperationModeREMOVE:
230
		return b.Remove(expression.Name(x.Name))
231
	case OperationModeADD:
232
		return b.Add(expression.Name(x.Name), expression.Value(x.Value))
233
	default:
234
		return x.updateConditionSet(b)
235
	}
236
}
237
238
func (x XUpdateCondition) updateConditionSet(b expression.UpdateBuilder) expression.UpdateBuilder {
239
	name := expression.Name(x.Name)
240
	value := expression.Value(x.Value)
241
	switch x.SetType {
242
	case SetTypePlus:
243
		return b.Set(name, expression.Plus(value, expression.Value(x.SetTypeValue2)))
244
	case SetTypeMinus:
245
		return b.Set(name, expression.Minus(value, expression.Value(x.SetTypeValue2)))
246
	case SetTypeListAppend:
247
		return b.Set(name, expression.ListAppend(value, expression.Value(x.SetTypeValue2)))
248
	case SetTypeIfNotExists:
249
		return b.Set(name, expression.IfNotExists(expression.Name(x.SetTypeKey), value))
250
	default:
251
		return b.Set(name, value)
252
	}
253
}
254
255
type OperationMode string
0 ignored issues
show
introduced by
exported type OperationMode should have comment or be unexported
Loading history...
256
257
const (
258
	OperationModeSET    OperationMode = "SET"
0 ignored issues
show
introduced by
exported const OperationModeSET should have comment (or a comment on this block) or be unexported
Loading history...
259
	OperationModeREMOVE OperationMode = "REMOVE"
260
	OperationModeADD    OperationMode = "ADD"
261
	OperationModeDELETE OperationMode = "DELETE"
262
)
263
264
type SetType string
0 ignored issues
show
introduced by
exported type SetType should have comment or be unexported
Loading history...
265
266
const (
267
	SetTypePlus        SetType = "PLUS"
0 ignored issues
show
introduced by
exported const SetTypePlus should have comment (or a comment on this block) or be unexported
Loading history...
268
	SetTypeMinus       SetType = "MINUS"
269
	SetTypeListAppend  SetType = "LIST_APPEND"
270
	SetTypeIfNotExists SetType = "IF_NOT_EXISTS"
271
)
272