@@ -19,6 +19,10 @@ var BakedInValidators = map[string]ValidationFunc{
1919 "lte" : isLte ,
2020 "gt" : isGt ,
2121 "gte" : isGte ,
22+ "gtefield" : isGteField ,
23+ "gtfield" : isGtField ,
24+ "ltefield" : isLteField ,
25+ "ltfield" : isLtField ,
2226 "alpha" : isAlpha ,
2327 "alphanum" : isAlphanum ,
2428 "numeric" : isNumeric ,
@@ -229,6 +233,156 @@ func hasValue(val interface{}, field interface{}, param string) bool {
229233 }
230234}
231235
236+ func isGteField (val interface {}, field interface {}, param string ) bool {
237+
238+ if val == nil {
239+ panic ("struct not passed for cross validation" )
240+ }
241+
242+ topVal := reflect .ValueOf (val )
243+
244+ if topVal .Kind () == reflect .Ptr && ! topVal .IsNil () {
245+ topVal = reflect .ValueOf (topVal .Elem ().Interface ())
246+ }
247+
248+ var topFieldVal reflect.Value
249+
250+ switch topVal .Kind () {
251+
252+ case reflect .Struct :
253+
254+ if topVal .Type () == reflect .TypeOf (time.Time {}) {
255+ topFieldVal = topVal
256+ break
257+ }
258+
259+ f := topVal .FieldByName (param )
260+
261+ if f .Kind () == reflect .Invalid {
262+ panic (fmt .Sprintf ("Field \" %s\" not found in struct" , param ))
263+ }
264+
265+ topFieldVal = f
266+
267+ default :
268+
269+ topFieldVal = topVal
270+ }
271+
272+ if topFieldVal .Kind () == reflect .Ptr && ! topFieldVal .IsNil () {
273+
274+ topFieldVal = reflect .ValueOf (topFieldVal .Elem ().Interface ())
275+ }
276+
277+ fv := reflect .ValueOf (field )
278+
279+ switch fv .Kind () {
280+
281+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
282+
283+ return fv .Int () >= topFieldVal .Int ()
284+
285+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
286+
287+ return fv .Uint () >= topFieldVal .Uint ()
288+
289+ case reflect .Float32 , reflect .Float64 :
290+
291+ return fv .Float () >= topFieldVal .Float ()
292+
293+ case reflect .Struct :
294+
295+ if fv .Type () == reflect .TypeOf (time.Time {}) {
296+
297+ if topFieldVal .Type () != reflect .TypeOf (time.Time {}) {
298+ panic ("Bad Top Level field type" )
299+ }
300+
301+ t := topFieldVal .Interface ().(time.Time )
302+ fieldTime := field .(time.Time )
303+
304+ return fieldTime .After (t ) || fieldTime .Equal (t )
305+ }
306+ }
307+
308+ panic (fmt .Sprintf ("Bad field type %T" , field ))
309+ }
310+
311+ func isGtField (val interface {}, field interface {}, param string ) bool {
312+
313+ if val == nil {
314+ panic ("struct not passed for cross validation" )
315+ }
316+
317+ topVal := reflect .ValueOf (val )
318+
319+ if topVal .Kind () == reflect .Ptr && ! topVal .IsNil () {
320+ topVal = reflect .ValueOf (topVal .Elem ().Interface ())
321+ }
322+
323+ var topFieldVal reflect.Value
324+
325+ switch topVal .Kind () {
326+
327+ case reflect .Struct :
328+
329+ if topVal .Type () == reflect .TypeOf (time.Time {}) {
330+ topFieldVal = topVal
331+ break
332+ }
333+
334+ f := topVal .FieldByName (param )
335+
336+ if f .Kind () == reflect .Invalid {
337+ panic (fmt .Sprintf ("Field \" %s\" not found in struct" , param ))
338+ }
339+
340+ topFieldVal = f
341+
342+ default :
343+
344+ topFieldVal = topVal
345+ }
346+
347+ if topFieldVal .Kind () == reflect .Ptr && ! topFieldVal .IsNil () {
348+
349+ topFieldVal = reflect .ValueOf (topFieldVal .Elem ().Interface ())
350+ }
351+
352+ fv := reflect .ValueOf (field )
353+
354+ switch fv .Kind () {
355+
356+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
357+
358+ return fv .Int () > topFieldVal .Int ()
359+
360+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
361+
362+ return fv .Uint () > topFieldVal .Uint ()
363+
364+ case reflect .Float32 , reflect .Float64 :
365+
366+ return fv .Float () > topFieldVal .Float ()
367+
368+ case reflect .Struct :
369+
370+ if fv .Type () == reflect .TypeOf (time.Time {}) {
371+
372+ if topFieldVal .Type () != reflect .TypeOf (time.Time {}) {
373+ panic ("Bad Top Level field type" )
374+ }
375+
376+ t := topFieldVal .Interface ().(time.Time )
377+ fieldTime := field .(time.Time )
378+
379+ return fieldTime .After (t )
380+ }
381+ }
382+
383+ panic (fmt .Sprintf ("Bad field type %T" , field ))
384+ }
385+
232386func isGte (val interface {}, field interface {}, param string ) bool {
233387
234388 st := reflect .ValueOf (field )
@@ -262,7 +416,7 @@ func isGte(val interface{}, field interface{}, param string) bool {
262416
263417 case reflect .Struct :
264418
265- if st .Type () == reflect .TypeOf (field ) {
419+ if st .Type () == reflect .TypeOf (time. Time {} ) {
266420
267421 now := time .Now ().UTC ()
268422 t := field .(time.Time )
@@ -306,7 +460,7 @@ func isGt(val interface{}, field interface{}, param string) bool {
306460 return st .Float () > p
307461 case reflect .Struct :
308462
309- if st .Type () == reflect .TypeOf (field ) {
463+ if st .Type () == reflect .TypeOf (time. Time {} ) {
310464
311465 return field .(time.Time ).After (time .Now ().UTC ())
312466 }
@@ -362,6 +516,156 @@ func hasMinOf(val interface{}, field interface{}, param string) bool {
362516 return isGte (val , field , param )
363517}
364518
519+ func isLteField (val interface {}, field interface {}, param string ) bool {
520+
521+ if val == nil {
522+ panic ("struct not passed for cross validation" )
523+ }
524+
525+ topVal := reflect .ValueOf (val )
526+
527+ if topVal .Kind () == reflect .Ptr && ! topVal .IsNil () {
528+ topVal = reflect .ValueOf (topVal .Elem ().Interface ())
529+ }
530+
531+ var topFieldVal reflect.Value
532+
533+ switch topVal .Kind () {
534+
535+ case reflect .Struct :
536+
537+ if topVal .Type () == reflect .TypeOf (time.Time {}) {
538+ topFieldVal = topVal
539+ break
540+ }
541+
542+ f := topVal .FieldByName (param )
543+
544+ if f .Kind () == reflect .Invalid {
545+ panic (fmt .Sprintf ("Field \" %s\" not found in struct" , param ))
546+ }
547+
548+ topFieldVal = f
549+
550+ default :
551+
552+ topFieldVal = topVal
553+ }
554+
555+ if topFieldVal .Kind () == reflect .Ptr && ! topFieldVal .IsNil () {
556+
557+ topFieldVal = reflect .ValueOf (topFieldVal .Elem ().Interface ())
558+ }
559+
560+ fv := reflect .ValueOf (field )
561+
562+ switch fv .Kind () {
563+
564+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
565+
566+ return fv .Int () <= topFieldVal .Int ()
567+
568+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
569+
570+ return fv .Uint () <= topFieldVal .Uint ()
571+
572+ case reflect .Float32 , reflect .Float64 :
573+
574+ return fv .Float () <= topFieldVal .Float ()
575+
576+ case reflect .Struct :
577+
578+ if fv .Type () == reflect .TypeOf (time.Time {}) {
579+
580+ if topFieldVal .Type () != reflect .TypeOf (time.Time {}) {
581+ panic ("Bad Top Level field type" )
582+ }
583+
584+ t := topFieldVal .Interface ().(time.Time )
585+ fieldTime := field .(time.Time )
586+
587+ return fieldTime .Before (t ) || fieldTime .Equal (t )
588+ }
589+ }
590+
591+ panic (fmt .Sprintf ("Bad field type %T" , field ))
592+ }
593+
594+ func isLtField (val interface {}, field interface {}, param string ) bool {
595+
596+ if val == nil {
597+ panic ("struct not passed for cross validation" )
598+ }
599+
600+ topVal := reflect .ValueOf (val )
601+
602+ if topVal .Kind () == reflect .Ptr && ! topVal .IsNil () {
603+ topVal = reflect .ValueOf (topVal .Elem ().Interface ())
604+ }
605+
606+ var topFieldVal reflect.Value
607+
608+ switch topVal .Kind () {
609+
610+ case reflect .Struct :
611+
612+ if topVal .Type () == reflect .TypeOf (time.Time {}) {
613+ topFieldVal = topVal
614+ break
615+ }
616+
617+ f := topVal .FieldByName (param )
618+
619+ if f .Kind () == reflect .Invalid {
620+ panic (fmt .Sprintf ("Field \" %s\" not found in struct" , param ))
621+ }
622+
623+ topFieldVal = f
624+
625+ default :
626+
627+ topFieldVal = topVal
628+ }
629+
630+ if topFieldVal .Kind () == reflect .Ptr && ! topFieldVal .IsNil () {
631+
632+ topFieldVal = reflect .ValueOf (topFieldVal .Elem ().Interface ())
633+ }
634+
635+ fv := reflect .ValueOf (field )
636+
637+ switch fv .Kind () {
638+
639+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
640+
641+ return fv .Int () < topFieldVal .Int ()
642+
643+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
644+
645+ return fv .Uint () < topFieldVal .Uint ()
646+
647+ case reflect .Float32 , reflect .Float64 :
648+
649+ return fv .Float () < topFieldVal .Float ()
650+
651+ case reflect .Struct :
652+
653+ if fv .Type () == reflect .TypeOf (time.Time {}) {
654+
655+ if topFieldVal .Type () != reflect .TypeOf (time.Time {}) {
656+ panic ("Bad Top Level field type" )
657+ }
658+
659+ t := topFieldVal .Interface ().(time.Time )
660+ fieldTime := field .(time.Time )
661+
662+ return fieldTime .Before (t )
663+ }
664+ }
665+
666+ panic (fmt .Sprintf ("Bad field type %T" , field ))
667+ }
668+
365669func isLte (val interface {}, field interface {}, param string ) bool {
366670
367671 st := reflect .ValueOf (field )
@@ -395,7 +699,7 @@ func isLte(val interface{}, field interface{}, param string) bool {
395699
396700 case reflect .Struct :
397701
398- if st .Type () == reflect .TypeOf (field ) {
702+ if st .Type () == reflect .TypeOf (time. Time {} ) {
399703
400704 now := time .Now ().UTC ()
401705 t := field .(time.Time )
@@ -440,7 +744,7 @@ func isLt(val interface{}, field interface{}, param string) bool {
440744
441745 case reflect .Struct :
442746
443- if st .Type () == reflect .TypeOf (field ) {
747+ if st .Type () == reflect .TypeOf (time. Time {} ) {
444748
445749 return field .(time.Time ).Before (time .Now ().UTC ())
446750 }
0 commit comments