Skip to content

Commit

Permalink
feat: add new rule required-if-all for package gvalid (#3455)
Browse files Browse the repository at this point in the history
  • Loading branch information
cococolanosugar authored Apr 11, 2024
1 parent 2523889 commit 91f449d
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 17 deletions.
23 changes: 23 additions & 0 deletions util/gvalid/gvalid_z_example_feature_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,29 @@ func ExampleRule_RequiredIf() {
// The WifeName field is required
}

func ExampleRule_RequiredIfAll() {
type BizReq struct {
ID uint `v:"required" dc:"Your ID"`
Name string `v:"required" dc:"Your name"`
Age int `v:"required" dc:"Your age"`
MoreInfo string `v:"required-if-all:id,1,age,18" dc:"Your more info"`
}
var (
ctx = context.Background()
req = BizReq{
ID: 1,
Name: "test",
Age: 18,
}
)
if err := g.Validator().Data(req).Run(ctx); err != nil {
fmt.Println(err)
}

// Output:
// The MoreInfo field is required
}

func ExampleRule_RequiredUnless() {
type BizReq struct {
ID uint `v:"required" dc:"Your ID"`
Expand Down
10 changes: 10 additions & 0 deletions util/gvalid/gvalid_z_unit_feature_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ func Test_RequiredIf(t *testing.T) {
})
}

func Test_RequiredIfAll(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
rule := "required-if-all:id,1,age,18"
t.Assert(g.Validator().Data("").Assoc(g.Map{"id": 1}).Rules(rule).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"age": 18}).Rules(rule).Run(ctx), nil)
t.Assert(g.Validator().Data("").Assoc(g.Map{"id": 0, "age": 20}).Rules(rule).Run(ctx), nil)
t.AssertNE(g.Validator().Data("").Assoc(g.Map{"id": 1, "age": 18}).Rules(rule).Run(ctx), nil)
})
}

func Test_RequiredUnless(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
rule := "required-unless:id,1,age,18"
Expand Down
43 changes: 26 additions & 17 deletions util/gvalid/internal/builtin/builtin_required_if.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import (
"errors"
"strings"

"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)

// RuleRequiredIf implements `required-if` rule:
// Required unless all given field and its value are equal.
// Required if any of given field and its value are equal.
//
// Format: required-if:field,value,...
// Example: required-if: id,1,age,18
// Example: required-if:id,1,age,18
type RuleRequiredIf struct{}

func init() {
Expand All @@ -40,24 +42,31 @@ func (r RuleRequiredIf) Run(in RunInput) error {
foundValue interface{}
dataMap = in.Data.Map()
)
if len(array)%2 != 0 {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid "%s" rule pattern: %s`,
r.Name(),
in.RulePattern,
)
}
// It supports multiple field and value pairs.
if len(array)%2 == 0 {
for i := 0; i < len(array); {
tk := array[i]
tv := array[i+1]
_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)
if in.Option.CaseInsensitive {
required = strings.EqualFold(tv, gconv.String(foundValue))
} else {
required = strings.Compare(tv, gconv.String(foundValue)) == 0
}
if required {
break
}
i += 2
for i := 0; i < len(array); {
var (
tk = array[i]
tv = array[i+1]
)
_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)
if in.Option.CaseInsensitive {
required = strings.EqualFold(tv, gconv.String(foundValue))
} else {
required = strings.Compare(tv, gconv.String(foundValue)) == 0
}
if required {
break
}
i += 2
}

if required && isRequiredEmpty(in.Value.Val()) {
return errors.New(in.Message)
}
Expand Down
75 changes: 75 additions & 0 deletions util/gvalid/internal/builtin/builtin_required_if_all.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package builtin

import (
"errors"
"strings"

"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)

// RuleRequiredIfAll implements `required-if-all` rule:
// Required if all given field and its value are equal.
//
// Format: required-if-all:field,value,...
// Example: required-if-all:id,1,age,18
type RuleRequiredIfAll struct{}

func init() {
Register(RuleRequiredIfAll{})
}

func (r RuleRequiredIfAll) Name() string {
return "required-if-all"
}

func (r RuleRequiredIfAll) Message() string {
return "The {field} field is required"
}

func (r RuleRequiredIfAll) Run(in RunInput) error {
var (
required = true
array = strings.Split(in.RulePattern, ",")
foundValue interface{}
dataMap = in.Data.Map()
)
if len(array)%2 != 0 {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
`invalid "%s" rule pattern: %s`,
r.Name(),
in.RulePattern,
)
}
for i := 0; i < len(array); {
var (
tk = array[i]
tv = array[i+1]
eq bool
)
_, foundValue = gutil.MapPossibleItemByKey(dataMap, tk)
if in.Option.CaseInsensitive {
eq = strings.EqualFold(tv, gconv.String(foundValue))
} else {
eq = strings.Compare(tv, gconv.String(foundValue)) == 0
}
if !eq {
required = false
break
}
i += 2
}
if required && isRequiredEmpty(in.Value.Val()) {
return errors.New(in.Message)
}
return nil
}

0 comments on commit 91f449d

Please sign in to comment.