@reventlessdev/reventless-local 3.0.0-alpha.249 → 3.0.0-alpha.251

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.
Files changed (174) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/package.json +13 -13
  3. package/src/BakedManifest.res +5 -6
  4. package/src/EmitCapabilities.res +3 -1
  5. package/src/LocalPlatformRegistry.res +3 -1
  6. package/src/LocalPlatformStart.res +7 -6
  7. package/src/LocalSeedTarget.res +3 -1
  8. package/src/Platform.res +291 -215
  9. package/src/ShellConfig.res +10 -17
  10. package/src/UiHints.res +8 -14
  11. package/src/UiSlots.res +10 -17
  12. package/src/adapter/Api/LocalEvents_Server.res +5 -3
  13. package/src/adapter/Api/LocalGraphQL_Adapter.res +4 -4
  14. package/src/adapter/Auth/LocalAuth.res +12 -16
  15. package/src/adapter/Auth/LocalAuth.res.mjs +2 -1
  16. package/src/adapter/Auth/UserStore.res +13 -40
  17. package/src/adapter/Auth/UserStore.res.mjs +11 -67
  18. package/src/adapter/Backend.res +1 -2
  19. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +42 -26
  20. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +13 -3
  21. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +15 -17
  22. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +18 -22
  23. package/src/adapter/Counter/LocalCounterHandler.res +1 -1
  24. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +33 -22
  25. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +57 -57
  26. package/src/adapter/DomainGraphQL_Server.res +35 -34
  27. package/src/adapter/DomainMCP_Server.res +45 -41
  28. package/src/adapter/EventCollector/LocalEventCollectorChannel.res +47 -36
  29. package/src/adapter/EventHistory/EventHistoryResolvers_GraphQL.res +15 -12
  30. package/src/adapter/EventLog/EventLogStorage_InMemory.res +9 -4
  31. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +36 -24
  32. package/src/adapter/EventTopic/LocalEventTopicPublisher.res +9 -3
  33. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +9 -14
  34. package/src/adapter/LocalBus.res +12 -12
  35. package/src/adapter/LocalCapabilities.res +6 -0
  36. package/src/adapter/LocalCapabilities.res.mjs +5 -2
  37. package/src/adapter/LocalGeocodeResolvers.res +1 -4
  38. package/src/adapter/LocalSideEffectHandler.res +1 -1
  39. package/src/adapter/LocalStateChangeDescriptor.res +2 -1
  40. package/src/adapter/MCP_ServerInstance.res +51 -39
  41. package/src/adapter/ObjectStore/LocalObjectStore.res +5 -2
  42. package/src/adapter/ObjectStore/ObjectStoreStorage_FileSystem.res +1 -2
  43. package/src/adapter/PlatformGraphQL_Server.res +10 -6
  44. package/src/adapter/PlatformGraphQL_Server.res.mjs +2 -1
  45. package/src/adapter/ProjectionCheckpoint.res +8 -1
  46. package/src/adapter/ProjectionPending.res +1 -3
  47. package/src/adapter/QueryDb/LocalQueryDbStorage.res +2 -1
  48. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +367 -269
  49. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +5 -3
  50. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +63 -40
  51. package/src/adapter/QueryDb/SortKey_Filter.res +14 -6
  52. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +12 -10
  53. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +8 -2
  54. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +1 -4
  55. package/src/adapter/Scheduler/LocalScheduledPublisher.res +12 -12
  56. package/src/adapter/SqliteDriver.res +16 -4
  57. package/src/adapter/Task/TaskBucket_Sqlite.res +5 -6
  58. package/src/components/Aggregate_Builder.res +6 -1
  59. package/src/components/Counter_Builder.res +1 -5
  60. package/src/components/DcbEventLog_Builder.res +5 -3
  61. package/src/components/ExtensionPoint_Builder.res +13 -15
  62. package/src/components/InboundTranslationSlice_Builder.res +3 -2
  63. package/src/components/OutboundTranslationSlice_Builder.res +3 -2
  64. package/src/components/ReadModel_Builder.res +18 -20
  65. package/src/components/StateViewSlice_Builder.res +3 -2
  66. package/src/components/Task_Builder.res +12 -13
  67. package/src/reset/LocalSeedReset.res +2 -5
  68. package/src/test/Mocks/MockDcbEventLogStorage.res +5 -1
  69. package/src/test/Mocks/MockEventLogStorage.res +8 -3
  70. package/src/test/Mocks/MockQueryDbStorage.res +3 -2
  71. package/src/test/TestRunner.res +1 -1
  72. package/tests/BakedManifestFilesTest.res +7 -10
  73. package/tests/LocalEventTapTest.res +26 -21
  74. package/tests/LocalPlatformStartTest.res +33 -28
  75. package/tests/PluginEventDecodeTest.res +3 -3
  76. package/tests/ShellConfigTest.res +30 -21
  77. package/tests/SplitApiFixtures.res +34 -10
  78. package/tests/SplitApiTest.res +92 -62
  79. package/tests/adapter/BackendParityTest.res +180 -130
  80. package/tests/adapter/CollectNEventsTest.res +6 -4
  81. package/tests/adapter/CommandAuthorizationTest.res +47 -41
  82. package/tests/adapter/CommandTopicChannelTest.res +163 -139
  83. package/tests/adapter/CounterHandlerTest.res +95 -77
  84. package/tests/adapter/DcbEventLogStorageSqliteTest.res +171 -168
  85. package/tests/adapter/DcbEventLogStorageTest.res +264 -207
  86. package/tests/adapter/DomainGraphQL_ServerTest.res +53 -43
  87. package/tests/adapter/EventCollectorChannelTest.res +153 -124
  88. package/tests/adapter/EventHistoryResolverTest.res +46 -18
  89. package/tests/adapter/EventLogSnapshotParityTest.res +57 -45
  90. package/tests/adapter/EventLogStorageSqliteTest.res +9 -10
  91. package/tests/adapter/EventTapTest.res +37 -20
  92. package/tests/adapter/EventTopicPublisherTest.res +74 -50
  93. package/tests/adapter/GraphQLSubscriptionBridgeTest.res +4 -3
  94. package/tests/adapter/GraphQL_SchemaInspectorTest.res +666 -568
  95. package/tests/adapter/GraphQL_SubscriptionResolversTest.res +105 -96
  96. package/tests/adapter/HeartbeatRunnerTest.res +99 -81
  97. package/tests/adapter/InboundTranslationMutationTest.res +4 -1
  98. package/tests/adapter/LocalAuthHttpTest.res +79 -85
  99. package/tests/adapter/LocalAuthLoginTest.res +42 -50
  100. package/tests/adapter/LocalAuthTest.res +8 -16
  101. package/tests/adapter/LocalAuthUserStoreTest.res +2 -7
  102. package/tests/adapter/LocalBusBoundedTest.res +187 -117
  103. package/tests/adapter/LocalBusPubSubTest.res +118 -76
  104. package/tests/adapter/LocalDispatchContextTest.res +1 -2
  105. package/tests/adapter/LocalEvents_ServerTest.res +242 -187
  106. package/tests/adapter/PgProjectionCatchupTest.res +44 -10
  107. package/tests/adapter/ProjectionCheckpointTest.res +261 -206
  108. package/tests/adapter/QueryDbGsiTtlTest.res +123 -83
  109. package/tests/adapter/QueryDbListPushdownParityTest.res +107 -67
  110. package/tests/adapter/QueryDbListResolverTest.res +225 -208
  111. package/tests/adapter/QueryDbResolvedFieldsTest.res +17 -14
  112. package/tests/adapter/QueryDbStorageSqliteTest.res +33 -49
  113. package/tests/adapter/QueryDbStorageTest.res +163 -117
  114. package/tests/adapter/QueryDbUnionRoundTripTest.res +8 -10
  115. package/tests/adapter/QueryEngineTest.res +179 -126
  116. package/tests/adapter/ScheduledPublisherTest.res +171 -135
  117. package/tests/adapter/ServedBucketHttpTest.res +65 -59
  118. package/tests/adapter/SortKey_FilterTest.res +19 -3
  119. package/tests/adapter/SqliteDriverTest.res +13 -10
  120. package/tests/adapter/TaskBucketTest.res +94 -80
  121. package/tests/components/aggregate/AggregateTest.res +31 -18
  122. package/tests/components/automationslice/AutomationSliceCallbackTest.res +259 -222
  123. package/tests/components/automationslice/AutomationSliceFixtures.res +4 -2
  124. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +38 -38
  125. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +12 -14
  126. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +8 -32
  127. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +7 -5
  128. package/tests/components/commandgenerator/CommandGeneratorTest.res +40 -31
  129. package/tests/components/commandtopic/CommandTopicFixtures.res +3 -4
  130. package/tests/components/commandtopic/CommandTopicStreamFixtures.res +7 -5
  131. package/tests/components/commandtopic/CommandTopicTest.res +24 -15
  132. package/tests/components/counter/CounterFixtures.res +6 -8
  133. package/tests/components/dcb/DcbCrossPartitionFixtures.res +8 -2
  134. package/tests/components/dcb/DcbCrossPartitionReadTest.res +20 -13
  135. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +12 -8
  136. package/tests/components/dcb/DcbEventLogStreamTest.res +88 -61
  137. package/tests/components/dcb/DcbFixtures.res +4 -1
  138. package/tests/components/dcb/DcbTest.res +9 -6
  139. package/tests/components/eventcollector/EventCollectorFixtures.res +0 -1
  140. package/tests/components/eventcollector/EventCollectorTest.res +6 -3
  141. package/tests/components/eventlog/EventLogAppendStreamTest.res +88 -68
  142. package/tests/components/eventlog/EventLogConflictTest.res +8 -4
  143. package/tests/components/eventlog/EventLogFixtures.res +3 -3
  144. package/tests/components/eventlog/EventLogProvisioningSeamTest.res +26 -13
  145. package/tests/components/eventlog/EventLogStreamTest.res +119 -56
  146. package/tests/components/eventlog/EventLogTest.res +20 -4
  147. package/tests/components/eventtopic/EventTopicFixtures.res +3 -3
  148. package/tests/components/eventtopic/EventTopicStreamFixtures.res +1 -2
  149. package/tests/components/eventtopic/EventTopicStreamTest.res +7 -1
  150. package/tests/components/extensionpoint/ExtensionPointFixtures.res +14 -9
  151. package/tests/components/extensionpoint/ExtensionPointTest.res +3 -2
  152. package/tests/components/heartbeat/HeartbeatFixtures.res +5 -6
  153. package/tests/components/heartbeat/HeartbeatTest.res +56 -47
  154. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +271 -249
  155. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +3 -2
  156. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +361 -276
  157. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +8 -10
  158. package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +37 -43
  159. package/tests/components/querydb/QueryDbFixtures.res +1 -5
  160. package/tests/components/querydb/QueryDbTest.res +2 -4
  161. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +15 -18
  162. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -7
  163. package/tests/components/readmodel/ReadModelFixtures.res +8 -8
  164. package/tests/components/scheduler/SchedulerTest.res +76 -58
  165. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +4 -4
  166. package/tests/components/stateviewslice/StateViewSliceDisplayNameFixtures.res +5 -7
  167. package/tests/components/stateviewslice/StateViewSliceFixtures.res +8 -6
  168. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +17 -11
  169. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +12 -2
  170. package/tests/components/task/TaskFixtures.res +5 -5
  171. package/tests/components/task/TaskTest.res +95 -80
  172. package/tests/plugin/PluginsProjection_GWT.res +3 -1
  173. package/tests/plugin/UiFragments_GWT.res +6 -1
  174. package/tests/reset/LocalSeedResetTest.res +1 -0
@@ -66,14 +66,20 @@ let plainCtx = ctxFor(~groups=["User"])
66
66
  let noArgs: JSON.t = JSON.Encode.object(Dict.make())
67
67
 
68
68
  let getString = (json: JSON.t, key: string): option<string> =>
69
- json->JSON.Decode.object->Option.flatMap(d => d->Dict.get(key))->Option.flatMap(JSON.Decode.string)
69
+ json
70
+ ->JSON.Decode.object
71
+ ->Option.flatMap(d => d->Dict.get(key))
72
+ ->Option.flatMap(JSON.Decode.string)
70
73
 
71
74
  let names = (json: JSON.t): array<string> =>
72
75
  json->JSON.Decode.array->Option.getOr([])->Array.filterMap(item => item->getString("name"))
73
76
 
74
77
  // One Bus carrying both views, resolvers registered for the Orders view with the
75
78
  // two configs the PPX writes from `@resolves` / `@resolvesMany`.
76
- let buildFixture = async (~suffix: string, ~retired: option<Reventless.StateAnnotations.retiredSpec>) => {
79
+ let buildFixture = async (
80
+ ~suffix: string,
81
+ ~retired: option<Reventless.StateAnnotations.retiredSpec>,
82
+ ) => {
77
83
  module Bus = LocalBus.Make()
78
84
  module Storage = LocalQueryDbStorage.Make(Bus)
79
85
  module Resolvers = QueryDbResolvers_GraphQL.Make(Bus)
@@ -144,10 +150,7 @@ let buildFixture = async (~suffix: string, ~retired: option<Reventless.StateAnno
144
150
  ReventlessCore.Plugin_Helpers.stateSchemaRegistry->Dict.set(
145
151
  productsName,
146
152
  productRowSchema
147
- ->S.Metadata.set(
148
- ~id=Reventless.StateAnnotations.stateAnnotationsId,
149
- annotations(~retired),
150
- )
153
+ ->S.Metadata.set(~id=Reventless.StateAnnotations.stateAnnotationsId, annotations(~retired))
151
154
  ->S.castToUnknown,
152
155
  )
153
156
 
@@ -169,7 +172,12 @@ let buildFixture = async (~suffix: string, ~retired: option<Reventless.StateAnno
169
172
  ~opts=({}: Pulumi.CustomResourceOptions.t),
170
173
  )
171
174
 
172
- let _ = await productOps.save("p-1", {productId: "p-1", name: "Book", archived: false}, Init, None)
175
+ let _ = await productOps.save(
176
+ "p-1",
177
+ {productId: "p-1", name: "Book", archived: false},
178
+ Init,
179
+ None,
180
+ )
173
181
  let _ = await productOps.save("p-2", {productId: "p-2", name: "Pen", archived: true}, Init, None)
174
182
  let _ = await orderOps.save(
175
183
  "o-1",
@@ -188,10 +196,7 @@ let buildFixture = async (~suffix: string, ~retired: option<Reventless.StateAnno
188
196
  Dict.fromArray([
189
197
  ("orderId", JSON.Encode.string("o-1")),
190
198
  ("productId", JSON.Encode.string("p-1")),
191
- (
192
- "productIds",
193
- ["p-1", "gone", "p-2"]->Array.map(JSON.Encode.string)->JSON.Encode.array,
194
- ),
199
+ ("productIds", ["p-1", "gone", "p-2"]->Array.map(JSON.Encode.string)->JSON.Encode.array),
195
200
  ]),
196
201
  )
197
202
 
@@ -222,9 +227,7 @@ describe("QueryDb cross-table field resolvers", () => {
222
227
 
223
228
  testPromise("a foreign key naming no row resolves to nothing", async () => {
224
229
  let (resolverFor, _) = await buildFixture(~suffix="C", ~retired=None)
225
- let orphan = JSON.Encode.object(
226
- Dict.fromArray([("productId", JSON.Encode.string("nope"))]),
227
- )
230
+ let orphan = JSON.Encode.object(Dict.fromArray([("productId", JSON.Encode.string("nope"))]))
228
231
  let product = await resolverFor("product")(orphan, noArgs, plainCtx)
229
232
  expect(product)->toBe(JSON.Encode.null)
230
233
  })
@@ -18,18 +18,12 @@ describe("QueryDbStorage_Sqlite", () => {
18
18
  let s = Storage.make(~name="rm1", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
19
19
  let ops = await s.operations->TestRunner.resolve
20
20
 
21
- let _ = await ops.save(
22
- "id1",
23
- JSON.Encode.string("value1"),
24
- ReventlessCore.QueryDb.Any,
25
- None,
26
- )
27
-
28
- let items =
29
- await ops.loadStream("id1")
30
- ->Stream.runCollect
31
- ->Effect.catchAll(_ => Effect.succeed([]))
32
- ->Effect.runPromise
21
+ let _ = await ops.save("id1", JSON.Encode.string("value1"), ReventlessCore.QueryDb.Any, None)
22
+
23
+ let items = await ops.loadStream("id1")
24
+ ->Stream.runCollect
25
+ ->Effect.catchAll(_ => Effect.succeed([]))
26
+ ->Effect.runPromise
33
27
 
34
28
  expect(items->Array.length)->toBe(1)
35
29
  expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("value1"))
@@ -48,11 +42,10 @@ describe("QueryDbStorage_Sqlite", () => {
48
42
  let _ = await ops.save("k", JSON.Encode.string("a"), ReventlessCore.QueryDb.Any, None)
49
43
  let _ = await ops.save("k", JSON.Encode.string("b"), ReventlessCore.QueryDb.Any, None)
50
44
 
51
- let items =
52
- await ops.loadStream("k")
53
- ->Stream.runCollect
54
- ->Effect.catchAll(_ => Effect.succeed([]))
55
- ->Effect.runPromise
45
+ let items = await ops.loadStream("k")
46
+ ->Stream.runCollect
47
+ ->Effect.catchAll(_ => Effect.succeed([]))
48
+ ->Effect.runPromise
56
49
 
57
50
  expect(items->Array.length)->toBe(1)
58
51
  expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("b"))
@@ -74,21 +67,18 @@ describe("QueryDbStorage_Sqlite", () => {
74
67
  ("id3", JSON.Encode.string("three"), None),
75
68
  ])
76
69
 
77
- let items1 =
78
- await ops.loadStream("id1")
79
- ->Stream.runCollect
80
- ->Effect.catchAll(_ => Effect.succeed([]))
81
- ->Effect.runPromise
82
- let items2 =
83
- await ops.loadStream("id2")
84
- ->Stream.runCollect
85
- ->Effect.catchAll(_ => Effect.succeed([]))
86
- ->Effect.runPromise
87
- let items3 =
88
- await ops.loadStream("id3")
89
- ->Stream.runCollect
90
- ->Effect.catchAll(_ => Effect.succeed([]))
91
- ->Effect.runPromise
70
+ let items1 = await ops.loadStream("id1")
71
+ ->Stream.runCollect
72
+ ->Effect.catchAll(_ => Effect.succeed([]))
73
+ ->Effect.runPromise
74
+ let items2 = await ops.loadStream("id2")
75
+ ->Stream.runCollect
76
+ ->Effect.catchAll(_ => Effect.succeed([]))
77
+ ->Effect.runPromise
78
+ let items3 = await ops.loadStream("id3")
79
+ ->Stream.runCollect
80
+ ->Effect.catchAll(_ => Effect.succeed([]))
81
+ ->Effect.runPromise
92
82
 
93
83
  expect(items1->Array.length)->toBe(1)
94
84
  expect(items2->Array.length)->toBe(1)
@@ -108,11 +98,10 @@ describe("QueryDbStorage_Sqlite", () => {
108
98
  let _ = await ops.save("k", JSON.Encode.string("a"), ReventlessCore.QueryDb.Any, None)
109
99
  let _ = await ops.delete("k", None)
110
100
 
111
- let items =
112
- await ops.loadStream("k")
113
- ->Stream.runCollect
114
- ->Effect.catchAll(_ => Effect.succeed([]))
115
- ->Effect.runPromise
101
+ let items = await ops.loadStream("k")
102
+ ->Stream.runCollect
103
+ ->Effect.catchAll(_ => Effect.succeed([]))
104
+ ->Effect.runPromise
116
105
 
117
106
  expect(items->Array.length)->toBe(0)
118
107
  })
@@ -120,8 +109,9 @@ describe("QueryDbStorage_Sqlite", () => {
120
109
  testPromise("items persist across a file reopen", async () => {
121
110
  let path = `/tmp/reventless-test-qdb-${Float.toString(Date.now())}.db`
122
111
 
123
- // Session 1: write
124
112
  {
113
+ // Session 1: write
114
+
125
115
  module TestBus = LocalBus.Make()
126
116
  module DbProvider = {
127
117
  let db = SqliteDriver.openDb(~path)
@@ -129,12 +119,7 @@ describe("QueryDbStorage_Sqlite", () => {
129
119
  module Storage = QueryDbStorage_Sqlite.Make(TestBus, DbProvider)
130
120
  let s = Storage.make(~name="persist", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
131
121
  let ops = await s.operations->TestRunner.resolve
132
- let _ = await ops.save(
133
- "k",
134
- JSON.Encode.string("hello"),
135
- ReventlessCore.QueryDb.Any,
136
- None,
137
- )
122
+ let _ = await ops.save("k", JSON.Encode.string("hello"), ReventlessCore.QueryDb.Any, None)
138
123
  DbProvider.db->SqliteDriver.close
139
124
  }
140
125
 
@@ -146,11 +131,10 @@ describe("QueryDbStorage_Sqlite", () => {
146
131
  module Storage2 = QueryDbStorage_Sqlite.Make(TestBus2, DbProvider2)
147
132
  let s2 = Storage2.make(~name="persist", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
148
133
  let ops2 = await s2.operations->TestRunner.resolve
149
- let items =
150
- await ops2.loadStream("k")
151
- ->Stream.runCollect
152
- ->Effect.catchAll(_ => Effect.succeed([]))
153
- ->Effect.runPromise
134
+ let items = await ops2.loadStream("k")
135
+ ->Stream.runCollect
136
+ ->Effect.catchAll(_ => Effect.succeed([]))
137
+ ->Effect.runPromise
154
138
 
155
139
  expect(items->Array.length)->toBe(1)
156
140
  expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("hello"))
@@ -9,163 +9,209 @@ let opts: Pulumi.CustomResourceOptions.t = {}
9
9
 
10
10
  describe("QueryDbStorage_InMemory", () => {
11
11
  describe("save and load", () => {
12
- testPromise("save stores state; loadStream retrieves it by id", async () => {
13
- module TestBus = LocalBus.Make()
14
- module Storage = LocalQueryDbStorage.Make(TestBus)
15
- let s = Storage.make(~name="rm1", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
16
- let ops = await s.operations->TestRunner.resolve
17
- let _ = await ops.save("id1", JSON.Encode.string("value1"), ReventlessCore.QueryDb.Any, None)
18
- let items =
19
- await ops.loadStream("id1")
12
+ testPromise(
13
+ "save stores state; loadStream retrieves it by id",
14
+ async () => {
15
+ module TestBus = LocalBus.Make()
16
+ module Storage = LocalQueryDbStorage.Make(TestBus)
17
+ let s = Storage.make(~name="rm1", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
18
+ let ops = await s.operations->TestRunner.resolve
19
+ let _ = await ops.save(
20
+ "id1",
21
+ JSON.Encode.string("value1"),
22
+ ReventlessCore.QueryDb.Any,
23
+ None,
24
+ )
25
+ let items = await ops.loadStream("id1")
20
26
  ->Stream.runCollect
21
27
  ->Effect.catchAll(_ => Effect.succeed([]))
22
28
  ->Effect.runPromise
23
- expect(items->Array.length)->toBe(1)
24
- expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("value1"))
25
- })
29
+ expect(items->Array.length)->toBe(1)
30
+ expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("value1"))
31
+ },
32
+ )
26
33
 
27
- testPromise("loadStream returns empty for unknown id", async () => {
28
- module TestBus = LocalBus.Make()
29
- module Storage = LocalQueryDbStorage.Make(TestBus)
30
- let s = Storage.make(~name="rm2", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
31
- let ops = await s.operations->TestRunner.resolve
32
- let items =
33
- await ops.loadStream("unknown")
34
+ testPromise(
35
+ "loadStream returns empty for unknown id",
36
+ async () => {
37
+ module TestBus = LocalBus.Make()
38
+ module Storage = LocalQueryDbStorage.Make(TestBus)
39
+ let s = Storage.make(~name="rm2", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
40
+ let ops = await s.operations->TestRunner.resolve
41
+ let items = await ops.loadStream("unknown")
34
42
  ->Stream.runCollect
35
43
  ->Effect.catchAll(_ => Effect.succeed([]))
36
44
  ->Effect.runPromise
37
- expect(items->Array.length)->toBe(0)
38
- })
45
+ expect(items->Array.length)->toBe(0)
46
+ },
47
+ )
39
48
 
40
- testPromise("save overwrites previous state for same id", async () => {
41
- module TestBus = LocalBus.Make()
42
- module Storage = LocalQueryDbStorage.Make(TestBus)
43
- let s = Storage.make(~name="rm3", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
44
- let ops = await s.operations->TestRunner.resolve
45
- let _ = await ops.save("id1", JSON.Encode.string("old"), ReventlessCore.QueryDb.Any, None)
46
- let _ = await ops.save("id1", JSON.Encode.string("new"), ReventlessCore.QueryDb.Any, None)
47
- let items =
48
- await ops.loadStream("id1")
49
+ testPromise(
50
+ "save overwrites previous state for same id",
51
+ async () => {
52
+ module TestBus = LocalBus.Make()
53
+ module Storage = LocalQueryDbStorage.Make(TestBus)
54
+ let s = Storage.make(~name="rm3", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
55
+ let ops = await s.operations->TestRunner.resolve
56
+ let _ = await ops.save("id1", JSON.Encode.string("old"), ReventlessCore.QueryDb.Any, None)
57
+ let _ = await ops.save("id1", JSON.Encode.string("new"), ReventlessCore.QueryDb.Any, None)
58
+ let items = await ops.loadStream("id1")
49
59
  ->Stream.runCollect
50
60
  ->Effect.catchAll(_ => Effect.succeed([]))
51
61
  ->Effect.runPromise
52
- expect(items->Array.length)->toBe(1)
53
- expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("new"))
54
- })
62
+ expect(items->Array.length)->toBe(1)
63
+ expect(items->Array.getUnsafe(0))->toEqual(JSON.Encode.string("new"))
64
+ },
65
+ )
55
66
 
56
- testPromise("load delegates to loadStream (backward-compat)", async () => {
57
- module TestBus = LocalBus.Make()
58
- module Storage = LocalQueryDbStorage.Make(TestBus)
59
- let s = Storage.make(~name="load-compat", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
60
- let ops = await s.operations->TestRunner.resolve
61
- let _ = await ops.save("compat-id", JSON.Encode.string("compat-val"), ReventlessCore.QueryDb.Any, None)
62
- let streamed = await ops.loadStream("compat-id")->Stream.runCollect->Effect.runPromise
63
- let loaded = await ops.load("compat-id")
64
- expect(loaded)->toEqual(Ok(streamed))
65
- })
67
+ testPromise(
68
+ "load delegates to loadStream (backward-compat)",
69
+ async () => {
70
+ module TestBus = LocalBus.Make()
71
+ module Storage = LocalQueryDbStorage.Make(TestBus)
72
+ let s = Storage.make(
73
+ ~name="load-compat",
74
+ ~indexes=[],
75
+ ~api=(),
76
+ ~apiRole=(),
77
+ ~owner=None,
78
+ ~opts,
79
+ )
80
+ let ops = await s.operations->TestRunner.resolve
81
+ let _ = await ops.save(
82
+ "compat-id",
83
+ JSON.Encode.string("compat-val"),
84
+ ReventlessCore.QueryDb.Any,
85
+ None,
86
+ )
87
+ let streamed = await ops.loadStream("compat-id")->Stream.runCollect->Effect.runPromise
88
+ let loaded = await ops.load("compat-id")
89
+ expect(loaded)->toEqual(Ok(streamed))
90
+ },
91
+ )
66
92
  })
67
93
 
68
94
  describe("saveBatch", () => {
69
- testPromise("stores multiple items; loadStream retrieves each by id", async () => {
70
- module TestBus = LocalBus.Make()
71
- module Storage = LocalQueryDbStorage.Make(TestBus)
72
- let s = Storage.make(~name="rm4", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
73
- let ops = await s.operations->TestRunner.resolve
74
- let _ = await ops.saveBatch([
75
- ("a", JSON.Encode.string("val-a"), None),
76
- ("b", JSON.Encode.string("val-b"), None),
77
- ])
78
- let itemsA =
79
- await ops.loadStream("a")
95
+ testPromise(
96
+ "stores multiple items; loadStream retrieves each by id",
97
+ async () => {
98
+ module TestBus = LocalBus.Make()
99
+ module Storage = LocalQueryDbStorage.Make(TestBus)
100
+ let s = Storage.make(~name="rm4", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
101
+ let ops = await s.operations->TestRunner.resolve
102
+ let _ = await ops.saveBatch([
103
+ ("a", JSON.Encode.string("val-a"), None),
104
+ ("b", JSON.Encode.string("val-b"), None),
105
+ ])
106
+ let itemsA = await ops.loadStream("a")
80
107
  ->Stream.runCollect
81
108
  ->Effect.catchAll(_ => Effect.succeed([]))
82
109
  ->Effect.runPromise
83
- let itemsB =
84
- await ops.loadStream("b")
110
+ let itemsB = await ops.loadStream("b")
85
111
  ->Stream.runCollect
86
112
  ->Effect.catchAll(_ => Effect.succeed([]))
87
113
  ->Effect.runPromise
88
- expect(itemsA->Array.getUnsafe(0))->toEqual(JSON.Encode.string("val-a"))
89
- expect(itemsB->Array.getUnsafe(0))->toEqual(JSON.Encode.string("val-b"))
90
- })
114
+ expect(itemsA->Array.getUnsafe(0))->toEqual(JSON.Encode.string("val-a"))
115
+ expect(itemsB->Array.getUnsafe(0))->toEqual(JSON.Encode.string("val-b"))
116
+ },
117
+ )
91
118
  })
92
119
 
93
120
  describe("count", () => {
94
- testPromise("returns the increment value (no real counting semantics)", async () => {
95
- module TestBus = LocalBus.Make()
96
- module Storage = LocalQueryDbStorage.Make(TestBus)
97
- let s = Storage.make(~name="rm5", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
98
- let ops = await s.operations->TestRunner.resolve
99
- let result = await ops.count("id1", "field", 5)
100
- expect(result)->toEqual(Ok(5))
101
- })
121
+ testPromise(
122
+ "returns the increment value (no real counting semantics)",
123
+ async () => {
124
+ module TestBus = LocalBus.Make()
125
+ module Storage = LocalQueryDbStorage.Make(TestBus)
126
+ let s = Storage.make(~name="rm5", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
127
+ let ops = await s.operations->TestRunner.resolve
128
+ let result = await ops.count("id1", "field", 5)
129
+ expect(result)->toEqual(Ok(5))
130
+ },
131
+ )
102
132
  })
103
133
 
104
134
  describe("delete", () => {
105
- testPromise("removes item; loadStream returns empty", async () => {
106
- module TestBus = LocalBus.Make()
107
- module Storage = LocalQueryDbStorage.Make(TestBus)
108
- let s = Storage.make(~name="rm6", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
109
- let ops = await s.operations->TestRunner.resolve
110
- let _ = await ops.save("del-id", JSON.Encode.string("v"), ReventlessCore.QueryDb.Any, None)
111
- let _ = await ops.delete("del-id", None)
112
- let items =
113
- await ops.loadStream("del-id")
135
+ testPromise(
136
+ "removes item; loadStream returns empty",
137
+ async () => {
138
+ module TestBus = LocalBus.Make()
139
+ module Storage = LocalQueryDbStorage.Make(TestBus)
140
+ let s = Storage.make(~name="rm6", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
141
+ let ops = await s.operations->TestRunner.resolve
142
+ let _ = await ops.save("del-id", JSON.Encode.string("v"), ReventlessCore.QueryDb.Any, None)
143
+ let _ = await ops.delete("del-id", None)
144
+ let items = await ops.loadStream("del-id")
114
145
  ->Stream.runCollect
115
146
  ->Effect.catchAll(_ => Effect.succeed([]))
116
147
  ->Effect.runPromise
117
- expect(items->Array.length)->toBe(0)
118
- })
148
+ expect(items->Array.length)->toBe(0)
149
+ },
150
+ )
119
151
 
120
- testPromise("deleteBatch removes multiple items", async () => {
121
- module TestBus = LocalBus.Make()
122
- module Storage = LocalQueryDbStorage.Make(TestBus)
123
- let s = Storage.make(~name="rm7", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
124
- let ops = await s.operations->TestRunner.resolve
125
- let _ = await ops.saveBatch([
126
- ("x", JSON.Encode.string("vx"), None),
127
- ("y", JSON.Encode.string("vy"), None),
128
- ])
129
- let _ = await ops.deleteBatch([("x", None), ("y", None)])
130
- let rx =
131
- await ops.loadStream("x")
152
+ testPromise(
153
+ "deleteBatch removes multiple items",
154
+ async () => {
155
+ module TestBus = LocalBus.Make()
156
+ module Storage = LocalQueryDbStorage.Make(TestBus)
157
+ let s = Storage.make(~name="rm7", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
158
+ let ops = await s.operations->TestRunner.resolve
159
+ let _ = await ops.saveBatch([
160
+ ("x", JSON.Encode.string("vx"), None),
161
+ ("y", JSON.Encode.string("vy"), None),
162
+ ])
163
+ let _ = await ops.deleteBatch([("x", None), ("y", None)])
164
+ let rx = await ops.loadStream("x")
132
165
  ->Stream.runCollect
133
166
  ->Effect.catchAll(_ => Effect.succeed([]))
134
167
  ->Effect.runPromise
135
- let ry =
136
- await ops.loadStream("y")
168
+ let ry = await ops.loadStream("y")
137
169
  ->Stream.runCollect
138
170
  ->Effect.catchAll(_ => Effect.succeed([]))
139
171
  ->Effect.runPromise
140
- expect(rx->Array.length)->toBe(0)
141
- expect(ry->Array.length)->toBe(0)
142
- })
172
+ expect(rx->Array.length)->toBe(0)
173
+ expect(ry->Array.length)->toBe(0)
174
+ },
175
+ )
143
176
  })
144
177
 
145
178
  describe("scan registration", () => {
146
- testPromise("after save, scan function returns all stored items", async () => {
147
- module TestBus = LocalBus.Make()
148
- module Storage = LocalQueryDbStorage.Make(TestBus)
149
- let s = Storage.make(~name="scan-rm", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
150
- let ops = await s.operations->TestRunner.resolve
151
- let _ = await ops.save("s1", JSON.Encode.string("item1"), ReventlessCore.QueryDb.Any, None)
152
- let _ = await ops.save("s2", JSON.Encode.string("item2"), ReventlessCore.QueryDb.Any, None)
153
- let scanFn = TestBus.getQueryDbScan("scan-rm")->Option.getOr(() => [])
154
- let all = scanFn()
155
- expect(all->Array.length)->toBe(2)
156
- })
179
+ testPromise(
180
+ "after save, scan function returns all stored items",
181
+ async () => {
182
+ module TestBus = LocalBus.Make()
183
+ module Storage = LocalQueryDbStorage.Make(TestBus)
184
+ let s = Storage.make(~name="scan-rm", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
185
+ let ops = await s.operations->TestRunner.resolve
186
+ let _ = await ops.save("s1", JSON.Encode.string("item1"), ReventlessCore.QueryDb.Any, None)
187
+ let _ = await ops.save("s2", JSON.Encode.string("item2"), ReventlessCore.QueryDb.Any, None)
188
+ let scanFn = TestBus.getQueryDbScan("scan-rm")->Option.getOr(() => [])
189
+ let all = scanFn()
190
+ expect(all->Array.length)->toBe(2)
191
+ },
192
+ )
157
193
 
158
- testPromise("after delete, scan function excludes deleted item", async () => {
159
- module TestBus = LocalBus.Make()
160
- module Storage = LocalQueryDbStorage.Make(TestBus)
161
- let s = Storage.make(~name="scan-rm2", ~indexes=[], ~api=(), ~apiRole=(), ~owner=None, ~opts)
162
- let ops = await s.operations->TestRunner.resolve
163
- let _ = await ops.save("keep", JSON.Encode.string("keep"), ReventlessCore.QueryDb.Any, None)
164
- let _ = await ops.save("gone", JSON.Encode.string("gone"), ReventlessCore.QueryDb.Any, None)
165
- let _ = await ops.delete("gone", None)
166
- let scanFn = TestBus.getQueryDbScan("scan-rm2")->Option.getOr(() => [])
167
- let all = scanFn()
168
- expect(all->Array.length)->toBe(1)
169
- })
194
+ testPromise(
195
+ "after delete, scan function excludes deleted item",
196
+ async () => {
197
+ module TestBus = LocalBus.Make()
198
+ module Storage = LocalQueryDbStorage.Make(TestBus)
199
+ let s = Storage.make(
200
+ ~name="scan-rm2",
201
+ ~indexes=[],
202
+ ~api=(),
203
+ ~apiRole=(),
204
+ ~owner=None,
205
+ ~opts,
206
+ )
207
+ let ops = await s.operations->TestRunner.resolve
208
+ let _ = await ops.save("keep", JSON.Encode.string("keep"), ReventlessCore.QueryDb.Any, None)
209
+ let _ = await ops.save("gone", JSON.Encode.string("gone"), ReventlessCore.QueryDb.Any, None)
210
+ let _ = await ops.delete("gone", None)
211
+ let scanFn = TestBus.getQueryDbScan("scan-rm2")->Option.getOr(() => [])
212
+ let all = scanFn()
213
+ expect(all->Array.length)->toBe(1)
214
+ },
215
+ )
170
216
  })
171
217
  })
@@ -76,11 +76,10 @@ describe("QueryDb round-trips a union field", () => {
76
76
  )
77
77
 
78
78
  // The stored row, as any read door would hand it back.
79
- let stored =
80
- await jsonOps.loadStream("c-1")
81
- ->Stream.runCollect
82
- ->Effect.catchAll(_ => Effect.succeed([]))
83
- ->Effect.runPromise
79
+ let stored = await jsonOps.loadStream("c-1")
80
+ ->Stream.runCollect
81
+ ->Effect.catchAll(_ => Effect.succeed([]))
82
+ ->Effect.runPromise
84
83
  let typename =
85
84
  stored
86
85
  ->Array.get(0)
@@ -91,11 +90,10 @@ describe("QueryDb round-trips a union field", () => {
91
90
  ->Option.flatMap(JSON.Decode.string)
92
91
  expect(typename)->toEqual(Some("GeolocationLocated"))
93
92
 
94
- let items =
95
- await Ops.loadStream("c-1"->CustomersSpec.Id.makeFromString)
96
- ->Stream.runCollect
97
- ->Effect.catchAll(_ => Effect.succeed([]))
98
- ->Effect.runPromise
93
+ let items = await Ops.loadStream("c-1"->CustomersSpec.Id.makeFromString)
94
+ ->Stream.runCollect
95
+ ->Effect.catchAll(_ => Effect.succeed([]))
96
+ ->Effect.runPromise
99
97
  switch items {
100
98
  | [{geolocation: Located({lat, lng})}] => expect((lat, lng))->toEqual((48.2082, 16.3738))
101
99
  | _ => expect("round trip")->toBe("Located with its point intact")