Passed
Push — main ( 556c6a...319d7e )
by Rushan
02:21 queued 11s
created

it.IsBetweenTime   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
dl 0
loc 6
c 0
b 0
f 0
ccs 1
cts 1
cp 1
crap 1
rs 10
nop 2
1
package it
2
3
import (
4
	"strconv"
5
	"time"
6
7
	"github.com/muonsoft/validation"
8
	"github.com/muonsoft/validation/code"
9
	"github.com/muonsoft/validation/generic"
10
	"github.com/muonsoft/validation/message"
11
)
12
13
// NumberComparisonConstraint is used for various numeric comparisons between integer and float values.
14
// Values are compared as integers if the compared and specified values are integers.
15
// Otherwise, numbers are always compared as floating point numbers.
16
type NumberComparisonConstraint struct {
17
	isIgnored       bool
18
	code            string
19
	messageTemplate string
20
	comparedValue   string
21
	isValid         func(value generic.Number) bool
22
}
23
24
// IsEqualToInteger checks that the number (integer or float) is equal to the specified integer value.
25
// Values are compared as integers if the compared and specified values are integers.
26
// Otherwise, numbers are always compared as floating point numbers.
27
//
28
// Example
29
//  v := 1
30
//  err := validator.ValidateNumber(&v, it.IsEqualToInteger(2))
31
func IsEqualToInteger(value int64) NumberComparisonConstraint {
32 1
	v := generic.NewNumberFromInt(value)
33
34 1
	return NumberComparisonConstraint{
35
		code:            code.Equal,
36
		messageTemplate: message.Equal,
37
		comparedValue:   v.String(),
38
		isValid: func(n generic.Number) bool {
39 1
			return n.IsEqualTo(v)
40
		},
41
	}
42
}
43
44
// IsEqualToFloat checks that the number (integer or float) is equal to the specified float value.
45
// Values are compared as integers if the compared and specified values are integers.
46
// Otherwise, numbers are always compared as floating point numbers.
47
//
48
// Example
49
//  v := 1.1
50
//  err := validator.ValidateNumber(&v, it.IsEqualToFloat(1.2))
51
func IsEqualToFloat(value float64) NumberComparisonConstraint {
52 1
	v := generic.NewNumberFromFloat(value)
53
54 1
	return NumberComparisonConstraint{
55
		code:            code.Equal,
56
		messageTemplate: message.Equal,
57
		comparedValue:   v.String(),
58
		isValid: func(n generic.Number) bool {
59 1
			return n.IsEqualTo(v)
60
		},
61
	}
62
}
63
64
// IsNotEqualToInteger checks that the number (integer or float) is not equal to the specified integer value.
65
// Values are compared as integers if the compared and specified values are integers.
66
// Otherwise, numbers are always compared as floating point numbers.
67
//
68
// Example
69
//  v := 1
70
//  err := validator.ValidateNumber(&v, it.IsNotEqualToInteger(1))
71
func IsNotEqualToInteger(value int64) NumberComparisonConstraint {
72 1
	v := generic.NewNumberFromInt(value)
73
74 1
	return NumberComparisonConstraint{
75
		code:            code.NotEqual,
76
		messageTemplate: message.NotEqual,
77
		comparedValue:   v.String(),
78
		isValid: func(n generic.Number) bool {
79 1
			return !n.IsEqualTo(v)
80
		},
81
	}
82
}
83
84
// IsNotEqualToFloat checks that the number (integer or float) is not equal to the specified float value.
85
// Values are compared as integers if the compared and specified values are integers.
86
// Otherwise, numbers are always compared as floating point numbers.
87
//
88
// Example
89
//  v := 1.1
90
//  err := validator.ValidateNumber(&v, it.IsNotEqualToFloat(1.1))
91
func IsNotEqualToFloat(value float64) NumberComparisonConstraint {
92 1
	v := generic.NewNumberFromFloat(value)
93
94 1
	return NumberComparisonConstraint{
95
		code:            code.NotEqual,
96
		messageTemplate: message.NotEqual,
97
		comparedValue:   v.String(),
98
		isValid: func(n generic.Number) bool {
99 1
			return !n.IsEqualTo(v)
100
		},
101
	}
102
}
103
104
// IsLessThanInteger checks that the number (integer or float) is less than the specified integer value.
105
// Values are compared as integers if the compared and specified values are integers.
106
// Otherwise, numbers are always compared as floating point numbers.
107
//
108
// Example
109
//  v := 1
110
//  err := validator.ValidateNumber(&v, it.IsLessThanInteger(1))
111
func IsLessThanInteger(value int64) NumberComparisonConstraint {
112 1
	v := generic.NewNumberFromInt(value)
113
114 1
	return NumberComparisonConstraint{
115
		code:            code.TooHigh,
116
		messageTemplate: message.TooHigh,
117
		comparedValue:   v.String(),
118
		isValid: func(n generic.Number) bool {
119 1
			return n.IsLessThan(v)
120
		},
121
	}
122
}
123
124
// IsLessThanFloat checks that the number (integer or float) is less than the specified float value.
125
// Values are compared as integers if the compared and specified values are integers.
126
// Otherwise, numbers are always compared as floating point numbers.
127
//
128
// Example
129
//  v := 1.1
130
//  err := validator.ValidateNumber(&v, it.IsLessThanFloat(1.1))
131
func IsLessThanFloat(value float64) NumberComparisonConstraint {
132 1
	v := generic.NewNumberFromFloat(value)
133
134 1
	return NumberComparisonConstraint{
135
		code:            code.TooHigh,
136
		messageTemplate: message.TooHigh,
137
		comparedValue:   v.String(),
138
		isValid: func(n generic.Number) bool {
139 1
			return n.IsLessThan(v)
140
		},
141
	}
142
}
143
144
// IsLessThanOrEqualInteger checks that the number (integer or float) is less than or
145
// equal to the specified integer value. Values are compared as integers if the compared
146
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
147
//
148
// Example
149
//  v := 1
150
//  err := validator.ValidateNumber(&v, it.IsLessThanOrEqualInteger(2))
151
func IsLessThanOrEqualInteger(value int64) NumberComparisonConstraint {
152 1
	v := generic.NewNumberFromInt(value)
153
154 1
	return NumberComparisonConstraint{
155
		code:            code.TooHighOrEqual,
156
		messageTemplate: message.TooHighOrEqual,
157
		comparedValue:   v.String(),
158
		isValid: func(n generic.Number) bool {
159 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
160
		},
161
	}
162
}
163
164
// IsLessThanOrEqualFloat checks that the number (integer or float) is less than or
165
// equal to the specified float value. Values are compared as integers if the compared
166
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
167
//
168
// Example
169
//  v := 1.1
170
//  err := validator.ValidateNumber(&v, it.IsLessThanOrEqualFloat(1.2))
171
func IsLessThanOrEqualFloat(value float64) NumberComparisonConstraint {
172 1
	v := generic.NewNumberFromFloat(value)
173
174 1
	return NumberComparisonConstraint{
175
		code:            code.TooHighOrEqual,
176
		messageTemplate: message.TooHighOrEqual,
177
		comparedValue:   v.String(),
178
		isValid: func(n generic.Number) bool {
179 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
180
		},
181
	}
182
}
183
184
// IsGreaterThanInteger checks that the number (integer or float) is greater than the specified integer value.
185
// Values are compared as integers if the compared and specified values are integers.
186
// Otherwise, numbers are always compared as floating point numbers.
187
//
188
// Example
189
//  v := 1
190
//  err := validator.ValidateNumber(&v, it.IsGreaterThanInteger(1))
191
func IsGreaterThanInteger(value int64) NumberComparisonConstraint {
192 1
	v := generic.NewNumberFromInt(value)
193
194 1
	return NumberComparisonConstraint{
195
		code:            code.TooLow,
196
		messageTemplate: message.TooLow,
197
		comparedValue:   v.String(),
198
		isValid: func(n generic.Number) bool {
199 1
			return n.IsGreaterThan(v)
200
		},
201
	}
202
}
203
204
// IsGreaterThanFloat checks that the number (integer or float) is greater than the specified float value.
205
// Values are compared as integers if the compared and specified values are integers.
206
// Otherwise, numbers are always compared as floating point numbers.
207
//
208
// Example
209
//  v := 1.1
210
//  err := validator.ValidateNumber(&v, it.IsGreaterThanFloat(1.1))
211
func IsGreaterThanFloat(value float64) NumberComparisonConstraint {
212 1
	v := generic.NewNumberFromFloat(value)
213
214 1
	return NumberComparisonConstraint{
215
		code:            code.TooLow,
216
		messageTemplate: message.TooLow,
217
		comparedValue:   v.String(),
218
		isValid: func(n generic.Number) bool {
219 1
			return n.IsGreaterThan(v)
220
		},
221
	}
222
}
223
224
// IsGreaterThanOrEqualInteger checks that the number (integer or float) is greater than or
225
// equal to the specified integer value. Values are compared as integers if the compared
226
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
227
//
228
// Example
229
//  v := 1
230
//  err := validator.ValidateNumber(&v, it.IsGreaterThanOrEqualInteger(2))
231
func IsGreaterThanOrEqualInteger(value int64) NumberComparisonConstraint {
232 1
	v := generic.NewNumberFromInt(value)
233
234 1
	return NumberComparisonConstraint{
235
		code:            code.TooLowOrEqual,
236
		messageTemplate: message.TooLowOrEqual,
237
		comparedValue:   v.String(),
238
		isValid: func(n generic.Number) bool {
239 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
240
		},
241
	}
242
}
243
244
// IsGreaterThanOrEqualFloat checks that the number (integer or float) is greater than or
245
// equal to the specified float value. Values are compared as integers if the compared
246
// and specified values are integers. Otherwise, numbers are always compared as floating point numbers.
247
//
248
// Example
249
//  v := 1.1
250
//  err := validator.ValidateNumber(&v, it.IsGreaterThanOrEqualFloat(1.2))
251
func IsGreaterThanOrEqualFloat(value float64) NumberComparisonConstraint {
252 1
	v := generic.NewNumberFromFloat(value)
253
254 1
	return NumberComparisonConstraint{
255
		code:            code.TooLowOrEqual,
256
		messageTemplate: message.TooLowOrEqual,
257
		comparedValue:   v.String(),
258
		isValid: func(n generic.Number) bool {
259 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
260
		},
261
	}
262
}
263
264
// IsPositive checks that the value is a positive number (integer or float). Zero is neither
265
// positive nor negative. If you want to allow zero use IsPositiveOrZero comparison.
266
//
267
// Example
268
//  v := -1
269
//  err := validator.ValidateNumber(&v, it.IsPositive())
270
func IsPositive() NumberComparisonConstraint {
271 1
	v := generic.NewNumberFromInt(0)
272
273 1
	return NumberComparisonConstraint{
274
		code:            code.NotPositive,
275
		messageTemplate: message.NotPositive,
276
		comparedValue:   v.String(),
277
		isValid: func(n generic.Number) bool {
278 1
			return n.IsGreaterThan(v)
279
		},
280
	}
281
}
282
283
// IsPositiveOrZero checks that the value is a positive number (integer or float) or equal to zero.
284
// If you don't want to allow zero as a valid value, use IsPositive comparison.
285
//
286
// Example
287
//  v := -1
288
//  err := validator.ValidateNumber(&v, it.IsPositiveOrZero())
289
func IsPositiveOrZero() NumberComparisonConstraint {
290 1
	v := generic.NewNumberFromInt(0)
291
292 1
	return NumberComparisonConstraint{
293
		code:            code.NotPositiveOrZero,
294
		messageTemplate: message.NotPositiveOrZero,
295
		comparedValue:   v.String(),
296
		isValid: func(n generic.Number) bool {
297 1
			return n.IsGreaterThan(v) || n.IsEqualTo(v)
298
		},
299
	}
300
}
301
302
// IsNegative checks that the value is a negative number (integer or float). Zero is neither
303
// positive nor negative. If you want to allow zero use IsNegativeOrZero comparison.
304
//
305
// Example
306
//  v := 1
307
//  err := validator.ValidateNumber(&v, it.IsNegative())
308
func IsNegative() NumberComparisonConstraint {
309 1
	v := generic.NewNumberFromInt(0)
310
311 1
	return NumberComparisonConstraint{
312
		code:            code.NotNegative,
313
		messageTemplate: message.NotNegative,
314
		comparedValue:   v.String(),
315
		isValid: func(n generic.Number) bool {
316 1
			return n.IsLessThan(v)
317
		},
318
	}
319
}
320
321
// IsNegativeOrZero checks that the value is a negative number (integer or float) or equal to zero.
322
// If you don't want to allow zero as a valid value, use IsNegative comparison.
323
//
324
// Example
325
//  v := -1
326
//  err := validator.ValidateNumber(&v, it.IsNegativeOrZero())
327
func IsNegativeOrZero() NumberComparisonConstraint {
328 1
	v := generic.NewNumberFromInt(0)
329
330 1
	return NumberComparisonConstraint{
331
		code:            code.NotNegativeOrZero,
332
		messageTemplate: message.NotNegativeOrZero,
333
		comparedValue:   v.String(),
334
		isValid: func(n generic.Number) bool {
335 1
			return n.IsLessThan(v) || n.IsEqualTo(v)
336
		},
337
	}
338
}
339
340
// SetUp always returns no error.
341
func (c NumberComparisonConstraint) SetUp() error {
342 1
	return nil
343
}
344
345
// Name is the constraint name.
346
func (c NumberComparisonConstraint) Name() string {
347
	return "NumberComparisonConstraint"
348
}
349
350
// Message sets the violation message template. You can use template parameters
351
// for injecting its values into the final message:
352
//
353
//  {{ comparedValue }} - the expected value;
354
//  {{ value }} - the current (invalid) value.
355
func (c NumberComparisonConstraint) Message(message string) NumberComparisonConstraint {
356 1
	c.messageTemplate = message
357 1
	return c
358
}
359
360
// When enables conditional validation of this constraint. If the expression evaluates to false,
361
// then the constraint will be ignored.
362
func (c NumberComparisonConstraint) When(condition bool) NumberComparisonConstraint {
363 1
	c.isIgnored = !condition
364 1
	return c
365
}
366
367
func (c NumberComparisonConstraint) ValidateNumber(value generic.Number, scope validation.Scope) error {
368 1
	if c.isIgnored || value.IsNil() || c.isValid(value) {
369 1
		return nil
370
	}
371
372 1
	return scope.BuildViolation(c.code, c.messageTemplate).
373
		SetParameters([]validation.TemplateParameter{
374
			{Key: "{{ comparedValue }}", Value: c.comparedValue},
375
			{Key: "{{ value }}", Value: value.String()},
376
		}).
377
		CreateViolation()
378
}
379
380
// RangeConstraint is used to check that a given number value is between some minimum and maximum.
381
// Values are compared as integers if the compared and specified values are integers.
382
// Otherwise, numbers are always compared as floating point numbers.
383
type RangeConstraint struct {
384
	isIgnored       bool
385
	messageTemplate string
386
	min             generic.Number
387
	max             generic.Number
388
}
389
390
// IsBetweenIntegers checks that the number (integer or float) is between specified minimum and
391
// maximum integer values. Values are compared as integers if the compared and specified
392
// values are integers. Otherwise, numbers are always compared as floating point numbers.
393
//
394
// Example
395
//	v := 1
396
//	err := validator.ValidateNumber(&v, it.IsBetweenIntegers(10, 20))
397
func IsBetweenIntegers(min, max int64) RangeConstraint {
398 1
	return RangeConstraint{
399
		min:             generic.NewNumberFromInt(min),
400
		max:             generic.NewNumberFromInt(max),
401
		messageTemplate: message.NotInRange,
402
	}
403
}
404
405
// IsBetweenFloats checks that the number (integer or float) is between specified minimum and
406
// maximum float values. Values are compared as integers if the compared and specified
407
// values are integers. Otherwise, numbers are always compared as floating point numbers.
408
//
409
// Example
410
//	v := 1.1
411
//	err := validator.ValidateNumber(&v, it.IsBetweenFloats(10.111, 20.222))
412
func IsBetweenFloats(min, max float64) RangeConstraint {
413 1
	return RangeConstraint{
414
		min:             generic.NewNumberFromFloat(min),
415
		max:             generic.NewNumberFromFloat(max),
416
		messageTemplate: message.NotInRange,
417
	}
418
}
419
420
// SetUp returns an error if min is greater than or equal to max.
421
func (c RangeConstraint) SetUp() error {
422 1
	if c.min.IsGreaterThan(c.max) || c.min.IsEqualTo(c.max) {
423 1
		return errInvalidRange
424
	}
425
426 1
	return nil
427
}
428
429
// Name is the constraint name.
430
func (c RangeConstraint) Name() string {
431 1
	return "RangeConstraint"
432
}
433
434
// Message sets the violation message template. You can use template parameters
435
// for injecting its values into the final message:
436
//
437
//  {{ max }} - the upper limit;
438
//  {{ min }} - the lower limit;
439
//  {{ value }} - the current (invalid) value.
440
func (c RangeConstraint) Message(message string) RangeConstraint {
441 1
	c.messageTemplate = message
442 1
	return c
443
}
444
445
// When enables conditional validation of this constraint. If the expression evaluates to false,
446
// then the constraint will be ignored.
447
func (c RangeConstraint) When(condition bool) RangeConstraint {
448 1
	c.isIgnored = !condition
449 1
	return c
450
}
451
452
func (c RangeConstraint) ValidateNumber(value generic.Number, scope validation.Scope) error {
453 1
	if c.isIgnored {
454 1
		return nil
455
	}
456 1
	if value.IsLessThan(c.min) || value.IsGreaterThan(c.max) {
457 1
		return c.newViolation(value, scope)
458
	}
459
460 1
	return nil
461
}
462
463
func (c RangeConstraint) newViolation(value generic.Number, scope validation.Scope) error {
464 1
	return scope.BuildViolation(code.NotInRange, c.messageTemplate).
465
		SetParameters([]validation.TemplateParameter{
466
			{Key: "{{ min }}", Value: c.min.String()},
467
			{Key: "{{ max }}", Value: c.max.String()},
468
			{Key: "{{ value }}", Value: value.String()},
469
		}).
470
		CreateViolation()
471
}
472
473
// StringComparisonConstraint is used to compare strings.
474
type StringComparisonConstraint struct {
475
	isIgnored       bool
476
	code            string
477
	messageTemplate string
478
	comparedValue   string
479
	isValid         func(value string) bool
480
}
481
482
// IsEqualToString checks that the string value is equal to the specified string value.
483
//
484
// Example
485
//  v := "actual"
486
//  err := validator.ValidateString(&v, it.IsEqualToString("expected"))
487
func IsEqualToString(value string) StringComparisonConstraint {
488 1
	return StringComparisonConstraint{
489
		code:            code.Equal,
490
		messageTemplate: message.Equal,
491
		comparedValue:   value,
492
		isValid: func(actualValue string) bool {
493 1
			return value == actualValue
494
		},
495
	}
496
}
497
498
// IsNotEqualToString checks that the string value is not equal to the specified string value.
499
//
500
// Example
501
//  v := "expected"
502
//  err := validator.ValidateString(&v, it.IsNotEqualToString("expected"))
503
func IsNotEqualToString(value string) StringComparisonConstraint {
504 1
	return StringComparisonConstraint{
505
		code:            code.NotEqual,
506
		messageTemplate: message.NotEqual,
507
		comparedValue:   value,
508
		isValid: func(actualValue string) bool {
509 1
			return value != actualValue
510
		},
511
	}
512
}
513
514
// SetUp always returns no error.
515
func (c StringComparisonConstraint) SetUp() error {
516 1
	return nil
517
}
518
519
// Name is the constraint name.
520
func (c StringComparisonConstraint) Name() string {
521
	return "StringComparisonConstraint"
522
}
523
524
// Message sets the violation message template. You can use template parameters
525
// for injecting its values into the final message:
526
//
527
//  {{ comparedValue }} - the expected value;
528
//  {{ value }} - the current (invalid) value.
529
//
530
// All string values are quoted strings.
531
func (c StringComparisonConstraint) Message(message string) StringComparisonConstraint {
532 1
	c.messageTemplate = message
533 1
	return c
534
}
535
536
// When enables conditional validation of this constraint. If the expression evaluates to false,
537
// then the constraint will be ignored.
538
func (c StringComparisonConstraint) When(condition bool) StringComparisonConstraint {
539 1
	c.isIgnored = !condition
540 1
	return c
541
}
542
543
func (c StringComparisonConstraint) ValidateString(value *string, scope validation.Scope) error {
544 1
	if c.isIgnored || value == nil || c.isValid(*value) {
545 1
		return nil
546
	}
547
548 1
	return scope.BuildViolation(c.code, c.messageTemplate).
549
		SetParameters([]validation.TemplateParameter{
550
			{Key: "{{ comparedValue }}", Value: strconv.Quote(c.comparedValue)},
551
			{Key: "{{ value }}", Value: strconv.Quote(*value)},
552
		}).
553
		CreateViolation()
554
}
555
556
// TimeComparisonConstraint is used to compare time values.
557
type TimeComparisonConstraint struct {
558
	isIgnored       bool
559
	code            string
560
	messageTemplate string
561
	comparedValue   time.Time
562
	layout          string
563
	isValid         func(value time.Time) bool
564
}
565
566
// IsEarlierThan checks that the given time is earlier than the specified value.
567
//
568
// Example
569
//  t := time.Now()
570
//  err := validator.ValidateTime(&t, it.IsEarlierThan(time.Now().Add(time.Hour)))
571
func IsEarlierThan(value time.Time) TimeComparisonConstraint {
572 1
	return TimeComparisonConstraint{
573
		code:            code.TooLate,
574
		messageTemplate: message.TooLate,
575
		comparedValue:   value,
576
		layout:          time.RFC3339,
577
		isValid: func(actualValue time.Time) bool {
578 1
			return actualValue.Before(value)
579
		},
580
	}
581
}
582
583
// IsEarlierThanOrEqual checks that the given time is earlier or equal to the specified value.
584
//
585
// Example
586
//  t := time.Now()
587
//  err := validator.ValidateTime(&t, it.IsEarlierThanOrEqual(time.Now().Add(time.Hour)))
588
func IsEarlierThanOrEqual(value time.Time) TimeComparisonConstraint {
589 1
	return TimeComparisonConstraint{
590
		code:            code.TooLateOrEqual,
591
		messageTemplate: message.TooLateOrEqual,
592
		comparedValue:   value,
593
		layout:          time.RFC3339,
594
		isValid: func(actualValue time.Time) bool {
595 1
			return actualValue.Before(value) || actualValue.Equal(value)
596
		},
597
	}
598
}
599
600
// IsLaterThan checks that the given time is later than the specified value.
601
//
602
// Example
603
//  t := time.Now()
604
//  err := validator.ValidateTime(&t, it.IsLaterThan(time.Now().Sub(time.Hour)))
605
func IsLaterThan(value time.Time) TimeComparisonConstraint {
606 1
	return TimeComparisonConstraint{
607
		code:            code.TooEarly,
608
		messageTemplate: message.TooEarly,
609
		comparedValue:   value,
610
		layout:          time.RFC3339,
611
		isValid: func(actualValue time.Time) bool {
612 1
			return actualValue.After(value)
613
		},
614
	}
615
}
616
617
// IsLaterThanOrEqual checks that the given time is later or equal to the specified value.
618
//
619
// Example
620
//  t := time.Now()
621
//  err := validator.ValidateTime(&t, it.IsLaterThanOrEqual(time.Now().Sub(time.Hour)))
622
func IsLaterThanOrEqual(value time.Time) TimeComparisonConstraint {
623 1
	return TimeComparisonConstraint{
624
		code:            code.TooEarlyOrEqual,
625
		messageTemplate: message.TooEarlyOrEqual,
626
		comparedValue:   value,
627
		layout:          time.RFC3339,
628
		isValid: func(actualValue time.Time) bool {
629 1
			return actualValue.After(value) || actualValue.Equal(value)
630
		},
631
	}
632
}
633
634
// SetUp always returns no error.
635
func (c TimeComparisonConstraint) SetUp() error {
636 1
	return nil
637
}
638
639
// Name is the constraint name.
640
func (c TimeComparisonConstraint) Name() string {
641
	return "TimeComparisonConstraint"
642
}
643
644
// Message sets the violation message template. You can use template parameters
645
// for injecting its values into the final message:
646
//
647
//  {{ comparedValue }} - the expected value;
648
//  {{ value }} - the current (invalid) value.
649
//
650
// All values are formatted by the layout that can be defined by the Layout method.
651
// Default layout is time.RFC3339.
652
func (c TimeComparisonConstraint) Message(message string) TimeComparisonConstraint {
653 1
	c.messageTemplate = message
654 1
	return c
655
}
656
657
// Layout can be used to set the layout that is used to format time values.
658
func (c TimeComparisonConstraint) Layout(layout string) TimeComparisonConstraint {
659 1
	c.layout = layout
660 1
	return c
661
}
662
663
// When enables conditional validation of this constraint. If the expression evaluates to false,
664
// then the constraint will be ignored.
665
func (c TimeComparisonConstraint) When(condition bool) TimeComparisonConstraint {
666 1
	c.isIgnored = !condition
667 1
	return c
668
}
669
670
func (c TimeComparisonConstraint) ValidateTime(value *time.Time, scope validation.Scope) error {
671 1
	if c.isIgnored || value == nil || c.isValid(*value) {
672 1
		return nil
673
	}
674
675 1
	return scope.BuildViolation(c.code, c.messageTemplate).
676
		SetParameters([]validation.TemplateParameter{
677
			{Key: "{{ comparedValue }}", Value: c.comparedValue.Format(c.layout)},
678
			{Key: "{{ value }}", Value: value.Format(c.layout)},
679
		}).
680
		CreateViolation()
681
}
682
683
// TimeRangeConstraint is used to check that a given time value is between some minimum and maximum.
684
type TimeRangeConstraint struct {
685
	isIgnored       bool
686
	messageTemplate string
687
	layout          string
688
	min             time.Time
689
	max             time.Time
690
}
691
692
// IsBetweenTime checks that the time is between specified minimum and maximum time values.
693
//
694
// Example
695
//	t := time.Now()
696
//	err := validator.ValidateTime(&t, it.IsBetweenTime(time.Now().Add(time.Hour), time.Now().Add(2*time.Hour)))
697
func IsBetweenTime(min, max time.Time) TimeRangeConstraint {
698 1
	return TimeRangeConstraint{
699
		messageTemplate: message.NotInRange,
700
		layout:          time.RFC3339,
701
		min:             min,
702
		max:             max,
703
	}
704
}
705
706
// SetUp returns an error if min is greater than or equal to max.
707
func (c TimeRangeConstraint) SetUp() error {
708 1
	if c.min.After(c.max) || c.min.Equal(c.max) {
709 1
		return errInvalidRange
710
	}
711
712 1
	return nil
713
}
714
715
// Name is the constraint name.
716
func (c TimeRangeConstraint) Name() string {
717 1
	return "TimeRangeConstraint"
718
}
719
720
// Message sets the violation message template. You can use template parameters
721
// for injecting its values into the final message:
722
//
723
//  {{ max }} - the upper limit;
724
//  {{ min }} - the lower limit;
725
//  {{ value }} - the current (invalid) value.
726
//
727
// All values are formatted by the layout that can be defined by the Layout method.
728
// Default layout is time.RFC3339.
729
func (c TimeRangeConstraint) Message(message string) TimeRangeConstraint {
730 1
	c.messageTemplate = message
731 1
	return c
732
}
733
734
// When enables conditional validation of this constraint. If the expression evaluates to false,
735
// then the constraint will be ignored.
736
func (c TimeRangeConstraint) When(condition bool) TimeRangeConstraint {
737 1
	c.isIgnored = !condition
738 1
	return c
739
}
740
741
// Layout can be used to set the layout that is used to format time values.
742
func (c TimeRangeConstraint) Layout(layout string) TimeRangeConstraint {
743 1
	c.layout = layout
744 1
	return c
745
}
746
747
func (c TimeRangeConstraint) ValidateTime(value *time.Time, scope validation.Scope) error {
748 1
	if c.isIgnored || value == nil {
749 1
		return nil
750
	}
751 1
	if value.Before(c.min) || value.After(c.max) {
752 1
		return c.newViolation(value, scope)
753
	}
754
755 1
	return nil
756
}
757
758
func (c TimeRangeConstraint) newViolation(value *time.Time, scope validation.Scope) validation.Violation {
759 1
	return scope.BuildViolation(code.NotInRange, c.messageTemplate).
760
		SetParameters([]validation.TemplateParameter{
761
			{Key: "{{ min }}", Value: c.min.Format(c.layout)},
762
			{Key: "{{ max }}", Value: c.max.Format(c.layout)},
763
			{Key: "{{ value }}", Value: value.Format(c.layout)},
764
		}).
765
		CreateViolation()
766
}
767