@reventlessdev/reventless-postgres 3.0.0-alpha.1

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 (128) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +202 -0
  3. package/__mocks__/emptyModule.js +1 -0
  4. package/lib/bs/.compiler.log +2 -0
  5. package/lib/bs/ReventlessPostgres.cmi +0 -0
  6. package/lib/bs/ReventlessPostgres.cmj +0 -0
  7. package/lib/bs/ReventlessPostgres.cmt +0 -0
  8. package/lib/bs/ReventlessPostgres.mlmap +9 -0
  9. package/lib/bs/build.ninja +0 -0
  10. package/lib/bs/compiler-info.json +8 -0
  11. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  12. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  13. package/lib/bs/src/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  14. package/lib/bs/src/DcbEventLogStorage_Postgres.ast +0 -0
  15. package/lib/bs/src/DcbEventLogStorage_Postgres.res +352 -0
  16. package/lib/bs/src/DcbEventLogStorage_Postgres.res.mjs +385 -0
  17. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  18. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  19. package/lib/bs/src/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  20. package/lib/bs/src/EventLogStorage_Postgres.ast +0 -0
  21. package/lib/bs/src/EventLogStorage_Postgres.res +176 -0
  22. package/lib/bs/src/EventLogStorage_Postgres.res.mjs +207 -0
  23. package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmi +0 -0
  24. package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmj +0 -0
  25. package/lib/bs/src/PgChangeFeed-ReventlessPostgres.cmt +0 -0
  26. package/lib/bs/src/PgChangeFeed.ast +0 -0
  27. package/lib/bs/src/PgChangeFeed.res +145 -0
  28. package/lib/bs/src/PgChangeFeed.res.mjs +90 -0
  29. package/lib/bs/src/PgDriver-ReventlessPostgres.cmi +0 -0
  30. package/lib/bs/src/PgDriver-ReventlessPostgres.cmj +0 -0
  31. package/lib/bs/src/PgDriver-ReventlessPostgres.cmt +0 -0
  32. package/lib/bs/src/PgDriver-ReventlessPostgres.cmti +0 -0
  33. package/lib/bs/src/PgDriver.ast +0 -0
  34. package/lib/bs/src/PgDriver.iast +0 -0
  35. package/lib/bs/src/PgDriver.res +111 -0
  36. package/lib/bs/src/PgDriver.res.mjs +85 -0
  37. package/lib/bs/src/PgDriver.resi +68 -0
  38. package/lib/bs/src/PgSchema-ReventlessPostgres.cmi +0 -0
  39. package/lib/bs/src/PgSchema-ReventlessPostgres.cmj +0 -0
  40. package/lib/bs/src/PgSchema-ReventlessPostgres.cmt +0 -0
  41. package/lib/bs/src/PgSchema.ast +0 -0
  42. package/lib/bs/src/PgSchema.res +256 -0
  43. package/lib/bs/src/PgSchema.res.mjs +46 -0
  44. package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
  45. package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmj +0 -0
  46. package/lib/bs/src/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
  47. package/lib/bs/src/QueryDbStorage_Postgres.ast +0 -0
  48. package/lib/bs/src/QueryDbStorage_Postgres.res +244 -0
  49. package/lib/bs/src/QueryDbStorage_Postgres.res.mjs +225 -0
  50. package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
  51. package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmj +0 -0
  52. package/lib/bs/src/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
  53. package/lib/bs/src/QueryEnginePostgres.ast +0 -0
  54. package/lib/bs/src/QueryEnginePostgres.res +127 -0
  55. package/lib/bs/src/QueryEnginePostgres.res.mjs +172 -0
  56. package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
  57. package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmj +0 -0
  58. package/lib/bs/tests/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
  59. package/lib/bs/tests/PostgresIntegrationTest.ast +0 -0
  60. package/lib/bs/tests/PostgresIntegrationTest.res +236 -0
  61. package/lib/bs/tests/PostgresIntegrationTest.res.mjs +328 -0
  62. package/lib/ocaml/.compiler.log +2 -0
  63. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  64. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  65. package/lib/ocaml/DcbEventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  66. package/lib/ocaml/DcbEventLogStorage_Postgres.ast +0 -0
  67. package/lib/ocaml/DcbEventLogStorage_Postgres.res +352 -0
  68. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmi +0 -0
  69. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmj +0 -0
  70. package/lib/ocaml/EventLogStorage_Postgres-ReventlessPostgres.cmt +0 -0
  71. package/lib/ocaml/EventLogStorage_Postgres.ast +0 -0
  72. package/lib/ocaml/EventLogStorage_Postgres.res +176 -0
  73. package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmi +0 -0
  74. package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmj +0 -0
  75. package/lib/ocaml/PgChangeFeed-ReventlessPostgres.cmt +0 -0
  76. package/lib/ocaml/PgChangeFeed.ast +0 -0
  77. package/lib/ocaml/PgChangeFeed.res +145 -0
  78. package/lib/ocaml/PgDriver-ReventlessPostgres.cmi +0 -0
  79. package/lib/ocaml/PgDriver-ReventlessPostgres.cmj +0 -0
  80. package/lib/ocaml/PgDriver-ReventlessPostgres.cmt +0 -0
  81. package/lib/ocaml/PgDriver-ReventlessPostgres.cmti +0 -0
  82. package/lib/ocaml/PgDriver.ast +0 -0
  83. package/lib/ocaml/PgDriver.iast +0 -0
  84. package/lib/ocaml/PgDriver.res +111 -0
  85. package/lib/ocaml/PgDriver.resi +68 -0
  86. package/lib/ocaml/PgSchema-ReventlessPostgres.cmi +0 -0
  87. package/lib/ocaml/PgSchema-ReventlessPostgres.cmj +0 -0
  88. package/lib/ocaml/PgSchema-ReventlessPostgres.cmt +0 -0
  89. package/lib/ocaml/PgSchema.ast +0 -0
  90. package/lib/ocaml/PgSchema.res +256 -0
  91. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmi +0 -0
  92. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmj +0 -0
  93. package/lib/ocaml/PostgresIntegrationTest-ReventlessPostgres.cmt +0 -0
  94. package/lib/ocaml/PostgresIntegrationTest.ast +0 -0
  95. package/lib/ocaml/PostgresIntegrationTest.res +236 -0
  96. package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmi +0 -0
  97. package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmj +0 -0
  98. package/lib/ocaml/QueryDbStorage_Postgres-ReventlessPostgres.cmt +0 -0
  99. package/lib/ocaml/QueryDbStorage_Postgres.ast +0 -0
  100. package/lib/ocaml/QueryDbStorage_Postgres.res +244 -0
  101. package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmi +0 -0
  102. package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmj +0 -0
  103. package/lib/ocaml/QueryEnginePostgres-ReventlessPostgres.cmt +0 -0
  104. package/lib/ocaml/QueryEnginePostgres.ast +0 -0
  105. package/lib/ocaml/QueryEnginePostgres.res +127 -0
  106. package/lib/ocaml/ReventlessPostgres.cmi +0 -0
  107. package/lib/ocaml/ReventlessPostgres.cmj +0 -0
  108. package/lib/ocaml/ReventlessPostgres.cmt +0 -0
  109. package/lib/ocaml/ReventlessPostgres.mlmap +9 -0
  110. package/package.json +56 -0
  111. package/rescript.json +36 -0
  112. package/src/DcbEventLogStorage_Postgres.res +352 -0
  113. package/src/DcbEventLogStorage_Postgres.res.mjs +385 -0
  114. package/src/EventLogStorage_Postgres.res +176 -0
  115. package/src/EventLogStorage_Postgres.res.mjs +207 -0
  116. package/src/PgChangeFeed.res +145 -0
  117. package/src/PgChangeFeed.res.mjs +90 -0
  118. package/src/PgDriver.res +111 -0
  119. package/src/PgDriver.res.mjs +85 -0
  120. package/src/PgDriver.resi +68 -0
  121. package/src/PgSchema.res +256 -0
  122. package/src/PgSchema.res.mjs +46 -0
  123. package/src/QueryDbStorage_Postgres.res +244 -0
  124. package/src/QueryDbStorage_Postgres.res.mjs +225 -0
  125. package/src/QueryEnginePostgres.res +127 -0
  126. package/src/QueryEnginePostgres.res.mjs +172 -0
  127. package/tests/PostgresIntegrationTest.res +236 -0
  128. package/tests/PostgresIntegrationTest.res.mjs +328 -0
@@ -0,0 +1,225 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Stream from "effect/Stream";
7
+ import * as Pulumi from "@pulumi/pulumi";
8
+ import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
9
+
10
+ function tableName(name) {
11
+ return "qdb_" + name.replaceAll("-", "_");
12
+ }
13
+
14
+ function sanitizeIdent(s) {
15
+ return s.replace(/[^A-Za-z0-9_]/g, "_");
16
+ }
17
+
18
+ let notExpiredClause = "(expires_at IS NULL OR expires_at > extract(epoch from now()))";
19
+
20
+ function jsonField(field) {
21
+ return `(item->>'` + field.replaceAll("'", "''") + `')`;
22
+ }
23
+
24
+ function compositeExpr(fields, sep) {
25
+ let escapedSep = sep.replaceAll("'", "''");
26
+ return fields.map(jsonField).join(` || '` + escapedSep + `' || `);
27
+ }
28
+
29
+ function indexExpressions(idx) {
30
+ let fields = idx.pkFields;
31
+ let pkExpr;
32
+ let exit = 0;
33
+ if (fields !== undefined && fields.length !== 0) {
34
+ pkExpr = compositeExpr(fields, Stdlib_Option.getOr(idx.pkSep, "/"));
35
+ } else {
36
+ exit = 1;
37
+ }
38
+ if (exit === 1) {
39
+ let field = idx.idField;
40
+ pkExpr = field !== undefined ? jsonField(field) : jsonField(idx.index);
41
+ }
42
+ let fields$1 = idx.skFields;
43
+ let skExpr;
44
+ let exit$1 = 0;
45
+ if (fields$1 !== undefined && fields$1.length !== 0) {
46
+ skExpr = compositeExpr(fields$1, Stdlib_Option.getOr(idx.skSep, "/"));
47
+ } else {
48
+ exit$1 = 1;
49
+ }
50
+ if (exit$1 === 1) {
51
+ let field$1 = idx.subIdField;
52
+ skExpr = field$1 !== undefined ? jsonField(field$1) : undefined;
53
+ }
54
+ return [
55
+ pkExpr,
56
+ skExpr
57
+ ];
58
+ }
59
+
60
+ async function ensureTable(pool, table) {
61
+ return await PgDriver$ReventlessPostgres.exec(pool, `CREATE TABLE IF NOT EXISTS ` + table + ` (partition_key text NOT NULL, sub_key text NOT NULL DEFAULT '', item jsonb NOT NULL, expires_at double precision, PRIMARY KEY (partition_key, sub_key))`);
62
+ }
63
+
64
+ async function ensureIndexes(pool, table, indexes) {
65
+ for (let i = 0, i_finish = indexes.length; i < i_finish; ++i) {
66
+ let idx = indexes[i];
67
+ let match = indexExpressions(idx);
68
+ let skExprOpt = match[1];
69
+ let pkExpr = match[0];
70
+ let indexName = `idx_` + table + `_` + sanitizeIdent(idx.index);
71
+ let cols = skExprOpt !== undefined ? pkExpr + `, ` + skExprOpt : pkExpr;
72
+ await PgDriver$ReventlessPostgres.exec(pool, `CREATE INDEX IF NOT EXISTS ` + indexName + ` ON ` + table + ` (` + cols + `)`);
73
+ }
74
+ }
75
+
76
+ function decodeItem(row) {
77
+ return Stdlib_Option.getOr(row["item"], null);
78
+ }
79
+
80
+ function computeSubKey(item, subIdField) {
81
+ if (subIdField === undefined) {
82
+ return "";
83
+ }
84
+ let match = Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(item), o => o[subIdField]);
85
+ if (typeof match === "string") {
86
+ return match;
87
+ } else {
88
+ return "";
89
+ }
90
+ }
91
+
92
+ function withId(item, partitionKey) {
93
+ let obj = Stdlib_JSON.Decode.object(item);
94
+ if (obj === undefined) {
95
+ return item;
96
+ }
97
+ if (!Stdlib_Option.isNone(obj["id"])) {
98
+ return item;
99
+ }
100
+ let copy = Object.assign({}, obj);
101
+ copy["id"] = partitionKey;
102
+ return copy;
103
+ }
104
+
105
+ function makeStorage(pool, name, indexes, subIdField) {
106
+ let table = tableName(name);
107
+ let ready = ensureTable(pool, table).then(() => ensureIndexes(pool, table, indexes));
108
+ let rowsFor = async id => {
109
+ await ready;
110
+ return (await PgDriver$ReventlessPostgres.query(pool, `SELECT item FROM ` + table + ` WHERE partition_key = $1 AND ` + notExpiredClause + ` ORDER BY sub_key ASC`, [id])).map(decodeItem);
111
+ };
112
+ let saveOne = async (id, state, ttl) => {
113
+ await ready;
114
+ let subKey = computeSubKey(state, subIdField);
115
+ let expiresAt = ttl !== undefined ? ttl : null;
116
+ await PgDriver$ReventlessPostgres.query(pool, `INSERT INTO ` + table + `(partition_key, sub_key, item, expires_at)
117
+ VALUES ($1, $2, $3::jsonb, $4)
118
+ ON CONFLICT (partition_key, sub_key)
119
+ DO UPDATE SET item = EXCLUDED.item, expires_at = EXCLUDED.expires_at`, [
120
+ id,
121
+ subKey,
122
+ JSON.stringify(state),
123
+ expiresAt
124
+ ]);
125
+ };
126
+ let load = async id => ({
127
+ TAG: "Ok",
128
+ _0: await rowsFor(id)
129
+ });
130
+ let loadStream = id => Stream.flatMap(Stream.fromEffect(Effect.promise(() => rowsFor(id))), arr => Stream.fromIterable(arr));
131
+ let save = async (id, state, _saveMode, ttl) => {
132
+ await saveOne(id, state, ttl);
133
+ return {
134
+ TAG: "Ok",
135
+ _0: undefined
136
+ };
137
+ };
138
+ let saveBatch = async batch => {
139
+ for (let i = 0, i_finish = batch.length; i < i_finish; ++i) {
140
+ let match = batch[i];
141
+ await saveOne(match[0], match[1], match[2]);
142
+ }
143
+ return {
144
+ TAG: "Ok",
145
+ _0: undefined
146
+ };
147
+ };
148
+ let count = async (id, fieldName, inc) => {
149
+ await ready;
150
+ let existing = Stdlib_Option.flatMap((await rowsFor(id))[0], Stdlib_JSON.Decode.object);
151
+ let current = Stdlib_Option.mapOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(existing, o => o[fieldName]), Stdlib_JSON.Decode.float), 0, prim => prim | 0);
152
+ let next = current + inc | 0;
153
+ let obj = existing !== undefined ? Object.assign({}, existing) : ({});
154
+ obj["id"] = id;
155
+ obj[fieldName] = next;
156
+ await saveOne(id, obj, undefined);
157
+ return {
158
+ TAG: "Ok",
159
+ _0: next
160
+ };
161
+ };
162
+ let $$delete = async (id, subIdOpt) => {
163
+ await ready;
164
+ if (subIdOpt !== undefined) {
165
+ await PgDriver$ReventlessPostgres.query(pool, `DELETE FROM ` + table + ` WHERE partition_key = $1 AND sub_key = $2`, [
166
+ id,
167
+ subIdOpt[1]
168
+ ]);
169
+ } else {
170
+ await PgDriver$ReventlessPostgres.query(pool, `DELETE FROM ` + table + ` WHERE partition_key = $1`, [id]);
171
+ }
172
+ return {
173
+ TAG: "Ok",
174
+ _0: undefined
175
+ };
176
+ };
177
+ let deleteBatch = async ids => {
178
+ for (let i = 0, i_finish = ids.length; i < i_finish; ++i) {
179
+ let match = ids[i];
180
+ await $$delete(match[0], match[1]);
181
+ }
182
+ return {
183
+ TAG: "Ok",
184
+ _0: undefined
185
+ };
186
+ };
187
+ let ops = {
188
+ load: load,
189
+ loadStream: loadStream,
190
+ save: save,
191
+ saveBatch: saveBatch,
192
+ count: count,
193
+ delete: $$delete,
194
+ deleteBatch: deleteBatch
195
+ };
196
+ return {
197
+ resources: [],
198
+ dataSourceName: Pulumi.output(""),
199
+ operations: Pulumi.output(ops)
200
+ };
201
+ }
202
+
203
+ function Make(P) {
204
+ let make = (name, indexes, subIdField, param, param$1, param$2, param$3) => makeStorage(P.pool, name, indexes, subIdField);
205
+ return {
206
+ make: make
207
+ };
208
+ }
209
+
210
+ export {
211
+ tableName,
212
+ sanitizeIdent,
213
+ notExpiredClause,
214
+ jsonField,
215
+ compositeExpr,
216
+ indexExpressions,
217
+ ensureTable,
218
+ ensureIndexes,
219
+ decodeItem,
220
+ computeSubKey,
221
+ withId,
222
+ makeStorage,
223
+ Make,
224
+ }
225
+ /* effect/Effect Not a pure module */
@@ -0,0 +1,127 @@
1
+ // Postgres QueryEngine — compiles the QueryEngine query/scan AST to SQL over the
2
+ // `qdb_<name>` JSONB tables (QueryDbStorage_Postgres). The reventless-local
3
+ // LocalQueryEngine reads from in-process bus registries and ignores filters; this
4
+ // one pushes filters down to SQL, the way a production engine must.
5
+
6
+ open ReventlessCore
7
+ open Reventless
8
+
9
+ let valueToText = (v: QueryEngine.value): string =>
10
+ switch v {
11
+ | QueryEngine.String(s) => s
12
+ | QueryEngine.Int(i) => i->Int.toString
13
+ | QueryEngine.Bool(b) => b ? "true" : "false"
14
+ }
15
+
16
+ let isNumeric = (v: QueryEngine.value): bool =>
17
+ switch v {
18
+ | QueryEngine.Int(_) => true
19
+ | _ => false
20
+ }
21
+
22
+ type paramBuilder = {mutable params: array<JSON.t>}
23
+ let param = (b: paramBuilder, v: JSON.t): string => {
24
+ b.params->Array.push(v)
25
+ "$" ++ Int.toString(b.params->Array.length)
26
+ }
27
+
28
+ let col = (field: string): string => `(item->>'${field->String.replaceAll("'", "''")}')`
29
+
30
+ // One Filter.config → SQL predicate, appending any bound params.
31
+ let filterSql = (b: paramBuilder, field: string, cmp: QueryEngine.Filter.comparator, v: QueryEngine.value): string => {
32
+ let c = col(field)
33
+ let bind = () => b->param(JSON.Encode.string(valueToText(v)))
34
+ let cmpSql = op =>
35
+ isNumeric(v) ? `${c}::numeric ${op} ${bind()}::numeric` : `${c} ${op} ${bind()}`
36
+ switch cmp {
37
+ | QueryEngine.Filter.Equal => cmpSql("=")
38
+ | Unequal => cmpSql("<>")
39
+ | LessOrEqual => cmpSql("<=")
40
+ | Less => cmpSql("<")
41
+ | GreaterOrEqual => cmpSql(">=")
42
+ | Greater => cmpSql(">")
43
+ | Exists => `(item ? '${field->String.replaceAll("'", "''")}')`
44
+ | NotExists => `NOT (item ? '${field->String.replaceAll("'", "''")}')`
45
+ | Contains => `strpos(${c}, ${bind()}) > 0`
46
+ | NotContains => `(${c} IS NULL OR strpos(${c}, ${bind()}) = 0)`
47
+ | BeginsWith => `starts_with(${c}, ${bind()})`
48
+ }
49
+ }
50
+
51
+ let subIdSql = (b: paramBuilder, field: string, cmp: QueryEngine.SubId.comparator, v: QueryEngine.value): string => {
52
+ let c = col(field)
53
+ let bind = () => b->param(JSON.Encode.string(valueToText(v)))
54
+ let cmpSql = op => isNumeric(v) ? `${c}::numeric ${op} ${bind()}::numeric` : `${c} ${op} ${bind()}`
55
+ switch cmp {
56
+ | QueryEngine.SubId.Equal => cmpSql("=")
57
+ | Unequal => cmpSql("<>")
58
+ | LessOrEqual => cmpSql("<=")
59
+ | Less => cmpSql("<")
60
+ | GreaterOrEqual => cmpSql(">=")
61
+ | Greater => cmpSql(">")
62
+ | BeginsWith => `starts_with(${c}, ${bind()})`
63
+ }
64
+ }
65
+
66
+ let notExpired = QueryDbStorage_Postgres.notExpiredClause
67
+
68
+ // Add `id` (from partition_key) when absent — matches allRows/scan in the SQLite
69
+ // engine; partition-key queries return items as stored.
70
+ let decodeRow = (~withId, row: dict<JSON.t>): JSON.t => {
71
+ let item = QueryDbStorage_Postgres.decodeItem(row)
72
+ if withId {
73
+ let pk = switch row->Dict.get("partition_key") {
74
+ | Some(JSON.String(s)) => s
75
+ | _ => ""
76
+ }
77
+ QueryDbStorage_Postgres.withId(item, pk)
78
+ } else {
79
+ item
80
+ }
81
+ }
82
+
83
+ module Make = (P: {let pool: PgDriver.pool}) => {
84
+ let query = async (
85
+ ~readModelName,
86
+ ~key=?,
87
+ ~id: QueryEngine.value,
88
+ ~subIdConfig=?,
89
+ ~filterConfigs=?,
90
+ ~ascending=?,
91
+ ~limit=?,
92
+ ): array<JSON.t> => {
93
+ let table = QueryDbStorage_Postgres.tableName(readModelName)
94
+ let keyStr = switch key {
95
+ | Some(k) => k
96
+ | None => valueToText(id)
97
+ }
98
+ let b = {params: []}
99
+ let where = [`partition_key = ${b->param(JSON.Encode.string(keyStr))}`, notExpired]
100
+ switch subIdConfig {
101
+ | Some((field, cmp, v)) => where->Array.push(subIdSql(b, field, cmp, v))
102
+ | None => ()
103
+ }
104
+ filterConfigs
105
+ ->Option.getOr([])
106
+ ->Array.forEach(((field, cmp, v)) => where->Array.push(filterSql(b, field, cmp, v)))
107
+ let dir = ascending->Option.getOr(true) ? "ASC" : "DESC"
108
+ let limitClause = switch limit {
109
+ | Some(n) => ` LIMIT ${b->param(JSON.Encode.int(n))}`
110
+ | None => ""
111
+ }
112
+ let sql = `SELECT partition_key, item FROM ${table} WHERE ${where->Array.join(" AND ")} ORDER BY sub_key ${dir}${limitClause}`
113
+ (await P.pool->PgDriver.query(sql, b.params))->Array.map(decodeRow(~withId=false, ...))
114
+ }
115
+
116
+ let scan = async (~readModelName, ~filterConfigs, ~limit): array<JSON.t> => {
117
+ let table = QueryDbStorage_Postgres.tableName(readModelName)
118
+ let b = {params: []}
119
+ let where = [notExpired]
120
+ filterConfigs->Array.forEach(((field, cmp, v)) => where->Array.push(filterSql(b, field, cmp, v)))
121
+ let sql = `SELECT partition_key, item FROM ${table} WHERE ${where->Array.join(" AND ")} ORDER BY partition_key, sub_key LIMIT ${b->param(JSON.Encode.int(limit))}`
122
+ (await P.pool->PgDriver.query(sql, b.params))->Array.map(decodeRow(~withId=true, ...))
123
+ }
124
+
125
+ let make: QueryDb_Adapter.queryEngineMaker = _allQueryDbs =>
126
+ Pulumi.Output.make({QueryEngine.scan, query})
127
+ }
@@ -0,0 +1,172 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
+ import * as Pulumi from "@pulumi/pulumi";
5
+ import * as PgDriver$ReventlessPostgres from "./PgDriver.res.mjs";
6
+ import * as QueryDbStorage_Postgres$ReventlessPostgres from "./QueryDbStorage_Postgres.res.mjs";
7
+
8
+ function valueToText(v) {
9
+ switch (v.TAG) {
10
+ case "String" :
11
+ return v._0;
12
+ case "Int" :
13
+ return v._0.toString();
14
+ case "Bool" :
15
+ if (v._0) {
16
+ return "true";
17
+ } else {
18
+ return "false";
19
+ }
20
+ }
21
+ }
22
+
23
+ function isNumeric(v) {
24
+ switch (v.TAG) {
25
+ case "Int" :
26
+ return true;
27
+ case "String" :
28
+ case "Bool" :
29
+ return false;
30
+ }
31
+ }
32
+
33
+ function param(b, v) {
34
+ b.params.push(v);
35
+ return "$" + b.params.length.toString();
36
+ }
37
+
38
+ function col(field) {
39
+ return `(item->>'` + field.replaceAll("'", "''") + `')`;
40
+ }
41
+
42
+ function filterSql(b, field, cmp, v) {
43
+ let c = col(field);
44
+ let cmpSql = op => {
45
+ if (isNumeric(v)) {
46
+ return c + `::numeric ` + op + ` ` + param(b, valueToText(v)) + `::numeric`;
47
+ } else {
48
+ return c + ` ` + op + ` ` + param(b, valueToText(v));
49
+ }
50
+ };
51
+ switch (cmp) {
52
+ case "Equal" :
53
+ return cmpSql("=");
54
+ case "Unequal" :
55
+ return cmpSql("<>");
56
+ case "LessOrEqual" :
57
+ return cmpSql("<=");
58
+ case "Less" :
59
+ return cmpSql("<");
60
+ case "GreaterOrEqual" :
61
+ return cmpSql(">=");
62
+ case "Greater" :
63
+ return cmpSql(">");
64
+ case "Exists" :
65
+ return `(item ? '` + field.replaceAll("'", "''") + `')`;
66
+ case "NotExists" :
67
+ return `NOT (item ? '` + field.replaceAll("'", "''") + `')`;
68
+ case "Contains" :
69
+ return `strpos(` + c + `, ` + param(b, valueToText(v)) + `) > 0`;
70
+ case "NotContains" :
71
+ return `(` + c + ` IS NULL OR strpos(` + c + `, ` + param(b, valueToText(v)) + `) = 0)`;
72
+ case "BeginsWith" :
73
+ return `starts_with(` + c + `, ` + param(b, valueToText(v)) + `)`;
74
+ }
75
+ }
76
+
77
+ function subIdSql(b, field, cmp, v) {
78
+ let c = col(field);
79
+ let cmpSql = op => {
80
+ if (isNumeric(v)) {
81
+ return c + `::numeric ` + op + ` ` + param(b, valueToText(v)) + `::numeric`;
82
+ } else {
83
+ return c + ` ` + op + ` ` + param(b, valueToText(v));
84
+ }
85
+ };
86
+ switch (cmp) {
87
+ case "Equal" :
88
+ return cmpSql("=");
89
+ case "Unequal" :
90
+ return cmpSql("<>");
91
+ case "LessOrEqual" :
92
+ return cmpSql("<=");
93
+ case "Less" :
94
+ return cmpSql("<");
95
+ case "GreaterOrEqual" :
96
+ return cmpSql(">=");
97
+ case "Greater" :
98
+ return cmpSql(">");
99
+ case "BeginsWith" :
100
+ return `starts_with(` + c + `, ` + param(b, valueToText(v)) + `)`;
101
+ }
102
+ }
103
+
104
+ function decodeRow(withId, row) {
105
+ let item = QueryDbStorage_Postgres$ReventlessPostgres.decodeItem(row);
106
+ if (!withId) {
107
+ return item;
108
+ }
109
+ let match = row["partition_key"];
110
+ let pk = typeof match === "string" ? match : "";
111
+ return QueryDbStorage_Postgres$ReventlessPostgres.withId(item, pk);
112
+ }
113
+
114
+ function Make(P) {
115
+ let query = async (readModelName, key, id, subIdConfig, filterConfigs, ascending, limit) => {
116
+ let table = QueryDbStorage_Postgres$ReventlessPostgres.tableName(readModelName);
117
+ let keyStr = key !== undefined ? key : valueToText(id);
118
+ let b = {
119
+ params: []
120
+ };
121
+ let where = [
122
+ `partition_key = ` + param(b, keyStr),
123
+ QueryDbStorage_Postgres$ReventlessPostgres.notExpiredClause
124
+ ];
125
+ if (subIdConfig !== undefined) {
126
+ where.push(subIdSql(b, subIdConfig[0], subIdConfig[1], subIdConfig[2]));
127
+ }
128
+ Stdlib_Option.getOr(filterConfigs, []).forEach(param => {
129
+ where.push(filterSql(b, param[0], param[1], param[2]));
130
+ });
131
+ let dir = Stdlib_Option.getOr(ascending, true) ? "ASC" : "DESC";
132
+ let limitClause = limit !== undefined ? ` LIMIT ` + param(b, limit) : "";
133
+ let sql = `SELECT partition_key, item FROM ` + table + ` WHERE ` + where.join(" AND ") + ` ORDER BY sub_key ` + dir + limitClause;
134
+ return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(false, extra));
135
+ };
136
+ let scan = async (readModelName, filterConfigs, limit) => {
137
+ let table = QueryDbStorage_Postgres$ReventlessPostgres.tableName(readModelName);
138
+ let b = {
139
+ params: []
140
+ };
141
+ let where = [QueryDbStorage_Postgres$ReventlessPostgres.notExpiredClause];
142
+ filterConfigs.forEach(param => {
143
+ where.push(filterSql(b, param[0], param[1], param[2]));
144
+ });
145
+ let sql = `SELECT partition_key, item FROM ` + table + ` WHERE ` + where.join(" AND ") + ` ORDER BY partition_key, sub_key LIMIT ` + param(b, limit);
146
+ return (await PgDriver$ReventlessPostgres.query(P.pool, sql, b.params)).map(extra => decodeRow(true, extra));
147
+ };
148
+ let make = _allQueryDbs => Pulumi.output({
149
+ scan: scan,
150
+ query: query
151
+ });
152
+ return {
153
+ query: query,
154
+ scan: scan,
155
+ make: make
156
+ };
157
+ }
158
+
159
+ let notExpired = QueryDbStorage_Postgres$ReventlessPostgres.notExpiredClause;
160
+
161
+ export {
162
+ valueToText,
163
+ isNumeric,
164
+ param,
165
+ col,
166
+ filterSql,
167
+ subIdSql,
168
+ notExpired,
169
+ decodeRow,
170
+ Make,
171
+ }
172
+ /* @pulumi/pulumi Not a pure module */