@reventlessdev/trait-address-geocoding 1.0.0-alpha.1 → 1.0.0-alpha.11
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/package.json +5 -5
- package/src/AddressGeocoding.res +5 -6
- package/src/AddressGeocoding_Conformance.res +13 -14
- package/src/AddressGeocoding_Conformance.res.mjs +14 -18
- package/src/AddressGeocoding_Guards.res +0 -1
- package/src/AddressGeocoding_Scaffold.res +7 -13
- package/src/AddressGeocoding_Scaffold.res.mjs +2 -2
- package/src/AddressGeocoding_Translate.res +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/trait-address-geocoding",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.11",
|
|
4
4
|
"description": "Address-geocoding domain trait: rules, host contract, conformance suite and emitter for grafting geocoding onto an aggregate",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": [
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"sury": "11.0.0-rc.2",
|
|
15
15
|
"sury-ppx": "11.0.0-rc.2",
|
|
16
|
-
"@reventlessdev/reventless-
|
|
17
|
-
"@reventlessdev/reventless-
|
|
18
|
-
"@reventlessdev/reventless-
|
|
19
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
16
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.209",
|
|
17
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.80",
|
|
18
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.163",
|
|
19
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.135"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"rescript": "12.3.0"
|
package/src/AddressGeocoding.res
CHANGED
|
@@ -6,7 +6,6 @@ staleness, redelivery, an outage is not a verdict, the stand-down — live in
|
|
|
6
6
|
host by `AddressGeocoding_Conformance`; the confidence rule stays core's
|
|
7
7
|
(`Reventless.Geocoding`). The spec surface is written by `AddressGeocoding_Scaffold`.
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
9
|
/** Whether the graft reports back into its host. This trait does — the two `@noApi`
|
|
11
10
|
commands — and the runner accepts nothing else yet; the flag is here so a
|
|
12
11
|
competency that only observes is not mis-modelled as one that writes. */
|
|
@@ -102,11 +101,11 @@ The two commands a caller changes the address through, as constructors a host
|
|
|
102
101
|
splices into its own command type.
|
|
103
102
|
|
|
104
103
|
These are public, and that is what kept them out of the trait until now. Both
|
|
105
|
-
are legal only while the entity is in some state the HOST names, and
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
stayed hand-written in every host, which is the
|
|
109
|
-
still had to transcribe.
|
|
104
|
+
are legal only while the entity is in some state the HOST names, and the
|
|
105
|
+
attribute that used to declare that could not be attached to a constructor a
|
|
106
|
+
host did not declare — it lowered to a dict on the parent union, and a spread
|
|
107
|
+
splices members. So the pair stayed hand-written in every host, which is the
|
|
108
|
+
whole of what a spreading host still had to transcribe.
|
|
110
109
|
|
|
111
110
|
`commandTransition` is what freed them: the host answers for them in an
|
|
112
111
|
exhaustive switch, in its own lifecycle vocabulary, and the compiler will not let
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
The conformance suite, run by a host against its own graft. `Make(Binding).register()`
|
|
3
|
-
inside a Jest test file registers one `describe` block; every assertion is written
|
|
4
|
-
over the binding, never over a host's constructors.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Warning 23 flags the spread in `geocoder` as redundant today; it is there for
|
|
8
|
-
// the day `Capabilities.t` grows a field.
|
|
9
1
|
@@warning("-23")
|
|
10
2
|
|
|
11
3
|
module Outcome = ReventlessGwt.Outcome
|
|
@@ -53,7 +45,9 @@ module Make = (B: AddressGeocoding.Binding) => {
|
|
|
53
45
|
let triggers =
|
|
54
46
|
B.triggers(B.subjectA)
|
|
55
47
|
->Array.map(e =>
|
|
56
|
-
e
|
|
48
|
+
e
|
|
49
|
+
->Reventless.Message.encode(B.Slice.consumedEventSchema)
|
|
50
|
+
->Reventless.Message.variantNameOfJson
|
|
57
51
|
)
|
|
58
52
|
->sorted
|
|
59
53
|
// Encoded through the aggregate's own schema, so a stand-down event is a
|
|
@@ -124,7 +118,10 @@ module Make = (B: AddressGeocoding.Binding) => {
|
|
|
124
118
|
|
|
125
119
|
A.test("a redelivered verdict is a no-op", () =>
|
|
126
120
|
A.givenEvents(
|
|
127
|
-
Array.concat(
|
|
121
|
+
Array.concat(
|
|
122
|
+
B.created(B.subjectA),
|
|
123
|
+
[B.unresolvable(~subject=B.subjectA, ~reason="no match")],
|
|
124
|
+
),
|
|
128
125
|
)
|
|
129
126
|
->A.whenCmd(B.markUnresolvable(~subject=B.subjectA, ~reason="no match"))
|
|
130
127
|
->A.thenNoEvent
|
|
@@ -147,10 +144,12 @@ module Make = (B: AddressGeocoding.Binding) => {
|
|
|
147
144
|
)
|
|
148
145
|
|
|
149
146
|
B.triggers(B.subjectA)->Array.forEachWithIndex((trigger, i) =>
|
|
150
|
-
S.testSync(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
S.testSync(
|
|
148
|
+
`trigger ${Int.toString(i + 1)} queues one TODO keyed by entity and subject`,
|
|
149
|
+
() =>
|
|
150
|
+
S.givenEvent(trigger)
|
|
151
|
+
->S.whenCollect(~sourceId=entityId)
|
|
152
|
+
->S.thenTodos([(todoKey(B.subjectA), B.item(~entityId, ~subject=B.subjectA))]),
|
|
154
153
|
)
|
|
155
154
|
)
|
|
156
155
|
|
|
@@ -28,7 +28,9 @@ function Make(B) {
|
|
|
28
28
|
let todoKey = subject => entityId + `:` + B.subjectText(subject);
|
|
29
29
|
let geocoder = answer => ({
|
|
30
30
|
geocode: param => Promise.resolve(answer),
|
|
31
|
-
messaging: Capabilities$Reventless.none.messaging
|
|
31
|
+
messaging: Capabilities$Reventless.none.messaging,
|
|
32
|
+
identityProvider: Capabilities$Reventless.none.identityProvider,
|
|
33
|
+
secrets: Capabilities$Reventless.none.secrets
|
|
32
34
|
});
|
|
33
35
|
let translateWith = answer => ((id, item) => B.translate(id, item, geocoder(answer)));
|
|
34
36
|
let describeCommand = cmd => JSON.stringify(Message$Reventless.encode(cmd, B.Slice.inboundCommandSchema));
|
|
@@ -110,23 +112,17 @@ function Make(B) {
|
|
|
110
112
|
relevance: 0.995
|
|
111
113
|
}]
|
|
112
114
|
})), "a location", B.isLocation));
|
|
113
|
-
S.test("a no-match completes the TODO with a verdict", undefined, () => thenReports(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
TAG: "Unavailable",
|
|
125
|
-
_0: "502"
|
|
126
|
-
}
|
|
127
|
-
}),
|
|
128
|
-
messaging: Capabilities$Reventless.none.messaging
|
|
129
|
-
})), todoKey(B.subjectA), "Pending"));
|
|
115
|
+
S.test("a no-match completes the TODO with a verdict", undefined, () => thenReports(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, geocoder({
|
|
116
|
+
TAG: "Error",
|
|
117
|
+
_0: "NoMatch"
|
|
118
|
+
}))), "a verdict", B.isVerdict));
|
|
119
|
+
S.test("an outage leaves the TODO pending", undefined, () => S.thenTodoStatus(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, geocoder({
|
|
120
|
+
TAG: "Error",
|
|
121
|
+
_0: {
|
|
122
|
+
TAG: "Unavailable",
|
|
123
|
+
_0: "502"
|
|
124
|
+
}
|
|
125
|
+
}))), todoKey(B.subjectA), "Pending"));
|
|
130
126
|
});
|
|
131
127
|
return {
|
|
132
128
|
A: A,
|
|
@@ -8,7 +8,6 @@ record in it would make every release that reshapes it a migration — and build
|
|
|
8
8
|
`resolution` per call from the fields it already holds. What comes back is a
|
|
9
9
|
verdict on one command, which the host names in its own event.
|
|
10
10
|
*/
|
|
11
|
-
|
|
12
11
|
/** The three fields the rules read, as the host holds them. Its invariant, which
|
|
13
12
|
every host arm must preserve: `resolvedFrom` is `None` or equal to `subject`. */
|
|
14
13
|
type resolution = {
|
|
@@ -24,11 +24,10 @@ and a host that needs it says so.
|
|
|
24
24
|
|
|
25
25
|
**What it does not do.** It never writes the host's policy. Which states an
|
|
26
26
|
address may be changed in, who may change it, what a host's own commands refuse
|
|
27
|
-
— those are
|
|
28
|
-
a trait cannot know. They are config when the host supplies them and absent
|
|
27
|
+
— those are `commandTransition` and `@authorize` over the host's own lifecycle,
|
|
28
|
+
which a trait cannot know. They are config when the host supplies them and absent
|
|
29
29
|
when it does not.
|
|
30
30
|
*/
|
|
31
|
-
|
|
32
31
|
/**
|
|
33
32
|
The names a graft needs, and nothing else.
|
|
34
33
|
|
|
@@ -46,7 +45,6 @@ type config = {
|
|
|
46
45
|
one of the slice's two triggers, because an entity created with an address
|
|
47
46
|
has never been geocoded. */
|
|
48
47
|
created: string,
|
|
49
|
-
|
|
50
48
|
/**
|
|
51
49
|
What this host calls the thing being geocoded, lowercase: `"address"`.
|
|
52
50
|
|
|
@@ -58,7 +56,6 @@ type config = {
|
|
|
58
56
|
spelled out. The emitted patch says which of the two you are getting.
|
|
59
57
|
*/
|
|
60
58
|
subject?: string,
|
|
61
|
-
|
|
62
59
|
/**
|
|
63
60
|
The creation event's payload *beyond* the subject, as declarations:
|
|
64
61
|
`["email: string"]`.
|
|
@@ -72,7 +69,6 @@ type config = {
|
|
|
72
69
|
conformance binding's histories. Omitted ⇒ omitted from the fixtures, which
|
|
73
70
|
only compiles when `createdFields` is omitted too. */
|
|
74
71
|
createdValues?: array<string>,
|
|
75
|
-
|
|
76
72
|
/** The slice component's name. Defaults to `Geocode<Entity><Subject>`. */
|
|
77
73
|
slice?: string,
|
|
78
74
|
/** The external box the Event Graph draws. Defaults to `"Geocoder"`; a host on
|
|
@@ -81,7 +77,6 @@ type config = {
|
|
|
81
77
|
/** The read model the projection patch is addressed to. Defaults to
|
|
82
78
|
`<Entity>s`. */
|
|
83
79
|
view?: string,
|
|
84
|
-
|
|
85
80
|
/** Two subjects that differ, for the histories in which the address changes.
|
|
86
81
|
Defaulted when absent — they are test data, not a decision. */
|
|
87
82
|
subjectA?: string,
|
|
@@ -227,8 +222,7 @@ let sliceTranslation = (c: config): string => {
|
|
|
227
222
|
", {" ++
|
|
228
223
|
c.entityId ++
|
|
229
224
|
": sourceId, " ++
|
|
230
|
-
n.subject ++
|
|
231
|
-
"})]"
|
|
225
|
+
n.subject ++ "})]"
|
|
232
226
|
lines([
|
|
233
227
|
`@@reventless.translation`,
|
|
234
228
|
``,
|
|
@@ -358,8 +352,8 @@ let conformanceBinding = (c: config): string => {
|
|
|
358
352
|
// host choice: a report must be legal in every state, or an answer landing after
|
|
359
353
|
// the entity moved on parks a TODO row forever. The two public commands are the
|
|
360
354
|
// host's call, so they are printed as a marked hole. That split is the same one
|
|
361
|
-
// the whole scaffold runs on, and it is why
|
|
362
|
-
//
|
|
355
|
+
// the whole scaffold runs on, and it is why an attribute could not serve here:
|
|
356
|
+
// one cannot be attached to a constructor the host did not declare.
|
|
363
357
|
let transitionArms = (c: config): array<string> => {
|
|
364
358
|
let n = namesOf(c)
|
|
365
359
|
[
|
|
@@ -582,11 +576,11 @@ let emit = (~config: config, ~into: string, ~tests: string): output => {
|
|
|
582
576
|
{
|
|
583
577
|
files: [
|
|
584
578
|
{
|
|
585
|
-
path: `${into}/
|
|
579
|
+
path: `${into}/OutboundTranslation/${n.slice}.res`,
|
|
586
580
|
contents: sliceSpec(config),
|
|
587
581
|
},
|
|
588
582
|
{
|
|
589
|
-
path: `${into}/
|
|
583
|
+
path: `${into}/OutboundTranslation/${n.slice}_Translation.res`,
|
|
590
584
|
contents: sliceTranslation(config),
|
|
591
585
|
},
|
|
592
586
|
{
|
|
@@ -414,11 +414,11 @@ function emit(config, into, tests) {
|
|
|
414
414
|
return {
|
|
415
415
|
files: [
|
|
416
416
|
{
|
|
417
|
-
path: into + `/
|
|
417
|
+
path: into + `/OutboundTranslation/` + n.slice + `.res`,
|
|
418
418
|
contents: sliceSpec(config)
|
|
419
419
|
},
|
|
420
420
|
{
|
|
421
|
-
path: into + `/
|
|
421
|
+
path: into + `/OutboundTranslation/` + n.slice + `_Translation.res`,
|
|
422
422
|
contents: sliceTranslation(config)
|
|
423
423
|
},
|
|
424
424
|
{
|
|
@@ -7,7 +7,6 @@ An outage is not a verdict — it comes back `Error`, which leaves the TODO pend
|
|
|
7
7
|
for another attempt — and once the retries are spent `exhaustedReason` is what the
|
|
8
8
|
host reports instead, by the same command a confident refusal produces.
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
10
|
/** The geocoder arrives as a capability, so the deployment decides what answers. */
|
|
12
11
|
let translate = async (
|
|
13
12
|
~text: string,
|