diff --git a/boolean.go b/boolean.go index d5130e2..ed944f6 100644 --- a/boolean.go +++ b/boolean.go @@ -6,9 +6,9 @@ import ( "github.com/Oudwins/zog/zconst" ) -var _ ZogSchema = &boolProcessor{} +var _ PrimitiveZogSchema[bool] = &BoolSchema{} -type boolProcessor struct { +type BoolSchema struct { preTransforms []p.PreTransform tests []p.Test postTransforms []p.PostTransform @@ -21,25 +21,25 @@ type boolProcessor struct { // ! INTERNALS // Returns the type of the schema -func (v *boolProcessor) getType() zconst.ZogType { +func (v *BoolSchema) getType() zconst.ZogType { return zconst.TypeBool } // Sets the coercer for the schema -func (v *boolProcessor) setCoercer(c conf.CoercerFunc) { +func (v *BoolSchema) setCoercer(c conf.CoercerFunc) { v.coercer = c } // Internal function to process the data -func (v *boolProcessor) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *BoolSchema) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { primitiveProcessor(val, dest, path, ctx, v.preTransforms, v.tests, v.postTransforms, v.defaultVal, v.required, v.catch, v.coercer, p.IsParseZeroValue) } // ! USER FACING FUNCTIONS // Returns a new Bool Schema -func Bool(opts ...SchemaOption) *boolProcessor { - b := &boolProcessor{ +func Bool(opts ...SchemaOption) *BoolSchema { + b := &BoolSchema{ coercer: conf.Coercers.Bool, // default coercer } for _, opt := range opts { @@ -48,7 +48,7 @@ func Bool(opts ...SchemaOption) *boolProcessor { return b } -func (v *boolProcessor) Parse(data any, dest *bool, options ...ParsingOption) p.ZogErrList { +func (v *BoolSchema) Parse(data any, dest *bool, options ...ParsingOption) p.ZogErrList { errs := p.NewErrsList() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -64,7 +64,7 @@ func (v *boolProcessor) Parse(data any, dest *bool, options ...ParsingOption) p. // GLOBAL METHODS // Adds pretransform function to schema -func (v *boolProcessor) PreTransform(transform p.PreTransform) *boolProcessor { +func (v *BoolSchema) PreTransform(transform p.PreTransform) *BoolSchema { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -73,7 +73,7 @@ func (v *boolProcessor) PreTransform(transform p.PreTransform) *boolProcessor { } // Adds posttransform function to schema -func (v *boolProcessor) PostTransform(transform p.PostTransform) *boolProcessor { +func (v *BoolSchema) PostTransform(transform p.PostTransform) *BoolSchema { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -83,7 +83,7 @@ func (v *boolProcessor) PostTransform(transform p.PostTransform) *boolProcessor // ! MODIFIERS // marks field as required -func (v *boolProcessor) Required(options ...TestOption) *boolProcessor { +func (v *BoolSchema) Required(options ...TestOption) *BoolSchema { r := p.Required() for _, opt := range options { opt(&r) @@ -93,31 +93,31 @@ func (v *boolProcessor) Required(options ...TestOption) *boolProcessor { } // marks field as optional -func (v *boolProcessor) Optional() *boolProcessor { +func (v *BoolSchema) Optional() *BoolSchema { v.required = nil return v } // sets the default value -func (v *boolProcessor) Default(val bool) *boolProcessor { +func (v *BoolSchema) Default(val bool) *BoolSchema { v.defaultVal = &val return v } // sets the catch value (i.e the value to use if the validation fails) -func (v *boolProcessor) Catch(val bool) *boolProcessor { +func (v *BoolSchema) Catch(val bool) *BoolSchema { v.catch = &val return v } // UNIQUE METHODS -func (v *boolProcessor) True() *boolProcessor { +func (v *BoolSchema) True() *BoolSchema { v.tests = append(v.tests, p.EQ[bool](true)) return v } -func (v *boolProcessor) False() *boolProcessor { +func (v *BoolSchema) False() *BoolSchema { v.tests = append(v.tests, p.EQ[bool](false)) return v } diff --git a/numbers.go b/numbers.go index dcb55df..df7d2b0 100644 --- a/numbers.go +++ b/numbers.go @@ -10,9 +10,9 @@ type Numeric interface { ~int | ~float64 } -var _ ZogSchema = &numberProcessor[int]{} +var _ PrimitiveZogSchema[int] = &NumberSchema[int]{} -type numberProcessor[T Numeric] struct { +type NumberSchema[T Numeric] struct { preTransforms []p.PreTransform tests []p.Test postTransforms []p.PostTransform @@ -25,25 +25,25 @@ type numberProcessor[T Numeric] struct { // ! INTERNALS // Returns the type of the schema -func (v *numberProcessor[T]) getType() zconst.ZogType { +func (v *NumberSchema[T]) getType() zconst.ZogType { return zconst.TypeNumber } // Sets the coercer for the schema -func (v *numberProcessor[T]) setCoercer(c conf.CoercerFunc) { +func (v *NumberSchema[T]) setCoercer(c conf.CoercerFunc) { v.coercer = c } // Internal function to process the data -func (v *numberProcessor[T]) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *NumberSchema[T]) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { primitiveProcessor(val, dest, path, ctx, v.preTransforms, v.tests, v.postTransforms, v.defaultVal, v.required, v.catch, v.coercer, p.IsParseZeroValue) } // ! USER FACING FUNCTIONS // creates a new float64 schema -func Float(opts ...SchemaOption) *numberProcessor[float64] { - s := &numberProcessor[float64]{ +func Float(opts ...SchemaOption) *NumberSchema[float64] { + s := &NumberSchema[float64]{ coercer: conf.Coercers.Float64, } for _, opt := range opts { @@ -53,8 +53,8 @@ func Float(opts ...SchemaOption) *numberProcessor[float64] { } // creates a new int schema -func Int(opts ...SchemaOption) *numberProcessor[int] { - s := &numberProcessor[int]{ +func Int(opts ...SchemaOption) *NumberSchema[int] { + s := &NumberSchema[int]{ coercer: conf.Coercers.Int, } for _, opt := range opts { @@ -64,7 +64,7 @@ func Int(opts ...SchemaOption) *numberProcessor[int] { } // parses the value and stores it in the destination -func (v *numberProcessor[T]) Parse(data any, dest *T, options ...ParsingOption) p.ZogErrList { +func (v *NumberSchema[T]) Parse(data any, dest *T, options ...ParsingOption) p.ZogErrList { errs := p.NewErrsList() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -80,7 +80,7 @@ func (v *numberProcessor[T]) Parse(data any, dest *T, options ...ParsingOption) // GLOBAL METHODS -func (v *numberProcessor[T]) PreTransform(transform p.PreTransform) *numberProcessor[T] { +func (v *NumberSchema[T]) PreTransform(transform p.PreTransform) *NumberSchema[T] { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -89,7 +89,7 @@ func (v *numberProcessor[T]) PreTransform(transform p.PreTransform) *numberProce } // Adds posttransform function to schema -func (v *numberProcessor[T]) PostTransform(transform p.PostTransform) *numberProcessor[T] { +func (v *NumberSchema[T]) PostTransform(transform p.PostTransform) *NumberSchema[T] { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -100,7 +100,7 @@ func (v *numberProcessor[T]) PostTransform(transform p.PostTransform) *numberPro // ! MODIFIERS // marks field as required -func (v *numberProcessor[T]) Required(options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) Required(options ...TestOption) *NumberSchema[T] { r := p.Required() for _, opt := range options { opt(&r) @@ -110,25 +110,25 @@ func (v *numberProcessor[T]) Required(options ...TestOption) *numberProcessor[T] } // marks field as optional -func (v *numberProcessor[T]) Optional() *numberProcessor[T] { +func (v *NumberSchema[T]) Optional() *NumberSchema[T] { v.required = nil return v } // sets the default value -func (v *numberProcessor[T]) Default(val T) *numberProcessor[T] { +func (v *NumberSchema[T]) Default(val T) *NumberSchema[T] { v.defaultVal = &val return v } // sets the catch value (i.e the value to use if the validation fails) -func (v *numberProcessor[T]) Catch(val T) *numberProcessor[T] { +func (v *NumberSchema[T]) Catch(val T) *NumberSchema[T] { v.catch = &val return v } // custom test function call it -> schema.Test(test, options) -func (v *numberProcessor[T]) Test(t p.Test, opts ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) Test(t p.Test, opts ...TestOption) *NumberSchema[T] { for _, opt := range opts { opt(&t) } @@ -139,7 +139,7 @@ func (v *numberProcessor[T]) Test(t p.Test, opts ...TestOption) *numberProcessor // UNIQUE METHODS // Check that the value is one of the enum values -func (v *numberProcessor[T]) OneOf(enum []T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) OneOf(enum []T, options ...TestOption) *NumberSchema[T] { t := p.In(enum) for _, opt := range options { opt(&t) @@ -149,7 +149,7 @@ func (v *numberProcessor[T]) OneOf(enum []T, options ...TestOption) *numberProce } // checks for equality -func (v *numberProcessor[T]) EQ(n T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) EQ(n T, options ...TestOption) *NumberSchema[T] { t := p.EQ(n) for _, opt := range options { opt(&t) @@ -159,7 +159,7 @@ func (v *numberProcessor[T]) EQ(n T, options ...TestOption) *numberProcessor[T] } // checks for lesser or equal -func (v *numberProcessor[T]) LTE(n T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) LTE(n T, options ...TestOption) *NumberSchema[T] { t := p.LTE(n) for _, opt := range options { opt(&t) @@ -169,7 +169,7 @@ func (v *numberProcessor[T]) LTE(n T, options ...TestOption) *numberProcessor[T] } // checks for greater or equal -func (v *numberProcessor[T]) GTE(n T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) GTE(n T, options ...TestOption) *NumberSchema[T] { t := p.GTE(n) for _, opt := range options { opt(&t) @@ -179,7 +179,7 @@ func (v *numberProcessor[T]) GTE(n T, options ...TestOption) *numberProcessor[T] } // checks for lesser -func (v *numberProcessor[T]) LT(n T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) LT(n T, options ...TestOption) *NumberSchema[T] { t := p.LT(n) for _, opt := range options { opt(&t) @@ -189,7 +189,7 @@ func (v *numberProcessor[T]) LT(n T, options ...TestOption) *numberProcessor[T] } // checks for greater -func (v *numberProcessor[T]) GT(n T, options ...TestOption) *numberProcessor[T] { +func (v *NumberSchema[T]) GT(n T, options ...TestOption) *NumberSchema[T] { t := p.GT(n) for _, opt := range options { opt(&t) diff --git a/pointers.go b/pointers.go index ccfccc3..6eae075 100644 --- a/pointers.go +++ b/pointers.go @@ -8,7 +8,9 @@ import ( "github.com/Oudwins/zog/zconst" ) -type pointerProcessor struct { +var _ ComplexZogSchema = &PointerSchema{} + +type PointerSchema struct { // preTransforms []p.PreTransform tests []p.Test schema ZogSchema @@ -18,24 +20,24 @@ type pointerProcessor struct { // catch *any } -func (v *pointerProcessor) getType() zconst.ZogType { +func (v *PointerSchema) getType() zconst.ZogType { return zconst.TypePtr } -func (v *pointerProcessor) setCoercer(c conf.CoercerFunc) { +func (v *PointerSchema) setCoercer(c conf.CoercerFunc) { v.schema.setCoercer(c) } // Ptr creates a pointer ZogSchema -func Ptr(schema ZogSchema) *pointerProcessor { - return &pointerProcessor{ +func Ptr(schema ZogSchema) *PointerSchema { + return &PointerSchema{ tests: []p.Test{}, schema: schema, } } // Parse the data into the destination pointer -func (v *pointerProcessor) Parse(data any, dest any, options ...ParsingOption) p.ZogErrMap { +func (v *PointerSchema) Parse(data any, dest any, options ...ParsingOption) p.ZogErrMap { errs := p.NewErrsMap() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -48,7 +50,7 @@ func (v *pointerProcessor) Parse(data any, dest any, options ...ParsingOption) p return errs.M } -func (v *pointerProcessor) process(data any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *PointerSchema) process(data any, dest any, path p.PathBuilder, ctx ParseCtx) { isZero := p.IsParseZeroValue(data, ctx) if isZero { if v.required != nil { @@ -70,7 +72,7 @@ func (v *pointerProcessor) process(data any, dest any, path p.PathBuilder, ctx P v.schema.process(data, di, path, ctx) } -func (v *pointerProcessor) NotNil(options ...TestOption) *pointerProcessor { +func (v *PointerSchema) NotNil(options ...TestOption) *PointerSchema { r := p.Test{ ErrCode: zconst.ErrCodeNotNil, } diff --git a/slices.go b/slices.go index cb0b9bc..6d9b3dc 100644 --- a/slices.go +++ b/slices.go @@ -9,9 +9,9 @@ import ( "github.com/Oudwins/zog/zconst" ) -var _ ZogSchema = &sliceProcessor{} +var _ ComplexZogSchema = &SliceSchema{} -type sliceProcessor struct { +type SliceSchema struct { preTransforms []p.PreTransform tests []p.Test schema ZogSchema @@ -25,17 +25,17 @@ type sliceProcessor struct { // ! INTERNALS // Returns the type of the schema -func (v *sliceProcessor) getType() zconst.ZogType { +func (v *SliceSchema) getType() zconst.ZogType { return zconst.TypeSlice } // Sets the coercer for the schema -func (v *sliceProcessor) setCoercer(c conf.CoercerFunc) { +func (v *SliceSchema) setCoercer(c conf.CoercerFunc) { v.coercer = c } // Internal function to process the data -func (v *sliceProcessor) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *SliceSchema) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { destType := zconst.TypeSlice // 1. preTransforms if v.preTransforms != nil { @@ -116,8 +116,8 @@ func (v *sliceProcessor) process(val any, dest any, path p.PathBuilder, ctx Pars // 4. postTransforms -> defered see above } -func Slice(schema ZogSchema, opts ...SchemaOption) *sliceProcessor { - s := &sliceProcessor{ +func Slice(schema ZogSchema, opts ...SchemaOption) *SliceSchema { + s := &SliceSchema{ schema: schema, coercer: conf.Coercers.Slice, // default coercer } @@ -128,7 +128,7 @@ func Slice(schema ZogSchema, opts ...SchemaOption) *sliceProcessor { } // only supports val = slice[any] & dest = &slice[] -func (v *sliceProcessor) Parse(data any, dest any, options ...ParsingOption) p.ZogErrMap { +func (v *SliceSchema) Parse(data any, dest any, options ...ParsingOption) p.ZogErrMap { errs := p.NewErrsMap() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -141,7 +141,7 @@ func (v *sliceProcessor) Parse(data any, dest any, options ...ParsingOption) p.Z } // Adds pretransform function to schema -func (v *sliceProcessor) PreTransform(transform p.PreTransform) *sliceProcessor { +func (v *SliceSchema) PreTransform(transform p.PreTransform) *SliceSchema { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -150,7 +150,7 @@ func (v *sliceProcessor) PreTransform(transform p.PreTransform) *sliceProcessor } // Adds posttransform function to schema -func (v *sliceProcessor) PostTransform(transform p.PostTransform) *sliceProcessor { +func (v *SliceSchema) PostTransform(transform p.PostTransform) *SliceSchema { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -161,7 +161,7 @@ func (v *sliceProcessor) PostTransform(transform p.PostTransform) *sliceProcesso // !MODIFIERS // marks field as required -func (v *sliceProcessor) Required(options ...TestOption) *sliceProcessor { +func (v *SliceSchema) Required(options ...TestOption) *SliceSchema { r := p.Required() for _, opt := range options { opt(&r) @@ -171,20 +171,20 @@ func (v *sliceProcessor) Required(options ...TestOption) *sliceProcessor { } // marks field as optional -func (v *sliceProcessor) Optional() *sliceProcessor { +func (v *SliceSchema) Optional() *SliceSchema { v.required = nil return v } // sets the default value -func (v *sliceProcessor) Default(val any) *sliceProcessor { +func (v *SliceSchema) Default(val any) *SliceSchema { v.defaultVal = val return v } // NOT IMPLEMENTED YET // sets the catch value (i.e the value to use if the validation fails) -// func (v *sliceProcessor) Catch(val string) *sliceProcessor { +// func (v *SliceSchema) Catch(val string) *SliceSchema { // v.catch = &val // return v // } @@ -192,7 +192,7 @@ func (v *sliceProcessor) Default(val any) *sliceProcessor { // !TESTS // custom test function call it -> schema.Test(t z.Test, opts ...TestOption) -func (v *sliceProcessor) Test(t p.Test, opts ...TestOption) *sliceProcessor { +func (v *SliceSchema) Test(t p.Test, opts ...TestOption) *SliceSchema { for _, opt := range opts { opt(&t) } @@ -201,7 +201,7 @@ func (v *sliceProcessor) Test(t p.Test, opts ...TestOption) *sliceProcessor { } // Minimum number of items -func (v *sliceProcessor) Min(n int, options ...TestOption) *sliceProcessor { +func (v *SliceSchema) Min(n int, options ...TestOption) *SliceSchema { v.tests = append(v.tests, sliceMin(n), ) @@ -213,7 +213,7 @@ func (v *sliceProcessor) Min(n int, options ...TestOption) *sliceProcessor { } // Maximum number of items -func (v *sliceProcessor) Max(n int, options ...TestOption) *sliceProcessor { +func (v *SliceSchema) Max(n int, options ...TestOption) *SliceSchema { v.tests = append(v.tests, sliceMax(n), ) @@ -224,7 +224,7 @@ func (v *sliceProcessor) Max(n int, options ...TestOption) *sliceProcessor { } // Exact number of items -func (v *sliceProcessor) Len(n int, options ...TestOption) *sliceProcessor { +func (v *SliceSchema) Len(n int, options ...TestOption) *SliceSchema { v.tests = append(v.tests, sliceLength(n), ) @@ -235,7 +235,7 @@ func (v *sliceProcessor) Len(n int, options ...TestOption) *sliceProcessor { } // Slice contains a specific value -func (v *sliceProcessor) Contains(value any, options ...TestOption) *sliceProcessor { +func (v *SliceSchema) Contains(value any, options ...TestOption) *SliceSchema { v.tests = append(v.tests, p.Test{ ErrCode: zconst.ErrCodeContains, diff --git a/string.go b/string.go index 014920e..21a96ed 100644 --- a/string.go +++ b/string.go @@ -10,12 +10,14 @@ import ( "github.com/Oudwins/zog/zconst" ) +var _ PrimitiveZogSchema[string] = &StringSchema{} + var ( emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$") uuidRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$`) ) -type stringProcessor struct { +type StringSchema struct { preTransforms []p.PreTransform tests []p.Test postTransforms []p.PostTransform @@ -28,25 +30,25 @@ type stringProcessor struct { // ! INTERNALS // Internal function to process the data -func (v *stringProcessor) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *StringSchema) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { primitiveProcessor(val, dest, path, ctx, v.preTransforms, v.tests, v.postTransforms, v.defaultVal, v.required, v.catch, v.coercer, p.IsParseZeroValue) } // Returns the type of the schema -func (v *stringProcessor) getType() zconst.ZogType { +func (v *StringSchema) getType() zconst.ZogType { return zconst.TypeString } // Sets the coercer for the schema -func (v *stringProcessor) setCoercer(c conf.CoercerFunc) { +func (v *StringSchema) setCoercer(c conf.CoercerFunc) { v.coercer = c } // ! USER FACING FUNCTIONS // Returns a new String Schema -func String(opts ...SchemaOption) *stringProcessor { - s := &stringProcessor{ +func String(opts ...SchemaOption) *StringSchema { + s := &StringSchema{ coercer: conf.Coercers.String, // default coercer } for _, opt := range opts { @@ -56,7 +58,7 @@ func String(opts ...SchemaOption) *stringProcessor { } // Parses the data into the destination string. Returns a list of errors -func (v *stringProcessor) Parse(data any, dest *string, options ...ParsingOption) p.ZogErrList { +func (v *StringSchema) Parse(data any, dest *string, options ...ParsingOption) p.ZogErrList { errs := p.NewErrsList() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -70,7 +72,7 @@ func (v *stringProcessor) Parse(data any, dest *string, options ...ParsingOption } // Adds pretransform function to schema -func (v *stringProcessor) PreTransform(transform p.PreTransform) *stringProcessor { +func (v *StringSchema) PreTransform(transform p.PreTransform) *StringSchema { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -79,7 +81,7 @@ func (v *stringProcessor) PreTransform(transform p.PreTransform) *stringProcesso } // PreTransform: trims the input data of whitespace if it is a string -func (v *stringProcessor) Trim() *stringProcessor { +func (v *StringSchema) Trim() *StringSchema { v.preTransforms = append(v.preTransforms, func(val any, ctx ParseCtx) (any, error) { s, ok := val.(string) if !ok { @@ -91,7 +93,7 @@ func (v *stringProcessor) Trim() *stringProcessor { } // Adds posttransform function to schema -func (v *stringProcessor) PostTransform(transform p.PostTransform) *stringProcessor { +func (v *StringSchema) PostTransform(transform p.PostTransform) *StringSchema { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -102,7 +104,7 @@ func (v *stringProcessor) PostTransform(transform p.PostTransform) *stringProces // ! MODIFIERS // marks field as required -func (v *stringProcessor) Required(options ...TestOption) *stringProcessor { +func (v *StringSchema) Required(options ...TestOption) *StringSchema { r := p.Required() for _, opt := range options { opt(&r) @@ -112,19 +114,19 @@ func (v *stringProcessor) Required(options ...TestOption) *stringProcessor { } // marks field as optional -func (v *stringProcessor) Optional() *stringProcessor { +func (v *StringSchema) Optional() *StringSchema { v.required = nil return v } // sets the default value -func (v *stringProcessor) Default(val string) *stringProcessor { +func (v *StringSchema) Default(val string) *StringSchema { v.defaultVal = &val return v } // sets the catch value (i.e the value to use if the validation fails) -func (v *stringProcessor) Catch(val string) *stringProcessor { +func (v *StringSchema) Catch(val string) *StringSchema { v.catch = &val return v } @@ -133,7 +135,7 @@ func (v *stringProcessor) Catch(val string) *stringProcessor { // ! Tests // custom test function call it -> schema.Test(t z.Test, opts ...TestOption) -func (v *stringProcessor) Test(t p.Test, opts ...TestOption) *stringProcessor { +func (v *StringSchema) Test(t p.Test, opts ...TestOption) *StringSchema { for _, opt := range opts { opt(&t) } @@ -142,7 +144,7 @@ func (v *stringProcessor) Test(t p.Test, opts ...TestOption) *stringProcessor { } // Test: checks that the value is one of the enum values -func (v *stringProcessor) OneOf(enum []string, options ...TestOption) *stringProcessor { +func (v *StringSchema) OneOf(enum []string, options ...TestOption) *StringSchema { t := p.In(enum) for _, opt := range options { opt(&t) @@ -152,7 +154,7 @@ func (v *stringProcessor) OneOf(enum []string, options ...TestOption) *stringPro } // Test: checks that the value is at least n characters long -func (v *stringProcessor) Min(n int, options ...TestOption) *stringProcessor { +func (v *StringSchema) Min(n int, options ...TestOption) *StringSchema { t := p.LenMin[string](n) for _, opt := range options { opt(&t) @@ -162,7 +164,7 @@ func (v *stringProcessor) Min(n int, options ...TestOption) *stringProcessor { } // Test: checks that the value is at most n characters long -func (v *stringProcessor) Max(n int, options ...TestOption) *stringProcessor { +func (v *StringSchema) Max(n int, options ...TestOption) *StringSchema { t := p.LenMax[string](n) for _, opt := range options { opt(&t) @@ -172,7 +174,7 @@ func (v *stringProcessor) Max(n int, options ...TestOption) *stringProcessor { } // Test: checks that the value is exactly n characters long -func (v *stringProcessor) Len(n int, options ...TestOption) *stringProcessor { +func (v *StringSchema) Len(n int, options ...TestOption) *StringSchema { t := p.Len[string](n) for _, opt := range options { opt(&t) @@ -182,7 +184,7 @@ func (v *stringProcessor) Len(n int, options ...TestOption) *stringProcessor { } // Test: checks that the value is a valid email address -func (v *stringProcessor) Email(options ...TestOption) *stringProcessor { +func (v *StringSchema) Email(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeEmail, ValidateFunc: func(v any, ctx ParseCtx) bool { @@ -201,7 +203,7 @@ func (v *stringProcessor) Email(options ...TestOption) *stringProcessor { } // Test: checks that the value is a valid URL -func (v *stringProcessor) URL(options ...TestOption) *stringProcessor { +func (v *StringSchema) URL(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeURL, ValidateFunc: func(v any, ctx ParseCtx) bool { @@ -221,7 +223,7 @@ func (v *stringProcessor) URL(options ...TestOption) *stringProcessor { } // Test: checks that the value has the prefix -func (v *stringProcessor) HasPrefix(s string, options ...TestOption) *stringProcessor { +func (v *StringSchema) HasPrefix(s string, options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeHasPrefix, Params: make(map[string]any, 1), @@ -242,7 +244,7 @@ func (v *stringProcessor) HasPrefix(s string, options ...TestOption) *stringProc } // Test: checks that the value has the suffix -func (v *stringProcessor) HasSuffix(s string, options ...TestOption) *stringProcessor { +func (v *StringSchema) HasSuffix(s string, options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeHasSuffix, Params: make(map[string]any, 1), @@ -263,7 +265,7 @@ func (v *stringProcessor) HasSuffix(s string, options ...TestOption) *stringProc } // Test: checks that the value contains the substring -func (v *stringProcessor) Contains(sub string, options ...TestOption) *stringProcessor { +func (v *StringSchema) Contains(sub string, options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeContains, Params: make(map[string]any, 1), @@ -284,7 +286,7 @@ func (v *stringProcessor) Contains(sub string, options ...TestOption) *stringPro } // Test: checks that the value contains an uppercase letter -func (v *stringProcessor) ContainsUpper(options ...TestOption) *stringProcessor { +func (v *StringSchema) ContainsUpper(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeContainsUpper, ValidateFunc: func(v any, ctx ParseCtx) bool { @@ -308,7 +310,7 @@ func (v *stringProcessor) ContainsUpper(options ...TestOption) *stringProcessor } // Test: checks that the value contains a digit -func (v *stringProcessor) ContainsDigit(options ...TestOption) *stringProcessor { +func (v *StringSchema) ContainsDigit(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeContainsDigit, ValidateFunc: func(v any, ctx ParseCtx) bool { @@ -334,7 +336,7 @@ func (v *stringProcessor) ContainsDigit(options ...TestOption) *stringProcessor } // Test: checks that the value contains a special character -func (v *stringProcessor) ContainsSpecial(options ...TestOption) *stringProcessor { +func (v *StringSchema) ContainsSpecial(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeContainsSpecial, @@ -362,7 +364,7 @@ func (v *stringProcessor) ContainsSpecial(options ...TestOption) *stringProcesso } // Test: checks that the value is a valid uuid -func (v *stringProcessor) UUID(options ...TestOption) *stringProcessor { +func (v *StringSchema) UUID(options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeUUID, ValidateFunc: func(v any, ctx ParseCtx) bool { @@ -381,7 +383,7 @@ func (v *stringProcessor) UUID(options ...TestOption) *stringProcessor { } // Test: checks that value matches to regex -func (v *stringProcessor) Match(regex *regexp.Regexp, options ...TestOption) *stringProcessor { +func (v *StringSchema) Match(regex *regexp.Regexp, options ...TestOption) *StringSchema { t := p.Test{ ErrCode: zconst.ErrCodeMatch, Params: make(map[string]any, 1), diff --git a/struct.go b/struct.go index 6b9ed34..cb9e718 100644 --- a/struct.go +++ b/struct.go @@ -10,9 +10,9 @@ import ( "github.com/Oudwins/zog/zconst" ) -var _ ZogSchema = &structProcessor{} +var _ ComplexZogSchema = &StructSchema{} -type structProcessor struct { +type StructSchema struct { preTransforms []p.PreTransform schema Schema postTransforms []p.PostTransform @@ -23,16 +23,16 @@ type structProcessor struct { } // Returns the type of the schema -func (v *structProcessor) getType() zconst.ZogType { +func (v *StructSchema) getType() zconst.ZogType { return zconst.TypeStruct } // Sets the coercer for the schema -func (v *structProcessor) setCoercer(c conf.CoercerFunc) { +func (v *StructSchema) setCoercer(c conf.CoercerFunc) { // noop } -func (v *structProcessor) process(data any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *StructSchema) process(data any, dest any, path p.PathBuilder, ctx ParseCtx) { destType := zconst.TypeStruct // 1. preTransforms if v.preTransforms != nil { @@ -109,7 +109,7 @@ func (v *structProcessor) process(data any, dest any, path p.PathBuilder, ctx Pa } switch schema := processor.(type) { - case *structProcessor: + case *StructSchema: schema.process(dataProv.GetNestedProvider(fieldKey), destPtr, path.Push(fieldKey), ctx) default: @@ -132,15 +132,15 @@ func (v *structProcessor) process(data any, dest any, path p.PathBuilder, ctx Pa // A map of field names to zog schemas type Schema map[string]ZogSchema -// Returns a new structProcessor which can be used to parse input data into a struct -func Struct(schema Schema) *structProcessor { - return &structProcessor{ +// Returns a new StructSchema which can be used to parse input data into a struct +func Struct(schema Schema) *StructSchema { + return &StructSchema{ schema: schema, } } // Parses val into destPtr and validates each field based on the schema. Only supports val = map[string]any & dest = &struct -func (v *structProcessor) Parse(data any, destPtr any, options ...ParsingOption) p.ZogErrMap { +func (v *StructSchema) Parse(data any, destPtr any, options ...ParsingOption) p.ZogErrMap { errs := p.NewErrsMap() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) for _, opt := range options { @@ -154,7 +154,7 @@ func (v *structProcessor) Parse(data any, destPtr any, options ...ParsingOption) } // Add a pretransform step to the schema -func (v *structProcessor) PreTransform(transform p.PreTransform) *structProcessor { +func (v *StructSchema) PreTransform(transform p.PreTransform) *StructSchema { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -163,7 +163,7 @@ func (v *structProcessor) PreTransform(transform p.PreTransform) *structProcesso } // Adds posttransform function to schema -func (v *structProcessor) PostTransform(transform p.PostTransform) *structProcessor { +func (v *StructSchema) PostTransform(transform p.PostTransform) *StructSchema { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -174,7 +174,7 @@ func (v *structProcessor) PostTransform(transform p.PostTransform) *structProces // ! MODIFIERS // marks field as required -func (v *structProcessor) Required(options ...TestOption) *structProcessor { +func (v *StructSchema) Required(options ...TestOption) *StructSchema { r := p.Required() for _, opt := range options { opt(&r) @@ -184,26 +184,26 @@ func (v *structProcessor) Required(options ...TestOption) *structProcessor { } // marks field as optional -func (v *structProcessor) Optional() *structProcessor { +func (v *StructSchema) Optional() *StructSchema { v.required = nil return v } // // sets the default value -// func (v *structProcessor) Default(val any) *structProcessor { +// func (v *StructSchema) Default(val any) *StructSchema { // v.defaultVal = val // return v // } // // sets the catch value (i.e the value to use if the validation fails) -// func (v *structProcessor) Catch(val any) *structProcessor { +// func (v *StructSchema) Catch(val any) *StructSchema { // v.catch = val // return v // } // ! VALIDATORS // custom test function call it -> schema.Test(t z.Test, opts ...TestOption) -func (v *structProcessor) Test(t p.Test, opts ...TestOption) *structProcessor { +func (v *StructSchema) Test(t p.Test, opts ...TestOption) *StructSchema { for _, opt := range opts { opt(&t) } diff --git a/struct_helpers.go b/struct_helpers.go index 8d4fc3c..7948003 100644 --- a/struct_helpers.go +++ b/struct_helpers.go @@ -17,8 +17,8 @@ import ( // - others: Additional schemas to merge // // Returns a new schema containing the merged fields and transforms -func (v *structProcessor) Merge(other *structProcessor, others ...*structProcessor) *structProcessor { - new := &structProcessor{ +func (v *StructSchema) Merge(other *StructSchema, others ...*StructSchema) *StructSchema { + new := &StructSchema{ preTransforms: make([]p.PreTransform, 0), postTransforms: make([]p.PostTransform, 0), tests: make([]p.Test, 0), @@ -56,8 +56,8 @@ func (v *structProcessor) Merge(other *structProcessor, others ...*structProcess // cloneShallow creates a shallow copy of the schema. // The new schema shares references to the transforms, tests and inner schema. -func (v *structProcessor) cloneShallow() *structProcessor { - new := &structProcessor{ +func (v *StructSchema) cloneShallow() *StructSchema { + new := &StructSchema{ preTransforms: v.preTransforms, postTransforms: v.postTransforms, tests: v.tests, @@ -73,7 +73,7 @@ func (v *structProcessor) cloneShallow() *structProcessor { // - For maps, fields are omitted when their boolean value is true // // Returns a new schema with the specified fields removed -func (v *structProcessor) Omit(vals ...any) *structProcessor { +func (v *StructSchema) Omit(vals ...any) *StructSchema { new := v.cloneShallow() new.schema = Schema{} maps.Copy(new.schema, v.schema) @@ -98,7 +98,7 @@ func (v *structProcessor) Omit(vals ...any) *structProcessor { // - For maps, fields are kept when their boolean value is true // // Returns a new schema containing only the specified fields -func (v *structProcessor) Pick(picks ...any) *structProcessor { +func (v *StructSchema) Pick(picks ...any) *StructSchema { new := v.cloneShallow() new.schema = Schema{} for _, pick := range picks { @@ -123,7 +123,7 @@ func (v *structProcessor) Pick(picks ...any) *structProcessor { // - schema: The schema containing fields to add // // Returns a new schema with the additional fields -func (v *structProcessor) Extend(schema Schema) *structProcessor { +func (v *StructSchema) Extend(schema Schema) *StructSchema { new := v.cloneShallow() new.schema = Schema{} maps.Copy(new.schema, v.schema) diff --git a/time.go b/time.go index 16314aa..83873ed 100644 --- a/time.go +++ b/time.go @@ -9,9 +9,9 @@ import ( ) // ! INTERNALS -var _ ZogSchema = &timeProcessor{} +var _ PrimitiveZogSchema[time.Time] = &TimeSchema{} -type timeProcessor struct { +type TimeSchema struct { preTransforms []p.PreTransform tests []p.Test postTransforms []p.PostTransform @@ -22,27 +22,27 @@ type timeProcessor struct { } // internal processes the data -func (v *timeProcessor) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { +func (v *TimeSchema) process(val any, dest any, path p.PathBuilder, ctx ParseCtx) { primitiveProcessor(val, dest, path, ctx, v.preTransforms, v.tests, v.postTransforms, v.defaultVal, v.required, v.catch, v.coercer, p.IsParseZeroValue) } // Returns the type of the schema -func (v *timeProcessor) getType() zconst.ZogType { +func (v *TimeSchema) getType() zconst.ZogType { return zconst.TypeTime } // Sets the coercer for the schema -func (v *timeProcessor) setCoercer(c conf.CoercerFunc) { +func (v *TimeSchema) setCoercer(c conf.CoercerFunc) { v.coercer = c } -type TimeFunc func(opts ...SchemaOption) *timeProcessor +type TimeFunc func(opts ...SchemaOption) *TimeSchema // ! USER FACING FUNCTIONS // Returns a new Time Schema -var Time TimeFunc = func(opts ...SchemaOption) *timeProcessor { - t := &timeProcessor{ +var Time TimeFunc = func(opts ...SchemaOption) *TimeSchema { + t := &TimeSchema{ coercer: conf.Coercers.Time, } for _, opt := range opts { @@ -73,7 +73,7 @@ func (t TimeFunc) Format(format string) SchemaOption { } // Parses the data into the destination time.Time. Returns a list of errors -func (v *timeProcessor) Parse(data any, dest *time.Time, options ...ParsingOption) p.ZogErrList { +func (v *TimeSchema) Parse(data any, dest *time.Time, options ...ParsingOption) p.ZogErrList { errs := p.NewErrsList() ctx := p.NewParseCtx(errs, conf.ErrorFormatter) @@ -89,7 +89,7 @@ func (v *timeProcessor) Parse(data any, dest *time.Time, options ...ParsingOptio } // Adds pretransform function to schema -func (v *timeProcessor) PreTransform(transform p.PreTransform) *timeProcessor { +func (v *TimeSchema) PreTransform(transform p.PreTransform) *TimeSchema { if v.preTransforms == nil { v.preTransforms = []p.PreTransform{} } @@ -98,7 +98,7 @@ func (v *timeProcessor) PreTransform(transform p.PreTransform) *timeProcessor { } // Adds posttransform function to schema -func (v *timeProcessor) PostTransform(transform p.PostTransform) *timeProcessor { +func (v *TimeSchema) PostTransform(transform p.PostTransform) *TimeSchema { if v.postTransforms == nil { v.postTransforms = []p.PostTransform{} } @@ -109,7 +109,7 @@ func (v *timeProcessor) PostTransform(transform p.PostTransform) *timeProcessor // ! MODIFIERS // marks field as required -func (v *timeProcessor) Required(options ...TestOption) *timeProcessor { +func (v *TimeSchema) Required(options ...TestOption) *TimeSchema { r := p.Required() for _, opt := range options { opt(&r) @@ -119,19 +119,19 @@ func (v *timeProcessor) Required(options ...TestOption) *timeProcessor { } // marks field as optional -func (v *timeProcessor) Optional() *timeProcessor { +func (v *TimeSchema) Optional() *TimeSchema { v.required = nil return v } // sets the default value -func (v *timeProcessor) Default(val time.Time) *timeProcessor { +func (v *TimeSchema) Default(val time.Time) *TimeSchema { v.defaultVal = &val return v } // sets the catch value (i.e the value to use if the validation fails) -func (v *timeProcessor) Catch(val time.Time) *timeProcessor { +func (v *TimeSchema) Catch(val time.Time) *TimeSchema { v.catch = &val return v } @@ -139,7 +139,7 @@ func (v *timeProcessor) Catch(val time.Time) *timeProcessor { // GLOBAL METHODS // custom test function call it -> schema.Test("error_code", func(val any, ctx ParseCtx) bool {return true}) -func (v *timeProcessor) Test(t p.Test, opts ...TestOption) *timeProcessor { +func (v *TimeSchema) Test(t p.Test, opts ...TestOption) *TimeSchema { for _, opt := range opts { opt(&t) } @@ -150,7 +150,7 @@ func (v *timeProcessor) Test(t p.Test, opts ...TestOption) *timeProcessor { // UNIQUE METHODS // Checks that the value is after the given time -func (v *timeProcessor) After(t time.Time, opts ...TestOption) *timeProcessor { +func (v *TimeSchema) After(t time.Time, opts ...TestOption) *TimeSchema { r := p.Test{ ErrCode: zconst.ErrCodeAfter, Params: make(map[string]any, 1), @@ -174,7 +174,7 @@ func (v *timeProcessor) After(t time.Time, opts ...TestOption) *timeProcessor { } // Checks that the value is before the given time -func (v *timeProcessor) Before(t time.Time, opts ...TestOption) *timeProcessor { +func (v *TimeSchema) Before(t time.Time, opts ...TestOption) *TimeSchema { r := p.Test{ ErrCode: zconst.ErrCodeBefore, @@ -197,7 +197,7 @@ func (v *timeProcessor) Before(t time.Time, opts ...TestOption) *timeProcessor { } // Checks that the value is equal to the given time -func (v *timeProcessor) EQ(t time.Time, opts ...TestOption) *timeProcessor { +func (v *TimeSchema) EQ(t time.Time, opts ...TestOption) *TimeSchema { r := p.Test{ ErrCode: zconst.ErrCodeEQ, Params: make(map[string]any, 1), diff --git a/zogSchema.go b/zogSchema.go index 2748e79..be3194b 100644 --- a/zogSchema.go +++ b/zogSchema.go @@ -11,12 +11,27 @@ import ( ) // The ZogSchema is the interface all schemas must implement +// This is most useful for internal use. If you are looking to pass schemas around, use the ComplexZogSchema or PrimitiveZogSchema interfaces if possible. type ZogSchema interface { process(val any, dest any, path p.PathBuilder, ctx ParseCtx) setCoercer(c conf.CoercerFunc) getType() zconst.ZogType } +// This is a common interface for all complex schemas (i.e structs, slices, pointers...) +// You can use this to pass any complex schema around +type ComplexZogSchema interface { + ZogSchema + Parse(val any, dest any, options ...ParsingOption) ZogErrMap +} + +// This is a common interface for all primitive schemas (i.e strings, numbers, booleans, time.Time...) +// You can use this to pass any primitive schema around +type PrimitiveZogSchema[T p.ZogPrimitive] interface { + ZogSchema + Parse(val any, dest *T, options ...ParsingOption) ZogErrList +} + // ! Passing Types through // ParseCtx is the context passed through the parser