From defa2c3645fcd254092081e028a3a99d0c933fff Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Mon, 21 Jun 2021 21:08:22 +0200 Subject: [PATCH] refactor: rename semantics of datatype to validator.Type --- README.md | 10 ++-- builder.go | 12 ++-- builder_test.go | 18 +++--- datatype/datatype.go | 23 -------- handler_test.go | 14 ++--- internal/config/config.go | 10 ++-- internal/config/config_test.go | 26 ++++----- internal/config/parameter.go | 14 ++--- internal/config/service.go | 8 +-- internal/dynfunc/signature.go | 6 +- {datatype => validator}/builtin/any.go | 10 ++-- {datatype => validator}/builtin/any_test.go | 6 +- {datatype => validator}/builtin/bool.go | 10 ++-- {datatype => validator}/builtin/bool_test.go | 6 +- {datatype => validator}/builtin/float.go | 10 ++-- {datatype => validator}/builtin/float_test.go | 6 +- {datatype => validator}/builtin/int.go | 10 ++-- {datatype => validator}/builtin/int_test.go | 6 +- {datatype => validator}/builtin/string.go | 10 ++-- .../builtin/string_test.go | 10 ++-- {datatype => validator}/builtin/uint.go | 10 ++-- {datatype => validator}/builtin/uint_test.go | 6 +- validator/validator.go | 55 +++++++++++++++++++ 23 files changed, 164 insertions(+), 132 deletions(-) delete mode 100644 datatype/datatype.go rename {datatype => validator}/builtin/any.go (54%) rename {datatype => validator}/builtin/any_test.go (87%) rename {datatype => validator}/builtin/bool.go (70%) rename {datatype => validator}/builtin/bool_test.go (91%) rename {datatype => validator}/builtin/float.go (75%) rename {datatype => validator}/builtin/float_test.go (93%) rename {datatype => validator}/builtin/int.go (79%) rename {datatype => validator}/builtin/int_test.go (93%) rename {datatype => validator}/builtin/string.go (91%) rename {datatype => validator}/builtin/string_test.go (94%) rename {datatype => validator}/builtin/uint.go (81%) rename {datatype => validator}/builtin/uint_test.go (93%) create mode 100644 validator/validator.go diff --git a/README.md b/README.md index 9c03075..467fbc1 100644 --- a/README.md +++ b/README.md @@ -89,16 +89,16 @@ import ( "github.com/xdrm-io/aicra" "github.com/xdrm-io/aicra/api" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func main() { builder := &aicra.Builder{} - // register data validators - builder.AddType(builtin.BoolDataType{}) - builder.AddType(builtin.UintDataType{}) - builder.AddType(builtin.StringDataType{}) + // add custom type validators + builder.Validate(builtin.BoolDataType{}) + builder.Validate(builtin.UintDataType{}) + builder.Validate(builtin.StringDataType{}) // load your configuration config, err := os.Open("api.json") diff --git a/builder.go b/builder.go index 0fc8d3b..fc17243 100644 --- a/builder.go +++ b/builder.go @@ -5,9 +5,9 @@ import ( "io" "net/http" - "github.com/xdrm-io/aicra/datatype" "github.com/xdrm-io/aicra/internal/config" "github.com/xdrm-io/aicra/internal/dynfunc" + "github.com/xdrm-io/aicra/validator" ) // Builder for an aicra server @@ -31,18 +31,18 @@ type apiHandler struct { dyn *dynfunc.Handler } -// AddType adds an available datatype to the api definition -func (b *Builder) AddType(t datatype.T) error { +// Validate adds an available Type to validate in the api definition +func (b *Builder) Validate(t validator.Type) error { if b.conf == nil { b.conf = &config.Server{} } if b.conf.Services != nil { return errLateType } - if b.conf.Types == nil { - b.conf.Types = make([]datatype.T, 0) + if b.conf.Validators == nil { + 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 } diff --git a/builder_test.go b/builder_test.go index 8bae2ac..457449b 100644 --- a/builder_test.go +++ b/builder_test.go @@ -8,26 +8,26 @@ import ( "testing" "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 { - if err := b.AddType(builtin.AnyDataType{}); err != nil { + if err := b.Validate(builtin.AnyDataType{}); err != nil { return err } - if err := b.AddType(builtin.BoolDataType{}); err != nil { + if err := b.Validate(builtin.BoolDataType{}); err != nil { return err } - if err := b.AddType(builtin.FloatDataType{}); err != nil { + if err := b.Validate(builtin.FloatDataType{}); err != nil { return err } - if err := b.AddType(builtin.IntDataType{}); err != nil { + if err := b.Validate(builtin.IntDataType{}); err != nil { return err } - if err := b.AddType(builtin.StringDataType{}); err != nil { + if err := b.Validate(builtin.StringDataType{}); err != nil { return err } - if err := b.AddType(builtin.UintDataType{}); err != nil { + if err := b.Validate(builtin.UintDataType{}); err != nil { return err } return nil @@ -35,7 +35,7 @@ func addBuiltinTypes(b *Builder) error { func TestAddType(t *testing.T) { builder := &Builder{} - err := builder.AddType(builtin.BoolDataType{}) + err := builder.Validate(builtin.BoolDataType{}) if err != nil { t.Fatalf("unexpected error: %s", err) } @@ -43,7 +43,7 @@ func TestAddType(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %s", err) } - err = builder.AddType(builtin.FloatDataType{}) + err = builder.Validate(builtin.FloatDataType{}) if err != errLateType { t.Fatalf("expected <%v> got <%v>", errLateType, err) } diff --git a/datatype/datatype.go b/datatype/datatype.go deleted file mode 100644 index 2e0a264..0000000 --- a/datatype/datatype.go +++ /dev/null @@ -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 -} diff --git a/handler_test.go b/handler_test.go index 00311f1..51e9719 100644 --- a/handler_test.go +++ b/handler_test.go @@ -12,26 +12,26 @@ import ( "github.com/xdrm-io/aicra" "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 { - if err := b.AddType(builtin.AnyDataType{}); err != nil { + if err := b.Validate(builtin.AnyDataType{}); err != nil { return err } - if err := b.AddType(builtin.BoolDataType{}); err != nil { + if err := b.Validate(builtin.BoolDataType{}); err != nil { return err } - if err := b.AddType(builtin.FloatDataType{}); err != nil { + if err := b.Validate(builtin.FloatDataType{}); err != nil { return err } - if err := b.AddType(builtin.IntDataType{}); err != nil { + if err := b.Validate(builtin.IntDataType{}); err != nil { return err } - if err := b.AddType(builtin.StringDataType{}); err != nil { + if err := b.Validate(builtin.StringDataType{}); err != nil { return err } - if err := b.AddType(builtin.UintDataType{}); err != nil { + if err := b.Validate(builtin.UintDataType{}); err != nil { return err } return nil diff --git a/internal/config/config.go b/internal/config/config.go index 1ac6fcc..cc529d0 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -7,13 +7,13 @@ import ( "net/http" "strings" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // Server definition type Server struct { - Types []datatype.T - Services []*Service + Validators []validator.Type + Services []*Service } // 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 -func (server Server) validate(datatypes ...datatype.T) error { +func (server Server) validate(datatypes ...validator.Type) error { for _, service := range server.Services { - err := service.validate(server.Types...) + err := service.validate(server.Validators...) if err != nil { return fmt.Errorf("%s '%s': %w", service.Method, service.Pattern, err) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 030e027..2bf019f 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestLegalServiceName(t *testing.T) { @@ -239,7 +239,7 @@ func TestParamEmptyRenameNoRename(t *testing.T) { } ]`) srv := &Server{} - srv.Types = append(srv.Types, builtin.AnyDataType{}) + srv.Validators = append(srv.Validators, builtin.AnyDataType{}) err := srv.Parse(r) if err != nil { t.Errorf("unexpected error: '%s'", err) @@ -275,8 +275,8 @@ func TestOptionalParam(t *testing.T) { } ]`) srv := &Server{} - srv.Types = append(srv.Types, builtin.AnyDataType{}) - srv.Types = append(srv.Types, builtin.BoolDataType{}) + srv.Validators = append(srv.Validators, builtin.AnyDataType{}) + srv.Validators = append(srv.Validators, builtin.BoolDataType{}) err := srv.Parse(r) if err != nil { 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) { srv := &Server{} - srv.Types = append(srv.Types, builtin.AnyDataType{}) + srv.Validators = append(srv.Validators, builtin.AnyDataType{}) err := srv.Parse(strings.NewReader(test.Raw)) 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) { srv := &Server{} - srv.Types = append(srv.Types, builtin.StringDataType{}) - srv.Types = append(srv.Types, builtin.UintDataType{}) + srv.Validators = append(srv.Validators, builtin.StringDataType{}) + srv.Validators = append(srv.Validators, builtin.UintDataType{}) err := srv.Parse(strings.NewReader(test.Config)) 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) { srv := &Server{} - srv.Types = append(srv.Types, builtin.AnyDataType{}) - srv.Types = append(srv.Types, builtin.IntDataType{}) - srv.Types = append(srv.Types, builtin.BoolDataType{}) + srv.Validators = append(srv.Validators, builtin.AnyDataType{}) + srv.Validators = append(srv.Validators, builtin.IntDataType{}) + srv.Validators = append(srv.Validators, builtin.BoolDataType{}) err := srv.Parse(strings.NewReader(test.Config)) if err != nil { @@ -1081,9 +1081,9 @@ func TestFindPriority(t *testing.T) { t.Run(fmt.Sprintf("method.%d", i), func(t *testing.T) { srv := &Server{} - srv.Types = append(srv.Types, builtin.AnyDataType{}) - srv.Types = append(srv.Types, builtin.IntDataType{}) - srv.Types = append(srv.Types, builtin.BoolDataType{}) + srv.Validators = append(srv.Validators, builtin.AnyDataType{}) + srv.Validators = append(srv.Validators, builtin.IntDataType{}) + srv.Validators = append(srv.Validators, builtin.BoolDataType{}) err := srv.Parse(strings.NewReader(test.Config)) if err != nil { diff --git a/internal/config/parameter.go b/internal/config/parameter.go index d0e5ab7..a22227b 100644 --- a/internal/config/parameter.go +++ b/internal/config/parameter.go @@ -3,7 +3,7 @@ package config import ( "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // Parameter represents a parameter definition (from api.json) @@ -12,13 +12,13 @@ type Parameter struct { Type string `json:"type"` Rename string `json:"name,omitempty"` Optional bool - // ExtractType is the type the Validator will cast into - ExtractType reflect.Type + // GoType is the type the Validator will cast into + GoType reflect.Type // 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 { return errMissingParamDesc } @@ -35,8 +35,8 @@ func (param *Parameter) validate(datatypes ...datatype.T) error { // find validator for _, dtype := range datatypes { - param.Validator = dtype.Build(param.Type, datatypes...) - param.ExtractType = dtype.Type() + param.Validator = dtype.Validator(param.Type, datatypes...) + param.GoType = dtype.GoType() if param.Validator != nil { break } diff --git a/internal/config/service.go b/internal/config/service.go index 3b051ba..6d10d27 100644 --- a/internal/config/service.go +++ b/internal/config/service.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) var braceRegex = regexp.MustCompile(`^{([a-z_-]+)}$`) @@ -97,7 +97,7 @@ func (svc *Service) matchPattern(uri string) bool { } // Validate implements the validator interface -func (svc *Service) validate(datatypes ...datatype.T) error { +func (svc *Service) validate(datatypes ...validator.Type) error { // check method err := svc.isMethodAvailable() if err != nil { @@ -195,7 +195,7 @@ func (svc *Service) isPatternValid() error { return nil } -func (svc *Service) validateInput(types []datatype.T) error { +func (svc *Service) validateInput(types []validator.Type) error { // ignore no parameter if svc.Input == nil || len(svc.Input) < 1 { @@ -285,7 +285,7 @@ func (svc *Service) validateInput(types []datatype.T) error { return nil } -func (svc *Service) validateOutput(types []datatype.T) error { +func (svc *Service) validateOutput(types []validator.Type) error { // ignore no parameter if svc.Output == nil || len(svc.Output) < 1 { diff --git a/internal/dynfunc/signature.go b/internal/dynfunc/signature.go index 35783ab..d5c30aa 100644 --- a/internal/dynfunc/signature.go +++ b/internal/dynfunc/signature.go @@ -31,17 +31,17 @@ func BuildSignature(service config.Service) *Signature { } // make a pointer if optional if param.Optional { - s.Input[param.Rename] = reflect.PtrTo(param.ExtractType) + s.Input[param.Rename] = reflect.PtrTo(param.GoType) continue } - s.Input[param.Rename] = param.ExtractType + s.Input[param.Rename] = param.GoType } for _, param := range service.Output { if len(param.Rename) < 1 { continue } - s.Output[param.Rename] = param.ExtractType + s.Output[param.Rename] = param.GoType } return s diff --git a/datatype/builtin/any.go b/validator/builtin/any.go similarity index 54% rename from datatype/builtin/any.go rename to validator/builtin/any.go index fdfd5f9..36a3e5a 100644 --- a/datatype/builtin/any.go +++ b/validator/builtin/any.go @@ -3,19 +3,19 @@ package builtin import ( "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // AnyDataType is what its name tells type AnyDataType struct{} -// Type returns the type of data -func (AnyDataType) Type() reflect.Type { +// GoType returns the type of data +func (AnyDataType) GoType() reflect.Type { return reflect.TypeOf(interface{}(nil)) } -// Build returns the validator -func (AnyDataType) Build(typeName string, registry ...datatype.T) datatype.Validator { +// Validator returns the validator +func (AnyDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc { // nothing if type not handled if typeName != "any" { return nil diff --git a/datatype/builtin/any_test.go b/validator/builtin/any_test.go similarity index 87% rename from datatype/builtin/any_test.go rename to validator/builtin/any_test.go index 8d9ae03..ab7a681 100644 --- a/datatype/builtin/any_test.go +++ b/validator/builtin/any_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestAny_AvailableTypes(t *testing.T) { @@ -26,7 +26,7 @@ func TestAny_AvailableTypes(t *testing.T) { } for _, test := range tests { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { @@ -47,7 +47,7 @@ func TestAny_AlwaysTrue(t *testing.T) { const typeName = "any" - validator := builtin.AnyDataType{}.Build(typeName) + validator := builtin.AnyDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() diff --git a/datatype/builtin/bool.go b/validator/builtin/bool.go similarity index 70% rename from datatype/builtin/bool.go rename to validator/builtin/bool.go index 720c59d..e5bd9df 100644 --- a/datatype/builtin/bool.go +++ b/validator/builtin/bool.go @@ -3,19 +3,19 @@ package builtin import ( "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // BoolDataType is what its name tells type BoolDataType struct{} -// Type returns the type of data -func (BoolDataType) Type() reflect.Type { +// GoType returns the type of data +func (BoolDataType) GoType() reflect.Type { return reflect.TypeOf(true) } -// Build returns the validator -func (BoolDataType) Build(typeName string, registry ...datatype.T) datatype.Validator { +// Validator returns the validator +func (BoolDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc { // nothing if type not handled if typeName != "bool" { return nil diff --git a/datatype/builtin/bool_test.go b/validator/builtin/bool_test.go similarity index 91% rename from datatype/builtin/bool_test.go rename to validator/builtin/bool_test.go index c44b262..1d59ec9 100644 --- a/datatype/builtin/bool_test.go +++ b/validator/builtin/bool_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestBool_AvailableTypes(t *testing.T) { @@ -26,7 +26,7 @@ func TestBool_AvailableTypes(t *testing.T) { for _, test := range tests { t.Run(test.Type, func(t *testing.T) { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { t.Errorf("expect %q to be handled", test.Type) @@ -49,7 +49,7 @@ func TestBool_Values(t *testing.T) { const typeName = "bool" - validator := builtin.BoolDataType{}.Build(typeName) + validator := builtin.BoolDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() diff --git a/datatype/builtin/float.go b/validator/builtin/float.go similarity index 75% rename from datatype/builtin/float.go rename to validator/builtin/float.go index 6bb39f9..0789444 100644 --- a/datatype/builtin/float.go +++ b/validator/builtin/float.go @@ -4,19 +4,19 @@ import ( "encoding/json" "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // FloatDataType is what its name tells type FloatDataType struct{} -// Type returns the type of data -func (FloatDataType) Type() reflect.Type { +// GoType returns the type of data +func (FloatDataType) GoType() reflect.Type { return reflect.TypeOf(float64(0)) } -// Build returns the validator -func (FloatDataType) Build(typeName string, registry ...datatype.T) datatype.Validator { +// Validator returns the validator +func (FloatDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc { // nothing if type not handled if typeName != "float64" && typeName != "float" { return nil diff --git a/datatype/builtin/float_test.go b/validator/builtin/float_test.go similarity index 93% rename from datatype/builtin/float_test.go rename to validator/builtin/float_test.go index 193dd7c..924036e 100644 --- a/datatype/builtin/float_test.go +++ b/validator/builtin/float_test.go @@ -5,7 +5,7 @@ import ( "math" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestFloat64_AvailableTypes(t *testing.T) { @@ -33,7 +33,7 @@ func TestFloat64_AvailableTypes(t *testing.T) { for _, test := range tests { t.Run(test.Type, func(t *testing.T) { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { t.Errorf("expect %q to be handled", test.Type) @@ -56,7 +56,7 @@ func TestFloat64_Values(t *testing.T) { const typeName = "float" - validator := builtin.FloatDataType{}.Build(typeName) + validator := builtin.FloatDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() diff --git a/datatype/builtin/int.go b/validator/builtin/int.go similarity index 79% rename from datatype/builtin/int.go rename to validator/builtin/int.go index b1473a6..1d0ad00 100644 --- a/datatype/builtin/int.go +++ b/validator/builtin/int.go @@ -5,19 +5,19 @@ import ( "math" "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // IntDataType is what its name tells type IntDataType struct{} -// Type returns the type of data -func (IntDataType) Type() reflect.Type { +// GoType returns the type of data +func (IntDataType) GoType() reflect.Type { return reflect.TypeOf(int(0)) } -// Build returns the validator -func (IntDataType) Build(typeName string, registry ...datatype.T) datatype.Validator { +// Validator returns the validator +func (IntDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc { // nothing if type not handled if typeName != "int" { return nil diff --git a/datatype/builtin/int_test.go b/validator/builtin/int_test.go similarity index 93% rename from datatype/builtin/int_test.go rename to validator/builtin/int_test.go index 8b7a157..cffea8f 100644 --- a/datatype/builtin/int_test.go +++ b/validator/builtin/int_test.go @@ -5,7 +5,7 @@ import ( "math" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestInt_AvailableTypes(t *testing.T) { @@ -27,7 +27,7 @@ func TestInt_AvailableTypes(t *testing.T) { for _, test := range tests { t.Run(test.Type, func(t *testing.T) { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { t.Errorf("expect %q to be handled", test.Type) @@ -50,7 +50,7 @@ func TestInt_Values(t *testing.T) { const typeName = "int" - validator := builtin.IntDataType{}.Build(typeName) + validator := builtin.IntDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() diff --git a/datatype/builtin/string.go b/validator/builtin/string.go similarity index 91% rename from datatype/builtin/string.go rename to validator/builtin/string.go index 902daf7..50544a7 100644 --- a/datatype/builtin/string.go +++ b/validator/builtin/string.go @@ -5,7 +5,7 @@ import ( "regexp" "strconv" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) var fixedLengthRegex = regexp.MustCompile(`^string\((\d+)\)$`) @@ -14,14 +14,14 @@ var variableLengthRegex = regexp.MustCompile(`^string\((\d+), ?(\d+)\)$`) // StringDataType is what its name tells type StringDataType struct{} -// Type returns the type of data -func (StringDataType) Type() reflect.Type { +// GoType returns the type of data +func (StringDataType) GoType() reflect.Type { return reflect.TypeOf(string("")) } -// Build returns the validator. +// Validator returns the validator. // 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" fixedLengthMatches := fixedLengthRegex.FindStringSubmatch(typeName) variableLengthMatches := variableLengthRegex.FindStringSubmatch(typeName) diff --git a/datatype/builtin/string_test.go b/validator/builtin/string_test.go similarity index 94% rename from datatype/builtin/string_test.go rename to validator/builtin/string_test.go index 4441525..7b91b2d 100644 --- a/datatype/builtin/string_test.go +++ b/validator/builtin/string_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestString_AvailableTypes(t *testing.T) { @@ -53,7 +53,7 @@ func TestString_AvailableTypes(t *testing.T) { for _, test := range tests { t.Run(test.Type, func(t *testing.T) { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { @@ -75,7 +75,7 @@ func TestString_AnyLength(t *testing.T) { const typeName = "string" - validator := builtin.StringDataType{}.Build(typeName) + validator := builtin.StringDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() @@ -133,7 +133,7 @@ func TestString_FixedLength(t *testing.T) { for i, test := range tests { 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 { t.Errorf("expect %q to be handled", test.Type) t.Fail() @@ -194,7 +194,7 @@ func TestString_VariableLength(t *testing.T) { for i, test := range tests { 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 { t.Errorf("expect %q to be handled", test.Type) t.Fail() diff --git a/datatype/builtin/uint.go b/validator/builtin/uint.go similarity index 81% rename from datatype/builtin/uint.go rename to validator/builtin/uint.go index 990d15b..d6e25cf 100644 --- a/datatype/builtin/uint.go +++ b/validator/builtin/uint.go @@ -5,19 +5,19 @@ import ( "math" "reflect" - "github.com/xdrm-io/aicra/datatype" + "github.com/xdrm-io/aicra/validator" ) // UintDataType is what its name tells type UintDataType struct{} -// Type returns the type of data -func (UintDataType) Type() reflect.Type { +// GoType returns the type of data +func (UintDataType) GoType() reflect.Type { return reflect.TypeOf(uint(0)) } -// Build returns the validator -func (UintDataType) Build(typeName string, registry ...datatype.T) datatype.Validator { +// Validator returns the validator +func (UintDataType) Validator(typeName string, registry ...validator.Type) validator.ValidateFunc { // nothing if type not handled if typeName != "uint" { return nil diff --git a/datatype/builtin/uint_test.go b/validator/builtin/uint_test.go similarity index 93% rename from datatype/builtin/uint_test.go rename to validator/builtin/uint_test.go index 6175321..9893264 100644 --- a/datatype/builtin/uint_test.go +++ b/validator/builtin/uint_test.go @@ -5,7 +5,7 @@ import ( "math" "testing" - "github.com/xdrm-io/aicra/datatype/builtin" + "github.com/xdrm-io/aicra/validator/builtin" ) func TestUint_AvailableTypes(t *testing.T) { @@ -27,7 +27,7 @@ func TestUint_AvailableTypes(t *testing.T) { for _, test := range tests { t.Run(test.Type, func(t *testing.T) { - validator := dt.Build(test.Type) + validator := dt.Validator(test.Type) if validator == nil { if test.Handled { t.Errorf("expect %q to be handled", test.Type) @@ -50,7 +50,7 @@ func TestUint_Values(t *testing.T) { const typeName = "uint" - validator := builtin.UintDataType{}.Build(typeName) + validator := builtin.UintDataType{}.Validator(typeName) if validator == nil { t.Errorf("expect %q to be handled", typeName) t.Fail() diff --git a/validator/validator.go b/validator/validator.go new file mode 100644 index 0000000..574f966 --- /dev/null +++ b/validator/validator.go @@ -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 +}