• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Oudwins / zog / 13269197352

11 Feb 2025 05:48PM UTC coverage: 86.667% (-0.4%) from 87.046%
13269197352

push

github

web-flow
fix!: structs can no longer be required or optional. Define this in the fields instead. If you need to model a struct that might exist use a pointer to a struct. This should not affect most users as now it works how everyone intuitively thought it worked. (#88)

* fix!: structs can no longer be required or optional. Define this in the fields instead. If you need to model a struct that might exist use a pointer to a struct

* tests: updated tests

* docs: updated docs

* docs: documented behaviour for errors during unmarshal

* fix: lint

25 of 43 new or added lines in 3 files covered. (58.14%)

9 existing lines in 2 files now uncovered.

1794 of 2070 relevant lines covered (86.67%)

28.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.98
/pointers.go
1
package zog
2

3
import (
4
        "reflect"
5

6
        "github.com/Oudwins/zog/conf"
7
        p "github.com/Oudwins/zog/internals"
8
        "github.com/Oudwins/zog/zconst"
9
)
10

11
var _ ComplexZogSchema = &PointerSchema{}
12

13
type PointerSchema struct {
14
        // preTransforms  []p.PreTransform
15
        tests    []p.Test
16
        schema   ZogSchema
17
        required *p.Test
18
        // postTransforms []p.PostTransform
19
        // defaultVal     *any
20
        // catch          *any
21
}
22

23
func (v *PointerSchema) getType() zconst.ZogType {
59✔
24
        return zconst.TypePtr
59✔
25
}
59✔
26

27
func (v *PointerSchema) setCoercer(c conf.CoercerFunc) {
1✔
28
        v.schema.setCoercer(c)
1✔
29
}
1✔
30

31
// Ptr creates a pointer ZogSchema
32
func Ptr(schema ZogSchema) *PointerSchema {
34✔
33
        return &PointerSchema{
34✔
34
                tests:  []p.Test{},
34✔
35
                schema: schema,
34✔
36
        }
34✔
37
}
34✔
38

39
// Parse the data into the destination pointer
40
func (v *PointerSchema) Parse(data any, dest any, options ...ExecOption) p.ZogIssueMap {
14✔
41
        errs := p.NewErrsMap()
14✔
42
        ctx := p.NewExecCtx(errs, conf.IssueFormatter)
14✔
43
        for _, opt := range options {
16✔
44
                opt(ctx)
2✔
45
        }
2✔
46
        path := p.PathBuilder("")
14✔
47

14✔
48
        v.process(ctx.NewSchemaCtx(data, dest, path, v.getType()))
14✔
49

14✔
50
        return errs.M
14✔
51
}
52

53
func (v *PointerSchema) process(ctx *p.SchemaCtx) {
30✔
54

30✔
55
        // TODO this is a mess. But couldn't figure out a simple way to support top level optional structs without doing this.
30✔
56
        // Companion code to this codde is in struct.go > process
30✔
57
        subCtx := ctx.NewSchemaCtx(ctx.Val, nil, ctx.Path, v.schema.getType())
30✔
58
        var err error
30✔
59
        if fn, ok := ctx.Val.(p.DpFactory); ok {
30✔
NEW
60
                ctx.Val, err = fn()
×
NEW
61
                if err != nil {
×
NEW
62
                        ctx.AddIssue(subCtx.IssueFromUnknownError(err))
×
NEW
63
                        return
×
NEW
64
                }
×
65
        }
66
        // End of messy code
67

68
        isZero := p.IsParseZeroValue(ctx.Val, ctx)
30✔
69
        if isZero {
37✔
70
                if v.required != nil {
11✔
71
                        // We set the destination type to the schema type because pointer doesn't have any issue messages. They pass through to the schema type
4✔
72
                        ctx.AddIssue(ctx.IssueFromTest(v.required, ctx.Val).SetDType(v.schema.getType()))
4✔
73
                }
4✔
74
                return
7✔
75
        }
76
        rv := reflect.ValueOf(ctx.DestPtr)
23✔
77
        destPtr := rv.Elem()
23✔
78
        if destPtr.IsNil() {
43✔
79
                // this sets the primitive also
20✔
80
                newVal := reflect.New(destPtr.Type().Elem())
20✔
81
                // this generates a new nil pointer
20✔
82
                //newVal := reflect.Zero(destPtr.Type())
20✔
83
                destPtr.Set(newVal)
20✔
84
        }
20✔
85
        di := destPtr.Interface()
23✔
86
        subCtx.DestPtr = di
23✔
87
        v.schema.process(subCtx)
23✔
88
}
89

90
// Validates a pointer pointer
91
func (v *PointerSchema) Validate(data any, options ...ExecOption) p.ZogIssueMap {
11✔
92
        errs := p.NewErrsMap()
11✔
93
        ctx := p.NewExecCtx(errs, conf.IssueFormatter)
11✔
94
        for _, opt := range options {
13✔
95
                opt(ctx)
2✔
96
        }
2✔
97
        v.validate(ctx.NewValidateSchemaCtx(data, p.PathBuilder(""), v.getType()))
11✔
98
        return errs.M
11✔
99
}
100

101
func (v *PointerSchema) validate(ctx *p.SchemaCtx) {
28✔
102
        rv := reflect.ValueOf(ctx.Val)
28✔
103
        destPtr := rv.Elem()
28✔
104
        if !destPtr.IsValid() || destPtr.IsNil() {
36✔
105
                if v.required != nil {
12✔
106
                        // We set the destination type to the schema type because pointer doesn't have any issue messages. They pass through to the schema type
4✔
107
                        ctx.AddIssue(ctx.IssueFromTest(v.required, ctx.Val).SetDType(v.schema.getType()))
4✔
108
                }
4✔
109
                return
8✔
110
        }
111
        di := destPtr.Interface()
19✔
112
        ctx.Val = di
19✔
113
        v.schema.validate(ctx.NewValidateSchemaCtx(di, ctx.Path, v.schema.getType()))
19✔
114
}
115

116
// Validate Existing Pointer
117

118
func (v *PointerSchema) NotNil(options ...TestOption) *PointerSchema {
7✔
119
        r := p.Test{
7✔
120
                IssueCode: zconst.IssueCodeNotNil,
7✔
121
        }
7✔
122
        for _, opt := range options {
10✔
123
                opt(&r)
3✔
124
        }
3✔
125
        v.required = &r
7✔
126
        return v
7✔
127
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc