@reventlessdev/reventless-postgres 3.0.0-alpha.5 → 3.0.0-alpha.51

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 (158) hide show
  1. package/CHANGELOG.md +369 -0
  2. package/README.md +83 -0
  3. package/lib/bs/.compiler.log +2 -2
  4. package/lib/bs/ReventlessPostgres.cmi +0 -0
  5. package/lib/bs/ReventlessPostgres.cmt +0 -0
  6. package/lib/bs/ReventlessPostgres.mlmap +3 -2
  7. package/lib/bs/compiler-info.json +2 -2
  8. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  9. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  10. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  11. package/lib/bs/src/DcbEventLogStorage_Postgres.ast +0 -0
  12. package/lib/bs/src/DcbEventLogStorage_Postgres.res +25 -340
  13. package/lib/bs/src/DcbEventLogStorage_Postgres.res.mjs +32 -348
  14. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  15. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  16. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  17. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.ast +0 -0
  18. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.res +350 -0
  19. package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.res.mjs +380 -0
  20. package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
  21. package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
  22. package/lib/bs/src/EventLogChangeFeed.ast +0 -0
  23. package/lib/bs/src/EventLogChangeFeed.res +5 -2
  24. package/lib/bs/src/EventLogChangeFeed.res.mjs +3 -3
  25. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  26. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  27. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  28. package/lib/bs/src/EventLogStorage_Postgres.ast +0 -0
  29. package/lib/bs/src/EventLogStorage_Postgres.res +12 -170
  30. package/lib/bs/src/EventLogStorage_Postgres.res.mjs +20 -186
  31. package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  32. package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  33. package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  34. package/lib/bs/src/EventLogStorage_Postgres_Ops.ast +0 -0
  35. package/lib/bs/src/EventLogStorage_Postgres_Ops.res +180 -0
  36. package/lib/bs/src/EventLogStorage_Postgres_Ops.res.mjs +202 -0
  37. package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmi +0 -0
  38. package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmt +0 -0
  39. package/lib/bs/src/PgChangeFeed.ast +0 -0
  40. package/lib/bs/src/PgChangeFeed.res +6 -1
  41. package/lib/bs/src/PgChangeFeed.res.mjs +6 -6
  42. package/lib/bs/src/PgDriver-ReventlessPostgres.cmi +0 -0
  43. package/lib/bs/src/PgDriver-ReventlessPostgres.cmt +0 -0
  44. package/lib/bs/src/PgDriver-ReventlessPostgres.cmti +0 -0
  45. package/lib/bs/src/PgDriver.ast +0 -0
  46. package/lib/bs/src/PgDriver.iast +0 -0
  47. package/lib/bs/src/PgSchema-ReventlessPostgres.cmi +0 -0
  48. package/lib/bs/src/PgSchema-ReventlessPostgres.cmt +0 -0
  49. package/lib/bs/src/PgSchema.ast +0 -0
  50. package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
  51. package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
  52. package/lib/bs/src/QueryDbStorage_Postgres.ast +0 -0
  53. package/lib/bs/src/QueryDbStorage_Postgres.res +10 -233
  54. package/lib/bs/src/QueryDbStorage_Postgres.res.mjs +25 -204
  55. package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  56. package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  57. package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  58. package/lib/bs/src/QueryDbStorage_Postgres_Ops.ast +0 -0
  59. package/lib/bs/src/QueryDbStorage_Postgres_Ops.res +229 -0
  60. package/lib/bs/src/QueryDbStorage_Postgres_Ops.res.mjs +222 -0
  61. package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
  62. package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
  63. package/lib/bs/src/QueryEnginePostgres.ast +0 -0
  64. package/lib/bs/src/QueryEnginePostgres.res +91 -10
  65. package/lib/bs/src/QueryEnginePostgres.res.mjs +89 -21
  66. package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
  67. package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
  68. package/lib/bs/tests/PostgresIntegrationTest.ast +0 -0
  69. package/lib/bs/tests/QueryEnginePostgresListPageTest-ReventlessPostgres.cmi +0 -0
  70. package/lib/bs/tests/QueryEnginePostgresListPageTest-ReventlessPostgres.cmt +0 -0
  71. package/lib/bs/tests/QueryEnginePostgresListPageTest.ast +0 -0
  72. package/lib/bs/tests/QueryEnginePostgresListPageTest.res +76 -0
  73. package/lib/bs/tests/QueryEnginePostgresListPageTest.res.mjs +136 -0
  74. package/lib/ocaml/.compiler.log +2 -2
  75. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  76. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  77. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  78. package/lib/ocaml/DcbEventLogStorage_Postgres.ast +0 -0
  79. package/lib/ocaml/DcbEventLogStorage_Postgres.res +25 -340
  80. package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  81. package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  82. package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  83. package/lib/ocaml/DcbEventLogStorage_Postgres_Ops.ast +0 -0
  84. package/lib/ocaml/DcbEventLogStorage_Postgres_Ops.res +350 -0
  85. package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
  86. package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
  87. package/lib/ocaml/EventLogChangeFeed.ast +0 -0
  88. package/lib/ocaml/EventLogChangeFeed.res +5 -2
  89. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  90. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  91. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  92. package/lib/ocaml/EventLogStorage_Postgres.ast +0 -0
  93. package/lib/ocaml/EventLogStorage_Postgres.res +12 -170
  94. package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  95. package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  96. package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  97. package/lib/ocaml/EventLogStorage_Postgres_Ops.ast +0 -0
  98. package/lib/ocaml/EventLogStorage_Postgres_Ops.res +180 -0
  99. package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmi +0 -0
  100. package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmt +0 -0
  101. package/lib/ocaml/PgChangeFeed.ast +0 -0
  102. package/lib/ocaml/PgChangeFeed.res +6 -1
  103. package/lib/ocaml/PgDriver-ReventlessPostgres.cmi +0 -0
  104. package/lib/ocaml/PgDriver-ReventlessPostgres.cmt +0 -0
  105. package/lib/ocaml/PgDriver-ReventlessPostgres.cmti +0 -0
  106. package/lib/ocaml/PgDriver.ast +0 -0
  107. package/lib/ocaml/PgDriver.iast +0 -0
  108. package/lib/ocaml/PgSchema-ReventlessPostgres.cmi +0 -0
  109. package/lib/ocaml/PgSchema-ReventlessPostgres.cmt +0 -0
  110. package/lib/ocaml/PgSchema.ast +0 -0
  111. package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
  112. package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
  113. package/lib/ocaml/QueryDbStorage_Postgres.ast +0 -0
  114. package/lib/ocaml/QueryDbStorage_Postgres.res +10 -233
  115. package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
  116. package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
  117. package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
  118. package/lib/ocaml/QueryDbStorage_Postgres_Ops.ast +0 -0
  119. package/lib/ocaml/QueryDbStorage_Postgres_Ops.res +229 -0
  120. package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
  121. package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
  122. package/lib/ocaml/QueryEnginePostgres.ast +0 -0
  123. package/lib/ocaml/QueryEnginePostgres.res +91 -10
  124. package/lib/ocaml/QueryEnginePostgresListPageTest.res +76 -0
  125. package/lib/ocaml/ReventlessPostgres.cmi +0 -0
  126. package/lib/ocaml/ReventlessPostgres.cmt +0 -0
  127. package/lib/ocaml/ReventlessPostgres.mlmap +3 -0
  128. package/package.json +11 -11
  129. package/rescript.json +2 -1
  130. package/src/DcbEventLogStorage_Postgres.res +25 -340
  131. package/src/DcbEventLogStorage_Postgres.res.mjs +32 -348
  132. package/src/DcbEventLogStorage_Postgres_Ops.res +350 -0
  133. package/src/DcbEventLogStorage_Postgres_Ops.res.mjs +380 -0
  134. package/src/EventLogChangeFeed.res +5 -2
  135. package/src/EventLogChangeFeed.res.mjs +3 -3
  136. package/src/EventLogStorage_Postgres.res +12 -170
  137. package/src/EventLogStorage_Postgres.res.mjs +20 -186
  138. package/src/EventLogStorage_Postgres_Ops.res +180 -0
  139. package/src/EventLogStorage_Postgres_Ops.res.mjs +202 -0
  140. package/src/PgChangeFeed.res +6 -1
  141. package/src/PgChangeFeed.res.mjs +6 -6
  142. package/src/QueryDbStorage_Postgres.res +10 -233
  143. package/src/QueryDbStorage_Postgres.res.mjs +25 -204
  144. package/src/QueryDbStorage_Postgres_Ops.res +229 -0
  145. package/src/QueryDbStorage_Postgres_Ops.res.mjs +222 -0
  146. package/src/QueryEnginePostgres.res +91 -10
  147. package/src/QueryEnginePostgres.res.mjs +89 -21
  148. package/tests/QueryEnginePostgresListPageTest.res +76 -0
  149. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
  150. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmj +0 -0
  151. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
  152. package/lib/ocaml/PostgresIntegrationTest.ast +0 -0
  153. package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmi +0 -0
  154. package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmj +0 -0
  155. package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmt +0 -0
  156. package/lib/ocaml/QueryEnginePostgresListPageTest.ast +0 -0
  157. package/tests/PostgresIntegrationTest.res.mjs +0 -377
  158. package/tests/QueryEnginePostgresListPageTest.res.mjs +0 -325
@@ -1,193 +1,14 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
4
- import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
5
- import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
- import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
7
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
- import * as Effect from "effect/Effect";
9
- import * as Stream$1 from "effect/Stream";
10
3
  import * as Pulumi from "@pulumi/pulumi";
11
- import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
12
- import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
4
+ import * as EventLogStorage_Postgres_Ops$ReventlessPostgres from "./EventLogStorage_Postgres_Ops.res.mjs";
13
5
 
14
- function noTracking(param) {
15
-
16
- }
17
-
18
- function decodePayload(row) {
19
- return Stdlib_Option.getOr(row["payload"], null);
20
- }
21
-
22
- function coerceInt(v) {
23
- switch (typeof v) {
24
- case "string" :
25
- return Stdlib_Option.getOr(Stdlib_Int.fromString(v, undefined), 0);
26
- case "number" :
27
- return v | 0;
28
- default:
29
- return 0;
30
- }
31
- }
32
-
33
- async function countAll(pool) {
34
- let row = await PgDriver$ReventlessPostgres.queryOne(pool, "SELECT COUNT(*)::bigint AS c FROM event_log", []);
35
- if (row !== undefined) {
36
- return Stdlib_Option.getOr(Stdlib_Option.map(row["c"], coerceInt), 0);
37
- } else {
38
- return 0;
39
- }
40
- }
41
-
42
- function isUniqueViolation(exn) {
43
- let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "");
44
- if (msg.includes("duplicate key") || msg.includes("unique")) {
45
- return true;
46
- } else {
47
- return msg.includes("23505");
48
- }
49
- }
50
-
51
- function makeStorage(pool, name, param, onAppendedOpt) {
52
- let onAppended = onAppendedOpt !== undefined ? onAppendedOpt : noTracking;
53
- let appendTracked = async (track, seqNr, id, jsons) => {
54
- if (jsons.length === 0) {
55
- return {
56
- TAG: "Ok",
57
- _0: undefined
58
- };
59
- }
60
- try {
61
- let rows = await PgDriver$ReventlessPostgres.query(pool, "INSERT INTO event_log(log_name, aggregate_id, seq_nr, payload, msg_id)\n SELECT $1, $2, $3::bigint + (ord - 1), value, value->>'msgId'\n FROM jsonb_array_elements($4::jsonb) WITH ORDINALITY AS t(value, ord)\n WHERE $3::bigint = (SELECT COALESCE(MAX(seq_nr), -1) + 1\n FROM event_log\n WHERE log_name = $1 AND aggregate_id = $2)\n RETURNING global_seq, msg_id", [
62
- name,
63
- id,
64
- seqNr,
65
- JSON.stringify(jsons)
66
- ]);
67
- if (rows.length === 0) {
68
- return {
69
- TAG: "Error",
70
- _0: "Conflict"
71
- };
72
- } else {
73
- if (track) {
74
- onAppended(Stdlib_Array.filterMap(rows, row => {
75
- let match = row["msg_id"];
76
- let match$1 = row["global_seq"];
77
- if (typeof match === "string" && match$1 !== undefined) {
78
- return [
79
- match,
80
- coerceInt(match$1)
81
- ];
82
- }
83
- }));
84
- }
85
- return {
86
- TAG: "Ok",
87
- _0: undefined
88
- };
89
- }
90
- } catch (raw_exn) {
91
- let exn = Primitive_exceptions.internalToException(raw_exn);
92
- if (isUniqueViolation(exn)) {
93
- return {
94
- TAG: "Error",
95
- _0: "Conflict"
96
- };
97
- } else {
98
- return {
99
- TAG: "Error",
100
- _0: {
101
- TAG: "StorageFailure",
102
- _0: Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "storage error")
103
- }
104
- };
105
- }
106
- }
107
- };
108
- let append = (seqNr, id, jsons) => appendTracked(true, seqNr, id, jsons);
109
- let replayArray = async (id, fromSeqOpt) => {
110
- let fromSeq = fromSeqOpt !== undefined ? fromSeqOpt : 0;
111
- return (await PgDriver$ReventlessPostgres.query(pool, "SELECT payload FROM event_log\n WHERE log_name = $1 AND aggregate_id = $2 AND seq_nr >= $3::bigint\n ORDER BY seq_nr ASC", [
112
- name,
113
- id,
114
- fromSeq
115
- ])).map(decodePayload);
116
- };
117
- let replay = id => replayArray(id, undefined);
118
- let replayStream = (id, fromSeq) => Stream$1.flatMap(Stream$1.fromEffect(Effect.promise(() => replayArray(id, fromSeq))), arr => Stream$1.fromIterable(arr));
119
- let latestSnapshot = async id => {
120
- let row = await PgDriver$ReventlessPostgres.queryOne(pool, "SELECT seq_nr, state, schema_hash FROM snapshot WHERE log_name = $1 AND aggregate_id = $2", [
121
- name,
122
- id
123
- ]);
124
- if (row === undefined) {
125
- return {
126
- TAG: "Ok",
127
- _0: undefined
128
- };
129
- }
130
- let match = row["seq_nr"];
131
- let match$1 = row["state"];
132
- let match$2 = row["schema_hash"];
133
- if (match !== undefined && match$1 !== undefined && typeof match$2 === "string") {
134
- return {
135
- TAG: "Ok",
136
- _0: {
137
- seqNr: coerceInt(match),
138
- state: match$1,
139
- schemaHash: match$2
140
- }
141
- };
142
- } else {
143
- return {
144
- TAG: "Error",
145
- _0: "snapshot row has unexpected shape"
146
- };
147
- }
148
- };
149
- let writeSnapshot = async (id, snap) => {
150
- try {
151
- await PgDriver$ReventlessPostgres.query(pool, "INSERT INTO snapshot(log_name, aggregate_id, seq_nr, state, schema_hash)\n VALUES ($1, $2, $3::bigint, $4::jsonb, $5)\n ON CONFLICT (log_name, aggregate_id)\n DO UPDATE SET seq_nr = EXCLUDED.seq_nr, state = EXCLUDED.state, schema_hash = EXCLUDED.schema_hash", [
152
- name,
153
- id,
154
- snap.seqNr,
155
- JSON.stringify(snap.state),
156
- snap.schemaHash
157
- ]);
158
- return {
159
- TAG: "Ok",
160
- _0: undefined
161
- };
162
- } catch (raw_exn) {
163
- let exn = Primitive_exceptions.internalToException(raw_exn);
164
- return {
165
- TAG: "Error",
166
- _0: Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "snapshot write error")
167
- };
168
- }
169
- };
170
- let appendStream = (startingSeqNr, id, stream) => Effect.flatMap(Stream.runCollect(stream), jsons => Effect.flatMap(Effect.promise(() => appendTracked(false, startingSeqNr, id, jsons)), result => {
171
- if (result.TAG === "Ok") {
172
- return Effect.succeed();
173
- }
174
- let msg = result._0;
175
- if (typeof msg !== "object") {
176
- return Effect.fail("conflict");
177
- } else {
178
- return Effect.fail(msg._0);
179
- }
180
- }));
181
- let ops = {
182
- append: append,
183
- replay: replay,
184
- replayStream: replayStream,
185
- appendStream: appendStream,
186
- latestSnapshot: latestSnapshot,
187
- writeSnapshot: writeSnapshot
188
- };
6
+ function makeStorage(pool, name, opts, onAppendedOpt) {
7
+ let onAppended = onAppendedOpt !== undefined ? onAppendedOpt : EventLogStorage_Postgres_Ops$ReventlessPostgres.noTracking;
8
+ let match = EventLogStorage_Postgres_Ops$ReventlessPostgres.makeOps(pool, name, opts, onAppended);
9
+ let ops = match[1];
189
10
  return [
190
- name,
11
+ match[0],
191
12
  ops,
192
13
  {
193
14
  resources: [],
@@ -196,12 +17,25 @@ function makeStorage(pool, name, param, onAppendedOpt) {
196
17
  ];
197
18
  }
198
19
 
20
+ let noTracking = EventLogStorage_Postgres_Ops$ReventlessPostgres.noTracking;
21
+
22
+ let decodePayload = EventLogStorage_Postgres_Ops$ReventlessPostgres.decodePayload;
23
+
24
+ let coerceInt = EventLogStorage_Postgres_Ops$ReventlessPostgres.coerceInt;
25
+
26
+ let countAll = EventLogStorage_Postgres_Ops$ReventlessPostgres.countAll;
27
+
28
+ let isUniqueViolation = EventLogStorage_Postgres_Ops$ReventlessPostgres.isUniqueViolation;
29
+
30
+ let makeOps = EventLogStorage_Postgres_Ops$ReventlessPostgres.makeOps;
31
+
199
32
  export {
200
33
  noTracking,
201
34
  decodePayload,
202
35
  coerceInt,
203
36
  countAll,
204
37
  isUniqueViolation,
38
+ makeOps,
205
39
  makeStorage,
206
40
  }
207
- /* Stream Not a pure module */
41
+ /* @pulumi/pulumi Not a pure module */
@@ -0,0 +1,180 @@
1
+ // Runtime-pure classic (OCC) event-log operations for the Postgres backend.
2
+ //
3
+ // This module holds everything the DEPLOYED Lambda runtime needs and imports NO
4
+ // `@pulumi/pulumi` — deploy-time-only. The deployed aggregate entry point pulls
5
+ // these ops in unconditionally at cold start, so any deploy-time dependency here
6
+ // leaks into the Lambda import graph and fails resolution (`@pulumi/pulumi` exists
7
+ // in no Lambda — not the layer, not `/var/runtime`). The thin
8
+ // `EventLogStorage_Postgres` wrapper adds the deploy-time `Pulumi.Output`-shaped
9
+ // adapter on top for local/deploy consumers; the runtime imports `makeOps` here.
10
+ // See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
11
+
12
+ open ReventlessCore
13
+
14
+ // Injected by reventless-local to feed the projection-checkpoint low-watermark
15
+ // (ProjectionPending, aggregate axis). Standalone/deploy use passes nothing.
16
+ type onAppended = array<(string, int)> => unit
17
+ let noTracking: onAppended = _ => ()
18
+
19
+ let decodePayload = (row: dict<JSON.t>): JSON.t =>
20
+ row->Dict.get("payload")->Option.getOr(JSON.Encode.null)
21
+
22
+ let coerceInt = (v: JSON.t): int =>
23
+ switch v {
24
+ | JSON.Number(n) => Float.toInt(n)
25
+ | JSON.String(s) => s->Int.fromString->Option.getOr(0)
26
+ | _ => 0
27
+ }
28
+
29
+ // Total events across all aggregates. Seeds the event-tap counter at startup so
30
+ // timeline numbering continues across restarts.
31
+ let countAll = async (pool: PgDriver.pool): int =>
32
+ switch await pool->PgDriver.queryOne("SELECT COUNT(*)::bigint AS c FROM event_log", []) {
33
+ | Some(row) => row->Dict.get("c")->Option.map(coerceInt)->Option.getOr(0)
34
+ | None => 0
35
+ }
36
+
37
+ let isUniqueViolation = (exn: exn): bool => {
38
+ let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("")
39
+ // pg surfaces the SQLSTATE on `.code`; the message also carries the constraint.
40
+ msg->String.includes("duplicate key") ||
41
+ msg->String.includes("unique") ||
42
+ msg->String.includes("23505")
43
+ }
44
+
45
+ // Builds the classic runtime op set bound to `pool`. Returns `(name, ops)`; the
46
+ // deploy-time `EventLog_Adapter` wrapper lives in `EventLogStorage_Postgres`.
47
+ let makeOps = (
48
+ ~pool: PgDriver.pool,
49
+ ~name: string,
50
+ ~opts as _,
51
+ ~onAppended=noTracking,
52
+ ): (string, EventLog_Adapter.operations) => {
53
+ let appendTracked = async (~track, seqNr: int, id: string, jsons: array<JSON.t>) => {
54
+ // Empty append is a legitimate no-op (at-least-once retries, idempotent
55
+ // commands), NOT a conflict — return before the guarded insert whose 0-row
56
+ // result would otherwise be read as a conflict.
57
+ if jsons->Array.length == 0 {
58
+ Ok()
59
+ } else {
60
+ try {
61
+ let rows = await pool->PgDriver.query(
62
+ "INSERT INTO event_log(log_name, aggregate_id, seq_nr, payload, msg_id)
63
+ SELECT $1, $2, $3::bigint + (ord - 1), value, value->>'msgId'
64
+ FROM jsonb_array_elements($4::jsonb) WITH ORDINALITY AS t(value, ord)
65
+ WHERE $3::bigint = (SELECT COALESCE(MAX(seq_nr), -1) + 1
66
+ FROM event_log
67
+ WHERE log_name = $1 AND aggregate_id = $2)
68
+ RETURNING global_seq, msg_id",
69
+ [
70
+ JSON.Encode.string(name),
71
+ JSON.Encode.string(id),
72
+ JSON.Encode.int(seqNr),
73
+ JSON.Encode.string(JSON.stringify(JSON.Array(jsons))),
74
+ ],
75
+ )
76
+ if rows->Array.length == 0 {
77
+ // WHERE guard rejected the seq — a genuine OCC conflict (gap or stale).
78
+ Error(EventLog.Conflict)
79
+ } else {
80
+ if track {
81
+ onAppended(
82
+ rows->Array.filterMap(row =>
83
+ switch (row->Dict.get("msg_id"), row->Dict.get("global_seq")) {
84
+ | (Some(JSON.String(msgId)), Some(gseq)) => Some((msgId, coerceInt(gseq)))
85
+ | _ => None
86
+ }
87
+ ),
88
+ )
89
+ }
90
+ Ok()
91
+ }
92
+ } catch {
93
+ | exn =>
94
+ isUniqueViolation(exn)
95
+ ? Error(EventLog.Conflict)
96
+ : Error(
97
+ EventLog.StorageFailure(
98
+ exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("storage error"),
99
+ ),
100
+ )
101
+ }
102
+ }
103
+ }
104
+
105
+ let append: EventLog.append<string, JSON.t> = (seqNr, id, jsons) =>
106
+ appendTracked(~track=true, seqNr, id, jsons)
107
+
108
+ let replayArray = async (id: string, ~fromSeq=0): array<JSON.t> =>
109
+ (await pool->PgDriver.query(
110
+ "SELECT payload FROM event_log
111
+ WHERE log_name = $1 AND aggregate_id = $2 AND seq_nr >= $3::bigint
112
+ ORDER BY seq_nr ASC",
113
+ [JSON.Encode.string(name), JSON.Encode.string(id), JSON.Encode.int(fromSeq)],
114
+ ))->Array.map(decodePayload)
115
+
116
+ let replay: EventLog.replay<string, JSON.t> = id => replayArray(id)
117
+
118
+ let replayStream = (id, ~fromSeq=?) =>
119
+ Effect.promise(() => replayArray(id, ~fromSeq?))
120
+ ->Stream.fromEffect
121
+ ->Stream.flatMap(arr => Stream.fromIterable(arr))
122
+
123
+ let latestSnapshot: EventLog.latestSnapshot<string> = async id =>
124
+ switch await pool->PgDriver.queryOne(
125
+ "SELECT seq_nr, state, schema_hash FROM snapshot WHERE log_name = $1 AND aggregate_id = $2",
126
+ [JSON.Encode.string(name), JSON.Encode.string(id)],
127
+ ) {
128
+ | Some(row) =>
129
+ switch (row->Dict.get("seq_nr"), row->Dict.get("state"), row->Dict.get("schema_hash")) {
130
+ | (Some(seq), Some(state), Some(JSON.String(schemaHash))) =>
131
+ Ok(Some({EventLog.seqNr: coerceInt(seq), state, schemaHash}))
132
+ | _ => Error("snapshot row has unexpected shape")
133
+ }
134
+ | None => Ok(None)
135
+ }
136
+
137
+ let writeSnapshot: EventLog.writeSnapshot<string> = async (id, snap) =>
138
+ try {
139
+ let _ = await pool->PgDriver.query(
140
+ "INSERT INTO snapshot(log_name, aggregate_id, seq_nr, state, schema_hash)
141
+ VALUES ($1, $2, $3::bigint, $4::jsonb, $5)
142
+ ON CONFLICT (log_name, aggregate_id)
143
+ DO UPDATE SET seq_nr = EXCLUDED.seq_nr, state = EXCLUDED.state, schema_hash = EXCLUDED.schema_hash",
144
+ [
145
+ JSON.Encode.string(name),
146
+ JSON.Encode.string(id),
147
+ JSON.Encode.int(snap.EventLog.seqNr),
148
+ JSON.Encode.string(JSON.stringify(snap.state)),
149
+ JSON.Encode.string(snap.schemaHash),
150
+ ],
151
+ )
152
+ Ok()
153
+ } catch {
154
+ | exn =>
155
+ Error(exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("snapshot write error"))
156
+ }
157
+
158
+ let appendStream: EventLog.appendStream<string, JSON.t> = (startingSeqNr, id, stream) =>
159
+ stream
160
+ ->Stream.runCollect
161
+ ->Effect.flatMap(jsons =>
162
+ Effect.promise(() => appendTracked(~track=false, startingSeqNr, id, jsons))->Effect.flatMap(result =>
163
+ switch result {
164
+ | Ok() => Effect.succeed()
165
+ | Error(EventLog.Conflict) => Effect.fail("conflict")
166
+ | Error(StorageFailure(msg)) => Effect.fail(msg)
167
+ }
168
+ )
169
+ )
170
+
171
+ let ops: EventLog_Adapter.operations = {
172
+ append,
173
+ replay,
174
+ replayStream,
175
+ appendStream,
176
+ latestSnapshot,
177
+ writeSnapshot,
178
+ }
179
+ (name, ops)
180
+ }
@@ -0,0 +1,202 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stream from "@reventlessdev/rescript-effect/src/Stream.res.mjs";
4
+ import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
5
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
+ import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
7
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+ import * as Effect from "effect/Effect";
9
+ import * as Stream$1 from "effect/Stream";
10
+ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
11
+ import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
12
+
13
+ function noTracking(param) {
14
+
15
+ }
16
+
17
+ function decodePayload(row) {
18
+ return Stdlib_Option.getOr(row["payload"], null);
19
+ }
20
+
21
+ function coerceInt(v) {
22
+ switch (typeof v) {
23
+ case "string" :
24
+ return Stdlib_Option.getOr(Stdlib_Int.fromString(v, undefined), 0);
25
+ case "number" :
26
+ return v | 0;
27
+ default:
28
+ return 0;
29
+ }
30
+ }
31
+
32
+ async function countAll(pool) {
33
+ let row = await PgDriver$ReventlessPostgres.queryOne(pool, "SELECT COUNT(*)::bigint AS c FROM event_log", []);
34
+ if (row !== undefined) {
35
+ return Stdlib_Option.getOr(Stdlib_Option.map(row["c"], coerceInt), 0);
36
+ } else {
37
+ return 0;
38
+ }
39
+ }
40
+
41
+ function isUniqueViolation(exn) {
42
+ let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "");
43
+ if (msg.includes("duplicate key") || msg.includes("unique")) {
44
+ return true;
45
+ } else {
46
+ return msg.includes("23505");
47
+ }
48
+ }
49
+
50
+ function makeOps(pool, name, param, onAppendedOpt) {
51
+ let onAppended = onAppendedOpt !== undefined ? onAppendedOpt : noTracking;
52
+ let appendTracked = async (track, seqNr, id, jsons) => {
53
+ if (jsons.length === 0) {
54
+ return {
55
+ TAG: "Ok",
56
+ _0: undefined
57
+ };
58
+ }
59
+ try {
60
+ let rows = await PgDriver$ReventlessPostgres.query(pool, "INSERT INTO event_log(log_name, aggregate_id, seq_nr, payload, msg_id)\n SELECT $1, $2, $3::bigint + (ord - 1), value, value->>'msgId'\n FROM jsonb_array_elements($4::jsonb) WITH ORDINALITY AS t(value, ord)\n WHERE $3::bigint = (SELECT COALESCE(MAX(seq_nr), -1) + 1\n FROM event_log\n WHERE log_name = $1 AND aggregate_id = $2)\n RETURNING global_seq, msg_id", [
61
+ name,
62
+ id,
63
+ seqNr,
64
+ JSON.stringify(jsons)
65
+ ]);
66
+ if (rows.length === 0) {
67
+ return {
68
+ TAG: "Error",
69
+ _0: "Conflict"
70
+ };
71
+ } else {
72
+ if (track) {
73
+ onAppended(Stdlib_Array.filterMap(rows, row => {
74
+ let match = row["msg_id"];
75
+ let match$1 = row["global_seq"];
76
+ if (typeof match === "string" && match$1 !== undefined) {
77
+ return [
78
+ match,
79
+ coerceInt(match$1)
80
+ ];
81
+ }
82
+ }));
83
+ }
84
+ return {
85
+ TAG: "Ok",
86
+ _0: undefined
87
+ };
88
+ }
89
+ } catch (raw_exn) {
90
+ let exn = Primitive_exceptions.internalToException(raw_exn);
91
+ if (isUniqueViolation(exn)) {
92
+ return {
93
+ TAG: "Error",
94
+ _0: "Conflict"
95
+ };
96
+ } else {
97
+ return {
98
+ TAG: "Error",
99
+ _0: {
100
+ TAG: "StorageFailure",
101
+ _0: Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "storage error")
102
+ }
103
+ };
104
+ }
105
+ }
106
+ };
107
+ let append = (seqNr, id, jsons) => appendTracked(true, seqNr, id, jsons);
108
+ let replayArray = async (id, fromSeqOpt) => {
109
+ let fromSeq = fromSeqOpt !== undefined ? fromSeqOpt : 0;
110
+ return (await PgDriver$ReventlessPostgres.query(pool, "SELECT payload FROM event_log\n WHERE log_name = $1 AND aggregate_id = $2 AND seq_nr >= $3::bigint\n ORDER BY seq_nr ASC", [
111
+ name,
112
+ id,
113
+ fromSeq
114
+ ])).map(decodePayload);
115
+ };
116
+ let replay = id => replayArray(id, undefined);
117
+ let replayStream = (id, fromSeq) => Stream$1.flatMap(Stream$1.fromEffect(Effect.promise(() => replayArray(id, fromSeq))), arr => Stream$1.fromIterable(arr));
118
+ let latestSnapshot = async id => {
119
+ let row = await PgDriver$ReventlessPostgres.queryOne(pool, "SELECT seq_nr, state, schema_hash FROM snapshot WHERE log_name = $1 AND aggregate_id = $2", [
120
+ name,
121
+ id
122
+ ]);
123
+ if (row === undefined) {
124
+ return {
125
+ TAG: "Ok",
126
+ _0: undefined
127
+ };
128
+ }
129
+ let match = row["seq_nr"];
130
+ let match$1 = row["state"];
131
+ let match$2 = row["schema_hash"];
132
+ if (match !== undefined && match$1 !== undefined && typeof match$2 === "string") {
133
+ return {
134
+ TAG: "Ok",
135
+ _0: {
136
+ seqNr: coerceInt(match),
137
+ state: match$1,
138
+ schemaHash: match$2
139
+ }
140
+ };
141
+ } else {
142
+ return {
143
+ TAG: "Error",
144
+ _0: "snapshot row has unexpected shape"
145
+ };
146
+ }
147
+ };
148
+ let writeSnapshot = async (id, snap) => {
149
+ try {
150
+ await PgDriver$ReventlessPostgres.query(pool, "INSERT INTO snapshot(log_name, aggregate_id, seq_nr, state, schema_hash)\n VALUES ($1, $2, $3::bigint, $4::jsonb, $5)\n ON CONFLICT (log_name, aggregate_id)\n DO UPDATE SET seq_nr = EXCLUDED.seq_nr, state = EXCLUDED.state, schema_hash = EXCLUDED.schema_hash", [
151
+ name,
152
+ id,
153
+ snap.seqNr,
154
+ JSON.stringify(snap.state),
155
+ snap.schemaHash
156
+ ]);
157
+ return {
158
+ TAG: "Ok",
159
+ _0: undefined
160
+ };
161
+ } catch (raw_exn) {
162
+ let exn = Primitive_exceptions.internalToException(raw_exn);
163
+ return {
164
+ TAG: "Error",
165
+ _0: Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "snapshot write error")
166
+ };
167
+ }
168
+ };
169
+ let appendStream = (startingSeqNr, id, stream) => Effect.flatMap(Stream.runCollect(stream), jsons => Effect.flatMap(Effect.promise(() => appendTracked(false, startingSeqNr, id, jsons)), result => {
170
+ if (result.TAG === "Ok") {
171
+ return Effect.succeed();
172
+ }
173
+ let msg = result._0;
174
+ if (typeof msg !== "object") {
175
+ return Effect.fail("conflict");
176
+ } else {
177
+ return Effect.fail(msg._0);
178
+ }
179
+ }));
180
+ let ops = {
181
+ append: append,
182
+ replay: replay,
183
+ replayStream: replayStream,
184
+ appendStream: appendStream,
185
+ latestSnapshot: latestSnapshot,
186
+ writeSnapshot: writeSnapshot
187
+ };
188
+ return [
189
+ name,
190
+ ops
191
+ ];
192
+ }
193
+
194
+ export {
195
+ noTracking,
196
+ decodePayload,
197
+ coerceInt,
198
+ countAll,
199
+ isUniqueViolation,
200
+ makeOps,
201
+ }
202
+ /* Stream Not a pure module */
@@ -18,7 +18,12 @@
18
18
  open ReventlessCore
19
19
  open Reventless
20
20
 
21
- module Dcb = DcbEventLogStorage_Postgres
21
+ // Runtime-pure ops module (no `@pulumi/pulumi`) — this feed is drained by the
22
+ // deployed change-feed relay Lambda, so its cold-start graph must stay
23
+ // Pulumi-free. `_Ops` carries every helper used below (mkBuilder,
24
+ // buildReadWhere, decodeCursor, selectColumns, rowToEvent); the deploy-time
25
+ // DcbEventLogStorage_Postgres only `include`s it and adds the Pulumi adapter.
26
+ module Dcb = DcbEventLogStorage_Postgres_Ops
22
27
 
23
28
  // One page of the feed. `events` are in (transaction_id, position) order;
24
29
  // `cursor` is the checkpoint to persist and to pass as the next `after` (None
@@ -2,15 +2,15 @@
2
2
 
3
3
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
4
  import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
5
- import * as DcbEventLogStorage_Postgres$ReventlessPostgres from "./DcbEventLogStorage_Postgres.res.mjs";
5
+ import * as DcbEventLogStorage_Postgres_Ops$ReventlessPostgres from "./DcbEventLogStorage_Postgres_Ops.res.mjs";
6
6
 
7
7
  async function readBatch(pool, logName, after, limitOpt) {
8
8
  let limit = limitOpt !== undefined ? limitOpt : 500;
9
- let b = DcbEventLogStorage_Postgres$ReventlessPostgres.mkBuilder();
10
- let where = DcbEventLogStorage_Postgres$ReventlessPostgres.buildReadWhere(b, logName, [], Stdlib_Option.flatMap(after, DcbEventLogStorage_Postgres$ReventlessPostgres.decodeCursor), true);
11
- let sql = `SELECT ` + DcbEventLogStorage_Postgres$ReventlessPostgres.selectColumns + ` FROM dcb_event WHERE ` + where + ` ORDER BY transaction_id ASC, position ASC LIMIT ` + limit.toString();
9
+ let b = DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.mkBuilder();
10
+ let where = DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.buildReadWhere(b, logName, [], Stdlib_Option.flatMap(after, DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.decodeCursor), true);
11
+ let sql = `SELECT ` + DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.selectColumns + ` FROM dcb_event WHERE ` + where + ` ORDER BY transaction_id ASC, position ASC LIMIT ` + limit.toString();
12
12
  let rows = await PgDriver$ReventlessPostgres.query(pool, sql, b.params);
13
- let events = rows.map(DcbEventLogStorage_Postgres$ReventlessPostgres.rowToEvent);
13
+ let events = rows.map(DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.rowToEvent);
14
14
  let last = events[events.length - 1 | 0];
15
15
  let cursor = last !== undefined ? last.position : undefined;
16
16
  return {
@@ -31,7 +31,7 @@ async function loadCheckpoint(pool, subscriber) {
31
31
  }
32
32
 
33
33
  async function saveCheckpoint(pool, subscriber, cursor) {
34
- let match = DcbEventLogStorage_Postgres$ReventlessPostgres.decodeCursor(cursor);
34
+ let match = DcbEventLogStorage_Postgres_Ops$ReventlessPostgres.decodeCursor(cursor);
35
35
  if (match !== undefined) {
36
36
  await PgDriver$ReventlessPostgres.query(pool, "INSERT INTO dcb_subscription(subscriber, last_tx, last_position)\n VALUES ($1, $2::xid8, $3::bigint)\n ON CONFLICT (subscriber)\n DO UPDATE SET last_tx = EXCLUDED.last_tx, last_position = EXCLUDED.last_position", [
37
37
  subscriber,