-
Notifications
You must be signed in to change notification settings - Fork 35
/
frequent_flier_account.go
81 lines (69 loc) · 2.61 KB
/
frequent_flier_account.go
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
package main
import "fmt"
// FrequentFlierAccount represents the state of an instance of the frequent flier
// account aggregate. It tracks changes on itself in the form of domain events.
type FrequentFlierAccount struct {
id string
miles int
tierPoints int
status Status
expectedVersion int
changes []interface{}
}
// RecordFlightTaken is used to record the fact that a customer has taken a flight
// which should be attached to this frequent flier account. The number of miles and
// tier points which apply are calculated externally.
//
// If recording this flight takes the account over a status boundary, it will
// automatically upgrade the account to the new status level.
func (self *FrequentFlierAccount) RecordFlightTaken(miles int, tierPoints int) {
self.trackChange(FlightTaken{MilesAdded: miles, TierPointsAdded: tierPoints})
if self.tierPoints > 20 && self.status != StatusGold {
self.trackChange(PromotedToGoldStatus{})
}
}
// String implements Stringer for FrequentFlierAccount instances.
func (a FrequentFlierAccount) String() string {
format := `FrequentFlierAccount: %s
Miles: %d
TierPoints: %d
Status: %s
(Expected Version: %d)
(Pending Changes: %d)
`
return fmt.Sprintf(format, a.id, a.miles, a.tierPoints, a.status, a.expectedVersion, len(a.changes))
}
// trackChange is used internally by bevhavious methods to apply a state change to
// the current instance and also track it in order that it can be persisted later.
func (state *FrequentFlierAccount) trackChange(event interface{}) {
state.changes = append(state.changes, event)
state.transition(event)
}
// transition imnplements the pattern match against event types used both as part
// of the fold when loading from history and when tracking an individual change.
func (state *FrequentFlierAccount) transition(event interface{}) {
switch e := event.(type) {
case FrequentFlierAccountCreated:
state.id = e.AccountId
state.miles = e.OpeningMiles
state.tierPoints = e.OpeningTierPoints
state.status = StatusRed
case StatusMatched:
state.status = e.NewStatus
case FlightTaken:
state.miles = state.miles + e.MilesAdded
state.tierPoints = state.tierPoints + e.TierPointsAdded
case PromotedToGoldStatus:
state.status = StatusGold
}
}
// NewFrequentFlierAccountFromHistory creates a FrequentFlierAccount given a history
// of the changes which have occurred for that account.
func NewFrequentFlierAccountFromHistory(events []interface{}) *FrequentFlierAccount {
state := &FrequentFlierAccount{}
for _, event := range events {
state.transition(event)
state.expectedVersion++
}
return state
}