lawspec 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API-MIGRATION.md +78 -2
- package/LANGUAGE.md +10 -7
- package/NATIVE-BINDINGS.md +1046 -0
- package/PRIMITIVES.md +1 -1
- package/README.md +73 -23
- package/REFINEMENTS.md +1 -1
- package/RELEASE-0.10.md +60 -0
- package/api.mjs +23 -3
- package/bin/lawspec.mjs +17 -4
- package/build.json +56 -36
- package/core.wasm +0 -0
- package/examples/native-payments/go/example/payments/domain.go +38 -0
- package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
- package/examples/native-payments/go/lawspec.json +136 -0
- package/examples/native-payments/haskell/lawspec.json +149 -0
- package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
- package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
- package/examples/native-payments/java/lawspec.json +165 -0
- package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
- package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
- package/examples/native-payments/javascript/lawspec.json +149 -0
- package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
- package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
- package/examples/native-payments/kotlin/lawspec.json +165 -0
- package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
- package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
- package/examples/native-payments/python/lawspec.json +149 -0
- package/examples/native-payments/python/src/payments_domain.py +60 -0
- package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
- package/examples/native-payments/rust/lawspec.json +167 -0
- package/examples/native-payments/rust/src/domain.rs +37 -0
- package/examples/native-payments/rust/src/lib.rs +2 -0
- package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
- package/examples/native-payments/typescript/lawspec.json +149 -0
- package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
- package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -0
- package/examples/specs/payments.lawspec +76 -0
- package/examples-command.mjs +5 -0
- package/files.mjs +6 -6
- package/index.d.ts +53 -2
- package/native-examples.mjs +81 -0
- package/package.json +2 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
package payments
|
|
2
|
+
|
|
3
|
+
import "math/big"
|
|
4
|
+
|
|
5
|
+
// Application-owned domain types, separate from generated canonical types.
|
|
6
|
+
type CurrencyCode int
|
|
7
|
+
|
|
8
|
+
const (
|
|
9
|
+
Dollars CurrencyCode = iota
|
|
10
|
+
Euros
|
|
11
|
+
Pounds
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
type Price struct {
|
|
15
|
+
Major LawSpecDecimal
|
|
16
|
+
Unit CurrencyCode
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type PaymentStatus interface{ payment() }
|
|
20
|
+
type Settled struct{ Price Price }
|
|
21
|
+
type Rejected struct{ Explanation string }
|
|
22
|
+
|
|
23
|
+
func (Settled) payment() {}
|
|
24
|
+
func (Rejected) payment() {}
|
|
25
|
+
|
|
26
|
+
// AddFee uses independent exact integer arithmetic, without ambient rounding.
|
|
27
|
+
func AddFee(price Price) Price {
|
|
28
|
+
exponent := min(price.Major.exponent, -1)
|
|
29
|
+
power := func(n int) *big.Int {
|
|
30
|
+
return new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(n)), nil)
|
|
31
|
+
}
|
|
32
|
+
amount := new(big.Int).Mul(price.Major.coefficient, power(price.Major.exponent-exponent))
|
|
33
|
+
fee := new(big.Int).Mul(big.NewInt(2), power(-1-exponent))
|
|
34
|
+
return Price{LawSpecDecimal{new(big.Int).Add(amount, fee), exponent}, price.Unit}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func Restore(value PaymentStatus) PaymentStatus { return value }
|
|
38
|
+
func Store(values []LawSpecMaybe[PaymentStatus]) []LawSpecMaybe[PaymentStatus] { return values }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package payments
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"math/big"
|
|
5
|
+
|
|
6
|
+
"pgregory.net/rapid"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func NativePrices() *rapid.Generator[Price] {
|
|
10
|
+
return rapid.Map(rapid.IntRange(100, 200), func(cents int) Price {
|
|
11
|
+
return Price{LawSpecDecimal{big.NewInt(int64(cents)), -2}, Euros}
|
|
12
|
+
})
|
|
13
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"sources": [
|
|
4
|
+
"laws"
|
|
5
|
+
],
|
|
6
|
+
"machineBits": 64,
|
|
7
|
+
"targets": [
|
|
8
|
+
{
|
|
9
|
+
"language": "go",
|
|
10
|
+
"root": ".",
|
|
11
|
+
"nativeBindings": {
|
|
12
|
+
"types": [
|
|
13
|
+
{
|
|
14
|
+
"type": "example.payments::type::Currency",
|
|
15
|
+
"native": [
|
|
16
|
+
"CurrencyCode"
|
|
17
|
+
],
|
|
18
|
+
"constructors": [
|
|
19
|
+
{
|
|
20
|
+
"constructor": "USD",
|
|
21
|
+
"native": [
|
|
22
|
+
"Dollars"
|
|
23
|
+
],
|
|
24
|
+
"style": "unit",
|
|
25
|
+
"fields": []
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"constructor": "EUR",
|
|
29
|
+
"native": [
|
|
30
|
+
"Euros"
|
|
31
|
+
],
|
|
32
|
+
"style": "unit",
|
|
33
|
+
"fields": []
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"constructor": "GBP",
|
|
37
|
+
"native": [
|
|
38
|
+
"Pounds"
|
|
39
|
+
],
|
|
40
|
+
"style": "unit",
|
|
41
|
+
"fields": []
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "example.payments::type::Money",
|
|
47
|
+
"native": [
|
|
48
|
+
"Price"
|
|
49
|
+
],
|
|
50
|
+
"constructors": [
|
|
51
|
+
{
|
|
52
|
+
"constructor": "Money",
|
|
53
|
+
"native": [
|
|
54
|
+
"Price"
|
|
55
|
+
],
|
|
56
|
+
"style": "record",
|
|
57
|
+
"fields": [
|
|
58
|
+
{
|
|
59
|
+
"field": "amount",
|
|
60
|
+
"native": "Major"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"field": "currency",
|
|
64
|
+
"native": "Unit"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"type": "example.payments::type::Payment",
|
|
72
|
+
"native": [
|
|
73
|
+
"PaymentStatus"
|
|
74
|
+
],
|
|
75
|
+
"constructors": [
|
|
76
|
+
{
|
|
77
|
+
"constructor": "Paid",
|
|
78
|
+
"native": [
|
|
79
|
+
"Settled"
|
|
80
|
+
],
|
|
81
|
+
"style": "variant",
|
|
82
|
+
"fields": [
|
|
83
|
+
{
|
|
84
|
+
"field": "value",
|
|
85
|
+
"native": "Price"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"constructor": "Declined",
|
|
91
|
+
"native": [
|
|
92
|
+
"Rejected"
|
|
93
|
+
],
|
|
94
|
+
"style": "variant",
|
|
95
|
+
"fields": [
|
|
96
|
+
{
|
|
97
|
+
"field": "reason",
|
|
98
|
+
"native": "Explanation"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"functions": [
|
|
106
|
+
{
|
|
107
|
+
"declaration": "example.payments::addFee",
|
|
108
|
+
"native": [
|
|
109
|
+
"AddFee"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"declaration": "example.payments::roundTrip",
|
|
114
|
+
"native": [
|
|
115
|
+
"Restore"
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"declaration": "example.payments::archive",
|
|
120
|
+
"native": [
|
|
121
|
+
"Store"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"generators": [
|
|
126
|
+
{
|
|
127
|
+
"type": "example.payments::type::Money",
|
|
128
|
+
"factory": [
|
|
129
|
+
"NativePrices"
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"sources": [
|
|
4
|
+
"laws"
|
|
5
|
+
],
|
|
6
|
+
"machineBits": 64,
|
|
7
|
+
"targets": [
|
|
8
|
+
{
|
|
9
|
+
"language": "haskell",
|
|
10
|
+
"root": ".",
|
|
11
|
+
"nativeBindings": {
|
|
12
|
+
"types": [
|
|
13
|
+
{
|
|
14
|
+
"type": "example.payments::type::Currency",
|
|
15
|
+
"native": [
|
|
16
|
+
"PaymentsDomain",
|
|
17
|
+
"CurrencyCode"
|
|
18
|
+
],
|
|
19
|
+
"constructors": [
|
|
20
|
+
{
|
|
21
|
+
"constructor": "USD",
|
|
22
|
+
"native": [
|
|
23
|
+
"PaymentsDomain",
|
|
24
|
+
"Dollars"
|
|
25
|
+
],
|
|
26
|
+
"style": "unit",
|
|
27
|
+
"fields": []
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"constructor": "EUR",
|
|
31
|
+
"native": [
|
|
32
|
+
"PaymentsDomain",
|
|
33
|
+
"Euros"
|
|
34
|
+
],
|
|
35
|
+
"style": "unit",
|
|
36
|
+
"fields": []
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"constructor": "GBP",
|
|
40
|
+
"native": [
|
|
41
|
+
"PaymentsDomain",
|
|
42
|
+
"Pounds"
|
|
43
|
+
],
|
|
44
|
+
"style": "unit",
|
|
45
|
+
"fields": []
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"type": "example.payments::type::Money",
|
|
51
|
+
"native": [
|
|
52
|
+
"PaymentsDomain",
|
|
53
|
+
"Price"
|
|
54
|
+
],
|
|
55
|
+
"constructors": [
|
|
56
|
+
{
|
|
57
|
+
"constructor": "Money",
|
|
58
|
+
"native": [
|
|
59
|
+
"PaymentsDomain",
|
|
60
|
+
"Price"
|
|
61
|
+
],
|
|
62
|
+
"style": "record",
|
|
63
|
+
"fields": [
|
|
64
|
+
{
|
|
65
|
+
"field": "amount",
|
|
66
|
+
"native": "major"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"field": "currency",
|
|
70
|
+
"native": "unit"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "example.payments::type::Payment",
|
|
78
|
+
"native": [
|
|
79
|
+
"PaymentsDomain",
|
|
80
|
+
"PaymentStatus"
|
|
81
|
+
],
|
|
82
|
+
"constructors": [
|
|
83
|
+
{
|
|
84
|
+
"constructor": "Paid",
|
|
85
|
+
"native": [
|
|
86
|
+
"PaymentsDomain",
|
|
87
|
+
"Settled"
|
|
88
|
+
],
|
|
89
|
+
"style": "variant",
|
|
90
|
+
"fields": [
|
|
91
|
+
{
|
|
92
|
+
"field": "value",
|
|
93
|
+
"native": "price"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"constructor": "Declined",
|
|
99
|
+
"native": [
|
|
100
|
+
"PaymentsDomain",
|
|
101
|
+
"Rejected"
|
|
102
|
+
],
|
|
103
|
+
"style": "variant",
|
|
104
|
+
"fields": [
|
|
105
|
+
{
|
|
106
|
+
"field": "reason",
|
|
107
|
+
"native": "explanation"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"functions": [
|
|
115
|
+
{
|
|
116
|
+
"declaration": "example.payments::addFee",
|
|
117
|
+
"native": [
|
|
118
|
+
"PaymentsDomain",
|
|
119
|
+
"addFee"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"declaration": "example.payments::roundTrip",
|
|
124
|
+
"native": [
|
|
125
|
+
"PaymentsDomain",
|
|
126
|
+
"restore"
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"declaration": "example.payments::archive",
|
|
131
|
+
"native": [
|
|
132
|
+
"PaymentsDomain",
|
|
133
|
+
"store"
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
],
|
|
137
|
+
"generators": [
|
|
138
|
+
{
|
|
139
|
+
"type": "example.payments::type::Money",
|
|
140
|
+
"factory": [
|
|
141
|
+
"PaymentGenerators",
|
|
142
|
+
"prices"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module PaymentsDomain where
|
|
2
|
+
|
|
3
|
+
import Data.Ratio ((%))
|
|
4
|
+
import Data.Text (Text)
|
|
5
|
+
import LawSpecRuntime (Decimal(..))
|
|
6
|
+
|
|
7
|
+
data CurrencyCode = Dollars | Euros | Pounds deriving (Eq, Show)
|
|
8
|
+
-- Deliberately reverse the logical field order.
|
|
9
|
+
data Price = Price { unit :: CurrencyCode, major :: Decimal } deriving (Eq, Show)
|
|
10
|
+
data PaymentStatus = Settled { price :: Price } | Rejected { explanation :: Text }
|
|
11
|
+
deriving (Eq, Show)
|
|
12
|
+
|
|
13
|
+
addFee :: Price -> Price
|
|
14
|
+
addFee value = case major value of
|
|
15
|
+
Decimal amount -> value { major = Decimal (amount + 1 % 5) }
|
|
16
|
+
|
|
17
|
+
restore :: PaymentStatus -> PaymentStatus
|
|
18
|
+
restore value = value
|
|
19
|
+
|
|
20
|
+
store :: [Maybe PaymentStatus] -> [Maybe PaymentStatus]
|
|
21
|
+
store values = values
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module PaymentGenerators where
|
|
2
|
+
|
|
3
|
+
import Data.Ratio ((%))
|
|
4
|
+
import Hedgehog (Gen)
|
|
5
|
+
import qualified Hedgehog.Gen as Gen
|
|
6
|
+
import qualified Hedgehog.Range as Range
|
|
7
|
+
import LawSpecRuntime (Decimal(..))
|
|
8
|
+
import PaymentsDomain
|
|
9
|
+
|
|
10
|
+
prices :: Gen Price
|
|
11
|
+
prices = (\cents -> Price Euros (Decimal (cents % 100))) <$>
|
|
12
|
+
Gen.integral (Range.linear 100 200)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"sources": [
|
|
4
|
+
"laws"
|
|
5
|
+
],
|
|
6
|
+
"machineBits": 64,
|
|
7
|
+
"targets": [
|
|
8
|
+
{
|
|
9
|
+
"language": "java",
|
|
10
|
+
"root": ".",
|
|
11
|
+
"nativeBindings": {
|
|
12
|
+
"types": [
|
|
13
|
+
{
|
|
14
|
+
"type": "example.payments::type::Currency",
|
|
15
|
+
"native": [
|
|
16
|
+
"domain",
|
|
17
|
+
"PaymentsDomain",
|
|
18
|
+
"CurrencyCode"
|
|
19
|
+
],
|
|
20
|
+
"constructors": [
|
|
21
|
+
{
|
|
22
|
+
"constructor": "USD",
|
|
23
|
+
"native": [
|
|
24
|
+
"domain",
|
|
25
|
+
"PaymentsDomain",
|
|
26
|
+
"CurrencyCode",
|
|
27
|
+
"Dollars"
|
|
28
|
+
],
|
|
29
|
+
"style": "unit",
|
|
30
|
+
"fields": []
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"constructor": "EUR",
|
|
34
|
+
"native": [
|
|
35
|
+
"domain",
|
|
36
|
+
"PaymentsDomain",
|
|
37
|
+
"CurrencyCode",
|
|
38
|
+
"Euros"
|
|
39
|
+
],
|
|
40
|
+
"style": "unit",
|
|
41
|
+
"fields": []
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"constructor": "GBP",
|
|
45
|
+
"native": [
|
|
46
|
+
"domain",
|
|
47
|
+
"PaymentsDomain",
|
|
48
|
+
"CurrencyCode",
|
|
49
|
+
"Pounds"
|
|
50
|
+
],
|
|
51
|
+
"style": "unit",
|
|
52
|
+
"fields": []
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"type": "example.payments::type::Money",
|
|
58
|
+
"native": [
|
|
59
|
+
"domain",
|
|
60
|
+
"PaymentsDomain",
|
|
61
|
+
"Price"
|
|
62
|
+
],
|
|
63
|
+
"constructors": [
|
|
64
|
+
{
|
|
65
|
+
"constructor": "Money",
|
|
66
|
+
"native": [
|
|
67
|
+
"domain",
|
|
68
|
+
"PaymentsDomain",
|
|
69
|
+
"Price"
|
|
70
|
+
],
|
|
71
|
+
"style": "record",
|
|
72
|
+
"fields": [
|
|
73
|
+
{
|
|
74
|
+
"field": "amount",
|
|
75
|
+
"native": "major"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"field": "currency",
|
|
79
|
+
"native": "unit"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"type": "example.payments::type::Payment",
|
|
87
|
+
"native": [
|
|
88
|
+
"domain",
|
|
89
|
+
"PaymentsDomain",
|
|
90
|
+
"PaymentStatus"
|
|
91
|
+
],
|
|
92
|
+
"constructors": [
|
|
93
|
+
{
|
|
94
|
+
"constructor": "Paid",
|
|
95
|
+
"native": [
|
|
96
|
+
"domain",
|
|
97
|
+
"PaymentsDomain",
|
|
98
|
+
"Settled"
|
|
99
|
+
],
|
|
100
|
+
"style": "variant",
|
|
101
|
+
"fields": [
|
|
102
|
+
{
|
|
103
|
+
"field": "value",
|
|
104
|
+
"native": "price"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"constructor": "Declined",
|
|
110
|
+
"native": [
|
|
111
|
+
"domain",
|
|
112
|
+
"PaymentsDomain",
|
|
113
|
+
"Rejected"
|
|
114
|
+
],
|
|
115
|
+
"style": "variant",
|
|
116
|
+
"fields": [
|
|
117
|
+
{
|
|
118
|
+
"field": "reason",
|
|
119
|
+
"native": "explanation"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"functions": [
|
|
127
|
+
{
|
|
128
|
+
"declaration": "example.payments::addFee",
|
|
129
|
+
"native": [
|
|
130
|
+
"domain",
|
|
131
|
+
"PaymentsDomain",
|
|
132
|
+
"apply_fee"
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"declaration": "example.payments::roundTrip",
|
|
137
|
+
"native": [
|
|
138
|
+
"domain",
|
|
139
|
+
"PaymentsDomain",
|
|
140
|
+
"restore"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"declaration": "example.payments::archive",
|
|
145
|
+
"native": [
|
|
146
|
+
"domain",
|
|
147
|
+
"PaymentsDomain",
|
|
148
|
+
"store"
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
"generators": [
|
|
153
|
+
{
|
|
154
|
+
"type": "example.payments::type::Money",
|
|
155
|
+
"factory": [
|
|
156
|
+
"domain",
|
|
157
|
+
"PaymentGenerators",
|
|
158
|
+
"prices"
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package domain;
|
|
2
|
+
|
|
3
|
+
import java.math.BigDecimal;
|
|
4
|
+
import java.util.List;
|
|
5
|
+
import lawspec.runtime.LawSpecRuntime.Maybe;
|
|
6
|
+
|
|
7
|
+
/** Application types, independent of generated LawSpec domain declarations. */
|
|
8
|
+
public final class PaymentsDomain {
|
|
9
|
+
private PaymentsDomain() {}
|
|
10
|
+
|
|
11
|
+
public enum CurrencyCode { Dollars, Euros, Pounds }
|
|
12
|
+
|
|
13
|
+
public record Price(BigDecimal major, CurrencyCode unit) {}
|
|
14
|
+
|
|
15
|
+
public sealed interface PaymentStatus permits Settled, Rejected {}
|
|
16
|
+
|
|
17
|
+
public record Settled(Price price) implements PaymentStatus {}
|
|
18
|
+
|
|
19
|
+
public record Rejected(String explanation) implements PaymentStatus {}
|
|
20
|
+
|
|
21
|
+
public static Price apply_fee(Price price) {
|
|
22
|
+
return new Price(price.major().add(new BigDecimal("0.2")), price.unit());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static PaymentStatus restore(PaymentStatus payment) {
|
|
26
|
+
return payment;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public static List<Maybe<PaymentStatus>> store(List<Maybe<PaymentStatus>> payments) {
|
|
30
|
+
return payments;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package domain;
|
|
2
|
+
|
|
3
|
+
import java.math.BigDecimal;
|
|
4
|
+
import java.math.BigInteger;
|
|
5
|
+
import org.jetbrains.jetCheck.Generator;
|
|
6
|
+
|
|
7
|
+
public final class PaymentGenerators {
|
|
8
|
+
private PaymentGenerators() {}
|
|
9
|
+
|
|
10
|
+
public static Generator<PaymentsDomain.Price> prices() {
|
|
11
|
+
return Generator.integers(100, 200)
|
|
12
|
+
.map(cents -> new PaymentsDomain.Price(
|
|
13
|
+
new BigDecimal(BigInteger.valueOf(cents), 2),
|
|
14
|
+
PaymentsDomain.CurrencyCode.Euros));
|
|
15
|
+
}
|
|
16
|
+
}
|