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

looplab / eventhorizon / 12622512440

05 Jan 2025 07:58PM UTC coverage: 27.495% (-39.9%) from 67.361%
12622512440

Pull #419

github

web-flow
Merge b3c17d928 into ac3a97277
Pull Request #419: fix(ci): update to up/download-artifact v4

1769 of 6434 relevant lines covered (27.49%)

1.41 hits per line

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

0.0
/command_check.go
1
// Copyright (c) 2014 - The Event Horizon authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package eventhorizon
16

17
import (
18
        "errors"
19
        "reflect"
20
        "time"
21

22
        "github.com/looplab/eventhorizon/uuid"
23
)
24

25
var (
26
        // ErrMissingCommand is when there is no command to be handled.
27
        ErrMissingCommand = errors.New("missing command")
28
        // ErrMissingAggregateID is when a command is missing an aggregate ID.
29
        ErrMissingAggregateID = errors.New("missing aggregate ID")
30
)
31

32
// IsZeroer is used to check if a type is zero-valued, and in that case
33
// is not allowed to be used in a command. See CheckCommand.
34
type IsZeroer interface {
35
        IsZero() bool
36
}
37

38
// CommandFieldError is returned by Dispatch when a field is incorrect.
39
type CommandFieldError struct {
40
        Field string
41
}
42

43
// Error implements the Error method of the error interface.
44
func (c *CommandFieldError) Error() string {
×
45
        return "missing field: " + c.Field
×
46
}
×
47

48
// CheckCommand checks a command for errors.
49
func CheckCommand(cmd Command) error {
×
50
        if cmd == nil {
×
51
                return ErrMissingCommand
×
52
        }
×
53

54
        if cmd.AggregateID() == uuid.Nil {
×
55
                return ErrMissingAggregateID
×
56
        }
×
57

58
        rv := reflect.Indirect(reflect.ValueOf(cmd))
×
59
        rt := rv.Type()
×
60

×
61
        for i := 0; i < rt.NumField(); i++ {
×
62
                field := rt.Field(i)
×
63
                if field.PkgPath != "" {
×
64
                        continue // Skip private field.
×
65
                }
66

67
                tag := field.Tag.Get("eh")
×
68
                if tag == "optional" {
×
69
                        continue // Optional field.
×
70
                }
71

72
                var zero bool
×
73
                switch foo := rv.Field(i).Interface().(type) {
×
74
                case IsZeroer:
×
75
                        zero = foo.IsZero()
×
76
                default:
×
77
                        zero = isZero(rv.Field(i))
×
78
                }
79

80
                if zero {
×
81
                        return &CommandFieldError{field.Name}
×
82
                }
×
83
        }
84

85
        return nil
×
86
}
87

88
func isZero(v reflect.Value) bool {
×
89
        switch v.Kind() {
×
90
        case reflect.Func, reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
×
91
                // Types that are not allowed at all.
×
92
                // NOTE: Would be better with its own error for this.
×
93
                return true
×
94
        case reflect.Map, reflect.Slice:
×
95
                return v.IsNil()
×
96
        case reflect.Array:
×
97
                // Special case to check zero values of UUIDs.
×
98
                switch obj := v.Interface().(type) {
×
99
                case uuid.UUID:
×
100
                        return obj == uuid.Nil
×
101
                }
102

103
                for i := 0; i < v.Len(); i++ {
×
104
                        if !isZero(v.Index(i)) {
×
105
                                return false
×
106
                        }
×
107
                }
108

109
                return true
×
110
        case reflect.Interface, reflect.String:
×
111
                z := reflect.Zero(v.Type())
×
112

×
113
                return v.Interface() == z.Interface()
×
114
        case reflect.Struct:
×
115
                // Special case to get zero values by method.
×
116
                switch obj := v.Interface().(type) {
×
117
                case time.Time:
×
118
                        return obj.IsZero()
×
119
                }
120

121
                // Check public fields for zero values.
122
                z := true
×
123

×
124
                for i := 0; i < v.NumField(); i++ {
×
125
                        if v.Type().Field(i).PkgPath != "" {
×
126
                                continue // Skip private fields.
×
127
                        }
128

129
                        z = z && isZero(v.Field(i))
×
130
                }
131

132
                return z
×
133
        default:
×
134
                // Don't check for zero for value types:
×
135
                // Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32,
×
136
                // Uint64, Float32, Float64, Complex64, Complex128
×
137
                return false
×
138
        }
139
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc