@@ -16,10 +16,12 @@ var BakedInValidators = map[string]Func{
1616 "len" : hasLengthOf ,
1717 "min" : hasMinOf ,
1818 "max" : hasMaxOf ,
19+ "eq" : isEq ,
1920 "lt" : isLt ,
2021 "lte" : isLte ,
2122 "gt" : isGt ,
2223 "gte" : isGte ,
24+ "eqfield" : isEqField ,
2325 "gtefield" : isGteField ,
2426 "gtfield" : isGtField ,
2527 "ltefield" : isLteField ,
@@ -40,6 +42,119 @@ var BakedInValidators = map[string]Func{
4042 "base64" : isBase64 ,
4143}
4244
45+ func isEqField (top interface {}, current interface {}, field interface {}, param string ) bool {
46+
47+ if current == nil {
48+ panic ("struct not passed for cross validation" )
49+ }
50+
51+ currentVal := reflect .ValueOf (current )
52+
53+ if currentVal .Kind () == reflect .Ptr && ! currentVal .IsNil () {
54+ currentVal = reflect .ValueOf (currentVal .Elem ().Interface ())
55+ }
56+
57+ var currentFielVal reflect.Value
58+
59+ switch currentVal .Kind () {
60+
61+ case reflect .Struct :
62+
63+ if currentVal .Type () == reflect .TypeOf (time.Time {}) {
64+ currentFielVal = currentVal
65+ break
66+ }
67+
68+ f := currentVal .FieldByName (param )
69+
70+ if f .Kind () == reflect .Invalid {
71+ panic (fmt .Sprintf ("Field \" %s\" not found in struct" , param ))
72+ }
73+
74+ currentFielVal = f
75+
76+ default :
77+
78+ currentFielVal = currentVal
79+ }
80+
81+ if currentFielVal .Kind () == reflect .Ptr && ! currentFielVal .IsNil () {
82+
83+ currentFielVal = reflect .ValueOf (currentFielVal .Elem ().Interface ())
84+ }
85+
86+ fv := reflect .ValueOf (field )
87+
88+ switch fv .Kind () {
89+
90+ case reflect .String :
91+ return fv .String () == currentFielVal .String ()
92+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
93+
94+ return fv .Int () == currentFielVal .Int ()
95+
96+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
97+
98+ return fv .Uint () == currentFielVal .Uint ()
99+
100+ case reflect .Float32 , reflect .Float64 :
101+
102+ return fv .Float () == currentFielVal .Float ()
103+ case reflect .Slice , reflect .Map , reflect .Array :
104+
105+ return int64 (fv .Len ()) == int64 (currentFielVal .Len ())
106+ case reflect .Struct :
107+
108+ if fv .Type () == reflect .TypeOf (time.Time {}) {
109+
110+ if currentFielVal .Type () != reflect .TypeOf (time.Time {}) {
111+ panic ("Bad Top Level field type" )
112+ }
113+
114+ t := currentFielVal .Interface ().(time.Time )
115+ fieldTime := field .(time.Time )
116+
117+ return fieldTime .Equal (t )
118+ }
119+ }
120+
121+ panic (fmt .Sprintf ("Bad field type %T" , field ))
122+ }
123+
124+ func isEq (top interface {}, current interface {}, field interface {}, param string ) bool {
125+
126+ st := reflect .ValueOf (field )
127+
128+ switch st .Kind () {
129+
130+ case reflect .String :
131+
132+ return st .String () == param
133+
134+ case reflect .Slice , reflect .Map , reflect .Array :
135+ p := asInt (param )
136+
137+ return int64 (st .Len ()) == p
138+
139+ case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
140+ p := asInt (param )
141+
142+ return st .Int () == p
143+
144+ case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
145+ p := asUint (param )
146+
147+ return st .Uint () == p
148+
149+ case reflect .Float32 , reflect .Float64 :
150+ p := asFloat (param )
151+
152+ return st .Float () == p
153+ }
154+
155+ panic (fmt .Sprintf ("Bad field type %T" , field ))
156+ }
157+
43158func isBase64 (top interface {}, current interface {}, field interface {}, param string ) bool {
44159 return matchesRegex (base64Regex , field )
45160}
0 commit comments