@reventlessdev/reventless-postgres 3.0.0-alpha.100 → 3.0.0-alpha.102
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 +17 -0
- package/lib/bs/.compiler.log +2 -2
- package/lib/bs/compiler-info.json +1 -1
- package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +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 +1 -1
- package/lib/bs/src/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmi +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 +1 -1
- package/lib/bs/src/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmt +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 +1 -1
- package/lib/bs/src/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- 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 +43 -0
- package/lib/bs/src/QueryEnginePostgres.res.mjs +25 -2
- package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
- package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmt +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.res.mjs +4 -4
- package/lib/ocaml/.compiler.log +2 -2
- package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +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 +1 -1
- package/lib/ocaml/DcbEventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/EventLogChangeFeed-ReventlessPostgres.cmt +0 -0
- package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmi +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 +1 -1
- package/lib/ocaml/EventLogStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmi +0 -0
- package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmt +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 +1 -1
- package/lib/ocaml/QueryDbStorage_Postgres_Ops-ReventlessPostgres.cmi +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 +1 -1
- 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 +43 -0
- package/package.json +6 -6
- package/src/DcbEventLogStorage_Postgres.res +1 -1
- package/src/DcbEventLogStorage_Postgres_Ops.res +1 -1
- package/src/EventLogStorage_Postgres.res +1 -1
- package/src/EventLogStorage_Postgres_Ops.res +1 -1
- package/src/QueryDbStorage_Postgres.res +1 -1
- package/src/QueryDbStorage_Postgres_Ops.res +1 -1
- package/src/QueryEnginePostgres.res +43 -0
- package/src/QueryEnginePostgres.res.mjs +25 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.102 (2026-08-16)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-postgres
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 3.0.0-alpha.101 (2026-08-16)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **core:** exclude retired rows from reads a caller may not widen ([662f31a](https://github.com/ReventlessDev/reventless-core/commit/662f31abb717bda5154199d349da6dcf8e2d3e78))
|
|
19
|
+
* **core:** let [@retired](https://github.com/retired) name a lifecycle state, not only a boolean ([6bb346b](https://github.com/ReventlessDev/reventless-core/commit/6bb346b4f6a5f33826fc24537953482a76067177))
|
|
20
|
+
* **core:** mark the state that retires a row, and allow more than one ([cb1461f](https://github.com/ReventlessDev/reventless-core/commit/cb1461f024d3ca3b53fd9c8b010a054e3fcc4555))
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
# 3.0.0-alpha.100 (2026-08-15)
|
|
7
24
|
|
|
8
25
|
**Note:** Version bump only for package @reventlessdev/reventless-postgres
|
package/lib/bs/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1786902407421)
|
|
2
|
+
#Done(1786902412808)
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
"bsc_hash": "75e3a59c95cc953608fd3dd6ea6ed68141bba4414a20a52f114261b8a48385fa",
|
|
5
5
|
"rescript_config_hash": "af2af60a0fa33b8249a96ff2758f36482843126dc4e07b9302842d011e0ad8c6",
|
|
6
6
|
"runtime_path": "/home/runner/work/reventless-core/reventless-core/node_modules/@rescript/runtime",
|
|
7
|
-
"generated_at": "
|
|
7
|
+
"generated_at": "1786902412813"
|
|
8
8
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// existing `DcbEventLogStorage_Postgres.*` reference keeps working) and adds only
|
|
9
9
|
// the deploy-time `DcbEventLog_Adapter` shape, keeping the historic `makeStorage`
|
|
10
10
|
// 3-tuple `(name, ops, adapter)` API unchanged.
|
|
11
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
12
12
|
|
|
13
13
|
open ReventlessCore
|
|
14
14
|
include DcbEventLogStorage_Postgres_Ops
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// would leak into the Lambda import graph and fail resolution on real Lambda. The
|
|
7
7
|
// thin `DcbEventLogStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped adapter for local/deploy consumers.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// real Lambda). This module `include`s that pure module and adds only the
|
|
8
8
|
// deploy-time `EventLog_Adapter` shape (`operations` wrapped in `Pulumi.Output`),
|
|
9
9
|
// keeping the historic `makeStorage` 3-tuple `(name, ops, adapter)` API unchanged.
|
|
10
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
include EventLogStorage_Postgres_Ops
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// in no Lambda — not the layer, not `/var/runtime`). The thin
|
|
8
8
|
// `EventLogStorage_Postgres` wrapper adds the deploy-time `Pulumi.Output`-shaped
|
|
9
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).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// that pure module (so every existing `QueryDbStorage_Postgres.*` reference keeps
|
|
7
7
|
// working) and adds only the deploy-time `Pulumi.Output`-shaped `storage` record
|
|
8
8
|
// and the `Make` provider functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// a deploy-time dep into its ESM import graph (which fails resolution on real
|
|
7
7
|
// Lambda). The thin `QueryDbStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped `storage` record + the `Make` functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -168,6 +168,39 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
168
168
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`
|
|
169
169
|
let jsonTextC = (field: string): string => `${col(field)} COLLATE "C"`
|
|
170
170
|
|
|
171
|
+
// "not retired", as jsonb rather than text. `->` keeps the value typed, so a
|
|
172
|
+
// JSON boolean true is distinguishable from the JSON string "true"; `->>`
|
|
173
|
+
// would render both as 'true' and hide a row the shared spec keeps, since that
|
|
174
|
+
// spec decodes strictly and reads a non-boolean as "no flag". `IS DISTINCT
|
|
175
|
+
// FROM` rather than `<>` so an absent key — NULL — keeps the row instead of
|
|
176
|
+
// making the whole predicate NULL and dropping it.
|
|
177
|
+
//
|
|
178
|
+
// The state form compares against JSON strings instead of `true`, one
|
|
179
|
+
// `IS DISTINCT FROM` per state, ANDed. Not `NOT IN`: that is ordinary
|
|
180
|
+
// equality, so an absent key makes the predicate NULL and drops a row this
|
|
181
|
+
// spec keeps. Same shape and same index behaviour as the single-state form —
|
|
182
|
+
// a handful of equality predicates over an enum-valued attribute cost what one
|
|
183
|
+
// over a boolean does — so the `@index` guidance carries over unchanged.
|
|
184
|
+
//
|
|
185
|
+
// A set naming no states withdraws nothing, so the predicate is vacuously
|
|
186
|
+
// true, matching what `isRetiredValue` answers for it.
|
|
187
|
+
let notRetiredC = (scope: Reventless.OwnerScope.retiredScope): string => {
|
|
188
|
+
let key = scope.field->String.replaceAll("'", "''")
|
|
189
|
+
let distinctFrom = lit => `(item->'${key}') IS DISTINCT FROM ${lit}`
|
|
190
|
+
switch scope.values {
|
|
191
|
+
| None => distinctFrom("'true'::jsonb")
|
|
192
|
+
| Some([]) => "TRUE"
|
|
193
|
+
| Some(states) =>
|
|
194
|
+
// Parenthesised though every caller ANDs these together already: a clause
|
|
195
|
+
// that is safe only because of where it is spliced is a clause that breaks
|
|
196
|
+
// the first time it is spliced somewhere else.
|
|
197
|
+
"(" ++
|
|
198
|
+
states
|
|
199
|
+
->Array.map(state => distinctFrom(`'"${state->String.replaceAll("'", "''")}"'::jsonb`))
|
|
200
|
+
->Array.join(" AND ") ++ ")"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
171
204
|
// Connection-list push-down. Builds `item->>'field'` predicates + keyset
|
|
172
205
|
// WHERE + `ORDER BY … LIMIT pageSize+1` so a page reads only what it returns
|
|
173
206
|
// rather than the whole read model. Reproduces `QueryDbListQuery` semantics
|
|
@@ -184,6 +217,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
184
217
|
~capability: GraphQL_FragmentGenerator.serverCapability,
|
|
185
218
|
~labelField as _,
|
|
186
219
|
~ownerScope: option<(string, string)>=?,
|
|
220
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
187
221
|
): option<JSON.t> => {
|
|
188
222
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
189
223
|
let filterDict =
|
|
@@ -220,6 +254,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
220
254
|
whereParts->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
221
255
|
| None => ()
|
|
222
256
|
}
|
|
257
|
+
switch retiredScope {
|
|
258
|
+
| Some(scope) => whereParts->Array.push(notRetiredC(scope))
|
|
259
|
+
| None => ()
|
|
260
|
+
}
|
|
223
261
|
let valString = v =>
|
|
224
262
|
switch v->JSON.Decode.string {
|
|
225
263
|
| Some(s) => Some(s)
|
|
@@ -320,6 +358,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
320
358
|
~id: string,
|
|
321
359
|
~argsDict: dict<JSON.t>,
|
|
322
360
|
~ownerScope: option<(string, string)>=?,
|
|
361
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
323
362
|
): JSON.t => {
|
|
324
363
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
325
364
|
let filterDict =
|
|
@@ -341,6 +380,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
341
380
|
where->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
342
381
|
| None => ()
|
|
343
382
|
}
|
|
383
|
+
switch retiredScope {
|
|
384
|
+
| Some(scope) => where->Array.push(notRetiredC(scope))
|
|
385
|
+
| None => ()
|
|
386
|
+
}
|
|
344
387
|
fstr("prefix")->Option.forEach(p =>
|
|
345
388
|
where->Array.push(`starts_with(sub_key, ${b->param(JSON.Encode.string(p))})`)
|
|
346
389
|
)
|
|
@@ -169,7 +169,23 @@ function Make(P) {
|
|
|
169
169
|
};
|
|
170
170
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`;
|
|
171
171
|
let jsonTextC = field => col(field) + ` COLLATE "C"`;
|
|
172
|
-
let
|
|
172
|
+
let notRetiredC = scope => {
|
|
173
|
+
let key = scope.field.replaceAll("'", "''");
|
|
174
|
+
let states = scope.values;
|
|
175
|
+
if (states !== undefined) {
|
|
176
|
+
if (states.length !== 0) {
|
|
177
|
+
return "(" + states.map(state => {
|
|
178
|
+
let lit = `'"` + state.replaceAll("'", "''") + `"'::jsonb`;
|
|
179
|
+
return `(item->'` + key + `') IS DISTINCT FROM ` + lit;
|
|
180
|
+
}).join(" AND ") + ")";
|
|
181
|
+
} else {
|
|
182
|
+
return "TRUE";
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
return `(item->'` + key + `') IS DISTINCT FROM ` + "'true'::jsonb";
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
let listPage = async (readModelName, argsDict, capability, param$1, ownerScope, retiredScope) => {
|
|
173
189
|
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
174
190
|
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
175
191
|
let strNonEmpty = k => Stdlib_Option.mapOr(Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string), false, s => s.length > 0);
|
|
@@ -186,6 +202,9 @@ function Make(P) {
|
|
|
186
202
|
if (ownerScope !== undefined) {
|
|
187
203
|
whereParts.push(jsonTextC(ownerScope[0]) + ` = ` + param(b, ownerScope[1]));
|
|
188
204
|
}
|
|
205
|
+
if (retiredScope !== undefined) {
|
|
206
|
+
whereParts.push(notRetiredC(retiredScope));
|
|
207
|
+
}
|
|
189
208
|
let valString = v => {
|
|
190
209
|
let s = Stdlib_JSON.Decode.string(v);
|
|
191
210
|
if (s !== undefined) {
|
|
@@ -234,7 +253,7 @@ function Make(P) {
|
|
|
234
253
|
let cursorValueOf = item => Stdlib_Option.getOr(QueryDbListQuery$ReventlessCore.getFieldString(item, cursorField), QueryDbListQuery$ReventlessCore.getId(item));
|
|
235
254
|
return QueryDbListQuery$ReventlessCore.buildConnection(pageItems, hasMore, false, cursorValueOf);
|
|
236
255
|
};
|
|
237
|
-
let itemsPage = async (readModelName, param$1, id, argsDict, ownerScope) => {
|
|
256
|
+
let itemsPage = async (readModelName, param$1, id, argsDict, ownerScope, retiredScope) => {
|
|
238
257
|
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
239
258
|
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
240
259
|
let fstr = k => Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string);
|
|
@@ -255,6 +274,9 @@ function Make(P) {
|
|
|
255
274
|
if (ownerScope !== undefined) {
|
|
256
275
|
where.push(jsonTextC(ownerScope[0]) + ` = ` + param(b, ownerScope[1]));
|
|
257
276
|
}
|
|
277
|
+
if (retiredScope !== undefined) {
|
|
278
|
+
where.push(notRetiredC(retiredScope));
|
|
279
|
+
}
|
|
258
280
|
Stdlib_Option.forEach(fstr("prefix"), p => {
|
|
259
281
|
where.push(`starts_with(sub_key, ` + param(b, p) + `)`);
|
|
260
282
|
});
|
|
@@ -316,6 +338,7 @@ function Make(P) {
|
|
|
316
338
|
byIds: byIds,
|
|
317
339
|
idExprC: idExprC,
|
|
318
340
|
jsonTextC: jsonTextC,
|
|
341
|
+
notRetiredC: notRetiredC,
|
|
319
342
|
listPage: listPage,
|
|
320
343
|
itemsPage: itemsPage
|
|
321
344
|
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -122,7 +122,7 @@ function orderBy(f, dir) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
function expectedFor(argsDict) {
|
|
125
|
-
return norm(QueryDbListQuery$ReventlessCore.run(seededItems, argsDict, capability, "name", param => {}, undefined));
|
|
125
|
+
return norm(QueryDbListQuery$ReventlessCore.run(seededItems, argsDict, capability, "name", param => {}, undefined, undefined));
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
let url = process.env["PG_URL"];
|
|
@@ -148,7 +148,7 @@ if (url !== undefined) {
|
|
|
148
148
|
});
|
|
149
149
|
let checkPushed = async (label, args) => {
|
|
150
150
|
let argsDict = Object.fromEntries(args);
|
|
151
|
-
let actual = await Eng.listPage(name, argsDict, capability, "name", undefined);
|
|
151
|
+
let actual = await Eng.listPage(name, argsDict, capability, "name", undefined, undefined);
|
|
152
152
|
if (actual !== undefined) {
|
|
153
153
|
globalThis.expect(norm(actual)).toEqual(expectedFor(argsDict));
|
|
154
154
|
} else {
|
|
@@ -156,7 +156,7 @@ if (url !== undefined) {
|
|
|
156
156
|
}
|
|
157
157
|
};
|
|
158
158
|
let checkFallback = async args => {
|
|
159
|
-
let r = await Eng.listPage(name, Object.fromEntries(args), capability, "name", undefined);
|
|
159
|
+
let r = await Eng.listPage(name, Object.fromEntries(args), capability, "name", undefined, undefined);
|
|
160
160
|
globalThis.expect(Stdlib_Option.isSome(r)).toBe(false);
|
|
161
161
|
};
|
|
162
162
|
globalThis.describe("QueryDb list push-down parity (Postgres ≡ QueryDbListQuery spec)", () => {
|
|
@@ -322,7 +322,7 @@ if (url !== undefined) {
|
|
|
322
322
|
});
|
|
323
323
|
let itemSeqs = conn => Stdlib_Array.filterMap(Stdlib_Option.getOr(Stdlib_Option.flatMap(field(conn, "edges"), Stdlib_JSON.Decode.array), []), e => Stdlib_Option.flatMap(field(e, "node"), n => str(n, "seq")));
|
|
324
324
|
let pageInfoBool = (conn, key) => Stdlib_Option.getOr(Stdlib_Option.flatMap(field(Stdlib_Option.getOr(field(conn, "pageInfo"), null), key), Stdlib_JSON.Decode.bool), false);
|
|
325
|
-
let itemsPage = args => Eng.itemsPage(itemsName, "seq", "order-1", Object.fromEntries(args), undefined);
|
|
325
|
+
let itemsPage = args => Eng.itemsPage(itemsName, "seq", "order-1", Object.fromEntries(args), undefined, undefined);
|
|
326
326
|
globalThis.describe("QueryEnginePostgres itemsPage (sub-id keyset)", () => {
|
|
327
327
|
globalThis.test("bare → all lines ASC, no next page", async () => {
|
|
328
328
|
let r = await itemsPage([]);
|
package/lib/ocaml/.compiler.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
#Start(
|
|
2
|
-
#Done(
|
|
1
|
+
#Start(1786902407421)
|
|
2
|
+
#Done(1786902412808)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// existing `DcbEventLogStorage_Postgres.*` reference keeps working) and adds only
|
|
9
9
|
// the deploy-time `DcbEventLog_Adapter` shape, keeping the historic `makeStorage`
|
|
10
10
|
// 3-tuple `(name, ops, adapter)` API unchanged.
|
|
11
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
12
12
|
|
|
13
13
|
open ReventlessCore
|
|
14
14
|
include DcbEventLogStorage_Postgres_Ops
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// would leak into the Lambda import graph and fail resolution on real Lambda. The
|
|
7
7
|
// thin `DcbEventLogStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped adapter for local/deploy consumers.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// real Lambda). This module `include`s that pure module and adds only the
|
|
8
8
|
// deploy-time `EventLog_Adapter` shape (`operations` wrapped in `Pulumi.Output`),
|
|
9
9
|
// keeping the historic `makeStorage` 3-tuple `(name, ops, adapter)` API unchanged.
|
|
10
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
include EventLogStorage_Postgres_Ops
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// in no Lambda — not the layer, not `/var/runtime`). The thin
|
|
8
8
|
// `EventLogStorage_Postgres` wrapper adds the deploy-time `Pulumi.Output`-shaped
|
|
9
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).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// that pure module (so every existing `QueryDbStorage_Postgres.*` reference keeps
|
|
7
7
|
// working) and adds only the deploy-time `Pulumi.Output`-shaped `storage` record
|
|
8
8
|
// and the `Make` provider functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// a deploy-time dep into its ESM import graph (which fails resolution on real
|
|
7
7
|
// Lambda). The thin `QueryDbStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped `storage` record + the `Make` functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -168,6 +168,39 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
168
168
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`
|
|
169
169
|
let jsonTextC = (field: string): string => `${col(field)} COLLATE "C"`
|
|
170
170
|
|
|
171
|
+
// "not retired", as jsonb rather than text. `->` keeps the value typed, so a
|
|
172
|
+
// JSON boolean true is distinguishable from the JSON string "true"; `->>`
|
|
173
|
+
// would render both as 'true' and hide a row the shared spec keeps, since that
|
|
174
|
+
// spec decodes strictly and reads a non-boolean as "no flag". `IS DISTINCT
|
|
175
|
+
// FROM` rather than `<>` so an absent key — NULL — keeps the row instead of
|
|
176
|
+
// making the whole predicate NULL and dropping it.
|
|
177
|
+
//
|
|
178
|
+
// The state form compares against JSON strings instead of `true`, one
|
|
179
|
+
// `IS DISTINCT FROM` per state, ANDed. Not `NOT IN`: that is ordinary
|
|
180
|
+
// equality, so an absent key makes the predicate NULL and drops a row this
|
|
181
|
+
// spec keeps. Same shape and same index behaviour as the single-state form —
|
|
182
|
+
// a handful of equality predicates over an enum-valued attribute cost what one
|
|
183
|
+
// over a boolean does — so the `@index` guidance carries over unchanged.
|
|
184
|
+
//
|
|
185
|
+
// A set naming no states withdraws nothing, so the predicate is vacuously
|
|
186
|
+
// true, matching what `isRetiredValue` answers for it.
|
|
187
|
+
let notRetiredC = (scope: Reventless.OwnerScope.retiredScope): string => {
|
|
188
|
+
let key = scope.field->String.replaceAll("'", "''")
|
|
189
|
+
let distinctFrom = lit => `(item->'${key}') IS DISTINCT FROM ${lit}`
|
|
190
|
+
switch scope.values {
|
|
191
|
+
| None => distinctFrom("'true'::jsonb")
|
|
192
|
+
| Some([]) => "TRUE"
|
|
193
|
+
| Some(states) =>
|
|
194
|
+
// Parenthesised though every caller ANDs these together already: a clause
|
|
195
|
+
// that is safe only because of where it is spliced is a clause that breaks
|
|
196
|
+
// the first time it is spliced somewhere else.
|
|
197
|
+
"(" ++
|
|
198
|
+
states
|
|
199
|
+
->Array.map(state => distinctFrom(`'"${state->String.replaceAll("'", "''")}"'::jsonb`))
|
|
200
|
+
->Array.join(" AND ") ++ ")"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
171
204
|
// Connection-list push-down. Builds `item->>'field'` predicates + keyset
|
|
172
205
|
// WHERE + `ORDER BY … LIMIT pageSize+1` so a page reads only what it returns
|
|
173
206
|
// rather than the whole read model. Reproduces `QueryDbListQuery` semantics
|
|
@@ -184,6 +217,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
184
217
|
~capability: GraphQL_FragmentGenerator.serverCapability,
|
|
185
218
|
~labelField as _,
|
|
186
219
|
~ownerScope: option<(string, string)>=?,
|
|
220
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
187
221
|
): option<JSON.t> => {
|
|
188
222
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
189
223
|
let filterDict =
|
|
@@ -220,6 +254,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
220
254
|
whereParts->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
221
255
|
| None => ()
|
|
222
256
|
}
|
|
257
|
+
switch retiredScope {
|
|
258
|
+
| Some(scope) => whereParts->Array.push(notRetiredC(scope))
|
|
259
|
+
| None => ()
|
|
260
|
+
}
|
|
223
261
|
let valString = v =>
|
|
224
262
|
switch v->JSON.Decode.string {
|
|
225
263
|
| Some(s) => Some(s)
|
|
@@ -320,6 +358,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
320
358
|
~id: string,
|
|
321
359
|
~argsDict: dict<JSON.t>,
|
|
322
360
|
~ownerScope: option<(string, string)>=?,
|
|
361
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
323
362
|
): JSON.t => {
|
|
324
363
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
325
364
|
let filterDict =
|
|
@@ -341,6 +380,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
341
380
|
where->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
342
381
|
| None => ()
|
|
343
382
|
}
|
|
383
|
+
switch retiredScope {
|
|
384
|
+
| Some(scope) => where->Array.push(notRetiredC(scope))
|
|
385
|
+
| None => ()
|
|
386
|
+
}
|
|
344
387
|
fstr("prefix")->Option.forEach(p =>
|
|
345
388
|
where->Array.push(`starts_with(sub_key, ${b->param(JSON.Encode.string(p))})`)
|
|
346
389
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-postgres",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.102",
|
|
4
4
|
"description": "Postgres storage backend for Reventless (classic + DCB event logs, query DB, change feed). Connection-string only — RDS/Aurora, any managed provider, or a local container.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -22,18 +22,18 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"pg": "^8.13.1",
|
|
24
24
|
"sury": "11.0.0-alpha.4",
|
|
25
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.236",
|
|
26
25
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
27
|
-
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
28
26
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
29
|
-
"@reventlessdev/
|
|
30
|
-
"@reventlessdev/reventless-
|
|
27
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
28
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.144",
|
|
29
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.238",
|
|
30
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.116"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/pg": "^8.11.10",
|
|
34
34
|
"rescript": "12.3.0",
|
|
35
35
|
"sury-ppx": "11.0.0-alpha.2",
|
|
36
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
36
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.68"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"rescript": "12.3.0"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// existing `DcbEventLogStorage_Postgres.*` reference keeps working) and adds only
|
|
9
9
|
// the deploy-time `DcbEventLog_Adapter` shape, keeping the historic `makeStorage`
|
|
10
10
|
// 3-tuple `(name, ops, adapter)` API unchanged.
|
|
11
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
12
12
|
|
|
13
13
|
open ReventlessCore
|
|
14
14
|
include DcbEventLogStorage_Postgres_Ops
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// would leak into the Lambda import graph and fail resolution on real Lambda. The
|
|
7
7
|
// thin `DcbEventLogStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped adapter for local/deploy consumers.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// real Lambda). This module `include`s that pure module and adds only the
|
|
8
8
|
// deploy-time `EventLog_Adapter` shape (`operations` wrapped in `Pulumi.Output`),
|
|
9
9
|
// keeping the historic `makeStorage` 3-tuple `(name, ops, adapter)` API unchanged.
|
|
10
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
include EventLogStorage_Postgres_Ops
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// in no Lambda — not the layer, not `/var/runtime`). The thin
|
|
8
8
|
// `EventLogStorage_Postgres` wrapper adds the deploy-time `Pulumi.Output`-shaped
|
|
9
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).
|
|
10
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
11
11
|
|
|
12
12
|
open ReventlessCore
|
|
13
13
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// that pure module (so every existing `QueryDbStorage_Postgres.*` reference keeps
|
|
7
7
|
// working) and adds only the deploy-time `Pulumi.Output`-shaped `storage` record
|
|
8
8
|
// and the `Make` provider functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// a deploy-time dep into its ESM import graph (which fails resolution on real
|
|
7
7
|
// Lambda). The thin `QueryDbStorage_Postgres` wrapper `include`s this and adds the
|
|
8
8
|
// deploy-time `Pulumi.Output`-shaped `storage` record + the `Make` functor.
|
|
9
|
-
// See docs/plans/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
9
|
+
// See docs/plans/done/deployed-lambda-esm-self-containment.md (Rung-3 finding).
|
|
10
10
|
|
|
11
11
|
open ReventlessCore
|
|
12
12
|
open Reventless.ReadModel
|
|
@@ -168,6 +168,39 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
168
168
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`
|
|
169
169
|
let jsonTextC = (field: string): string => `${col(field)} COLLATE "C"`
|
|
170
170
|
|
|
171
|
+
// "not retired", as jsonb rather than text. `->` keeps the value typed, so a
|
|
172
|
+
// JSON boolean true is distinguishable from the JSON string "true"; `->>`
|
|
173
|
+
// would render both as 'true' and hide a row the shared spec keeps, since that
|
|
174
|
+
// spec decodes strictly and reads a non-boolean as "no flag". `IS DISTINCT
|
|
175
|
+
// FROM` rather than `<>` so an absent key — NULL — keeps the row instead of
|
|
176
|
+
// making the whole predicate NULL and dropping it.
|
|
177
|
+
//
|
|
178
|
+
// The state form compares against JSON strings instead of `true`, one
|
|
179
|
+
// `IS DISTINCT FROM` per state, ANDed. Not `NOT IN`: that is ordinary
|
|
180
|
+
// equality, so an absent key makes the predicate NULL and drops a row this
|
|
181
|
+
// spec keeps. Same shape and same index behaviour as the single-state form —
|
|
182
|
+
// a handful of equality predicates over an enum-valued attribute cost what one
|
|
183
|
+
// over a boolean does — so the `@index` guidance carries over unchanged.
|
|
184
|
+
//
|
|
185
|
+
// A set naming no states withdraws nothing, so the predicate is vacuously
|
|
186
|
+
// true, matching what `isRetiredValue` answers for it.
|
|
187
|
+
let notRetiredC = (scope: Reventless.OwnerScope.retiredScope): string => {
|
|
188
|
+
let key = scope.field->String.replaceAll("'", "''")
|
|
189
|
+
let distinctFrom = lit => `(item->'${key}') IS DISTINCT FROM ${lit}`
|
|
190
|
+
switch scope.values {
|
|
191
|
+
| None => distinctFrom("'true'::jsonb")
|
|
192
|
+
| Some([]) => "TRUE"
|
|
193
|
+
| Some(states) =>
|
|
194
|
+
// Parenthesised though every caller ANDs these together already: a clause
|
|
195
|
+
// that is safe only because of where it is spliced is a clause that breaks
|
|
196
|
+
// the first time it is spliced somewhere else.
|
|
197
|
+
"(" ++
|
|
198
|
+
states
|
|
199
|
+
->Array.map(state => distinctFrom(`'"${state->String.replaceAll("'", "''")}"'::jsonb`))
|
|
200
|
+
->Array.join(" AND ") ++ ")"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
171
204
|
// Connection-list push-down. Builds `item->>'field'` predicates + keyset
|
|
172
205
|
// WHERE + `ORDER BY … LIMIT pageSize+1` so a page reads only what it returns
|
|
173
206
|
// rather than the whole read model. Reproduces `QueryDbListQuery` semantics
|
|
@@ -184,6 +217,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
184
217
|
~capability: GraphQL_FragmentGenerator.serverCapability,
|
|
185
218
|
~labelField as _,
|
|
186
219
|
~ownerScope: option<(string, string)>=?,
|
|
220
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
187
221
|
): option<JSON.t> => {
|
|
188
222
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
189
223
|
let filterDict =
|
|
@@ -220,6 +254,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
220
254
|
whereParts->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
221
255
|
| None => ()
|
|
222
256
|
}
|
|
257
|
+
switch retiredScope {
|
|
258
|
+
| Some(scope) => whereParts->Array.push(notRetiredC(scope))
|
|
259
|
+
| None => ()
|
|
260
|
+
}
|
|
223
261
|
let valString = v =>
|
|
224
262
|
switch v->JSON.Decode.string {
|
|
225
263
|
| Some(s) => Some(s)
|
|
@@ -320,6 +358,7 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
320
358
|
~id: string,
|
|
321
359
|
~argsDict: dict<JSON.t>,
|
|
322
360
|
~ownerScope: option<(string, string)>=?,
|
|
361
|
+
~retiredScope: option<Reventless.OwnerScope.retiredScope>=?,
|
|
323
362
|
): JSON.t => {
|
|
324
363
|
let table = QueryDbStorage_Postgres_Ops.tableName(readModelName)
|
|
325
364
|
let filterDict =
|
|
@@ -341,6 +380,10 @@ module Make = (P: {let pool: PgDriver.pool}) => {
|
|
|
341
380
|
where->Array.push(`${jsonTextC(field)} = ${b->param(JSON.Encode.string(required))}`)
|
|
342
381
|
| None => ()
|
|
343
382
|
}
|
|
383
|
+
switch retiredScope {
|
|
384
|
+
| Some(scope) => where->Array.push(notRetiredC(scope))
|
|
385
|
+
| None => ()
|
|
386
|
+
}
|
|
344
387
|
fstr("prefix")->Option.forEach(p =>
|
|
345
388
|
where->Array.push(`starts_with(sub_key, ${b->param(JSON.Encode.string(p))})`)
|
|
346
389
|
)
|
|
@@ -169,7 +169,23 @@ function Make(P) {
|
|
|
169
169
|
};
|
|
170
170
|
let idExprC = `COALESCE(item->>'id', partition_key) COLLATE "C"`;
|
|
171
171
|
let jsonTextC = field => col(field) + ` COLLATE "C"`;
|
|
172
|
-
let
|
|
172
|
+
let notRetiredC = scope => {
|
|
173
|
+
let key = scope.field.replaceAll("'", "''");
|
|
174
|
+
let states = scope.values;
|
|
175
|
+
if (states !== undefined) {
|
|
176
|
+
if (states.length !== 0) {
|
|
177
|
+
return "(" + states.map(state => {
|
|
178
|
+
let lit = `'"` + state.replaceAll("'", "''") + `"'::jsonb`;
|
|
179
|
+
return `(item->'` + key + `') IS DISTINCT FROM ` + lit;
|
|
180
|
+
}).join(" AND ") + ")";
|
|
181
|
+
} else {
|
|
182
|
+
return "TRUE";
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
return `(item->'` + key + `') IS DISTINCT FROM ` + "'true'::jsonb";
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
let listPage = async (readModelName, argsDict, capability, param$1, ownerScope, retiredScope) => {
|
|
173
189
|
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
174
190
|
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
175
191
|
let strNonEmpty = k => Stdlib_Option.mapOr(Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string), false, s => s.length > 0);
|
|
@@ -186,6 +202,9 @@ function Make(P) {
|
|
|
186
202
|
if (ownerScope !== undefined) {
|
|
187
203
|
whereParts.push(jsonTextC(ownerScope[0]) + ` = ` + param(b, ownerScope[1]));
|
|
188
204
|
}
|
|
205
|
+
if (retiredScope !== undefined) {
|
|
206
|
+
whereParts.push(notRetiredC(retiredScope));
|
|
207
|
+
}
|
|
189
208
|
let valString = v => {
|
|
190
209
|
let s = Stdlib_JSON.Decode.string(v);
|
|
191
210
|
if (s !== undefined) {
|
|
@@ -234,7 +253,7 @@ function Make(P) {
|
|
|
234
253
|
let cursorValueOf = item => Stdlib_Option.getOr(QueryDbListQuery$ReventlessCore.getFieldString(item, cursorField), QueryDbListQuery$ReventlessCore.getId(item));
|
|
235
254
|
return QueryDbListQuery$ReventlessCore.buildConnection(pageItems, hasMore, false, cursorValueOf);
|
|
236
255
|
};
|
|
237
|
-
let itemsPage = async (readModelName, param$1, id, argsDict, ownerScope) => {
|
|
256
|
+
let itemsPage = async (readModelName, param$1, id, argsDict, ownerScope, retiredScope) => {
|
|
238
257
|
let table = QueryDbStorage_Postgres_Ops$ReventlessPostgres.tableName(readModelName);
|
|
239
258
|
let filterDict = Stdlib_Option.getOr(Stdlib_Option.flatMap(argsDict["filter"], Stdlib_JSON.Decode.object), {});
|
|
240
259
|
let fstr = k => Stdlib_Option.flatMap(filterDict[k], Stdlib_JSON.Decode.string);
|
|
@@ -255,6 +274,9 @@ function Make(P) {
|
|
|
255
274
|
if (ownerScope !== undefined) {
|
|
256
275
|
where.push(jsonTextC(ownerScope[0]) + ` = ` + param(b, ownerScope[1]));
|
|
257
276
|
}
|
|
277
|
+
if (retiredScope !== undefined) {
|
|
278
|
+
where.push(notRetiredC(retiredScope));
|
|
279
|
+
}
|
|
258
280
|
Stdlib_Option.forEach(fstr("prefix"), p => {
|
|
259
281
|
where.push(`starts_with(sub_key, ` + param(b, p) + `)`);
|
|
260
282
|
});
|
|
@@ -316,6 +338,7 @@ function Make(P) {
|
|
|
316
338
|
byIds: byIds,
|
|
317
339
|
idExprC: idExprC,
|
|
318
340
|
jsonTextC: jsonTextC,
|
|
341
|
+
notRetiredC: notRetiredC,
|
|
319
342
|
listPage: listPage,
|
|
320
343
|
itemsPage: itemsPage
|
|
321
344
|
};
|