LoginSignup
2
0

More than 1 year has passed since last update.

validatorの *csfield タグはArray, Slice, Mapのlenを比較したい時につける

Posted at

この投稿で使用している言語、ライブラリのバージョン

疑問に思ったこと

validatorのタグには、gtecsfieldgtefieldや、ltcsfieldltfieldといったcs付きとそうでないものがあります。

この違いは何か?

例えば gtecsfield/gtefieldは以下のような説明があります。

Tag Description
gtecsfield Field Greater Than or Equal To Another Relative Field
gtefield Field Greater Than or Equal To Another Field

この説明を読んで、ある構造体Aが別の構造体Bを持っていて、AのフィールドとBのフィールドとを比較したい場合に *csfieldタグ を使用するのかな?と思っていました。

例えばこんな感じ

type Event struct {
	Name         string
	StartDate    time.Time `validate:"gtecsfield=Notification.NotificationTime"`
	Notification Notification
}

type Notification struct {
	NotificationTime time.Time
}

でもこのコードはStartDateのタグをgtecsfieldからgtefieldに変更しても問題なく動きます。

package main

import (
	"fmt"
	"time"

	"github.com/go-playground/validator/v10"
)

type Event struct {
	Name         string
	StartDate    time.Time `validate:"gtefield=Notification.NotificationTime"` // <= `gtecsfield`ではなく`gtefield`を使う
	Notification Notification
}

type Notification struct {
	NotificationTime time.Time
}

func main() {
	validate := validator.New()
	now := time.Now()

	validEvent := Event{
		Name:      "EventName1",
		StartDate: now,
		Notification: Notification{
			NotificationTime: now.AddDate(0, 0, -1),
		},
	}

	if err := validate.Struct(validEvent); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("validEvent errs=%+v\n", errrs)
		}
	}

	invalidEvent := Event{
		Name:      "EventName1",
		StartDate: now,
		Notification: Notification{
			NotificationTime: now.AddDate(0, 0, 1),
		},
	}

	if err := validate.Struct(invalidEvent); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("invalidEvent errs=%+v\n", errrs)
		}
	}
}

$ go run main.go
invalidEvent errs=Key: 'Event.StartDate' Error:Field validation for 'StartDate' failed on the 'gtefield' tag

じゃあ *csfield ってどこで使うの?

該当箇所のソースコード

gtecsfieldgtefieldのそれぞれのタグを使用した場合に呼ばれる関数はそれぞれ以下の通りです。

gtecsfieldタグを使った場合に呼ばれる関数

gtefieldタグを使った場合に呼ばれる関数

ローカル変数が若干異なることを除き、違いは一箇所だけで *csfield は Array, Slice, Map の場合にlenで比較しています。

gtecsfieldタグはArray, Slice, Mapの場合lenで比較している

gtefieldタグはArray, Slice, Mapの判定をしていない

試してみると確かにgtefieldではSliceのサイズでのバリデーションができませんでした。

main.go
package main

import (
	"fmt"
	"github.com/go-playground/validator/v10"
)

type Hoge struct {
	Items1 []string `validate:"gtecsfield=Items2"`
	Items2 []string
}

type Fuga struct {
	Items1 []string `validate:"gtefield=Items2"`
	Items2 []string
}

func main() {
	validate := validator.New()

	hoge := Hoge{
		Items1: []string{"A", "B"},
		Items2: []string{"A", "B", "C"},
	}

	if err := validate.Struct(hoge); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("hoge errs=%+v\n", errrs)
		}
	}

	fuga := Fuga{
		Items1: []string{"A", "B"},
		Items2: []string{"A", "B", "C"},
	}

	if err := validate.Struct(fuga); err != nil {
		errs := err.(validator.ValidationErrors)
		for _, errrs := range errs {
			fmt.Printf("fuga errs=%+v\n", errrs) // Items2でバリデーション違反になってほしいがならない
		}
	}
}

$ go run main.go
hoge errs=Key: 'Hoge.Items1' Error:Field validation for 'Items1' failed on the 'gtecsfield' tag

まとめ

gtecsfieldltcsfieldといったcs付きのタグは Array, Slice, Map の場合にlenを見てくれるのが違い。

基本的には cs 付きのタグを使っておけば良さそう。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0