Skip to content

Commit

Permalink
feat: update sliceg pkg and validator pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
sliveryou committed Mar 6, 2024
1 parent 92803d4 commit 8ab06bd
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 112 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ func BinarySearch[T constraints.Ordered](x []T, target T) (int, bool)
func BinarySearchFunc[E, T any](x []E, target T, cmp func(a E, b T) int) (int, bool)
func Clip[T any](s []T) []T
func Clone[T any](s []T, needInit ...bool) []T
func Compact[T comparable](s []T) []T
func CompactFunc[T any](s []T, f func(v T) bool) []T
func Contain[T comparable](s []T, v T) bool
func ContainFunc[T any](s []T, f func(v T) bool) bool
func Count[T comparable](s []T) map[T]int
Expand Down Expand Up @@ -614,4 +616,10 @@ type IdCard
type USCC
func NewUSCC(uscc string) USCC
func (uscc USCC) IsValid() bool
type Validator
func MustNewValidator() *Validator
func NewValidator() (*Validator, error)
func (v *Validator) Translate(err error) error
func (v *Validator) TranslateAll(err error) error
func (v *Validator) Validate(r *http.Request, data any) error
```
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ require (
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20230420155350-5d9e357047b1 h1:esPLYTcXPu8wpTcWCNGwSDTodgJwTTFNfeELKb4ewTg=
golang.org/x/exp v0.0.0-20230420155350-5d9e357047b1/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
29 changes: 28 additions & 1 deletion sliceg/sliceg.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func Extract[T any](s []T, n int) []T {
return es
}

// Fill returns slice filled with v,
// Fill returns the slice filled with v,
// where n is the number of v should be filled.
func Fill[T any](v T, n int) []T {
if n < 0 {
Expand Down Expand Up @@ -282,6 +282,33 @@ func SubsetFunc[T any](slice, subset []T, cmp func(a, b T) int) bool {
return true
}

// Compact returns the slice that all zero values removed.
func Compact[T comparable](s []T) []T {
var zero T
cs := make([]T, 0, len(s))

for _, v := range s {
if v != zero {
cs = append(cs, v)
}
}

return cs
}

// CompactFunc returns the slice that all satisfies f(v) values removed.
func CompactFunc[T any](s []T, f func(v T) bool) []T {
cs := make([]T, 0, len(s))

for _, v := range s {
if !f(v) {
cs = append(cs, v)
}
}

return cs
}

// Clone returns a copy of the slice.
// The elements are copied using assignment, so this is a shallow clone.
func Clone[T any](s []T, needInit ...bool) []T {
Expand Down
28 changes: 28 additions & 0 deletions sliceg/sliceg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,34 @@ func TestSubsetFunc(t *testing.T) {
assert.False(t, SubsetFunc(s2, []string{"y", "o", "u"}, strings.Compare))
}

func TestCompact(t *testing.T) {
s1 := []int64{3, 0, 6, 0, 9, 0}
assert.Equal(t, []int64{3, 6, 9}, Compact(s1))

s2 := []string{"a", "", "", "b", "", "c"}
assert.Equal(t, []string{"a", "b", "c"}, Compact(s2))

s3 := []string{"", "", "", "a"}
assert.Equal(t, []string{"a"}, Compact(s3))
}

func TestCompactFunc(t *testing.T) {
s1 := []int64{3, 0, 6, 0, 9, 0}
assert.Equal(t, []int64{3, 6, 9}, CompactFunc(s1, func(v int64) bool {
return v == 0
}))

s2 := []string{"a", "", "", "b", "", "c"}
assert.Equal(t, []string{"a", "b", "c"}, CompactFunc(s2, func(v string) bool {
return v == ""
}))

s3 := []string{"", "", "", "a"}
assert.Equal(t, []string{"a"}, CompactFunc(s3, func(v string) bool {
return v == ""
}))
}

func TestClone(t *testing.T) {
s1 := []int{1, 2, 3}
s2 := Clone(s1)
Expand Down
177 changes: 115 additions & 62 deletions validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package validator

import (
"errors"
"net/http"
"reflect"
"regexp"
"strings"
Expand All @@ -12,6 +13,9 @@ import (
zht "github.com/go-playground/validator/v10/translations/zh"
)

// ErrUnexpected unexpected error.
var ErrUnexpected = errors.New("参数校验出错")

const (
bankcardRegexString = "^[0-9]{15,19}$"
corpaccountRegexString = "^[0-9]{9,25}$"
Expand All @@ -20,11 +24,7 @@ const (
)

var (
// ErrUnexpected unexpected error.
ErrUnexpected = errors.New("参数校验出错")

ti ut.Translator
vi *validator.Validate
v = MustNewValidator()

bankcardRegex = regexp.MustCompile(bankcardRegexString)
corpaccountRegex = regexp.MustCompile(corpaccountRegexString)
Expand All @@ -39,13 +39,15 @@ var (
"PATCH": {},
"OPTIONS": {},
}

validatorFuncMap = map[string]validator.Func{
"idcard": idcard,
"bankcard": bankcard,
"uscc": uscc,
"corpaccount": corpaccount,
"httpmethod": httpmethod,
}

defaultTags = []string{
"skip_unless",
"eq_ignore_case",
Expand Down Expand Up @@ -113,6 +115,107 @@ var (
}
)

// Validator represents the validator structure.
type Validator struct {
V *validator.Validate
T ut.Translator
}

// NewValidator new a validator.
func NewValidator() (*Validator, error) {
vi := validator.New()
vi.SetTagName("validate")
vi.RegisterTagNameFunc(getLabelTagName)

zhi := zh.New()
uti := ut.New(zhi)
ti, _ := uti.GetTranslator("zh")

if err := zht.RegisterDefaultTranslations(vi, ti); err != nil {
return nil, err
}

for tag, fn := range validatorFuncMap {
if err := vi.RegisterValidation(tag, fn); err != nil {
return nil, err
}
if err := registerTranslation(tag, vi, ti, true); err != nil {
return nil, err
}
}

for _, defaultTag := range defaultTags {
if err := registerTranslation(defaultTag, vi, ti, false); err != nil {
return nil, err
}
}

return &Validator{
V: vi,
T: ti,
}, nil
}

// MustNewValidator must new a validator.
func MustNewValidator() *Validator {
v, err := NewValidator()
if err != nil {
panic(err)
}

return v
}

// Validate validates the request and parsed data.
func (v *Validator) Validate(r *http.Request, data any) error {
return v.Translate(v.V.Struct(data))
}

// Translate translates the validation errors.
func (v *Validator) Translate(err error) error {
if err != nil {
var (
es validateErrors
ves validator.ValidationErrors
)

if errors.As(err, &ves) {
for _, ve := range ves {
es = append(es, ve.Translate(v.T))
}
}

return es
}

return nil
}

// TranslateAll translates all validation errors.
func (v *Validator) TranslateAll(err error) error {
if err != nil {
var (
es []string
ves validator.ValidationErrors
)

if errors.As(err, &ves) {
for _, ve := range ves {
es = append(es, ve.Translate(v.T))
}
}

if len(es) == 0 {
return ErrUnexpected
}

return errors.New(strings.Join(es, ","))
}

return nil
}

// validateErrors represents the validation error strings.
type validateErrors []string

// Error returns the validation error string and implement the error interface,
Expand All @@ -127,6 +230,10 @@ func (ves validateErrors) Error() string {

// ParseErr parses the content of validation error.
func ParseErr(err error) string {
if err == nil {
return ""
}

var ves validateErrors
ok := errors.As(err, &ves)
if ok && len(ves) > 0 {
Expand All @@ -136,66 +243,19 @@ func ParseErr(err error) string {
return err.Error()
}

func init() {
var err error
vi = validator.New()
vi.SetTagName("validate")
vi.RegisterTagNameFunc(getLabelTagName)

zhi := zh.New()
uti := ut.New(zhi)
ti, _ = uti.GetTranslator("zh")

err = zht.RegisterDefaultTranslations(vi, ti)
checkErr(err)

for tag, fn := range validatorFuncMap {
err = vi.RegisterValidation(tag, fn)
checkErr(err)
err = registerTranslation(tag, vi, ti, true)
checkErr(err)
}
for _, defaultTag := range defaultTags {
_ = registerTranslation(defaultTag, vi, ti, false)
}
}

// Verify checks the data validity of the exportable field of the structure according to the validate tag.
func Verify(obj interface{}) error {
return convertErr(vi.Struct(obj))
return v.Translate(v.V.Struct(obj))
}

// VerifyVar checks the data validity of the field according to the validate tag.
func VerifyVar(field interface{}, tag string) error {
return convertErr(vi.Var(field, tag))
return v.Translate(v.V.Var(field, tag))
}

// VerifyVarWithValue checks the data validity of the field against another field according to the validate tag.
func VerifyVarWithValue(field, other interface{}, tag string) error {
return convertErr(vi.VarWithValue(field, other, tag))
}

// convertErr converts err to validation error.
func convertErr(err error) error {
if err != nil {
var (
ves validateErrors
ive *validator.InvalidValidationError
ve validator.ValidationErrors
)
if errors.As(err, &ive) {
return ves
}
if errors.As(err, &ve) {
for _, err := range ve {
ves = append(ves, err.Translate(ti))
}
}

return ves
}

return nil
return v.Translate(v.V.VarWithValue(field, other, tag))
}

// getLabelTagName gets the label name.
Expand Down Expand Up @@ -259,10 +319,3 @@ func httpmethod(fl validator.FieldLevel) bool {
_, ok := httpMethodMap[strings.ToUpper(fl.Field().String())]
return ok
}

// checkErr checks the err.
func checkErr(err error) {
if err != nil {
panic(err)
}
}
Loading

0 comments on commit 8ab06bd

Please sign in to comment.