-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from behzadsh/develop
Beta Release
- Loading branch information
Showing
114 changed files
with
9,132 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package bag | ||
|
||
type ErrorBag map[string][]string | ||
|
||
func (b ErrorBag) IsEmpty() bool { | ||
return len(b) == 0 | ||
} | ||
|
||
func (b ErrorBag) Add(selector string, msg ...string) { | ||
b[selector] = append(b[selector], msg...) | ||
} | ||
|
||
func (b ErrorBag) FirstOf(name string) string { | ||
msg, ok := b[name] | ||
if !ok { | ||
return "" | ||
} | ||
|
||
return msg[0] | ||
} | ||
|
||
func (b ErrorBag) Has(name string) bool { | ||
_, ok := b[name] | ||
|
||
return ok | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package bag | ||
|
||
import ( | ||
"encoding/json" | ||
"strings" | ||
|
||
"github.com/spf13/cast" | ||
) | ||
|
||
type InputBag map[string]any | ||
|
||
func (b InputBag) Get(selector string) (any, bool) { | ||
parts := strings.Split(selector, ".") | ||
|
||
if len(parts) == 1 { | ||
v, ok := b[selector] | ||
return v, ok | ||
} | ||
|
||
base := b[parts[0]] | ||
for i := 1; i < len(parts); i++ { | ||
if k, err := cast.ToIntE(parts[i]); err == nil { | ||
tmp, err := cast.ToSliceE(base) | ||
if err != nil || len(tmp) <= k { | ||
return nil, false | ||
} | ||
|
||
base = tmp[k] | ||
continue | ||
} | ||
|
||
tmp, ok := base.(map[string]any) | ||
if !ok { | ||
return nil, false | ||
} | ||
|
||
v, ok := tmp[parts[i]] | ||
if !ok { | ||
return nil, false | ||
} | ||
base = v | ||
} | ||
|
||
return base, base != nil | ||
} | ||
|
||
func (b InputBag) Has(selector string) bool { | ||
parts := strings.Split(selector, ".") | ||
|
||
if len(parts) == 1 { | ||
_, ok := b[selector] | ||
return ok | ||
} | ||
|
||
base := b[parts[0]] | ||
for i := 1; i < len(parts); i++ { | ||
if k, err := cast.ToIntE(parts[i]); err == nil { | ||
tmp, err := cast.ToSliceE(base) | ||
if err != nil || len(tmp) <= k { | ||
return false | ||
} | ||
|
||
base = tmp[k] | ||
continue | ||
} | ||
|
||
tmp, ok := base.(map[string]any) | ||
if !ok { | ||
return false | ||
} | ||
|
||
v, ok := tmp[parts[i]] | ||
if !ok { | ||
return false | ||
} | ||
base = v | ||
} | ||
|
||
return base != nil | ||
} | ||
|
||
func NewInputBagFromStruct(input any) InputBag { | ||
b, _ := json.Marshal(input) | ||
|
||
var bag InputBag | ||
_ = json.Unmarshal(b, &bag) | ||
|
||
return bag | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,17 @@ | ||
module github.com/behzadsh/go.validator | ||
|
||
go 1.19 | ||
go 1.18 | ||
|
||
require ( | ||
github.com/behzadsh/go.localization v1.0.0 | ||
github.com/spf13/cast v1.5.0 | ||
github.com/stretchr/testify v1.8.1 | ||
github.com/thoas/go-funk v0.9.2 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v2 v2.4.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
github.com/behzadsh/go.localization v1.0.0 h1:tKComBbksYGsbExZvTRIq1WqW/7ITQpIoezpiK5ge5I= | ||
github.com/behzadsh/go.localization v1.0.0/go.mod h1:4d37qq5QyJw/zygHl0mNPQ7p9tAv2gHnqjWkLDKQaJ0= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= | ||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= | ||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= | ||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= | ||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= | ||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
github.com/thoas/go-funk v0.9.2 h1:oKlNYv0AY5nyf9g+/GhMgS/UO2ces0QRdPKwkhY3VCk= | ||
github.com/thoas/go-funk v0.9.2/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package validation | ||
|
||
import "github.com/behzadsh/go.validator/rules" | ||
|
||
var defaultLocale string | ||
|
||
var stopOnFirstFailure bool | ||
|
||
var registry map[string]rules.Rule | ||
|
||
func init() { | ||
// initiate with default rules | ||
registerDefaultRules() | ||
|
||
defaultLocale = "en" | ||
} | ||
|
||
func SetDefaultLocale(locale string) { | ||
defaultLocale = locale | ||
} | ||
|
||
func StopOnFirstFailure() { | ||
stopOnFirstFailure = true | ||
} | ||
|
||
func Register(ruleName string, rule rules.Rule) { | ||
registry[ruleName] = rule | ||
} | ||
|
||
func registerDefaultRules() { | ||
registry = map[string]rules.Rule{ | ||
"after": &rules.After{}, | ||
"afterOrEqual": &rules.AfterOrEqual{}, | ||
"alpha": &rules.Alpha{}, | ||
"alphaDash": &rules.AlphaDash{}, | ||
"alphaNum": &rules.AlphaNum{}, | ||
"alphaSpace": &rules.AlphaSpace{}, | ||
"array": &rules.Array{}, | ||
"before": &rules.Before{}, | ||
"beforeOrEqual": &rules.BeforeOrEqual{}, | ||
"between": &rules.Between{}, | ||
"boolean": &rules.Boolean{}, | ||
"dateTime": &rules.DateTime{}, | ||
"different": &rules.Different{}, | ||
"digits": &rules.Digits{}, | ||
"digitsBetween": &rules.DigitsBetween{}, | ||
"email": &rules.Email{}, | ||
"endsWith": &rules.EndsWith{}, | ||
"gt": &rules.GreaterThan{}, | ||
"gte": &rules.GreaterThanEqual{}, | ||
"in": &rules.In{}, | ||
"integer": &rules.Integer{}, | ||
"length": &rules.Length{}, | ||
"lowercase": &rules.Lowercase{}, | ||
"lt": &rules.LessThan{}, | ||
"lte": &rules.LessThanEqual{}, | ||
"max": &rules.Max{}, | ||
"maxDigits": &rules.MaxDigits{}, | ||
"maxLength": &rules.MaxLength{}, | ||
"min": &rules.Min{}, | ||
"minDigits": &rules.MinDigits{}, | ||
"minLength": &rules.MinLength{}, | ||
"neq": &rules.NotEqual{}, | ||
"notIn": &rules.NotIn{}, | ||
"notRegex": &rules.NotRegex{}, | ||
"numeric": &rules.Numeric{}, | ||
"regex": &rules.Regex{}, | ||
"required": &rules.Required{}, | ||
"requiredIf": &rules.RequiredIf{}, | ||
"requiredUnless": &rules.RequiredUnless{}, | ||
"requiredWith": &rules.RequiredWith{}, | ||
"requiredWithAll": &rules.RequiredWithAll{}, | ||
"requiredWithout": &rules.RequiredWithout{}, | ||
"requiredWithoutAll": &rules.RequiredWithoutAll{}, | ||
"sameAs": &rules.SameAs{}, | ||
"startsWith": &rules.StartsWith{}, | ||
"string": &rules.String{}, | ||
"uppercase": &rules.Uppercase{}, | ||
"uuid": &rules.UUID{}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package validation | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/behzadsh/go.validator/rules" | ||
) | ||
|
||
func TestSetDefaultLocale(t *testing.T) { | ||
SetDefaultLocale("es") | ||
|
||
assert.Equal(t, "es", defaultLocale) | ||
} | ||
|
||
func TestStopOnFirstFailure(t *testing.T) { | ||
StopOnFirstFailure() | ||
|
||
assert.True(t, stopOnFirstFailure) | ||
} | ||
|
||
func TestRegister(t *testing.T) { | ||
// empty registry | ||
registry = map[string]rules.Rule{} | ||
|
||
rule := &rules.After{} | ||
Register("after", rule) | ||
|
||
assert.Equal(t, rule, registry["after"]) | ||
assert.NotEqual(t, rule, registry["something"]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package validation | ||
|
||
import "github.com/behzadsh/go.validator/bag" | ||
|
||
type Result struct { | ||
Errors bag.ErrorBag | ||
} | ||
|
||
func NewResult() Result { | ||
return Result{ | ||
Errors: make(bag.ErrorBag), | ||
} | ||
} | ||
|
||
func (r Result) Failed() bool { | ||
return !r.Errors.IsEmpty() | ||
} | ||
|
||
func (r Result) addError(selector string, errorMsg ...string) { | ||
r.Errors.Add(selector, errorMsg...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package validation | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestNewResult(t *testing.T) { | ||
res := NewResult() | ||
|
||
assert.NotNil(t, res) | ||
assert.Empty(t, res.Errors) | ||
} | ||
|
||
func TestResult_Failed(t *testing.T) { | ||
res := NewResult() | ||
assert.False(t, res.Failed()) | ||
|
||
res.addError("something", "error") | ||
assert.True(t, res.Failed()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package validation | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/spf13/cast" | ||
"github.com/thoas/go-funk" | ||
|
||
"github.com/behzadsh/go.validator/rules" | ||
"github.com/behzadsh/go.validator/translation" | ||
) | ||
|
||
type ruleIndicator string | ||
|
||
func (r ruleIndicator) load(locale string) rules.Rule { | ||
name, params := r.parseRuleParams() | ||
rule, ok := registry[name] | ||
if !ok || rule == nil { | ||
panic(fmt.Errorf("rule %s is not registered", name)) | ||
} | ||
|
||
if ruleWithParams, ok := rule.(rules.RuleWithParams); ok { | ||
paramNum := len(params) | ||
minRequiredParams := ruleWithParams.MinRequiredParams() | ||
|
||
if paramNum < minRequiredParams { | ||
panic(fmt.Errorf("rule %s need at least %d parameter, got %d", name, minRequiredParams, paramNum)) | ||
} | ||
|
||
ruleWithParams.AddParams(params) | ||
} | ||
|
||
if translatableRule, ok := rule.(translation.TranslatableRule); ok { | ||
translatableRule.AddLocale(locale) | ||
translatableRule.AddTranslationFunction(translation.GetDefaultTranslatorFunc()) | ||
} | ||
|
||
return rule | ||
} | ||
|
||
func (r ruleIndicator) parseRuleParams() (string, []string) { | ||
parts := strings.SplitN(string(r), ":", 2) | ||
if len(parts) == 1 { | ||
return parts[0], nil | ||
} | ||
|
||
return parts[0], cast.ToStringSlice(funk.Map(strings.Split(parts[1], ","), func(s string) string { | ||
return strings.TrimSpace(s) | ||
})) | ||
} |
Oops, something went wrong.