• 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.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
        "fmt"
20
        "sync"
21

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

25
// Command is a domain command that is sent to a Dispatcher.
26
//
27
// A command name should 1) be in present tense and 2) contain the intent
28
// (MoveCustomer vs CorrectCustomerAddress).
29
//
30
// The command should contain all the data needed when handling it as fields.
31
// These fields can take an optional "eh" tag, which adds properties. For now
32
// only "optional" is a valid tag: `eh:"optional"`.
33
type Command interface {
34
        // AggregateID returns the ID of the aggregate that the command should be
35
        // handled by.
36
        AggregateID() uuid.UUID
37

38
        // AggregateType returns the type of the aggregate that the command can be
39
        // handled by.
40
        AggregateType() AggregateType
41

42
        // CommandType returns the type of the command.
43
        CommandType() CommandType
44
}
45

46
// CommandType is the type of a command, used as its unique identifier.
47
type CommandType string
48

49
// String returns the string representation of a command type.
50
func (ct CommandType) String() string {
×
51
        return string(ct)
×
52
}
×
53

54
// CommandIDer provides a unique command ID to be used for request tracking etc.
55
type CommandIDer interface {
56
        // CommandID returns the ID of the command instance being handled.
57
        CommandID() uuid.UUID
58
}
59

60
// ErrCommandNotRegistered is when no command factory was registered.
61
var ErrCommandNotRegistered = errors.New("command not registered")
62

63
// RegisterCommand registers an command factory for a type. The factory is
64
// used to create concrete command types.
65
//
66
// An example would be:
67
//     RegisterCommand(func() Command { return &MyCommand{} })
68
func RegisterCommand(factory func() Command) {
×
69
        // Check that the created command matches the type registered.
×
70
        // TODO: Explore the use of reflect/gob for creating concrete types without
×
71
        // a factory func.
×
72
        cmd := factory()
×
73
        if cmd == nil {
×
74
                panic("eventhorizon: created command is nil")
×
75
        }
76

77
        commandType := cmd.CommandType()
×
78
        if commandType == CommandType("") {
×
79
                panic("eventhorizon: attempt to register empty command type")
×
80
        }
81

82
        commandsMu.Lock()
×
83
        defer commandsMu.Unlock()
×
84

×
85
        if _, ok := commands[commandType]; ok {
×
86
                panic(fmt.Sprintf("eventhorizon: registering duplicate types for %q", commandType))
×
87
        }
88

89
        commands[commandType] = factory
×
90
}
91

92
// UnregisterCommand removes the registration of the command factory for
93
// a type. This is mainly useful in mainenance situations where the command type
94
// needs to be switched at runtime.
95
func UnregisterCommand(commandType CommandType) {
×
96
        if commandType == CommandType("") {
×
97
                panic("eventhorizon: attempt to unregister empty command type")
×
98
        }
99

100
        commandsMu.Lock()
×
101
        defer commandsMu.Unlock()
×
102

×
103
        if _, ok := commands[commandType]; !ok {
×
104
                panic(fmt.Sprintf("eventhorizon: unregister of non-registered type %q", commandType))
×
105
        }
106

107
        delete(commands, commandType)
×
108
}
109

110
// CreateCommand creates an command of a type with an ID using the factory
111
// registered with RegisterCommand.
112
func CreateCommand(commandType CommandType) (Command, error) {
×
113
        commandsMu.RLock()
×
114
        defer commandsMu.RUnlock()
×
115

×
116
        if factory, ok := commands[commandType]; ok {
×
117
                return factory(), nil
×
118
        }
×
119

120
        return nil, ErrCommandNotRegistered
×
121
}
122

123
// ListCommands returns a list of all registered command types.
124
func RegisteredCommands() map[CommandType]func() Command {
×
125
        commandsMu.Lock()
×
126
        defer commandsMu.Unlock()
×
127

×
128
        mapCopy := make(map[CommandType]func() Command)
×
129
        for key, val := range commands {
×
130
                mapCopy[key] = val
×
131
        }
×
132

133
        return mapCopy
×
134
}
135

136
var commands = make(map[CommandType]func() Command)
137
var commandsMu sync.RWMutex
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