2017-02-22 38 views
0

Я хотел бы проверить следующую структуру:Golang валидатор многопрофильное зависимость

type CarModel struct { 
    gorm.Model 
    OwnerID int `json:"ownerid" validate:"nonzero"` 
    Type  string `json:"type" validate:"regexp=(?)(A|B)"` 
    A  string `json:"url" validate:"isurl"` 
    B   string `json:"ip" validate:"isip"` 
} 

Я хотел бы подтвердить А и В в зависимости от типа, если тип = А, то А должен существовать и должен быть URL, НО B не должно существовать , если тип = B, тогда A не должно существовать, а B должен быть IP

это возможно с помощью валидатора?

Я попытался пользовательскую проверку, но я не могу найти способ, чтобы увидеть значение типа:

func checkB(v interface{}, param string) error { 
    theB := reflect.ValueOf(v) 
    if theB.Kind() != reflect.String { 
     return validator.ErrUnsupported 
    } 
    //check if B is an IP 
    ipcool := net.ParseIP(theB.String()) 
    if ipcool == nil { 
     return errors.New("B : ip incorrecte " + theB.String()) 
    } 
    return nil 
} 

После ответа Алекс Никол, я хотел бы прежде всего поблагодарить вас за вашу помощь.

Если я правильно понял, я бы перебрать все поля «Подтвердить», чтобы сохранить след значения TYPE, А и В, а затем проверить их в зависимости от типа ...

Я сделал это:

func checkMonitor(v interface{}) error { 
    var mytype string 
    var myA string 
    var myB string 

    val := reflect.ValueOf(v) 
    // Iterate through fields 
    for i := 0; i < val.NumField(); i++ { 
     // Lookup the validate tag 
     field := val.Type().Field(i) 
     tags := field.Tag 
     _, ok := tags.Lookup("validate") 
     if !ok { 
      // No validate tag. 
      continue 
     } 

     // Get the value of the field. 
     fieldValue := val.Field(i) 

     switch field.Name { 
     case "Type": 
      mytype = fieldValue.Interface() 
     case "A": 
      myA = fieldValue.Interface() 
     case "B": 
      myB = fieldValue.Interface() 
     } 
     // Validation logic here. 
     //fmt.Println("field", field.Name, "has validate tag", validate, "and value", fieldValue.Interface()) 
    } 
    if mytype == "A" { 
     if myA == "" { 
      return errors.New("A vide et type A") 
     } 
     ipcool := net.ParseIP(myA) 
     if ipcool == nil { 
      return errors.New("A incorrecte " + myA) 
     } 
    } else if mytype == "HTML" { 
     if myB == "" { 
      return errors.New("B vide et type B") 
     } 
     _, urlpascool := url.ParseRequestURI(myB) 
     if urlpascool != nil { 
      return errors.New("B incorrecte " + myB) 
     } 
    } 
    return nil 
} 

но получил ошибку на MyType, Mya и Myb в случае переключения:

не может использовать fieldValue.Interface() (тип интерфейса {}) как тип строки в назначении: требуется тип утверждения

EDIT: просто нужно использовать мой мозг:

switch field.Name { 
case "Type": 
    mytype = fieldValue.String() 
case "A": 
    myA = fieldValue.String() 
case "B": 
    myB = fieldValue.Interface() 
} 

ответ

1

Вы, вероятно, хотите использовать отражение перебрать полей структуры, получить validate метку для каждого поля и проверьте поле. Это означает, что вам придется выполнять проверку на уровне структуры. В противном случае, если вы передадите функцию myInstance.OwnerID функции, вы потеряете связанный с ней тег.

Этот код перебирает полей структуры и получает validate тег для каждого:

func checkStruct(v interface{}) error { 
    val := reflect.ValueOf(v) 

    // Iterate through fields 
    for i := 0; i < val.NumField(); i++ { 
     // Lookup the validate tag 
     field := val.Type().Field(i) 
     tags := field.Tag 
     validate, ok := tags.Lookup("validate") 
     if !ok { 
      // No validate tag. 
      continue 
     } 

     // Get the value of the field. 
     fieldValue := val.Field(i) 

     // Validation logic here. 
     fmt.Println("field", field.Name, "has validate tag", validate, "and value", 
      fieldValue.Interface()) 
    } 
    return nil 
} 

Например, мы могли бы передать его на следующий CarModel:

checkStruct(CarModel{ 
    OwnerID: 2, 
    Type: "B", 
    A:  "http://google.com", 
    B:  "192.168.1.1", 
}) 

и напечатает вышли следующим образом:

field OwnerID has validate tag nonzero and value 2 
field Type has validate tag regexp=(?)(A|B) and value B 
field A has validate tag isurl and value http://google.com 
field B has validate tag isip and value 192.168.1.1 
0

Похоже на вашу проверку правила очень сложны, но вы можете дать validating.

Предположим, у нас уже есть два настроили валидаторы IsURL и IsIP, то ваши правила проверки могут быть реализованы следующим образом:

import (
    "regexp" 

    v "github.com/RussellLuo/validating" 
) 

// Customized validators 
var (
    MatchRegexp = func(pattern string) v.Validator { 
     return v.FromFunc(func(field v.Field) v.Errors { 
      switch t := field.ValuePtr.(type) { 
      case *string: 
       if matched, _ := regexp.MatchString(pattern, *t); !matched { 
        return v.NewErrors(field.Name, v.ErrInvalid, "does not match") 
       } 
       return nil 
      default: 
       return v.NewErrors(field.Name, v.ErrUnsupported, "is unsupported") 
      } 
     }) 
    } 
    // IsURL and IsIP are omitted 
) 

type CarModel struct { 
    gorm.Model 
    OwnerID int `json:"ownerid"` 
    Type  string `json:"type"` 
    A   string `json:"url"` 
    B   string `json:"ip"` 
} 

func main() { 
    car := CarModel{} 
    errs := v.Validate(v.Schema{ 
     v.F("ownerid", &car.OwnerID): v.Nonzero(), 
     v.F("type", &car.Type):  MatchRegexp("(A|B)"), 
     v.F("a", &car.A): v.Lazy(func() v.Validator { 
      if car.Type == "A" { 
       return v.All(v.Nonzero(), IsURL()) 
      } 
      return v.Not(v.Nonzero()) 
     }), 
     v.F("b", &car.B): v.Lazy(func() v.Validator { 
      if car.Type == "B" { 
       return v.All(v.Nonzero(), IsIP()) 
      } 
      return v.Not(v.Nonzero()) 
     }), 
    }) 
}