Skip to content

Commit

Permalink
Merge pull request #1 from behzadsh/develop
Browse files Browse the repository at this point in the history
Beta Release
  • Loading branch information
behzadsh authored Dec 29, 2022
2 parents 0a621fe + c3406a5 commit 4d448e2
Show file tree
Hide file tree
Showing 114 changed files with 9,132 additions and 3 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: '^1.16'
go-version: '^1.18'
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup golangci-lint
Expand All @@ -25,7 +25,7 @@ jobs:
needs: lint
strategy:
matrix:
go: [1.16, 1.17, 1.18, 1.19]
go: [1.18, 1.19]
runs-on: ubuntu-latest
steps:
- name: Set up Go ${{ matrix.go }}
Expand Down
26 changes: 26 additions & 0 deletions bag/error_bag.go
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
}
89 changes: 89 additions & 0 deletions bag/input_bag.go
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
}
16 changes: 15 additions & 1 deletion go.mod
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
)
33 changes: 33 additions & 0 deletions go.sum
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=
81 changes: 81 additions & 0 deletions init.go
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{},
}
}
32 changes: 32 additions & 0 deletions init_test.go
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"])
}
21 changes: 21 additions & 0 deletions result.go
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...)
}
22 changes: 22 additions & 0 deletions result_test.go
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())
}
51 changes: 51 additions & 0 deletions rule_name.go
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)
}))
}
Loading

0 comments on commit 4d448e2

Please sign in to comment.