Skip to content

constraint.ConditionalConstraint

marrow16 edited this page Jan 21, 2023 · 4 revisions

Prev Home Next

Constraint: ConditionalConstraint

Description

Is a special constraint that wraps another constraint - but the wrapped constraint is only checked when the specified when conditions or other properties expression are met

V8n Tag Abbreviation

cond

Fields

Field Type Description
When []string is the condition tokens that determine when the wrapped constraint is checked
Others OthersExpr is the others (properties) expression to be evaluated to determine when the wrapped constraint is checked
Constraint Constraint is the wrapped constraint
FailNotMet bool specifies that the conditional constraint should fail if the conditions are not met
By default, if the conditions are not met the conditional constraint passes (without calling the wrapped constraint)
NotMetMessage string is the message used when FailNotMet is set and the conditions are not met

Note: Either or both the When/Others fields can be set.

Examples

Using When condition (programmatic) example...
package main

import (
    "fmt"
    "net/http"
    "strings"

    "github.com/marrow16/valix"
)

func main() {
    validator := &valix.Validator{
        Properties: valix.Properties{
            "foo": {
                Type:        valix.JsonString,
                Constraints: valix.Constraints{
                    &valix.ConditionalConstraint{
                        When:       []string{"METHOD_POST"},
                        Constraint: &valix.StringNotBlank{},
                    },
                },
            },
        },
    }

    req := buildSimulatedHttpReq("POST", `{"foo": ""}`)
    ok, violations, _ := validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    req = buildSimulatedHttpReq("POST", `{"foo": "not blank now"}`)
    ok, violations, _ = validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    req = buildSimulatedHttpReq("PATCH", `{"foo": ""}`)
    ok, violations, _ = validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }
}

func buildSimulatedHttpReq(method string, body string) *http.Request {
    req, _ := http.NewRequest(method, "example.com/test", strings.NewReader(body))
    return req
}

try on go-playground

Using Others expression (programmatic) example...
package main

import (
    "fmt"

    "github.com/marrow16/valix"
)

func main() {
    validator := &valix.Validator{
        Properties: valix.Properties{
            "foo": {
                Type: valix.JsonString,
                Constraints: valix.Constraints{
                    &valix.ConditionalConstraint{
                        Others:     valix.MustParseExpression("(bar && !baz) || (!bar && baz)"),
                        Constraint: &valix.StringNotBlank{},
                    },
                },
            },
            "bar": {
                Type: valix.JsonString,
            },
            "baz": {
                Type: valix.JsonString,
            },
        },
    }

    ok, violations, _ := validator.ValidateString(`{"foo": "", "bar": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": "", "baz": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": ""}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": "", "bar": "here", "baz": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }
}

try on go-playground


Using When condition (struct v8n tag) example...
package main

import (
    "fmt"
    "net/http"
    "strings"

    "github.com/marrow16/valix"
)

type MyStruct struct {
    Foo string `json:"foo" v8n:"&[METHOD_POST]StringNotBlank{}"`
}

var validator = valix.MustCompileValidatorFor(MyStruct{}, nil)

func main() {
    req := buildSimulatedHttpReq("POST", `{"foo": ""}`)
    ok, violations, _ := validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    req = buildSimulatedHttpReq("POST", `{"foo": "not blank now"}`)
    ok, violations, _ = validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    req = buildSimulatedHttpReq("PATCH", `{"foo": ""}`)
    ok, violations, _ = validator.RequestValidate(req)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }
}

func buildSimulatedHttpReq(method string, body string) *http.Request {
    req, _ := http.NewRequest(method, "example.com/test", strings.NewReader(body))
    return req
}

try on go-playground

Using Others expression (struct v8n tag) example...
package main

import (
    "fmt"

    "github.com/marrow16/valix"
)

type MyStruct struct {
    Foo string `json:"foo" v8n:"&<(bar && !baz) || (!bar && baz)>StringNotBlank{}"`
    Bar string `json:"bar"`
    Baz string `json:"baz"`
}

var validator = valix.MustCompileValidatorFor(MyStruct{}, nil)

func main() {
    ok, violations, _ := validator.ValidateString(`{"foo": "", "bar": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": "", "baz": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": ""}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }

    ok, violations, _ = validator.ValidateString(`{"foo": "", "bar": "here", "baz": "here"}`)
    fmt.Printf("Passed? %v\n", ok)
    for i, v := range violations {
        fmt.Printf("Violation[%d] Message: %s, Property: %s, Path: %s\n", i+1, v.Message, v.Property, v.Path)
    }
}

try on go-playground

Clone this wiki locally