Skip to content

Commit

Permalink
Merge pull request #1 from orsinium-labs/any-of
Browse files Browse the repository at this point in the history
Add AnyOf
  • Loading branch information
orsinium authored Nov 24, 2024
2 parents 1c3538b + eafaf6b commit 75a8bc7
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 4 deletions.
29 changes: 29 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# https://taskfile.dev
version: "3"

tasks:
release:
desc: Tag and upload release
cmds:
- which gh
- test v{{.CLI_ARGS}}
- git tag v{{.CLI_ARGS}}
- git push
- git push --tags
- gh release create --generate-notes v{{.CLI_ARGS}}

lint:
desc: Run Go linters
cmds:
- golangci-lint run

test:
desc: Run go tests with coverage and timeout and without cache
cmds:
- go test -count 1 -cover -timeout 1s ./...

all:
desc: Run all tests and linters
cmds:
- task: lint
- task: test
39 changes: 39 additions & 0 deletions valdo/composers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type allOf struct {
vs []Validator
}

// AllOf requires all of the given validators to pass.
func AllOf(vs ...Validator) Validator {
return allOf{vs: vs}
}
Expand All @@ -32,6 +33,44 @@ func (n allOf) Schema() jsony.Object {
}
}

type anyOf struct {
vs []Validator
}

// Nullable allows null (nil) value for the given validator.
func Nullable(v Validator) Validator {
return AnyOf(v, Null())
}

// AllOf requires at least one of the given validators to pass.
func AnyOf(vs ...Validator) Validator {
return anyOf{vs: vs}
}

// Validate implements [Validator].
func (n anyOf) Validate(data any) Error {
errors := Errors{}
for _, v := range n.vs {
err := v.Validate(data)
if err == nil {
return nil
}
errors.Add(err)
}
return ErrAnyOf{Errors: errors}
}

// Schema implements [Validator].
func (n anyOf) Schema() jsony.Object {
ss := make(jsony.Array[jsony.Object], len(n.vs))
for i, v := range n.vs {
ss[i] = v.Schema()
}
return jsony.Object{
jsony.Field{K: "anyOf", V: ss},
}
}

type notType struct {
v Validator
}
Expand Down
59 changes: 59 additions & 0 deletions valdo/composers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package valdo_test

import (
"testing"

"github.com/orsinium-labs/valdo/valdo"
)

func TestAllOf(t *testing.T) {
t.Parallel()
val := valdo.AllOf(
valdo.Int(valdo.Min(2)),
valdo.Int(valdo.Max(4)),
)
noErr(valdo.Validate(val, []byte(`2`)))
noErr(valdo.Validate(val, []byte(`3`)))
noErr(valdo.Validate(val, []byte(`4`)))
isErr[valdo.ErrMin](valdo.Validate(val, []byte(`1`)))
isErr[valdo.ErrMax](valdo.Validate(val, []byte(`5`)))
isEq(string(valdo.Schema(val)), `{"allOf":[{"type":"integer","minimum":2},{"type":"integer","maximum":4}]}`)
}

func TestAnyOf(t *testing.T) {
t.Parallel()
val := valdo.AnyOf(
valdo.Int(valdo.Min(5)),
valdo.Int(valdo.Max(2)),
)
noErr(valdo.Validate(val, []byte(`1`)))
noErr(valdo.Validate(val, []byte(`2`)))
noErr(valdo.Validate(val, []byte(`5`)))
noErr(valdo.Validate(val, []byte(`5`)))
isErr[valdo.ErrAnyOf](valdo.Validate(val, []byte(`3`)))
isErr[valdo.ErrAnyOf](valdo.Validate(val, []byte(`4`)))
isEq(string(valdo.Schema(val)), `{"anyOf":[{"type":"integer","minimum":5},{"type":"integer","maximum":2}]}`)
}

func TestNot(t *testing.T) {
t.Parallel()
val := valdo.Not(
valdo.Int(valdo.Min(4)),
)
noErr(valdo.Validate(val, []byte(`1`)))
noErr(valdo.Validate(val, []byte(`2`)))
noErr(valdo.Validate(val, []byte(`3`)))
isErr[valdo.ErrNot](valdo.Validate(val, []byte(`4`)))
isErr[valdo.ErrNot](valdo.Validate(val, []byte(`5`)))
isEq(string(valdo.Schema(val)), `{"not":{"type":"integer","minimum":4}}`)
}

func TestNullable(t *testing.T) {
t.Parallel()
val := valdo.Nullable(valdo.Int())
noErr(valdo.Validate(val, []byte(`1`)))
noErr(valdo.Validate(val, []byte(`2`)))
noErr(valdo.Validate(val, []byte(`3`)))
noErr(valdo.Validate(val, []byte(`null`)))
isErr[valdo.ErrAnyOf](valdo.Validate(val, []byte(`false`)))
}
Loading

0 comments on commit 75a8bc7

Please sign in to comment.