-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathpreprocess.go
More file actions
98 lines (88 loc) · 2.63 KB
/
Copy pathpreprocess.go
File metadata and controls
98 lines (88 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package zog
import (
"fmt"
"github.com/Oudwins/zog/conf"
p "github.com/Oudwins/zog/pkgs/internals"
"github.com/Oudwins/zog/zconst"
)
type PreprocessSchema[F any, T any] struct {
schema ZogSchema
fn func(data F, ctx Ctx) (out T, err error)
}
// out should never be a pointer type
func Preprocess[F any, T any](fn func(data F, ctx Ctx) (out T, err error), schema ZogSchema) *PreprocessSchema[F, T] {
return &PreprocessSchema[F, T]{fn: fn, schema: schema}
}
func (s *PreprocessSchema[F, T]) process(ctx *p.SchemaCtx) {
v, ok := ctx.Data.(F)
if !ok {
ctx.AddIssue(ctx.IssueFromCoerce(fmt.Errorf("preprocess expected %T but got %T", v, ctx.Data)))
return
}
out, err := s.fn(v, ctx)
if err != nil {
ctx.AddIssue(ctx.IssueFromUnknownError(err))
return
}
ctx.Data = p.UnwrapPtr(out)
s.schema.process(ctx)
}
func (s *PreprocessSchema[F, T]) validate(ctx *p.SchemaCtx) {
v, ok := ctx.ValPtr.(F)
if !ok {
// We have to go directly to the exec context as that is what formats. We cannot use ctx because it will try to catch the issue and this is an uncatchable issue
// since we cannot set the value as its not of preprocess input type
ctx.ExecCtx.AddIssue(ctx.IssueFromInvalidType("preprocess input type", ctx.ValPtr, "validating a preprocessed schema"))
return
}
out, err := s.fn(v, ctx)
if err != nil {
ctx.AddIssue(ctx.Issue().SetMessage(err.Error()))
return
}
switch v := ctx.ValPtr.(type) {
case *T:
*v = out
case **T:
*v = &out
default:
panic(fmt.Sprintf("Preprocessed should be passed in schema.Validate() a value pointer that is compatible with its returned type T. Either *T or **T. Got %T", v))
}
s.schema.validate(ctx)
}
func (s *PreprocessSchema[F, T]) getType() zconst.ZogType {
return s.schema.getType()
}
func (s *PreprocessSchema[F, T]) setCoercer(coercer CoercerFunc) {
s.schema.setCoercer(coercer)
}
func (s *PreprocessSchema[F, T]) Parse(data F, destPtr *T, options ...ExecOption) ZogIssueList {
errs := p.NewErrsList()
defer errs.Free()
ctx := p.NewExecCtx(errs, conf.IssueFormatter)
defer ctx.Free()
for _, opt := range options {
opt(ctx)
}
path := p.NewPathBuilder()
defer path.Free()
sctx := ctx.NewSchemaCtx(data, destPtr, path, s.getType())
defer sctx.Free()
s.process(sctx)
return errs.List
}
func (s *PreprocessSchema[F, T]) Validate(data *T, options ...ExecOption) ZogIssueList {
errs := p.NewErrsList()
defer errs.Free()
ctx := p.NewExecCtx(errs, conf.IssueFormatter)
defer ctx.Free()
for _, opt := range options {
opt(ctx)
}
path := p.NewPathBuilder()
defer path.Free()
sctx := ctx.NewSchemaCtx(data, data, path, s.getType())
defer sctx.Free()
s.validate(sctx)
return errs.List
}