envio 2.26.0-rc.0 → 2.26.0-rc.2

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.
@@ -1,19 +1,27 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
  'use strict';
3
3
 
4
+ var Fs = require("fs");
5
+ var Path = require("path");
4
6
  var $$Array = require("rescript/lib/js/array.js");
5
7
  var Table = require("./db/Table.res.js");
6
8
  var Utils = require("./Utils.res.js");
7
9
  var Js_exn = require("rescript/lib/js/js_exn.js");
8
10
  var Schema = require("./db/Schema.res.js");
11
+ var Js_dict = require("rescript/lib/js/js_dict.js");
12
+ var Logging = require("./Logging.res.js");
13
+ var $$Promise = require("./bindings/Promise.res.js");
14
+ var Internal = require("./Internal.res.js");
9
15
  var Belt_Array = require("rescript/lib/js/belt_Array.js");
10
- var Caml_int32 = require("rescript/lib/js/caml_int32.js");
16
+ var Belt_Option = require("rescript/lib/js/belt_Option.js");
11
17
  var Caml_option = require("rescript/lib/js/caml_option.js");
12
18
  var Persistence = require("./Persistence.res.js");
19
+ var Child_process = require("child_process");
20
+ var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
13
21
  var S$RescriptSchema = require("rescript-schema/src/S.res.js");
14
22
  var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
15
23
 
16
- function makeCreateIndexSql(tableName, indexFields, pgSchema) {
24
+ function makeCreateIndexQuery(tableName, indexFields, pgSchema) {
17
25
  var indexName = tableName + "_" + indexFields.join("_");
18
26
  var index = Belt_Array.map(indexFields, (function (idx) {
19
27
  return "\"" + idx + "\"";
@@ -21,20 +29,20 @@ function makeCreateIndexSql(tableName, indexFields, pgSchema) {
21
29
  return "CREATE INDEX IF NOT EXISTS \"" + indexName + "\" ON \"" + pgSchema + "\".\"" + tableName + "\"(" + index + ");";
22
30
  }
23
31
 
24
- function makeCreateTableIndicesSql(table, pgSchema) {
32
+ function makeCreateTableIndicesQuery(table, pgSchema) {
25
33
  var tableName = table.tableName;
26
34
  var createIndex = function (indexField) {
27
- return makeCreateIndexSql(tableName, [indexField], pgSchema);
35
+ return makeCreateIndexQuery(tableName, [indexField], pgSchema);
28
36
  };
29
37
  var createCompositeIndex = function (indexFields) {
30
- return makeCreateIndexSql(tableName, indexFields, pgSchema);
38
+ return makeCreateIndexQuery(tableName, indexFields, pgSchema);
31
39
  };
32
40
  var singleIndices = Table.getSingleIndices(table);
33
41
  var compositeIndices = Table.getCompositeIndices(table);
34
42
  return Belt_Array.map(singleIndices, createIndex).join("\n") + Belt_Array.map(compositeIndices, createCompositeIndex).join("\n");
35
43
  }
36
44
 
37
- function makeCreateTableSql(table, pgSchema) {
45
+ function makeCreateTableQuery(table, pgSchema) {
38
46
  var fieldsMapped = Belt_Array.map(Table.getFields(table), (function (field) {
39
47
  var defaultValue = field.defaultValue;
40
48
  var fieldType = field.fieldType;
@@ -58,11 +66,11 @@ function makeCreateTableSql(table, pgSchema) {
58
66
  ) + ");";
59
67
  }
60
68
 
61
- function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesOpt, enumsOpt, cleanRunOpt) {
69
+ function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt) {
62
70
  var generalTables = generalTablesOpt !== undefined ? generalTablesOpt : [];
63
71
  var entities = entitiesOpt !== undefined ? entitiesOpt : [];
64
72
  var enums = enumsOpt !== undefined ? enumsOpt : [];
65
- var cleanRun = cleanRunOpt !== undefined ? cleanRunOpt : false;
73
+ var isEmptyPgSchema = isEmptyPgSchemaOpt !== undefined ? isEmptyPgSchemaOpt : false;
66
74
  var allTables = $$Array.copy(generalTables);
67
75
  var allEntityTables = [];
68
76
  entities.forEach(function (entity) {
@@ -73,22 +81,20 @@ function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesO
73
81
  var derivedSchema = Schema.make(allEntityTables);
74
82
  var query = {
75
83
  contents: (
76
- cleanRun ? "DROP SCHEMA IF EXISTS \"" + pgSchema + "\" CASCADE;\nCREATE SCHEMA \"" + pgSchema + "\";" : "CREATE SCHEMA IF NOT EXISTS \"" + pgSchema + "\";"
77
- ) + ("GRANT ALL ON SCHEMA \"" + pgSchema + "\" TO " + pgUser + ";\nGRANT ALL ON SCHEMA \"" + pgSchema + "\" TO public;")
84
+ isEmptyPgSchema && pgSchema === "public" ? "" : "DROP SCHEMA IF EXISTS \"" + pgSchema + "\" CASCADE;\nCREATE SCHEMA \"" + pgSchema + "\";\n"
85
+ ) + ("GRANT ALL ON SCHEMA \"" + pgSchema + "\" TO \"" + pgUser + "\";\nGRANT ALL ON SCHEMA \"" + pgSchema + "\" TO public;")
78
86
  };
79
87
  enums.forEach(function (enumConfig) {
80
88
  var enumCreateQuery = "CREATE TYPE \"" + pgSchema + "\"." + enumConfig.name + " AS ENUM(" + enumConfig.variants.map(function (v) {
81
89
  return "'" + v + "'";
82
90
  }).join(", ") + ");";
83
- query.contents = query.contents + "\n" + (
84
- cleanRun ? enumCreateQuery : "IF NOT EXISTS (\n SELECT 1 FROM pg_type \n WHERE typname = '" + enumConfig.name.toLowerCase() + "' \n AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = '" + pgSchema + "')\n) THEN \n " + enumCreateQuery + "\nEND IF;"
85
- );
91
+ query.contents = query.contents + "\n" + enumCreateQuery;
86
92
  });
87
93
  allTables.forEach(function (table) {
88
- query.contents = query.contents + "\n" + makeCreateTableSql(table, pgSchema);
94
+ query.contents = query.contents + "\n" + makeCreateTableQuery(table, pgSchema);
89
95
  });
90
96
  allTables.forEach(function (table) {
91
- var indices = makeCreateTableIndicesSql(table, pgSchema);
97
+ var indices = makeCreateTableIndicesQuery(table, pgSchema);
92
98
  if (indices !== "") {
93
99
  query.contents = query.contents + "\n" + indices;
94
100
  return ;
@@ -102,22 +108,27 @@ function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesO
102
108
  functionsQuery.contents = functionsQuery.contents + "\n" + entity.entityHistory.createInsertFnQuery;
103
109
  Table.getDerivedFromFields(entity.table).forEach(function (derivedFromField) {
104
110
  var indexField = Utils.unwrapResultExn(Schema.getDerivedFromFieldName(derivedSchema, derivedFromField));
105
- query.contents = query.contents + "\n" + makeCreateIndexSql(derivedFromField.derivedFromEntity, [indexField], pgSchema);
111
+ query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
106
112
  });
107
113
  });
108
- return [cleanRun || Utils.$$Array.isEmpty(enums) ? query.contents : "DO $$ BEGIN " + query.contents + " END $$;"].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
114
+ functionsQuery.contents = functionsQuery.contents + "\n" + ("CREATE OR REPLACE FUNCTION get_cache_row_count(table_name text) \n RETURNS integer AS $$\n DECLARE\n result integer;\n BEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\n END;\n $$ LANGUAGE plpgsql;");
115
+ return [query.contents].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
109
116
  }
110
117
 
111
- function makeLoadByIdSql(pgSchema, tableName) {
118
+ function makeLoadByIdQuery(pgSchema, tableName) {
112
119
  return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE id = $1 LIMIT 1;";
113
120
  }
114
121
 
115
- function makeLoadByIdsSql(pgSchema, tableName) {
122
+ function makeLoadByFieldQuery(pgSchema, tableName, fieldName, operator) {
123
+ return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE \"" + fieldName + "\" " + operator + " $1;";
124
+ }
125
+
126
+ function makeLoadByIdsQuery(pgSchema, tableName) {
116
127
  return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE id = ANY($1::text[]);";
117
128
  }
118
129
 
119
- function makeInsertUnnestSetSql(pgSchema, table, itemSchema, isRawEvents) {
120
- var match = Table.toSqlParams(table, itemSchema);
130
+ function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents) {
131
+ var match = Table.toSqlParams(table, itemSchema, pgSchema);
121
132
  var quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
122
133
  var primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table);
123
134
  return "INSERT INTO \"" + pgSchema + "\".\"" + table.tableName + "\" (" + match.quotedFieldNames.join(", ") + ")\nSELECT * FROM unnest(" + match.arrayFieldTypes.map(function (arrayFieldType, idx) {
@@ -133,8 +144,8 @@ function makeInsertUnnestSetSql(pgSchema, table, itemSchema, isRawEvents) {
133
144
  ) + ";";
134
145
  }
135
146
 
136
- function makeInsertValuesSetSql(pgSchema, table, itemSchema, itemsCount) {
137
- var match = Table.toSqlParams(table, itemSchema);
147
+ function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
148
+ var match = Table.toSqlParams(table, itemSchema, pgSchema);
138
149
  var quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
139
150
  var quotedFieldNames = match.quotedFieldNames;
140
151
  var primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table);
@@ -166,18 +177,20 @@ function makeInsertValuesSetSql(pgSchema, table, itemSchema, itemsCount) {
166
177
 
167
178
  var rawEventsTableName = "raw_events";
168
179
 
180
+ var eventSyncStateTableName = "event_sync_state";
181
+
169
182
  function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
170
- var match = Table.toSqlParams(table, itemSchema);
183
+ var match = Table.toSqlParams(table, itemSchema, pgSchema);
171
184
  var isRawEvents = table.tableName === rawEventsTableName;
172
185
  if (isRawEvents || !match.hasArrayField) {
173
186
  return {
174
- sql: makeInsertUnnestSetSql(pgSchema, table, itemSchema, isRawEvents),
187
+ query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents),
175
188
  convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.unnest(match.dbSchema), "Output", "Input", "Sync", false),
176
189
  isInsertValues: false
177
190
  };
178
191
  } else {
179
192
  return {
180
- sql: makeInsertValuesSetSql(pgSchema, table, itemSchema, 500),
193
+ query: makeInsertValuesSetQuery(pgSchema, table, itemSchema, 500),
181
194
  convertOrThrow: S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(itemSchema), (function (param) {
182
195
  return {
183
196
  s: (function (prim) {
@@ -201,6 +214,24 @@ function chunkArray(arr, chunkSize) {
201
214
  return chunks;
202
215
  }
203
216
 
217
+ function removeInvalidUtf8InPlace(entities) {
218
+ entities.forEach(function (item) {
219
+ Utils.Dict.forEachWithKey(item, (function (key, value) {
220
+ if (typeof value === "string") {
221
+ item[key] = value.replaceAll("\x00", "");
222
+ return ;
223
+ }
224
+
225
+ }));
226
+ });
227
+ }
228
+
229
+ var pgEncodingErrorSchema = S$RescriptSchema.object(function (s) {
230
+ s.tag("message", "invalid byte sequence for encoding \"UTF8\": 0x00");
231
+ });
232
+
233
+ var PgEncodingError = /* @__PURE__ */Caml_exceptions.create("PgStorage.PgEncodingError");
234
+
204
235
  var setQueryCache = new WeakMap();
205
236
 
206
237
  async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
@@ -208,30 +239,24 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
208
239
  return ;
209
240
  }
210
241
  var cached = setQueryCache.get(table);
211
- var query;
242
+ var data;
212
243
  if (cached !== undefined) {
213
- query = Caml_option.valFromOption(cached);
244
+ data = Caml_option.valFromOption(cached);
214
245
  } else {
215
246
  var newQuery = makeTableBatchSetQuery(pgSchema, table, itemSchema);
216
247
  setQueryCache.set(table, newQuery);
217
- query = newQuery;
248
+ data = newQuery;
218
249
  }
219
- var sqlQuery = query.sql;
220
250
  try {
221
- var payload = query.convertOrThrow(items);
222
- if (!query.isInsertValues) {
223
- return await sql.unsafe(sqlQuery, payload, {prepare: true});
251
+ if (!data.isInsertValues) {
252
+ return await sql.unsafe(data.query, data.convertOrThrow(items), {prepare: true});
224
253
  }
225
- var match = itemSchema.t;
226
- var fieldsCount;
227
- fieldsCount = typeof match !== "object" || match.TAG !== "object" ? Js_exn.raiseError("Expected an object schema for table") : match.items.length;
228
- var maxChunkSize = Math.imul(500, fieldsCount);
229
- var chunks = chunkArray(payload, maxChunkSize);
254
+ var chunks = chunkArray(items, 500);
230
255
  var responses = [];
231
256
  chunks.forEach(function (chunk) {
232
257
  var chunkSize = chunk.length;
233
- var isFullChunk = chunkSize === maxChunkSize;
234
- var response = sql.unsafe(isFullChunk ? sqlQuery : makeInsertValuesSetSql(pgSchema, table, itemSchema, Caml_int32.div(chunkSize, fieldsCount)), chunk, {prepare: true});
258
+ var isFullChunk = chunkSize === 500;
259
+ var response = sql.unsafe(isFullChunk ? data.query : makeInsertValuesSetQuery(pgSchema, table, itemSchema, chunkSize), data.convertOrThrow(chunk), {prepare: true});
235
260
  responses.push(response);
236
261
  });
237
262
  await Promise.all(responses);
@@ -250,34 +275,128 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
250
275
  throw {
251
276
  RE_EXN_ID: Persistence.StorageError,
252
277
  message: "Failed to insert items into table \"" + table.tableName + "\"",
253
- reason: exn,
278
+ reason: Internal.prettifyExn(exn),
254
279
  Error: new Error()
255
280
  };
256
281
  }
257
282
  }
258
283
 
259
- function make(sql, pgSchema, pgUser) {
284
+ function setEntityHistoryOrThrow(sql, entityHistory, rows, shouldCopyCurrentEntity, shouldRemoveInvalidUtf8Opt) {
285
+ var shouldRemoveInvalidUtf8 = shouldRemoveInvalidUtf8Opt !== undefined ? shouldRemoveInvalidUtf8Opt : false;
286
+ return Promise.all(Belt_Array.map(rows, (function (historyRow) {
287
+ var row = S$RescriptSchema.reverseConvertToJsonOrThrow(historyRow, entityHistory.schema);
288
+ if (shouldRemoveInvalidUtf8) {
289
+ removeInvalidUtf8InPlace([row]);
290
+ }
291
+ return entityHistory.insertFn(sql, row, shouldCopyCurrentEntity !== undefined ? shouldCopyCurrentEntity : !Belt_Option.getWithDefault(historyRow.containsRollbackDiffChange, false));
292
+ })));
293
+ }
294
+
295
+ function makeSchemaTableNamesQuery(pgSchema) {
296
+ return "SELECT table_name FROM information_schema.tables WHERE table_schema = '" + pgSchema + "';";
297
+ }
298
+
299
+ var cacheTablePrefixLength = Internal.cacheTablePrefix.length;
300
+
301
+ function makeSchemaCacheTableInfoQuery(pgSchema) {
302
+ return "SELECT \n t.table_name,\n get_cache_row_count(t.table_name) as count\n FROM information_schema.tables t\n WHERE t.table_schema = '" + pgSchema + "' \n AND t.table_name LIKE '" + Internal.cacheTablePrefix + "%';";
303
+ }
304
+
305
+ var psqlExecState = {
306
+ contents: "Unknown"
307
+ };
308
+
309
+ async function getConnectedPsqlExec(pgUser, pgHost, pgDatabase, pgPort) {
310
+ var promise = psqlExecState.contents;
311
+ if (typeof promise === "object") {
312
+ if (promise.TAG === "Pending") {
313
+ return await promise._0;
314
+ } else {
315
+ return promise._0;
316
+ }
317
+ }
318
+ var promise$1 = new Promise((function (resolve, _reject) {
319
+ var binary = "psql";
320
+ Child_process.exec(binary + " --version", (function (error, param, param$1) {
321
+ if (error === null) {
322
+ return resolve({
323
+ TAG: "Ok",
324
+ _0: binary + " -h " + pgHost + " -p " + pgPort.toString() + " -U " + pgUser + " -d " + pgDatabase
325
+ });
326
+ }
327
+ var binary$1 = "docker-compose exec -T -u " + pgUser + " envio-postgres psql";
328
+ Child_process.exec(binary$1 + " --version", (function (error, param, param$1) {
329
+ if (error === null) {
330
+ return resolve({
331
+ TAG: "Ok",
332
+ _0: binary$1 + " -h " + pgHost + " -p " + (5432).toString() + " -U " + pgUser + " -d " + pgDatabase
333
+ });
334
+ } else {
335
+ return resolve({
336
+ TAG: "Error",
337
+ _0: "Please check if \"psql\" binary is installed or docker-compose is running for the local indexer."
338
+ });
339
+ }
340
+ }));
341
+ }));
342
+ }));
343
+ psqlExecState.contents = {
344
+ TAG: "Pending",
345
+ _0: promise$1
346
+ };
347
+ var result = await promise$1;
348
+ psqlExecState.contents = {
349
+ TAG: "Resolved",
350
+ _0: result
351
+ };
352
+ return result;
353
+ }
354
+
355
+ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onInitialize, onNewTables) {
356
+ var psqlExecOptions_env = Js_dict.fromArray([
357
+ [
358
+ "PGPASSWORD",
359
+ pgPassword
360
+ ],
361
+ [
362
+ "PATH",
363
+ process.env.PATH
364
+ ]
365
+ ]);
366
+ var psqlExecOptions = {
367
+ env: psqlExecOptions_env
368
+ };
369
+ var cacheDirPath = Path.resolve("..", ".envio", "cache");
260
370
  var isInitialized = async function () {
261
- var schemas = await sql.unsafe("SELECT schema_name FROM information_schema.schemata WHERE schema_name = '" + pgSchema + "';");
262
- return Utils.$$Array.notEmpty(schemas);
371
+ var envioTables = await sql.unsafe("SELECT table_schema FROM information_schema.tables WHERE table_schema = '" + pgSchema + "' AND table_name = '" + eventSyncStateTableName + "';");
372
+ return Utils.$$Array.notEmpty(envioTables);
263
373
  };
264
- var initialize = async function (entitiesOpt, generalTablesOpt, enumsOpt, cleanRunOpt) {
374
+ var initialize = async function (entitiesOpt, generalTablesOpt, enumsOpt) {
265
375
  var entities = entitiesOpt !== undefined ? entitiesOpt : [];
266
376
  var generalTables = generalTablesOpt !== undefined ? generalTablesOpt : [];
267
377
  var enums = enumsOpt !== undefined ? enumsOpt : [];
268
- var cleanRun = cleanRunOpt !== undefined ? cleanRunOpt : false;
269
- var queries = makeInitializeTransaction(pgSchema, pgUser, generalTables, entities, enums, cleanRun);
378
+ var schemaTableNames = await sql.unsafe(makeSchemaTableNamesQuery(pgSchema));
379
+ if (Utils.$$Array.notEmpty(schemaTableNames) && !schemaTableNames.some(function (table) {
380
+ return table.table_name === eventSyncStateTableName;
381
+ })) {
382
+ Js_exn.raiseError("Cannot run Envio migrations on PostgreSQL schema \"" + pgSchema + "\" because it contains non-Envio tables. Running migrations would delete all data in this schema.\n\nTo resolve this:\n1. If you want to use this schema, first backup any important data, then drop it with: \"pnpm envio local db-migrate down\"\n2. Or specify a different schema name by setting the \"ENVIO_PG_PUBLIC_SCHEMA\" environment variable\n3. Or manually drop the schema in your database if you're certain the data is not needed.");
383
+ }
384
+ var queries = makeInitializeTransaction(pgSchema, pgUser, generalTables, entities, enums, Utils.$$Array.isEmpty(schemaTableNames));
270
385
  await sql.begin(function (sql) {
271
386
  return queries.map(function (query) {
272
387
  return sql.unsafe(query);
273
388
  });
274
389
  });
390
+ if (onInitialize !== undefined) {
391
+ return await onInitialize();
392
+ }
393
+
275
394
  };
276
395
  var loadByIdsOrThrow = async function (ids, table, rowsSchema) {
277
396
  var rows;
278
397
  try {
279
398
  rows = await (
280
- ids.length !== 1 ? sql.unsafe(makeLoadByIdsSql(pgSchema, table.tableName), [ids], {prepare: true}) : sql.unsafe(makeLoadByIdSql(pgSchema, table.tableName), ids, {prepare: true})
399
+ ids.length !== 1 ? sql.unsafe(makeLoadByIdsQuery(pgSchema, table.tableName), [ids], {prepare: true}) : sql.unsafe(makeLoadByIdQuery(pgSchema, table.tableName), ids, {prepare: true})
281
400
  );
282
401
  }
283
402
  catch (raw_exn){
@@ -302,32 +421,221 @@ function make(sql, pgSchema, pgUser) {
302
421
  };
303
422
  }
304
423
  };
424
+ var loadByFieldOrThrow = async function (fieldName, fieldSchema, fieldValue, operator, table, rowsSchema) {
425
+ var params;
426
+ try {
427
+ params = [S$RescriptSchema.reverseConvertToJsonOrThrow(fieldValue, fieldSchema)];
428
+ }
429
+ catch (raw_exn){
430
+ var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
431
+ throw {
432
+ RE_EXN_ID: Persistence.StorageError,
433
+ message: "Failed loading \"" + table.tableName + "\" from storage by field \"" + fieldName + "\". Couldn't serialize provided value.",
434
+ reason: exn,
435
+ Error: new Error()
436
+ };
437
+ }
438
+ var rows;
439
+ try {
440
+ rows = await sql.unsafe(makeLoadByFieldQuery(pgSchema, table.tableName, fieldName, operator), params, {prepare: true});
441
+ }
442
+ catch (raw_exn$1){
443
+ var exn$1 = Caml_js_exceptions.internalToOCamlException(raw_exn$1);
444
+ throw {
445
+ RE_EXN_ID: Persistence.StorageError,
446
+ message: "Failed loading \"" + table.tableName + "\" from storage by field \"" + fieldName + "\"",
447
+ reason: exn$1,
448
+ Error: new Error()
449
+ };
450
+ }
451
+ try {
452
+ return S$RescriptSchema.parseOrThrow(rows, rowsSchema);
453
+ }
454
+ catch (raw_exn$2){
455
+ var exn$2 = Caml_js_exceptions.internalToOCamlException(raw_exn$2);
456
+ throw {
457
+ RE_EXN_ID: Persistence.StorageError,
458
+ message: "Failed to parse \"" + table.tableName + "\" loaded from storage by ids",
459
+ reason: exn$2,
460
+ Error: new Error()
461
+ };
462
+ }
463
+ };
305
464
  var setOrThrow$1 = function (items, table, itemSchema) {
306
465
  return setOrThrow(sql, items, table, itemSchema, pgSchema);
307
466
  };
467
+ var setEffectCacheOrThrow = async function (effect, items, initialize) {
468
+ var cacheMeta = effect.cache;
469
+ var match = cacheMeta !== undefined ? cacheMeta : Js_exn.raiseError("Failed to set effect cache for \"" + effect.name + "\". Effect has no cache enabled.");
470
+ var table = match.table;
471
+ if (initialize) {
472
+ await sql.unsafe(makeCreateTableQuery(table, pgSchema));
473
+ if (onNewTables !== undefined) {
474
+ await onNewTables([table.tableName]);
475
+ }
476
+
477
+ }
478
+ return await setOrThrow$1(items, table, match.itemSchema);
479
+ };
480
+ var dumpEffectCache = async function () {
481
+ try {
482
+ var cacheTableInfo = (await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema))).filter(function (i) {
483
+ return i.count > 0;
484
+ });
485
+ if (!Utils.$$Array.notEmpty(cacheTableInfo)) {
486
+ return ;
487
+ }
488
+ try {
489
+ await Fs.promises.access(cacheDirPath);
490
+ }
491
+ catch (exn){
492
+ await Fs.promises.mkdir(cacheDirPath, {
493
+ recursive: true
494
+ });
495
+ }
496
+ var psqlExec = await getConnectedPsqlExec(pgUser, pgHost, pgDatabase, pgPort);
497
+ if (psqlExec.TAG !== "Ok") {
498
+ return Logging.error("Failed to dump cache. " + psqlExec._0);
499
+ }
500
+ var psqlExec$1 = psqlExec._0;
501
+ Logging.info("Dumping cache: " + cacheTableInfo.map(function (param) {
502
+ return param.table_name + " (" + String(param.count) + " rows)";
503
+ }).join(", "));
504
+ var promises = cacheTableInfo.map(async function (param) {
505
+ var tableName = param.table_name;
506
+ var cacheName = tableName.slice(cacheTablePrefixLength);
507
+ var outputFile = Path.join(cacheDirPath, cacheName + ".tsv");
508
+ var command = psqlExec$1 + " -c 'COPY \"" + pgSchema + "\".\"" + tableName + "\" TO STDOUT WITH (FORMAT text, HEADER);' > " + outputFile;
509
+ return new Promise((function (resolve, reject) {
510
+ Child_process.exec(command, psqlExecOptions, (function (error, stdout, param) {
511
+ if (error === null) {
512
+ return resolve(stdout);
513
+ } else {
514
+ return reject(error);
515
+ }
516
+ }));
517
+ }));
518
+ });
519
+ await Promise.all(promises);
520
+ return Logging.info("Successfully dumped cache to " + cacheDirPath);
521
+ }
522
+ catch (raw_exn){
523
+ var exn$1 = Caml_js_exceptions.internalToOCamlException(raw_exn);
524
+ return Logging.errorWithExn(Internal.prettifyExn(exn$1), "Failed to dump cache.");
525
+ }
526
+ };
527
+ var restoreEffectCache = async function (withUpload) {
528
+ if (withUpload) {
529
+ var nothingToUploadErrorMessage = "Nothing to upload.";
530
+ var match = await Promise.all([
531
+ $$Promise.$$catch(Fs.promises.readdir(cacheDirPath).then(function (e) {
532
+ return {
533
+ TAG: "Ok",
534
+ _0: e
535
+ };
536
+ }), (function (param) {
537
+ return Promise.resolve({
538
+ TAG: "Error",
539
+ _0: nothingToUploadErrorMessage
540
+ });
541
+ })),
542
+ getConnectedPsqlExec(pgUser, pgHost, pgDatabase, pgPort)
543
+ ]);
544
+ var exit = 0;
545
+ var message;
546
+ var entries = match[0];
547
+ if (entries.TAG === "Ok") {
548
+ var psqlExec = match[1];
549
+ if (psqlExec.TAG === "Ok") {
550
+ var psqlExec$1 = psqlExec._0;
551
+ var cacheFiles = entries._0.filter(function (entry) {
552
+ return entry.endsWith(".tsv");
553
+ });
554
+ await Promise.all(cacheFiles.map(function (entry) {
555
+ var effectName = entry.slice(0, -4);
556
+ var table = Internal.makeCacheTable(effectName);
557
+ return sql.unsafe(makeCreateTableQuery(table, pgSchema)).then(function () {
558
+ var inputFile = Path.join(cacheDirPath, entry);
559
+ var command = psqlExec$1 + " -c 'COPY \"" + pgSchema + "\".\"" + table.tableName + "\" FROM STDIN WITH (FORMAT text, HEADER);' < " + inputFile;
560
+ return new Promise((function (resolve, reject) {
561
+ Child_process.exec(command, psqlExecOptions, (function (error, stdout, param) {
562
+ if (error === null) {
563
+ return resolve(stdout);
564
+ } else {
565
+ return reject(error);
566
+ }
567
+ }));
568
+ }));
569
+ });
570
+ }));
571
+ Logging.info("Successfully uploaded cache.");
572
+ } else {
573
+ message = match[1]._0;
574
+ exit = 1;
575
+ }
576
+ } else {
577
+ message = entries._0;
578
+ exit = 1;
579
+ }
580
+ if (exit === 1) {
581
+ if (message === nothingToUploadErrorMessage) {
582
+ Logging.info("No cache found to upload.");
583
+ } else {
584
+ Logging.error("Failed to upload cache, continuing without it. " + message);
585
+ }
586
+ }
587
+
588
+ }
589
+ var cacheTableInfo = await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema));
590
+ if (withUpload && Utils.$$Array.notEmpty(cacheTableInfo) && onNewTables !== undefined) {
591
+ await onNewTables(cacheTableInfo.map(function (info) {
592
+ return info.table_name;
593
+ }));
594
+ }
595
+ return cacheTableInfo.map(function (info) {
596
+ return {
597
+ effectName: info.table_name.slice(cacheTablePrefixLength),
598
+ count: info.count
599
+ };
600
+ });
601
+ };
308
602
  return {
309
603
  isInitialized: isInitialized,
310
604
  initialize: initialize,
311
605
  loadByIdsOrThrow: loadByIdsOrThrow,
312
- setOrThrow: setOrThrow$1
606
+ loadByFieldOrThrow: loadByFieldOrThrow,
607
+ setOrThrow: setOrThrow$1,
608
+ setEffectCacheOrThrow: setEffectCacheOrThrow,
609
+ dumpEffectCache: dumpEffectCache,
610
+ restoreEffectCache: restoreEffectCache
313
611
  };
314
612
  }
315
613
 
316
614
  var maxItemsPerQuery = 500;
317
615
 
318
- exports.makeCreateIndexSql = makeCreateIndexSql;
319
- exports.makeCreateTableIndicesSql = makeCreateTableIndicesSql;
320
- exports.makeCreateTableSql = makeCreateTableSql;
616
+ exports.makeCreateIndexQuery = makeCreateIndexQuery;
617
+ exports.makeCreateTableIndicesQuery = makeCreateTableIndicesQuery;
618
+ exports.makeCreateTableQuery = makeCreateTableQuery;
321
619
  exports.makeInitializeTransaction = makeInitializeTransaction;
322
- exports.makeLoadByIdSql = makeLoadByIdSql;
323
- exports.makeLoadByIdsSql = makeLoadByIdsSql;
324
- exports.makeInsertUnnestSetSql = makeInsertUnnestSetSql;
325
- exports.makeInsertValuesSetSql = makeInsertValuesSetSql;
620
+ exports.makeLoadByIdQuery = makeLoadByIdQuery;
621
+ exports.makeLoadByFieldQuery = makeLoadByFieldQuery;
622
+ exports.makeLoadByIdsQuery = makeLoadByIdsQuery;
623
+ exports.makeInsertUnnestSetQuery = makeInsertUnnestSetQuery;
624
+ exports.makeInsertValuesSetQuery = makeInsertValuesSetQuery;
326
625
  exports.rawEventsTableName = rawEventsTableName;
626
+ exports.eventSyncStateTableName = eventSyncStateTableName;
327
627
  exports.maxItemsPerQuery = maxItemsPerQuery;
328
628
  exports.makeTableBatchSetQuery = makeTableBatchSetQuery;
329
629
  exports.chunkArray = chunkArray;
630
+ exports.removeInvalidUtf8InPlace = removeInvalidUtf8InPlace;
631
+ exports.pgEncodingErrorSchema = pgEncodingErrorSchema;
632
+ exports.PgEncodingError = PgEncodingError;
330
633
  exports.setQueryCache = setQueryCache;
331
634
  exports.setOrThrow = setOrThrow;
635
+ exports.setEntityHistoryOrThrow = setEntityHistoryOrThrow;
636
+ exports.makeSchemaTableNamesQuery = makeSchemaTableNamesQuery;
637
+ exports.cacheTablePrefixLength = cacheTablePrefixLength;
638
+ exports.makeSchemaCacheTableInfoQuery = makeSchemaCacheTableInfoQuery;
639
+ exports.getConnectedPsqlExec = getConnectedPsqlExec;
332
640
  exports.make = make;
333
- /* setQueryCache Not a pure module */
641
+ /* pgEncodingErrorSchema Not a pure module */
@@ -590,3 +590,15 @@ module EffectCallsCount = {
590
590
  gauge->SafeGauge.handleInt(~labels=effectName, ~value=callsCount)
591
591
  }
592
592
  }
593
+
594
+ module EffectCacheCount = {
595
+ let gauge = SafeGauge.makeOrThrow(
596
+ ~name="envio_effect_cache_count",
597
+ ~help="The number of items in the effect cache.",
598
+ ~labelSchema=effectLabelsSchema,
599
+ )
600
+
601
+ let set = (~count, ~effectName) => {
602
+ gauge->SafeGauge.handleInt(~labels=effectName, ~value=count)
603
+ }
604
+ }
@@ -700,6 +700,17 @@ var EffectCallsCount = {
700
700
  set: set$21
701
701
  };
702
702
 
703
+ var gauge$22 = makeOrThrow$1("envio_effect_cache_count", "The number of items in the effect cache.", effectLabelsSchema);
704
+
705
+ function set$22(count, effectName) {
706
+ handleInt$1(gauge$22, effectName, count);
707
+ }
708
+
709
+ var EffectCacheCount = {
710
+ gauge: gauge$22,
711
+ set: set$22
712
+ };
713
+
703
714
  exports.loadEntitiesDurationCounter = loadEntitiesDurationCounter;
704
715
  exports.eventRouterDurationCounter = eventRouterDurationCounter;
705
716
  exports.executeBatchDurationCounter = executeBatchDurationCounter;
@@ -747,4 +758,5 @@ exports.ProgressBlockNumber = ProgressBlockNumber;
747
758
  exports.ProgressEventsCount = ProgressEventsCount;
748
759
  exports.effectLabelsSchema = effectLabelsSchema;
749
760
  exports.EffectCallsCount = EffectCallsCount;
761
+ exports.EffectCacheCount = EffectCacheCount;
750
762
  /* loadEntitiesDurationCounter Not a pure module */