refactor: rename semantics of datatype to validator.Type
This commit is contained in:
parent
0ee814abbe
commit
defa2c3645
10
README.md
10
README.md
|
@ -89,16 +89,16 @@ import (
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra"
|
"github.com/xdrm-io/aicra"
|
||||||
"github.com/xdrm-io/aicra/api"
|
"github.com/xdrm-io/aicra/api"
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
builder := &aicra.Builder{}
|
builder := &aicra.Builder{}
|
||||||
|
|
||||||
// register data validators
|
// add custom type validators
|
||||||
builder.AddType(builtin.BoolDataType{})
|
builder.Validate(builtin.BoolDataType{})
|
||||||
builder.AddType(builtin.UintDataType{})
|
builder.Validate(builtin.UintDataType{})
|
||||||
builder.AddType(builtin.StringDataType{})
|
builder.Validate(builtin.StringDataType{})
|
||||||
|
|
||||||
// load your configuration
|
// load your configuration
|
||||||
config, err := os.Open("api.json")
|
config, err := os.Open("api.json")
|
||||||
|
|
12
builder.go
12
builder.go
|
@ -5,9 +5,9 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
|
||||||
"github.com/xdrm-io/aicra/internal/config"
|
"github.com/xdrm-io/aicra/internal/config"
|
||||||
"github.com/xdrm-io/aicra/internal/dynfunc"
|
"github.com/xdrm-io/aicra/internal/dynfunc"
|
||||||
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Builder for an aicra server
|
// Builder for an aicra server
|
||||||
|
@ -31,18 +31,18 @@ type apiHandler struct {
|
||||||
dyn *dynfunc.Handler
|
dyn *dynfunc.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddType adds an available datatype to the api definition
|
// Validate adds an available Type to validate in the api definition
|
||||||
func (b *Builder) AddType(t datatype.T) error {
|
func (b *Builder) Validate(t validator.Type) error {
|
||||||
if b.conf == nil {
|
if b.conf == nil {
|
||||||
b.conf = &config.Server{}
|
b.conf = &config.Server{}
|
||||||
}
|
}
|
||||||
if b.conf.Services != nil {
|
if b.conf.Services != nil {
|
||||||
return errLateType
|
return errLateType
|
||||||
}
|
}
|
||||||
if b.conf.Types == nil {
|
if b.conf.Validators == nil {
|
||||||
b.conf.Types = make([]datatype.T, 0)
|
b.conf.Validators = make([]validator.Type, 0)
|
||||||
}
|
}
|
||||||
b.conf.Types = append(b.conf.Types, t)
|
b.conf.Validators = append(b.conf.Validators, t)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,26 +8,26 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/api"
|
"github.com/xdrm-io/aicra/api"
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addBuiltinTypes(b *Builder) error {
|
func addBuiltinTypes(b *Builder) error {
|
||||||
if err := b.AddType(builtin.AnyDataType{}); err != nil {
|
if err := b.Validate(builtin.AnyDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.BoolDataType{}); err != nil {
|
if err := b.Validate(builtin.BoolDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.FloatDataType{}); err != nil {
|
if err := b.Validate(builtin.FloatDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.IntDataType{}); err != nil {
|
if err := b.Validate(builtin.IntDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.StringDataType{}); err != nil {
|
if err := b.Validate(builtin.StringDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.UintDataType{}); err != nil {
|
if err := b.Validate(builtin.UintDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -35,7 +35,7 @@ func addBuiltinTypes(b *Builder) error {
|
||||||
|
|
||||||
func TestAddType(t *testing.T) {
|
func TestAddType(t *testing.T) {
|
||||||
builder := &Builder{}
|
builder := &Builder{}
|
||||||
err := builder.AddType(builtin.BoolDataType{})
|
err := builder.Validate(builtin.BoolDataType{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ func TestAddType(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err)
|
t.Fatalf("unexpected error: %s", err)
|
||||||
}
|
}
|
||||||
err = builder.AddType(builtin.FloatDataType{})
|
err = builder.Validate(builtin.FloatDataType{})
|
||||||
if err != errLateType {
|
if err != errLateType {
|
||||||
t.Fatalf("expected <%v> got <%v>", errLateType, err)
|
t.Fatalf("expected <%v> got <%v>", errLateType, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package datatype
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validator returns whether a given value fulfills the datatype
|
|
||||||
// and casts the value into a common go type.
|
|
||||||
//
|
|
||||||
// for example, if a validator checks for upper case strings,
|
|
||||||
// whether the value is a []byte, a string or a []rune, if the
|
|
||||||
// value matches the validator's checks, it will be cast it into
|
|
||||||
// a common go type, say, string.
|
|
||||||
type Validator func(value interface{}) (cast interface{}, valid bool)
|
|
||||||
|
|
||||||
// T represents a datatype. The Build function returns a Validator if
|
|
||||||
// it manages types with the name `typeDefinition` (from the configuration field "type"); else it or returns NIL if the type
|
|
||||||
// definition does not match this datatype; the registry is passed to allow recursive datatypes (e.g. slices, structs, etc)
|
|
||||||
// The datatype's validator (when input is valid) must return a cast's go type matching the `Type() reflect.Type`
|
|
||||||
type T interface {
|
|
||||||
Type() reflect.Type
|
|
||||||
Build(typeDefinition string, registry ...T) Validator
|
|
||||||
}
|
|
|
@ -12,26 +12,26 @@ import (
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra"
|
"github.com/xdrm-io/aicra"
|
||||||
"github.com/xdrm-io/aicra/api"
|
"github.com/xdrm-io/aicra/api"
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addBuiltinTypes(b *aicra.Builder) error {
|
func addBuiltinTypes(b *aicra.Builder) error {
|
||||||
if err := b.AddType(builtin.AnyDataType{}); err != nil {
|
if err := b.Validate(builtin.AnyDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.BoolDataType{}); err != nil {
|
if err := b.Validate(builtin.BoolDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.FloatDataType{}); err != nil {
|
if err := b.Validate(builtin.FloatDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.IntDataType{}); err != nil {
|
if err := b.Validate(builtin.IntDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.StringDataType{}); err != nil {
|
if err := b.Validate(builtin.StringDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := b.AddType(builtin.UintDataType{}); err != nil {
|
if err := b.Validate(builtin.UintDataType{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -7,13 +7,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server definition
|
// Server definition
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Types []datatype.T
|
Validators []validator.Type
|
||||||
Services []*Service
|
Services []*Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a configuration into a server. Server.Types must be set beforehand to
|
// Parse a configuration into a server. Server.Types must be set beforehand to
|
||||||
|
@ -32,9 +32,9 @@ func (srv *Server) Parse(r io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate implements the validator interface
|
// validate implements the validator interface
|
||||||
func (server Server) validate(datatypes ...datatype.T) error {
|
func (server Server) validate(datatypes ...validator.Type) error {
|
||||||
for _, service := range server.Services {
|
for _, service := range server.Services {
|
||||||
err := service.validate(server.Types...)
|
err := service.validate(server.Validators...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s '%s': %w", service.Method, service.Pattern, err)
|
return fmt.Errorf("%s '%s': %w", service.Method, service.Pattern, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLegalServiceName(t *testing.T) {
|
func TestLegalServiceName(t *testing.T) {
|
||||||
|
@ -239,7 +239,7 @@ func TestParamEmptyRenameNoRename(t *testing.T) {
|
||||||
}
|
}
|
||||||
]`)
|
]`)
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.AnyDataType{})
|
srv.Validators = append(srv.Validators, builtin.AnyDataType{})
|
||||||
err := srv.Parse(r)
|
err := srv.Parse(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: '%s'", err)
|
t.Errorf("unexpected error: '%s'", err)
|
||||||
|
@ -275,8 +275,8 @@ func TestOptionalParam(t *testing.T) {
|
||||||
}
|
}
|
||||||
]`)
|
]`)
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.AnyDataType{})
|
srv.Validators = append(srv.Validators, builtin.AnyDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.BoolDataType{})
|
srv.Validators = append(srv.Validators, builtin.BoolDataType{})
|
||||||
err := srv.Parse(r)
|
err := srv.Parse(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: '%s'", err)
|
t.Errorf("unexpected error: '%s'", err)
|
||||||
|
@ -588,7 +588,7 @@ func TestParseParameters(t *testing.T) {
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.AnyDataType{})
|
srv.Validators = append(srv.Validators, builtin.AnyDataType{})
|
||||||
err := srv.Parse(strings.NewReader(test.Raw))
|
err := srv.Parse(strings.NewReader(test.Raw))
|
||||||
|
|
||||||
if err == nil && test.Error != nil {
|
if err == nil && test.Error != nil {
|
||||||
|
@ -827,8 +827,8 @@ func TestServiceCollision(t *testing.T) {
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.StringDataType{})
|
srv.Validators = append(srv.Validators, builtin.StringDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.UintDataType{})
|
srv.Validators = append(srv.Validators, builtin.UintDataType{})
|
||||||
err := srv.Parse(strings.NewReader(test.Config))
|
err := srv.Parse(strings.NewReader(test.Config))
|
||||||
|
|
||||||
if err == nil && test.Error != nil {
|
if err == nil && test.Error != nil {
|
||||||
|
@ -997,9 +997,9 @@ func TestMatchSimple(t *testing.T) {
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.AnyDataType{})
|
srv.Validators = append(srv.Validators, builtin.AnyDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.IntDataType{})
|
srv.Validators = append(srv.Validators, builtin.IntDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.BoolDataType{})
|
srv.Validators = append(srv.Validators, builtin.BoolDataType{})
|
||||||
err := srv.Parse(strings.NewReader(test.Config))
|
err := srv.Parse(strings.NewReader(test.Config))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1081,9 +1081,9 @@ func TestFindPriority(t *testing.T) {
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) {
|
||||||
srv := &Server{}
|
srv := &Server{}
|
||||||
srv.Types = append(srv.Types, builtin.AnyDataType{})
|
srv.Validators = append(srv.Validators, builtin.AnyDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.IntDataType{})
|
srv.Validators = append(srv.Validators, builtin.IntDataType{})
|
||||||
srv.Types = append(srv.Types, builtin.BoolDataType{})
|
srv.Validators = append(srv.Validators, builtin.BoolDataType{})
|
||||||
err := srv.Parse(strings.NewReader(test.Config))
|
err := srv.Parse(strings.NewReader(test.Config))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package config
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parameter represents a parameter definition (from api.json)
|
// Parameter represents a parameter definition (from api.json)
|
||||||
|
@ -12,13 +12,13 @@ type Parameter struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Rename string `json:"name,omitempty"`
|
Rename string `json:"name,omitempty"`
|
||||||
Optional bool
|
Optional bool
|
||||||
// ExtractType is the type the Validator will cast into
|
// GoType is the type the Validator will cast into
|
||||||
ExtractType reflect.Type
|
GoType reflect.Type
|
||||||
// Validator is inferred from the "type" property
|
// Validator is inferred from the "type" property
|
||||||
Validator datatype.Validator
|
Validator validator.ValidateFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (param *Parameter) validate(datatypes ...datatype.T) error {
|
func (param *Parameter) validate(datatypes ...validator.Type) error {
|
||||||
if len(param.Description) < 1 {
|
if len(param.Description) < 1 {
|
||||||
return errMissingParamDesc
|
return errMissingParamDesc
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ func (param *Parameter) validate(datatypes ...datatype.T) error {
|
||||||
|
|
||||||
// find validator
|
// find validator
|
||||||
for _, dtype := range datatypes {
|
for _, dtype := range datatypes {
|
||||||
param.Validator = dtype.Build(param.Type, datatypes...)
|
param.Validator = dtype.Validator(param.Type, datatypes...)
|
||||||
param.ExtractType = dtype.Type()
|
param.GoType = dtype.GoType()
|
||||||
if param.Validator != nil {
|
if param.Validator != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
var braceRegex = regexp.MustCompile(`^{([a-z_-]+)}$`)
|
var braceRegex = regexp.MustCompile(`^{([a-z_-]+)}$`)
|
||||||
|
@ -97,7 +97,7 @@ func (svc *Service) matchPattern(uri string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate implements the validator interface
|
// Validate implements the validator interface
|
||||||
func (svc *Service) validate(datatypes ...datatype.T) error {
|
func (svc *Service) validate(datatypes ...validator.Type) error {
|
||||||
// check method
|
// check method
|
||||||
err := svc.isMethodAvailable()
|
err := svc.isMethodAvailable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -195,7 +195,7 @@ func (svc *Service) isPatternValid() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Service) validateInput(types []datatype.T) error {
|
func (svc *Service) validateInput(types []validator.Type) error {
|
||||||
|
|
||||||
// ignore no parameter
|
// ignore no parameter
|
||||||
if svc.Input == nil || len(svc.Input) < 1 {
|
if svc.Input == nil || len(svc.Input) < 1 {
|
||||||
|
@ -285,7 +285,7 @@ func (svc *Service) validateInput(types []datatype.T) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *Service) validateOutput(types []datatype.T) error {
|
func (svc *Service) validateOutput(types []validator.Type) error {
|
||||||
|
|
||||||
// ignore no parameter
|
// ignore no parameter
|
||||||
if svc.Output == nil || len(svc.Output) < 1 {
|
if svc.Output == nil || len(svc.Output) < 1 {
|
||||||
|
|
|
@ -31,17 +31,17 @@ func BuildSignature(service config.Service) *Signature {
|
||||||
}
|
}
|
||||||
// make a pointer if optional
|
// make a pointer if optional
|
||||||
if param.Optional {
|
if param.Optional {
|
||||||
s.Input[param.Rename] = reflect.PtrTo(param.ExtractType)
|
s.Input[param.Rename] = reflect.PtrTo(param.GoType)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.Input[param.Rename] = param.ExtractType
|
s.Input[param.Rename] = param.GoType
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, param := range service.Output {
|
for _, param := range service.Output {
|
||||||
if len(param.Rename) < 1 {
|
if len(param.Rename) < 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.Output[param.Rename] = param.ExtractType
|
s.Output[param.Rename] = param.GoType
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -3,19 +3,19 @@ package builtin
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AnyDataType is what its name tells
|
// AnyDataType is what its name tells
|
||||||
type AnyDataType struct{}
|
type AnyDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (AnyDataType) Type() reflect.Type {
|
func (AnyDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(interface{}(nil))
|
return reflect.TypeOf(interface{}(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator
|
// Validator returns the validator
|
||||||
func (AnyDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (AnyDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
// nothing if type not handled
|
// nothing if type not handled
|
||||||
if typeName != "any" {
|
if typeName != "any" {
|
||||||
return nil
|
return nil
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAny_AvailableTypes(t *testing.T) {
|
func TestAny_AvailableTypes(t *testing.T) {
|
||||||
|
@ -26,7 +26,7 @@ func TestAny_AvailableTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
|
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
|
@ -47,7 +47,7 @@ func TestAny_AlwaysTrue(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "any"
|
const typeName = "any"
|
||||||
|
|
||||||
validator := builtin.AnyDataType{}.Build(typeName)
|
validator := builtin.AnyDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -3,19 +3,19 @@ package builtin
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BoolDataType is what its name tells
|
// BoolDataType is what its name tells
|
||||||
type BoolDataType struct{}
|
type BoolDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (BoolDataType) Type() reflect.Type {
|
func (BoolDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(true)
|
return reflect.TypeOf(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator
|
// Validator returns the validator
|
||||||
func (BoolDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (BoolDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
// nothing if type not handled
|
// nothing if type not handled
|
||||||
if typeName != "bool" {
|
if typeName != "bool" {
|
||||||
return nil
|
return nil
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBool_AvailableTypes(t *testing.T) {
|
func TestBool_AvailableTypes(t *testing.T) {
|
||||||
|
@ -26,7 +26,7 @@ func TestBool_AvailableTypes(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Type, func(t *testing.T) {
|
t.Run(test.Type, func(t *testing.T) {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
|
@ -49,7 +49,7 @@ func TestBool_Values(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "bool"
|
const typeName = "bool"
|
||||||
|
|
||||||
validator := builtin.BoolDataType{}.Build(typeName)
|
validator := builtin.BoolDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -4,19 +4,19 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FloatDataType is what its name tells
|
// FloatDataType is what its name tells
|
||||||
type FloatDataType struct{}
|
type FloatDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (FloatDataType) Type() reflect.Type {
|
func (FloatDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(float64(0))
|
return reflect.TypeOf(float64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator
|
// Validator returns the validator
|
||||||
func (FloatDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (FloatDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
// nothing if type not handled
|
// nothing if type not handled
|
||||||
if typeName != "float64" && typeName != "float" {
|
if typeName != "float64" && typeName != "float" {
|
||||||
return nil
|
return nil
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFloat64_AvailableTypes(t *testing.T) {
|
func TestFloat64_AvailableTypes(t *testing.T) {
|
||||||
|
@ -33,7 +33,7 @@ func TestFloat64_AvailableTypes(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Type, func(t *testing.T) {
|
t.Run(test.Type, func(t *testing.T) {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
|
@ -56,7 +56,7 @@ func TestFloat64_Values(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "float"
|
const typeName = "float"
|
||||||
|
|
||||||
validator := builtin.FloatDataType{}.Build(typeName)
|
validator := builtin.FloatDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -5,19 +5,19 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IntDataType is what its name tells
|
// IntDataType is what its name tells
|
||||||
type IntDataType struct{}
|
type IntDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (IntDataType) Type() reflect.Type {
|
func (IntDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(int(0))
|
return reflect.TypeOf(int(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator
|
// Validator returns the validator
|
||||||
func (IntDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (IntDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
// nothing if type not handled
|
// nothing if type not handled
|
||||||
if typeName != "int" {
|
if typeName != "int" {
|
||||||
return nil
|
return nil
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInt_AvailableTypes(t *testing.T) {
|
func TestInt_AvailableTypes(t *testing.T) {
|
||||||
|
@ -27,7 +27,7 @@ func TestInt_AvailableTypes(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Type, func(t *testing.T) {
|
t.Run(test.Type, func(t *testing.T) {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
|
@ -50,7 +50,7 @@ func TestInt_Values(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "int"
|
const typeName = "int"
|
||||||
|
|
||||||
validator := builtin.IntDataType{}.Build(typeName)
|
validator := builtin.IntDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`)
|
||||||
|
@ -14,14 +14,14 @@ var variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`)
|
||||||
// StringDataType is what its name tells
|
// StringDataType is what its name tells
|
||||||
type StringDataType struct{}
|
type StringDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (StringDataType) Type() reflect.Type {
|
func (StringDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(string(""))
|
return reflect.TypeOf(string(""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator.
|
// Validator returns the validator.
|
||||||
// availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
// availables type names are : `string`, `string(length)` and `string(minLength, maxLength)`.
|
||||||
func (s StringDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (s StringDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
simple := typeName == "string"
|
simple := typeName == "string"
|
||||||
fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName)
|
fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName)
|
||||||
variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName)
|
variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName)
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestString_AvailableTypes(t *testing.T) {
|
func TestString_AvailableTypes(t *testing.T) {
|
||||||
|
@ -53,7 +53,7 @@ func TestString_AvailableTypes(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Type, func(t *testing.T) {
|
t.Run(test.Type, func(t *testing.T) {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
|
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
|
@ -75,7 +75,7 @@ func TestString_AnyLength(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "string"
|
const typeName = "string"
|
||||||
|
|
||||||
validator := builtin.StringDataType{}.Build(typeName)
|
validator := builtin.StringDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -133,7 +133,7 @@ func TestString_FixedLength(t *testing.T) {
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||||
validator := builtin.StringDataType{}.Build(test.Type)
|
validator := builtin.StringDataType{}.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
@ -194,7 +194,7 @@ func TestString_VariableLength(t *testing.T) {
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||||
validator := builtin.StringDataType{}.Build(test.Type)
|
validator := builtin.StringDataType{}.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -5,19 +5,19 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype"
|
"github.com/xdrm-io/aicra/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UintDataType is what its name tells
|
// UintDataType is what its name tells
|
||||||
type UintDataType struct{}
|
type UintDataType struct{}
|
||||||
|
|
||||||
// Type returns the type of data
|
// GoType returns the type of data
|
||||||
func (UintDataType) Type() reflect.Type {
|
func (UintDataType) GoType() reflect.Type {
|
||||||
return reflect.TypeOf(uint(0))
|
return reflect.TypeOf(uint(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the validator
|
// Validator returns the validator
|
||||||
func (UintDataType) Build(typeName string, registry ...datatype.T) datatype.Validator {
|
func (UintDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc {
|
||||||
// nothing if type not handled
|
// nothing if type not handled
|
||||||
if typeName != "uint" {
|
if typeName != "uint" {
|
||||||
return nil
|
return nil
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xdrm-io/aicra/datatype/builtin"
|
"github.com/xdrm-io/aicra/validator/builtin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUint_AvailableTypes(t *testing.T) {
|
func TestUint_AvailableTypes(t *testing.T) {
|
||||||
|
@ -27,7 +27,7 @@ func TestUint_AvailableTypes(t *testing.T) {
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.Type, func(t *testing.T) {
|
t.Run(test.Type, func(t *testing.T) {
|
||||||
validator := dt.Build(test.Type)
|
validator := dt.Validator(test.Type)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
if test.Handled {
|
if test.Handled {
|
||||||
t.Errorf("expect %q to be handled", test.Type)
|
t.Errorf("expect %q to be handled", test.Type)
|
||||||
|
@ -50,7 +50,7 @@ func TestUint_Values(t *testing.T) {
|
||||||
|
|
||||||
const typeName = "uint"
|
const typeName = "uint"
|
||||||
|
|
||||||
validator := builtin.UintDataType{}.Build(typeName)
|
validator := builtin.UintDataType{}.Validator(typeName)
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
t.Errorf("expect %q to be handled", typeName)
|
t.Errorf("expect %q to be handled", typeName)
|
||||||
t.Fail()
|
t.Fail()
|
|
@ -0,0 +1,55 @@
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateFunc returns whether a given value fulfills the datatype and casts
|
||||||
|
// the value into a go type.
|
||||||
|
//
|
||||||
|
// for example, if a validator checks for upper case strings, whether the value
|
||||||
|
// is a []byte, a string or a []rune, if the value matches is all upper-case, it
|
||||||
|
// will be cast into a go type, say, string.
|
||||||
|
type ValidateFunc func(value interface{}) (cast interface{}, valid bool)
|
||||||
|
|
||||||
|
// Type defines an available in/out parameter "type" for the aicra configuration
|
||||||
|
//
|
||||||
|
// A Type maps to a go type in order to generate the handler signature from the
|
||||||
|
// aicra configuration
|
||||||
|
//
|
||||||
|
// A Type returns a custom validator when the typename matches
|
||||||
|
type Type interface {
|
||||||
|
// Validator function when the typename matches. It must return nil when the
|
||||||
|
// typename does not match
|
||||||
|
//
|
||||||
|
// The `typename` argument has to match types used in your aicra configuration
|
||||||
|
// in parameter definitions ("in", "out") and in the "type" json field.
|
||||||
|
//
|
||||||
|
// basic example:
|
||||||
|
// - `IntType.Validator("string")`` should return nil
|
||||||
|
// - `IntType.Validator("int")`` should return its ValidateFunc
|
||||||
|
//
|
||||||
|
// The `typename` is not returned by a simple method i.e. `TypeName() string`
|
||||||
|
// because it allows for validation relative to the typename, for instance:
|
||||||
|
// - `VarcharType.Validator("varchar")` valides any string
|
||||||
|
// - `VarcharType.Validator("varchar(2)")` validates any string of 2
|
||||||
|
// characters
|
||||||
|
// - `VarcharType.Validator("varchar(1,3)")` validates any string
|
||||||
|
// with a length between 1 and 3
|
||||||
|
//
|
||||||
|
// The `registry` argument represents all other available Types. It allows a
|
||||||
|
// Type to use other available Types internally.
|
||||||
|
//
|
||||||
|
// recursive example: slices
|
||||||
|
// - `SliceType.Validator("[]int", reg...)` validates a slice containing
|
||||||
|
// values that are valide to the `IntType`
|
||||||
|
// - `SliceType.Validator("[]varchar", reg...)` validates a slice containing
|
||||||
|
// values that are valid to the `VarcharType`
|
||||||
|
//
|
||||||
|
// and so on.. this works for maps, structs, etc
|
||||||
|
Validator(typename string, registry ...Type) ValidateFunc
|
||||||
|
|
||||||
|
// GoType must return the go type associated with the output type of ValidateFunc.
|
||||||
|
// It is used to define handlers' signature from the configuration file.
|
||||||
|
GoType() reflect.Type
|
||||||
|
}
|
Loading…
Reference in New Issue