@reventlessdev/reventless-postgres 3.0.0-alpha.5 → 3.0.0-alpha.50
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/CHANGELOG.md +361 -0
- package/README.md +83 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/ReventlessPostgres.cmi +0 -0
- package/lib/bs/ReventlessPostgres.cmt +0 -0
- package/lib/bs/ReventlessPostgres.mlmap +3 -2
- package/lib/bs/compiler-info.json +2 -2
- package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres.ast +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres.res +25 -340
- package/lib/bs/src/DcbEventLogStorage_Postgres.res.mjs +32 -348
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.ast +0 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.res +350 -0
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops.res.mjs +380 -0
- package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/EventLogChangeFeed.ast +0 -0
- package/lib/bs/src/EventLogChangeFeed.res +5 -2
- package/lib/bs/src/EventLogChangeFeed.res.mjs +3 -3
- package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
- package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/EventLogStorage_Postgres.ast +0 -0
- package/lib/bs/src/EventLogStorage_Postgres.res +12 -170
- package/lib/bs/src/EventLogStorage_Postgres.res.mjs +20 -186
- package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/EventLogStorage_Postgres_Ops.ast +0 -0
- package/lib/bs/src/EventLogStorage_Postgres_Ops.res +180 -0
- package/lib/bs/src/EventLogStorage_Postgres_Ops.res.mjs +202 -0
- package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/PgChangeFeed.ast +0 -0
- package/lib/bs/src/PgChangeFeed.res +6 -1
- package/lib/bs/src/PgChangeFeed.res.mjs +6 -6
- package/lib/bs/src/PgDriver-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/PgDriver-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/PgDriver-ReventlessPostgres.cmti +0 -0
- package/lib/bs/src/PgDriver.ast +0 -0
- package/lib/bs/src/PgDriver.iast +0 -0
- package/lib/bs/src/PgSchema-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/PgSchema-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/PgSchema.ast +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres.ast +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres.res +10 -233
- package/lib/bs/src/QueryDbStorage_Postgres.res.mjs +25 -204
- package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres_Ops.ast +0 -0
- package/lib/bs/src/QueryDbStorage_Postgres_Ops.res +229 -0
- package/lib/bs/src/QueryDbStorage_Postgres_Ops.res.mjs +222 -0
- package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/QueryEnginePostgres.ast +0 -0
- package/lib/bs/src/QueryEnginePostgres.res +91 -10
- package/lib/bs/src/QueryEnginePostgres.res.mjs +89 -21
- package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
- package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
- package/lib/bs/tests/PostgresIntegrationTest.ast +0 -0
- package/lib/bs/tests/QueryEnginePostgresListPageTest-ReventlessPostgres.cmi +0 -0
- package/lib/bs/tests/QueryEnginePostgresListPageTest-ReventlessPostgres.cmt +0 -0
- package/lib/bs/tests/QueryEnginePostgresListPageTest.ast +0 -0
- package/lib/bs/tests/QueryEnginePostgresListPageTest.res +76 -0
- package/lib/bs/tests/QueryEnginePostgresListPageTest.res.mjs +136 -0
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres.ast +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres.res +25 -340
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops.ast +0 -0
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops.res +350 -0
- package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/EventLogChangeFeed.ast +0 -0
- package/lib/ocaml/EventLogChangeFeed.res +5 -2
- package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/EventLogStorage_Postgres.ast +0 -0
- package/lib/ocaml/EventLogStorage_Postgres.res +12 -170
- package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/EventLogStorage_Postgres_Ops.ast +0 -0
- package/lib/ocaml/EventLogStorage_Postgres_Ops.res +180 -0
- package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/PgChangeFeed.ast +0 -0
- package/lib/ocaml/PgChangeFeed.res +6 -1
- package/lib/ocaml/PgDriver-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/PgDriver-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/PgDriver-ReventlessPostgres.cmti +0 -0
- package/lib/ocaml/PgDriver.ast +0 -0
- package/lib/ocaml/PgDriver.iast +0 -0
- package/lib/ocaml/PgSchema-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/PgSchema-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/PgSchema.ast +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres.ast +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres.res +10 -233
- package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres_Ops.ast +0 -0
- package/lib/ocaml/QueryDbStorage_Postgres_Ops.res +229 -0
- package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/QueryEnginePostgres.ast +0 -0
- package/lib/ocaml/QueryEnginePostgres.res +91 -10
- package/lib/ocaml/QueryEnginePostgresListPageTest.res +76 -0
- package/lib/ocaml/ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/ReventlessPostgres.mlmap +3 -0
- package/package.json +11 -11
- package/rescript.json +2 -1
- package/src/DcbEventLogStorage_Postgres.res +25 -340
- package/src/DcbEventLogStorage_Postgres.res.mjs +32 -348
- package/src/DcbEventLogStorage_Postgres_Ops.res +350 -0
- package/src/DcbEventLogStorage_Postgres_Ops.res.mjs +380 -0
- package/src/EventLogChangeFeed.res +5 -2
- package/src/EventLogChangeFeed.res.mjs +3 -3
- package/src/EventLogStorage_Postgres.res +12 -170
- package/src/EventLogStorage_Postgres.res.mjs +20 -186
- package/src/EventLogStorage_Postgres_Ops.res +180 -0
- package/src/EventLogStorage_Postgres_Ops.res.mjs +202 -0
- package/src/PgChangeFeed.res +6 -1
- package/src/PgChangeFeed.res.mjs +6 -6
- package/src/QueryDbStorage_Postgres.res +10 -233
- package/src/QueryDbStorage_Postgres.res.mjs +25 -204
- package/src/QueryDbStorage_Postgres_Ops.res +229 -0
- package/src/QueryDbStorage_Postgres_Ops.res.mjs +222 -0
- package/src/QueryEnginePostgres.res +91 -10
- package/src/QueryEnginePostgres.res.mjs +89 -21
- package/tests/QueryEnginePostgresListPageTest.res +76 -0
- package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/PostgresIntegrationTest.ast +0 -0
- package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmj +0 -0
- package/lib/ocaml/QueryEnginePostgresListPageTest-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/QueryEnginePostgresListPageTest.ast +0 -0
- package/tests/PostgresIntegrationTest.res.mjs +0 -377
- package/tests/QueryEnginePostgresListPageTest.res.mjs +0 -325
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
-
import * as
|
|
5
|
+
import * as Stdlib_Nullable from "@rescript/runtime/lib/es6/Stdlib_Nullable.js";
|
|
6
6
|
import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
|
|
7
7
|
import * as QueryDbListQuery$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/QueryDbListQuery.res.mjs";
|
|
8
|
-
import * as
|
|
8
|
+
import * as QueryDbStorage_Postgres_Ops$ReventlessPostgres from "./QueryDbStorage_Postgres_Ops.res.mjs";
|
|
9
9
|
|
|
10
10
|
function valueToText(v) {
|
|
11
11
|
switch (v.TAG) {
|
|
@@ -104,25 +104,25 @@ function subIdSql(b, field, cmp, v) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
function decodeRow(withId, row) {
|
|
107
|
-
let item =
|
|
107
|
+
let item = QueryDbStorage_Postgres_Ops$ReventlessPostgres.decodeItem(row);
|
|
108
108
|
if (!withId) {
|
|
109
109
|
return item;
|
|
110
110
|
}
|
|
111
111
|
let match = row["partition_key"];
|
|
112
112
|
let pk = typeof match === "string" ? match : "";
|
|
113
|
-
return
|
|
113
|
+
return QueryDbStorage_Postgres_Ops$ReventlessPostgres.withId(item, pk);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
function Make(P) {
|
|
117
117
|
let query = async (readModelName, key, id, subIdConfig, filterConfigs, ascending, limit) => {
|
|
118
|
-
let table =
|
|
118
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
119
119
|
let keyStr = key !== undefined ? key : valueToText(id);
|
|
120
120
|
let b = {
|
|
121
121
|
params: []
|
|
122
122
|
};
|
|
123
123
|
let where = [
|
|
124
124
|
`partition_key = ` + param(b, keyStr),
|
|
125
|
-
|
|
125
|
+
QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause
|
|
126
126
|
];
|
|
127
127
|
if (subIdConfig !== undefined) {
|
|
128
128
|
where.push(subIdSql(b, subIdConfig[0], subIdConfig[1], subIdConfig[2]));
|
|
@@ -136,11 +136,11 @@ function Make(P) {
|
|
|
136
136
|
return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(false, extra));
|
|
137
137
|
};
|
|
138
138
|
let scan = async (readModelName, filterConfigs, limit) => {
|
|
139
|
-
let table =
|
|
139
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
140
140
|
let b = {
|
|
141
141
|
params: []
|
|
142
142
|
};
|
|
143
|
-
let where = [
|
|
143
|
+
let where = [QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause];
|
|
144
144
|
filterConfigs.forEach(param => {
|
|
145
145
|
where.push(filterSql(b, param[0], param[1], param[2]));
|
|
146
146
|
});
|
|
@@ -148,29 +148,29 @@ function Make(P) {
|
|
|
148
148
|
return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(true, extra));
|
|
149
149
|
};
|
|
150
150
|
let indexLookup = async (readModelName, field, value) => {
|
|
151
|
-
let table =
|
|
151
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
152
152
|
let b = {
|
|
153
153
|
params: []
|
|
154
154
|
};
|
|
155
|
-
let sql = `SELECT partition_key, item FROM ` + table + ` WHERE ` + col(field) + ` = ` + param(b, value) + ` AND ` +
|
|
155
|
+
let sql = `SELECT partition_key, item FROM ` + table + ` WHERE ` + col(field) + ` = ` + param(b, value) + ` AND ` + QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause;
|
|
156
156
|
return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(true, extra));
|
|
157
157
|
};
|
|
158
158
|
let byIds = async (readModelName, ids) => {
|
|
159
159
|
if (ids.length === 0) {
|
|
160
160
|
return [];
|
|
161
161
|
}
|
|
162
|
-
let table =
|
|
162
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
163
163
|
let b = {
|
|
164
164
|
params: []
|
|
165
165
|
};
|
|
166
166
|
let idsJson = ids.map(prim => prim);
|
|
167
|
-
let sql = `SELECT partition_key, item FROM ` + table + ` WHERE partition_key = ANY(` + param(b, idsJson) + `::text[]) AND ` +
|
|
167
|
+
let sql = `SELECT partition_key, item FROM ` + table + ` WHERE partition_key = ANY(` + param(b, idsJson) + `::text[]) AND ` + QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause;
|
|
168
168
|
return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(true, extra));
|
|
169
169
|
};
|
|
170
170
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`;
|
|
171
171
|
let jsonTextC = field => col(field) + ` COLLATE "C"`;
|
|
172
172
|
let listPage = async (readModelName, argsDict, capability, param$1) => {
|
|
173
|
-
let table =
|
|
173
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
174
174
|
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
175
175
|
let strNonEmpty = k => Stdlib_Option.mapOr(Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string), false, s => s.length > 0);
|
|
176
176
|
let hasIds = Stdlib_Option.mapOr(Stdlib_Option.flatMap(filterDict["ids"], Stdlib_JSON.Decode.array), false, a => a.length !== 0);
|
|
@@ -182,7 +182,7 @@ function Make(P) {
|
|
|
182
182
|
let b = {
|
|
183
183
|
params: []
|
|
184
184
|
};
|
|
185
|
-
let whereParts = [
|
|
185
|
+
let whereParts = [QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause];
|
|
186
186
|
let valString = v => {
|
|
187
187
|
let s = Stdlib_JSON.Decode.string(v);
|
|
188
188
|
if (s !== undefined) {
|
|
@@ -231,10 +231,78 @@ function Make(P) {
|
|
|
231
231
|
let cursorValueOf = item => Stdlib_Option.getOr(QueryDbListQuery$ReventlessCore.getFieldString(item, cursorField), QueryDbListQuery$ReventlessCore.getId(item));
|
|
232
232
|
return QueryDbListQuery$ReventlessCore.buildConnection(pageItems, hasMore, false, cursorValueOf);
|
|
233
233
|
};
|
|
234
|
-
let
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
let itemsPage = async (readModelName, param$1, id, argsDict) => {
|
|
235
|
+
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
236
|
+
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
237
|
+
let fstr = k => Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string);
|
|
238
|
+
let orderDesc = Stdlib_Option.mapOr(fstr("order"), false, o => o === "DESC");
|
|
239
|
+
let last = Stdlib_Option.map(Stdlib_Option.flatMap(argsDict["last"], Stdlib_JSON.Decode.float), prim => prim | 0);
|
|
240
|
+
let first = Stdlib_Option.map(Stdlib_Option.flatMap(argsDict["first"], Stdlib_JSON.Decode.float), prim => prim | 0);
|
|
241
|
+
let after = Stdlib_Option.flatMap(argsDict["after"], Stdlib_JSON.Decode.string);
|
|
242
|
+
let before = Stdlib_Option.flatMap(argsDict["before"], Stdlib_JSON.Decode.string);
|
|
243
|
+
let isBackward = Stdlib_Option.isSome(last);
|
|
244
|
+
let sk = `sub_key COLLATE "C"`;
|
|
245
|
+
let b = {
|
|
246
|
+
params: []
|
|
247
|
+
};
|
|
248
|
+
let where = [
|
|
249
|
+
`partition_key = ` + param(b, id),
|
|
250
|
+
QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause
|
|
251
|
+
];
|
|
252
|
+
Stdlib_Option.forEach(fstr("prefix"), p => {
|
|
253
|
+
where.push(`starts_with(sub_key, ` + param(b, p) + `)`);
|
|
254
|
+
});
|
|
255
|
+
Stdlib_Option.forEach(fstr("from"), f => {
|
|
256
|
+
where.push(sk + ` >= ` + param(b, f));
|
|
257
|
+
});
|
|
258
|
+
Stdlib_Option.forEach(fstr("to"), t => {
|
|
259
|
+
where.push(sk + ` <= ` + param(b, t));
|
|
260
|
+
});
|
|
261
|
+
Stdlib_Option.forEach(fstr("eq"), e => {
|
|
262
|
+
where.push(sk + ` = ` + param(b, e));
|
|
263
|
+
});
|
|
264
|
+
if (isBackward) {
|
|
265
|
+
if (before !== undefined) {
|
|
266
|
+
where.push(sk + ` < ` + param(b, QueryDbListQuery$ReventlessCore.decodeCursor(before)));
|
|
267
|
+
}
|
|
268
|
+
} else if (after !== undefined) {
|
|
269
|
+
where.push(sk + ` > ` + param(b, QueryDbListQuery$ReventlessCore.decodeCursor(after)));
|
|
270
|
+
}
|
|
271
|
+
let fetchDesc = isBackward ? !orderDesc : orderDesc;
|
|
272
|
+
let pageSize = Stdlib_Option.getOr(isBackward ? last : first, QueryDbListQuery$ReventlessCore.defaultListPageSize);
|
|
273
|
+
let sql = `SELECT partition_key, sub_key, item FROM ` + table + ` WHERE ` + where.join(" AND ") + ` ORDER BY ` + sk + ` ` + (
|
|
274
|
+
fetchDesc ? "DESC" : "ASC"
|
|
275
|
+
) + ` LIMIT ` + param(b, pageSize + 1 | 0);
|
|
276
|
+
let rows = await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params);
|
|
277
|
+
let hasMore = rows.length > pageSize;
|
|
278
|
+
let taken = rows.slice(0, pageSize);
|
|
279
|
+
let logical = isBackward ? taken.toReversed() : taken;
|
|
280
|
+
let pageItems = logical.map(extra => decodeRow(false, extra));
|
|
281
|
+
let subKeyOf = row => {
|
|
282
|
+
let match = row["sub_key"];
|
|
283
|
+
if (typeof match === "string") {
|
|
284
|
+
return match;
|
|
285
|
+
} else {
|
|
286
|
+
return "";
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
let cursors = logical.map(subKeyOf);
|
|
290
|
+
let edges = pageItems.map((item, i) => ({
|
|
291
|
+
node: item,
|
|
292
|
+
cursor: QueryDbListQuery$ReventlessCore.encodeCursor(cursors[i])
|
|
293
|
+
}));
|
|
294
|
+
let startCursor = Stdlib_Option.map(cursors[0], QueryDbListQuery$ReventlessCore.encodeCursor);
|
|
295
|
+
let endCursor = Stdlib_Option.map(cursors[cursors.length - 1 | 0], QueryDbListQuery$ReventlessCore.encodeCursor);
|
|
296
|
+
return {
|
|
297
|
+
edges: edges,
|
|
298
|
+
pageInfo: {
|
|
299
|
+
hasNextPage: !isBackward && hasMore,
|
|
300
|
+
hasPreviousPage: isBackward && hasMore,
|
|
301
|
+
startCursor: Stdlib_Nullable.fromOption(startCursor),
|
|
302
|
+
endCursor: Stdlib_Nullable.fromOption(endCursor)
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
};
|
|
238
306
|
return {
|
|
239
307
|
query: query,
|
|
240
308
|
scan: scan,
|
|
@@ -243,11 +311,11 @@ function Make(P) {
|
|
|
243
311
|
idExprC: idExprC,
|
|
244
312
|
jsonTextC: jsonTextC,
|
|
245
313
|
listPage: listPage,
|
|
246
|
-
|
|
314
|
+
itemsPage: itemsPage
|
|
247
315
|
};
|
|
248
316
|
}
|
|
249
317
|
|
|
250
|
-
let notExpired =
|
|
318
|
+
let notExpired = QueryDbStorage_Postgres_Ops$ReventlessPostgres.notExpiredClause;
|
|
251
319
|
|
|
252
320
|
export {
|
|
253
321
|
valueToText,
|
|
@@ -260,4 +328,4 @@ export {
|
|
|
260
328
|
decodeRow,
|
|
261
329
|
Make,
|
|
262
330
|
}
|
|
263
|
-
/*
|
|
331
|
+
/* PgDriver-ReventlessPostgres Not a pure module */
|
|
@@ -233,4 +233,80 @@ switch processEnv->Dict.get("PG_URL") {
|
|
|
233
233
|
expect(items->Array.length)->toBe(0)
|
|
234
234
|
})
|
|
235
235
|
})
|
|
236
|
+
|
|
237
|
+
// ── itemsPage (sub-id connection) ─────────────────────────────────────────
|
|
238
|
+
// A sub-id read model: partition "order-1" holds 5 lines keyed by `seq`.
|
|
239
|
+
let itemsName = "itemsparity"
|
|
240
|
+
let mkLine = seq => {
|
|
241
|
+
let o = Dict.make()
|
|
242
|
+
o->Dict.set("id", JSON.Encode.string("order-1"))
|
|
243
|
+
o->Dict.set("seq", JSON.Encode.string(seq))
|
|
244
|
+
JSON.Encode.object(o)
|
|
245
|
+
}
|
|
246
|
+
let seqs = ["a", "b", "c", "d", "e"]
|
|
247
|
+
beforeAllAsync(async () => {
|
|
248
|
+
let ops = QueryDbStorage_Postgres.makeOperations(
|
|
249
|
+
~pool,
|
|
250
|
+
~name=itemsName,
|
|
251
|
+
~indexes=[],
|
|
252
|
+
~subIdField=Some("seq"),
|
|
253
|
+
)
|
|
254
|
+
for i in 0 to seqs->Array.length - 1 {
|
|
255
|
+
let _ = await ops.save("order-1", mkLine(seqs->Array.getUnsafe(i)), QueryDb.Any, None)
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
// Extract node `seq` values in edge order.
|
|
260
|
+
let itemSeqs = (conn: JSON.t) =>
|
|
261
|
+
conn
|
|
262
|
+
->field("edges")
|
|
263
|
+
->Option.flatMap(JSON.Decode.array)
|
|
264
|
+
->Option.getOr([])
|
|
265
|
+
->Array.filterMap(e => e->field("node")->Option.flatMap(n => n->str("seq")))
|
|
266
|
+
|
|
267
|
+
let pageInfoBool = (conn, key) =>
|
|
268
|
+
conn->field("pageInfo")->Option.getOr(JSON.Encode.null)->field(key)->Option.flatMap(JSON.Decode.bool)->Option.getOr(false)
|
|
269
|
+
|
|
270
|
+
let itemsPage = args =>
|
|
271
|
+
Eng.itemsPage(~readModelName=itemsName, ~subIdField="seq", ~id="order-1", ~argsDict=argsOf(args))
|
|
272
|
+
|
|
273
|
+
describe("QueryEnginePostgres itemsPage (sub-id keyset)", () => {
|
|
274
|
+
testPromise("bare → all lines ASC, no next page", async () => {
|
|
275
|
+
let r = await itemsPage([])
|
|
276
|
+
expect(r->itemSeqs)->toEqual(["a", "b", "c", "d", "e"])
|
|
277
|
+
expect(pageInfoBool(r, "hasNextPage"))->toBe(false)
|
|
278
|
+
})
|
|
279
|
+
testPromise("first:2 → [a,b], hasNextPage", async () => {
|
|
280
|
+
let r = await itemsPage([("first", JSON.Encode.int(2))])
|
|
281
|
+
expect(r->itemSeqs)->toEqual(["a", "b"])
|
|
282
|
+
expect(pageInfoBool(r, "hasNextPage"))->toBe(true)
|
|
283
|
+
})
|
|
284
|
+
testPromise("first:2 after b → [c,d]", async () => {
|
|
285
|
+
let r = await itemsPage([("first", JSON.Encode.int(2)), ("after", JSON.Encode.string(cur("b")))])
|
|
286
|
+
expect(r->itemSeqs)->toEqual(["c", "d"])
|
|
287
|
+
})
|
|
288
|
+
testPromise("order DESC → [e..a]", async () => {
|
|
289
|
+
let r = await itemsPage([("filter", filterOf([("order", JSON.Encode.string("DESC"))]))])
|
|
290
|
+
expect(r->itemSeqs)->toEqual(["e", "d", "c", "b", "a"])
|
|
291
|
+
})
|
|
292
|
+
testPromise("filter eq c → [c]", async () => {
|
|
293
|
+
let r = await itemsPage([("filter", filterOf([("eq", JSON.Encode.string("c"))]))])
|
|
294
|
+
expect(r->itemSeqs)->toEqual(["c"])
|
|
295
|
+
})
|
|
296
|
+
testPromise("filter from b to d → [b,c,d]", async () => {
|
|
297
|
+
let r = await itemsPage([
|
|
298
|
+
("filter", filterOf([("from", JSON.Encode.string("b")), ("to", JSON.Encode.string("d"))])),
|
|
299
|
+
])
|
|
300
|
+
expect(r->itemSeqs)->toEqual(["b", "c", "d"])
|
|
301
|
+
})
|
|
302
|
+
testPromise("prefix c → [c]", async () => {
|
|
303
|
+
let r = await itemsPage([("filter", filterOf([("prefix", JSON.Encode.string("c"))]))])
|
|
304
|
+
expect(r->itemSeqs)->toEqual(["c"])
|
|
305
|
+
})
|
|
306
|
+
testPromise("backward last:2 before d → [b,c] (logical ASC)", async () => {
|
|
307
|
+
let r = await itemsPage([("last", JSON.Encode.int(2)), ("before", JSON.Encode.string(cur("d")))])
|
|
308
|
+
expect(r->itemSeqs)->toEqual(["b", "c"])
|
|
309
|
+
expect(pageInfoBool(r, "hasPreviousPage"))->toBe(true)
|
|
310
|
+
})
|
|
311
|
+
})
|
|
236
312
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
5
|
-
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
6
|
-
import * as PgDriver$ReventlessPostgres from "../src/PgDriver.res.mjs";
|
|
7
|
-
import * as PgSchema$ReventlessPostgres from "../src/PgSchema.res.mjs";
|
|
8
|
-
import * as PgChangeFeed$ReventlessPostgres from "../src/PgChangeFeed.res.mjs";
|
|
9
|
-
import * as EventLogChangeFeed$ReventlessPostgres from "../src/EventLogChangeFeed.res.mjs";
|
|
10
|
-
import * as EventLogStorage_Postgres$ReventlessPostgres from "../src/EventLogStorage_Postgres.res.mjs";
|
|
11
|
-
import * as DcbEventLogStorage_Postgres$ReventlessPostgres from "../src/DcbEventLogStorage_Postgres.res.mjs";
|
|
12
|
-
|
|
13
|
-
let opts = {};
|
|
14
|
-
|
|
15
|
-
function jsonObj(pairs) {
|
|
16
|
-
return Object.fromEntries(pairs);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function stored(eventType, tags, data) {
|
|
20
|
-
return {
|
|
21
|
-
eventType: eventType,
|
|
22
|
-
data: data,
|
|
23
|
-
tags: tags,
|
|
24
|
-
meta: Message$ReventlessCore.generateMeta("pg-test", undefined, undefined, undefined, undefined, undefined, undefined, undefined)
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function evJson(msgId, v) {
|
|
29
|
-
return Object.fromEntries([
|
|
30
|
-
[
|
|
31
|
-
"msgId",
|
|
32
|
-
msgId
|
|
33
|
-
],
|
|
34
|
-
[
|
|
35
|
-
"v",
|
|
36
|
-
v
|
|
37
|
-
]
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let url = process.env["PG_URL"];
|
|
42
|
-
|
|
43
|
-
if (url !== undefined) {
|
|
44
|
-
let pool = PgDriver$ReventlessPostgres.makePool({
|
|
45
|
-
connectionString: url
|
|
46
|
-
});
|
|
47
|
-
globalThis.beforeAll(async () => {
|
|
48
|
-
await PgSchema$ReventlessPostgres.ensureSchema(pool);
|
|
49
|
-
return await PgSchema$ReventlessPostgres.truncateAll(pool);
|
|
50
|
-
});
|
|
51
|
-
globalThis.afterAll(() => {
|
|
52
|
-
PgDriver$ReventlessPostgres.endPool(pool);
|
|
53
|
-
});
|
|
54
|
-
globalThis.describe("classic OCC event log", () => {
|
|
55
|
-
globalThis.test("append, replay, and conflict on wrong seq", async () => {
|
|
56
|
-
let match = EventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, "ct-orders", opts, undefined);
|
|
57
|
-
let ops = match[1];
|
|
58
|
-
let r0 = await ops.append(0, "agg-1", [
|
|
59
|
-
evJson("m0", 1),
|
|
60
|
-
evJson("m1", 2)
|
|
61
|
-
]);
|
|
62
|
-
if (r0.TAG === "Ok") {
|
|
63
|
-
globalThis.expect(true).toBe(true);
|
|
64
|
-
} else {
|
|
65
|
-
globalThis.expect("append").toBe("ok");
|
|
66
|
-
}
|
|
67
|
-
let rStale = await ops.append(0, "agg-1", [evJson("m2", 3)]);
|
|
68
|
-
if (rStale.TAG === "Ok") {
|
|
69
|
-
globalThis.expect("stale").toBe("conflict");
|
|
70
|
-
} else {
|
|
71
|
-
let tmp = rStale._0;
|
|
72
|
-
if (typeof tmp !== "object") {
|
|
73
|
-
globalThis.expect(true).toBe(true);
|
|
74
|
-
} else {
|
|
75
|
-
globalThis.expect("stale").toBe("conflict");
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
let rGap = await ops.append(5, "agg-1", [evJson("m3", 4)]);
|
|
79
|
-
if (rGap.TAG === "Ok") {
|
|
80
|
-
globalThis.expect("gap").toBe("conflict");
|
|
81
|
-
} else {
|
|
82
|
-
let tmp$1 = rGap._0;
|
|
83
|
-
if (typeof tmp$1 !== "object") {
|
|
84
|
-
globalThis.expect(true).toBe(true);
|
|
85
|
-
} else {
|
|
86
|
-
globalThis.expect("gap").toBe("conflict");
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
let rNext = await ops.append(2, "agg-1", [evJson("m4", 5)]);
|
|
90
|
-
if (rNext.TAG === "Ok") {
|
|
91
|
-
globalThis.expect(true).toBe(true);
|
|
92
|
-
} else {
|
|
93
|
-
globalThis.expect("next").toBe("ok");
|
|
94
|
-
}
|
|
95
|
-
let evs = await ops.replay("agg-1");
|
|
96
|
-
globalThis.expect(evs.length).toBe(3);
|
|
97
|
-
let rEmpty = await ops.append(3, "agg-1", []);
|
|
98
|
-
if (rEmpty.TAG === "Ok") {
|
|
99
|
-
globalThis.expect(true).toBe(true);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
globalThis.expect("empty").toBe("ok");
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
globalThis.describe("DCB event log", () => {
|
|
106
|
-
let makeLog = name => DcbEventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, name, [], {
|
|
107
|
-
TAG: "Simple",
|
|
108
|
-
_0: {
|
|
109
|
-
key: "k"
|
|
110
|
-
}
|
|
111
|
-
}, undefined, opts, undefined, undefined);
|
|
112
|
-
globalThis.test("append + read round-trips events with tags", async () => {
|
|
113
|
-
let match = makeLog("dcb-rt");
|
|
114
|
-
let ops = match[1];
|
|
115
|
-
let e1 = stored("ItemAdded", [{
|
|
116
|
-
key: "itemId",
|
|
117
|
-
value: "x1"
|
|
118
|
-
}], Object.fromEntries([[
|
|
119
|
-
"n",
|
|
120
|
-
"w"
|
|
121
|
-
]]));
|
|
122
|
-
let r = await ops.append([e1], undefined);
|
|
123
|
-
if (r.TAG === "Ok") {
|
|
124
|
-
globalThis.expect(true).toBe(true);
|
|
125
|
-
} else {
|
|
126
|
-
globalThis.expect(r._0).toBe("ok");
|
|
127
|
-
}
|
|
128
|
-
let read = await ops.read([], undefined);
|
|
129
|
-
globalThis.expect(read.events.length).toBe(1);
|
|
130
|
-
let first = read.events[0];
|
|
131
|
-
globalThis.expect(first.eventType).toBe("ItemAdded");
|
|
132
|
-
globalThis.expect(first.tags[0].key).toBe("itemId");
|
|
133
|
-
globalThis.expect(first.tags[0].value).toBe("x1");
|
|
134
|
-
});
|
|
135
|
-
globalThis.test("conditional append conflicts when the boundary already has an event", async () => {
|
|
136
|
-
let match = makeLog("dcb-cond");
|
|
137
|
-
let ops = match[1];
|
|
138
|
-
let mk = who => stored("Reserved", [{
|
|
139
|
-
key: "seatId",
|
|
140
|
-
value: "s1"
|
|
141
|
-
}], Object.fromEntries([[
|
|
142
|
-
"who",
|
|
143
|
-
who
|
|
144
|
-
]]));
|
|
145
|
-
let r1 = await ops.append([mk("a")], undefined);
|
|
146
|
-
if (r1.TAG === "Ok") {
|
|
147
|
-
globalThis.expect(true).toBe(true);
|
|
148
|
-
} else {
|
|
149
|
-
globalThis.expect("first").toBe("ok");
|
|
150
|
-
}
|
|
151
|
-
let cond_query = [{
|
|
152
|
-
eventTypes: ["Reserved"],
|
|
153
|
-
tags: [{
|
|
154
|
-
key: "seatId",
|
|
155
|
-
value: "s1"
|
|
156
|
-
}]
|
|
157
|
-
}];
|
|
158
|
-
let cond = {
|
|
159
|
-
query: cond_query
|
|
160
|
-
};
|
|
161
|
-
let r2 = await ops.append([mk("b")], cond);
|
|
162
|
-
if (r2.TAG === "Ok") {
|
|
163
|
-
globalThis.expect("second").toBe("conflict");
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
let tmp = r2._0;
|
|
167
|
-
if (typeof tmp !== "object") {
|
|
168
|
-
globalThis.expect(true).toBe(true);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
globalThis.expect("second").toBe("conflict");
|
|
172
|
-
});
|
|
173
|
-
let writeSkew = (strategy, logName) => {
|
|
174
|
-
globalThis.test(`write-skew: exactly one of two concurrent appends wins (` + logName + `)`, async () => {
|
|
175
|
-
let match = DcbEventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, logName, [], {
|
|
176
|
-
TAG: "Simple",
|
|
177
|
-
_0: {
|
|
178
|
-
key: "k"
|
|
179
|
-
}
|
|
180
|
-
}, undefined, opts, strategy, undefined);
|
|
181
|
-
let ops = match[1];
|
|
182
|
-
let cond_query = [{
|
|
183
|
-
eventTypes: ["Reserved"],
|
|
184
|
-
tags: [{
|
|
185
|
-
key: "seatId",
|
|
186
|
-
value: "hot"
|
|
187
|
-
}]
|
|
188
|
-
}];
|
|
189
|
-
let cond = {
|
|
190
|
-
query: cond_query
|
|
191
|
-
};
|
|
192
|
-
let mk = who => stored("Reserved", [{
|
|
193
|
-
key: "seatId",
|
|
194
|
-
value: "hot"
|
|
195
|
-
}], Object.fromEntries([[
|
|
196
|
-
"who",
|
|
197
|
-
who
|
|
198
|
-
]]));
|
|
199
|
-
let p1 = ops.append([mk("a")], cond);
|
|
200
|
-
let p2 = ops.append([mk("b")], cond);
|
|
201
|
-
let r1 = await p1;
|
|
202
|
-
let r2 = await p2;
|
|
203
|
-
let isOk = r => r.TAG === "Ok";
|
|
204
|
-
let isConflict = r => Primitive_object.equal(r, {
|
|
205
|
-
TAG: "Error",
|
|
206
|
-
_0: "Conflict"
|
|
207
|
-
});
|
|
208
|
-
let oks = [
|
|
209
|
-
r1,
|
|
210
|
-
r2
|
|
211
|
-
].filter(isOk).length;
|
|
212
|
-
let conflicts = [
|
|
213
|
-
r1,
|
|
214
|
-
r2
|
|
215
|
-
].filter(isConflict).length;
|
|
216
|
-
globalThis.expect(oks).toBe(1);
|
|
217
|
-
globalThis.expect(conflicts).toBe(1);
|
|
218
|
-
let read = await ops.read([{
|
|
219
|
-
tags: [{
|
|
220
|
-
key: "seatId",
|
|
221
|
-
value: "hot"
|
|
222
|
-
}]
|
|
223
|
-
}], undefined);
|
|
224
|
-
globalThis.expect(read.events.length).toBe(1);
|
|
225
|
-
});
|
|
226
|
-
};
|
|
227
|
-
writeSkew("AdvisoryLocks", "dcb-skew-advisory");
|
|
228
|
-
writeSkew("RowLocks", "dcb-skew-rows");
|
|
229
|
-
globalThis.test("hot tag: N concurrent conditional appends, exactly one wins", async () => {
|
|
230
|
-
let match = makeLog("dcb-hot");
|
|
231
|
-
let ops = match[1];
|
|
232
|
-
let cond_query = [{
|
|
233
|
-
eventTypes: ["Claimed"],
|
|
234
|
-
tags: [{
|
|
235
|
-
key: "prizeId",
|
|
236
|
-
value: "p1"
|
|
237
|
-
}]
|
|
238
|
-
}];
|
|
239
|
-
let cond = {
|
|
240
|
-
query: cond_query
|
|
241
|
-
};
|
|
242
|
-
let promises = Stdlib_Array.make(12, 0).map((param, i) => ops.append([stored("Claimed", [{
|
|
243
|
-
key: "prizeId",
|
|
244
|
-
value: "p1"
|
|
245
|
-
}], Object.fromEntries([[
|
|
246
|
-
"who",
|
|
247
|
-
i
|
|
248
|
-
]]))], cond));
|
|
249
|
-
let results = await Promise.all(promises);
|
|
250
|
-
let oks = results.filter(r => r.TAG === "Ok").length;
|
|
251
|
-
globalThis.expect(oks).toBe(1);
|
|
252
|
-
let read = await ops.read([{
|
|
253
|
-
tags: [{
|
|
254
|
-
key: "prizeId",
|
|
255
|
-
value: "p1"
|
|
256
|
-
}]
|
|
257
|
-
}], undefined);
|
|
258
|
-
globalThis.expect(read.events.length).toBe(1);
|
|
259
|
-
});
|
|
260
|
-
globalThis.test("cursors are monotonic and usable as `after`", async () => {
|
|
261
|
-
let match = makeLog("dcb-cursor");
|
|
262
|
-
let ops = match[1];
|
|
263
|
-
let mk = i => stored("Tick", [{
|
|
264
|
-
key: "streamId",
|
|
265
|
-
value: "c1"
|
|
266
|
-
}], Object.fromEntries([[
|
|
267
|
-
"i",
|
|
268
|
-
i
|
|
269
|
-
]]));
|
|
270
|
-
await ops.append([mk(0)], undefined);
|
|
271
|
-
let pos = await ops.append([mk(1)], undefined);
|
|
272
|
-
let mid;
|
|
273
|
-
mid = pos.TAG === "Ok" ? pos._0 : "";
|
|
274
|
-
await ops.append([mk(2)], undefined);
|
|
275
|
-
let read = await ops.read([{
|
|
276
|
-
tags: [{
|
|
277
|
-
key: "streamId",
|
|
278
|
-
value: "c1"
|
|
279
|
-
}]
|
|
280
|
-
}], mid);
|
|
281
|
-
globalThis.expect(read.events.length).toBe(1);
|
|
282
|
-
globalThis.expect(read.events[0].eventType).toBe("Tick");
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
globalThis.describe("change feed", () => {
|
|
286
|
-
globalThis.test("drains all events and checkpoints", async () => {
|
|
287
|
-
let match = DcbEventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, "feed-log", [], {
|
|
288
|
-
TAG: "Simple",
|
|
289
|
-
_0: {
|
|
290
|
-
key: "k"
|
|
291
|
-
}
|
|
292
|
-
}, undefined, opts, undefined, undefined);
|
|
293
|
-
let mk = i => stored("Fed", [{
|
|
294
|
-
key: "id",
|
|
295
|
-
value: "f"
|
|
296
|
-
}], Object.fromEntries([[
|
|
297
|
-
"i",
|
|
298
|
-
i
|
|
299
|
-
]]));
|
|
300
|
-
await match[1].append([
|
|
301
|
-
mk(0),
|
|
302
|
-
mk(1),
|
|
303
|
-
mk(2)
|
|
304
|
-
], undefined);
|
|
305
|
-
let collected = {
|
|
306
|
-
contents: 0
|
|
307
|
-
};
|
|
308
|
-
let processed = await PgChangeFeed$ReventlessPostgres.drain(pool, "feed-log", "sub-1", undefined, async evs => {
|
|
309
|
-
collected.contents = collected.contents + evs.length | 0;
|
|
310
|
-
});
|
|
311
|
-
globalThis.expect(processed).toBe(3);
|
|
312
|
-
globalThis.expect(collected.contents).toBe(3);
|
|
313
|
-
let again = await PgChangeFeed$ReventlessPostgres.drain(pool, "feed-log", "sub-1", undefined, async param => {});
|
|
314
|
-
globalThis.expect(again).toBe(0);
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
globalThis.describe("classic change feed (event_log, B2.5)", () => {
|
|
318
|
-
globalThis.test("drains classic events in commit order, with fields, then checkpoints", async () => {
|
|
319
|
-
let match = EventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, "cf-orders", opts, undefined);
|
|
320
|
-
let ops = match[1];
|
|
321
|
-
await ops.append(0, "agg-1", [
|
|
322
|
-
evJson("m0", 1),
|
|
323
|
-
evJson("m1", 2)
|
|
324
|
-
]);
|
|
325
|
-
await ops.append(0, "agg-2", [evJson("m2", 3)]);
|
|
326
|
-
let collected = {
|
|
327
|
-
contents: []
|
|
328
|
-
};
|
|
329
|
-
let processed = await EventLogChangeFeed$ReventlessPostgres.drain(pool, "cf-orders", "cf-sub", undefined, async evs => {
|
|
330
|
-
collected.contents = collected.contents.concat(evs);
|
|
331
|
-
});
|
|
332
|
-
globalThis.expect(processed).toBe(3);
|
|
333
|
-
globalThis.expect(collected.contents.length).toBe(3);
|
|
334
|
-
let first = collected.contents[0];
|
|
335
|
-
globalThis.expect(first.aggregateId).toBe("agg-1");
|
|
336
|
-
globalThis.expect(first.seqNr).toBe(0);
|
|
337
|
-
globalThis.expect(first.msgId).toEqual("m0");
|
|
338
|
-
let cursors = collected.contents.map(e => e.cursor);
|
|
339
|
-
let increasing = true;
|
|
340
|
-
for (let i = 1, i_finish = cursors.length; i < i_finish; ++i) {
|
|
341
|
-
if (cursors[i] <= cursors[i - 1 | 0]) {
|
|
342
|
-
increasing = false;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
globalThis.expect(increasing).toBe(true);
|
|
346
|
-
let again = await EventLogChangeFeed$ReventlessPostgres.drain(pool, "cf-orders", "cf-sub", undefined, async param => {});
|
|
347
|
-
globalThis.expect(again).toBe(0);
|
|
348
|
-
});
|
|
349
|
-
globalThis.test("concurrent appends across aggregates: every event drained exactly once", async () => {
|
|
350
|
-
let match = EventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, "cf-concurrent", opts, undefined);
|
|
351
|
-
let ops = match[1];
|
|
352
|
-
let promises = Stdlib_Array.make(20, 0).map((param, i) => ops.append(0, "agg-" + i.toString(), [evJson("m" + i.toString(), i)]));
|
|
353
|
-
await Promise.all(promises);
|
|
354
|
-
let collected = {
|
|
355
|
-
contents: []
|
|
356
|
-
};
|
|
357
|
-
await EventLogChangeFeed$ReventlessPostgres.drain(pool, "cf-concurrent", "cf-conc-sub", undefined, async evs => {
|
|
358
|
-
collected.contents = collected.contents.concat(evs);
|
|
359
|
-
});
|
|
360
|
-
globalThis.expect(collected.contents.length).toBe(20);
|
|
361
|
-
let distinctCursors = new Set(collected.contents.map(e => e.cursor));
|
|
362
|
-
globalThis.expect(distinctCursors.size).toBe(20);
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
} else {
|
|
366
|
-
globalThis.test("Postgres integration (skipped — set PG_URL to run)", () => {
|
|
367
|
-
globalThis.expect(true).toBe(true);
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
export {
|
|
372
|
-
opts,
|
|
373
|
-
jsonObj,
|
|
374
|
-
stored,
|
|
375
|
-
evJson,
|
|
376
|
-
}
|
|
377
|
-
/* url Not a pure module */
|