envio 2.27.6 → 2.28.0-alpha.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.
- package/package.json +5 -5
- package/rescript.json +3 -0
- package/src/FetchState.res +21 -14
- package/src/FetchState.res.js +14 -5
- package/src/Hasura.res +31 -12
- package/src/Hasura.res.js +31 -13
- package/src/Internal.res +7 -4
- package/src/InternalConfig.res +20 -0
- package/src/InternalConfig.res.js +2 -0
- package/src/Js.shim.ts +11 -0
- package/src/LoadManager.res +12 -6
- package/src/LoadManager.res.js +13 -6
- package/src/Persistence.res +25 -33
- package/src/Persistence.res.js +18 -20
- package/src/PgStorage.res +162 -102
- package/src/PgStorage.res.js +146 -103
- package/src/Prometheus.res +2 -2
- package/src/Prometheus.res.js +2 -3
- package/src/bindings/Pino.res +1 -1
- package/src/bindings/Pino.res.js +2 -1
- package/src/bindings/Postgres.res +1 -1
- package/src/db/EntityHistory.res +18 -17
- package/src/db/EntityHistory.res.js +28 -26
- package/src/db/InternalTable.gen.ts +43 -0
- package/src/db/InternalTable.res +430 -0
- package/src/db/InternalTable.res.js +315 -0
- package/src/vendored/Rest.res +11 -2
- package/src/vendored/Rest.res.js +44 -35
package/src/PgStorage.res.js
CHANGED
|
@@ -16,6 +16,7 @@ var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
|
16
16
|
var Belt_Option = require("rescript/lib/js/belt_Option.js");
|
|
17
17
|
var Caml_option = require("rescript/lib/js/caml_option.js");
|
|
18
18
|
var Persistence = require("./Persistence.res.js");
|
|
19
|
+
var InternalTable = require("./db/InternalTable.res.js");
|
|
19
20
|
var Child_process = require("child_process");
|
|
20
21
|
var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
|
|
21
22
|
var S$RescriptSchema = require("rescript-schema/src/S.res.js");
|
|
@@ -68,11 +69,18 @@ function makeCreateTableQuery(table, pgSchema) {
|
|
|
68
69
|
) + ");";
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
function makeInitializeTransaction(pgSchema, pgUser,
|
|
72
|
-
var
|
|
72
|
+
function makeInitializeTransaction(pgSchema, pgUser, chainConfigsOpt, entitiesOpt, enumsOpt, isEmptyPgSchemaOpt) {
|
|
73
|
+
var chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
73
74
|
var entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
74
75
|
var enums = enumsOpt !== undefined ? enumsOpt : [];
|
|
75
76
|
var isEmptyPgSchema = isEmptyPgSchemaOpt !== undefined ? isEmptyPgSchemaOpt : false;
|
|
77
|
+
var generalTables = [
|
|
78
|
+
InternalTable.EventSyncState.table,
|
|
79
|
+
InternalTable.Chains.table,
|
|
80
|
+
InternalTable.PersistedState.table,
|
|
81
|
+
InternalTable.EndOfBlockRangeScannedData.table,
|
|
82
|
+
InternalTable.RawEvents.table
|
|
83
|
+
];
|
|
76
84
|
var allTables = $$Array.copy(generalTables);
|
|
77
85
|
var allEntityTables = [];
|
|
78
86
|
entities.forEach(function (entity) {
|
|
@@ -107,12 +115,18 @@ function makeInitializeTransaction(pgSchema, pgUser, generalTablesOpt, entitiesO
|
|
|
107
115
|
contents: ""
|
|
108
116
|
};
|
|
109
117
|
entities.forEach(function (entity) {
|
|
110
|
-
functionsQuery.contents = functionsQuery.contents + "\n" + entity.entityHistory.
|
|
118
|
+
functionsQuery.contents = functionsQuery.contents + "\n" + entity.entityHistory.makeInsertFnQuery(pgSchema);
|
|
111
119
|
Table.getDerivedFromFields(entity.table).forEach(function (derivedFromField) {
|
|
112
120
|
var indexField = Utils.unwrapResultExn(Schema.getDerivedFromFieldName(derivedSchema, derivedFromField));
|
|
113
121
|
query.contents = query.contents + "\n" + makeCreateIndexQuery(derivedFromField.derivedFromEntity, [indexField], pgSchema);
|
|
114
122
|
});
|
|
115
123
|
});
|
|
124
|
+
query.contents = query.contents + "\n" + InternalTable.Views.makeMetaViewQuery(pgSchema);
|
|
125
|
+
query.contents = query.contents + "\n" + InternalTable.Views.makeChainMetadataViewQuery(pgSchema);
|
|
126
|
+
var initialChainsValuesQuery = InternalTable.Chains.makeInitialValuesQuery(pgSchema, chainConfigs);
|
|
127
|
+
if (initialChainsValuesQuery !== undefined) {
|
|
128
|
+
query.contents = query.contents + "\n" + initialChainsValuesQuery;
|
|
129
|
+
}
|
|
116
130
|
functionsQuery.contents = functionsQuery.contents + "\n" + ("CREATE OR REPLACE FUNCTION " + getCacheRowCountFnName + "(table_name text) \nRETURNS integer AS $$\nDECLARE\n result integer;\nBEGIN\n EXECUTE format('SELECT COUNT(*) FROM \"" + pgSchema + "\".%I', table_name) INTO result;\n RETURN result;\nEND;\n$$ LANGUAGE plpgsql;");
|
|
117
131
|
return [query.contents].concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : []);
|
|
118
132
|
}
|
|
@@ -129,6 +143,10 @@ function makeLoadByIdsQuery(pgSchema, tableName) {
|
|
|
129
143
|
return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\" WHERE id = ANY($1::text[]);";
|
|
130
144
|
}
|
|
131
145
|
|
|
146
|
+
function makeLoadAllQuery(pgSchema, tableName) {
|
|
147
|
+
return "SELECT * FROM \"" + pgSchema + "\".\"" + tableName + "\";";
|
|
148
|
+
}
|
|
149
|
+
|
|
132
150
|
function makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents) {
|
|
133
151
|
var match = Table.toSqlParams(table, itemSchema, pgSchema);
|
|
134
152
|
var quotedNonPrimaryFieldNames = match.quotedNonPrimaryFieldNames;
|
|
@@ -177,13 +195,9 @@ function makeInsertValuesSetQuery(pgSchema, table, itemSchema, itemsCount) {
|
|
|
177
195
|
) + ";";
|
|
178
196
|
}
|
|
179
197
|
|
|
180
|
-
var rawEventsTableName = "raw_events";
|
|
181
|
-
|
|
182
|
-
var eventSyncStateTableName = "event_sync_state";
|
|
183
|
-
|
|
184
198
|
function makeTableBatchSetQuery(pgSchema, table, itemSchema) {
|
|
185
199
|
var match = Table.toSqlParams(table, itemSchema, pgSchema);
|
|
186
|
-
var isRawEvents = table.tableName ===
|
|
200
|
+
var isRawEvents = table.tableName === InternalTable.RawEvents.table.tableName;
|
|
187
201
|
if (isRawEvents || !match.hasArrayField) {
|
|
188
202
|
return {
|
|
189
203
|
query: makeInsertUnnestSetQuery(pgSchema, table, itemSchema, isRawEvents),
|
|
@@ -285,13 +299,24 @@ async function setOrThrow(sql, items, table, itemSchema, pgSchema) {
|
|
|
285
299
|
|
|
286
300
|
function setEntityHistoryOrThrow(sql, entityHistory, rows, shouldCopyCurrentEntity, shouldRemoveInvalidUtf8Opt) {
|
|
287
301
|
var shouldRemoveInvalidUtf8 = shouldRemoveInvalidUtf8Opt !== undefined ? shouldRemoveInvalidUtf8Opt : false;
|
|
288
|
-
return
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
302
|
+
return Belt_Array.map(rows, (function (historyRow) {
|
|
303
|
+
var row = S$RescriptSchema.reverseConvertToJsonOrThrow(historyRow, entityHistory.schema);
|
|
304
|
+
if (shouldRemoveInvalidUtf8) {
|
|
305
|
+
removeInvalidUtf8InPlace([row]);
|
|
306
|
+
}
|
|
307
|
+
return $$Promise.$$catch(entityHistory.insertFn(sql, row, shouldCopyCurrentEntity !== undefined ? shouldCopyCurrentEntity : !Belt_Option.getWithDefault(historyRow.containsRollbackDiffChange, false)), (function (exn) {
|
|
308
|
+
var reason = Utils.prettifyExn(exn);
|
|
309
|
+
var detail = (reason?.detail || "");
|
|
310
|
+
throw {
|
|
311
|
+
RE_EXN_ID: Persistence.StorageError,
|
|
312
|
+
message: "Failed to insert history item into table \"" + entityHistory.table.tableName + "\"." + (
|
|
313
|
+
detail !== "" ? " Details: " + detail : ""
|
|
314
|
+
),
|
|
315
|
+
reason: reason,
|
|
316
|
+
Error: new Error()
|
|
317
|
+
};
|
|
318
|
+
}));
|
|
319
|
+
}));
|
|
295
320
|
}
|
|
296
321
|
|
|
297
322
|
function makeSchemaTableNamesQuery(pgSchema) {
|
|
@@ -370,29 +395,112 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onI
|
|
|
370
395
|
};
|
|
371
396
|
var cacheDirPath = Path.resolve("..", ".envio", "cache");
|
|
372
397
|
var isInitialized = async function () {
|
|
373
|
-
var envioTables = await sql.unsafe("SELECT table_schema FROM information_schema.tables WHERE table_schema = '" + pgSchema + "' AND table_name = '" +
|
|
398
|
+
var envioTables = await sql.unsafe("SELECT table_schema FROM information_schema.tables WHERE table_schema = '" + pgSchema + "' AND table_name = '" + InternalTable.EventSyncState.table.tableName + "' OR table_name = '" + InternalTable.Chains.table.tableName + "';");
|
|
374
399
|
return Utils.$$Array.notEmpty(envioTables);
|
|
375
400
|
};
|
|
376
|
-
var
|
|
401
|
+
var restoreEffectCache = async function (withUpload) {
|
|
402
|
+
if (withUpload) {
|
|
403
|
+
var nothingToUploadErrorMessage = "Nothing to upload.";
|
|
404
|
+
var match = await Promise.all([
|
|
405
|
+
$$Promise.$$catch(Fs.promises.readdir(cacheDirPath).then(function (e) {
|
|
406
|
+
return {
|
|
407
|
+
TAG: "Ok",
|
|
408
|
+
_0: e
|
|
409
|
+
};
|
|
410
|
+
}), (function (param) {
|
|
411
|
+
return Promise.resolve({
|
|
412
|
+
TAG: "Error",
|
|
413
|
+
_0: nothingToUploadErrorMessage
|
|
414
|
+
});
|
|
415
|
+
})),
|
|
416
|
+
getConnectedPsqlExec(pgUser, pgHost, pgDatabase, pgPort)
|
|
417
|
+
]);
|
|
418
|
+
var exit = 0;
|
|
419
|
+
var message;
|
|
420
|
+
var entries = match[0];
|
|
421
|
+
if (entries.TAG === "Ok") {
|
|
422
|
+
var psqlExec = match[1];
|
|
423
|
+
if (psqlExec.TAG === "Ok") {
|
|
424
|
+
var psqlExec$1 = psqlExec._0;
|
|
425
|
+
var cacheFiles = entries._0.filter(function (entry) {
|
|
426
|
+
return entry.endsWith(".tsv");
|
|
427
|
+
});
|
|
428
|
+
await Promise.all(cacheFiles.map(function (entry) {
|
|
429
|
+
var effectName = entry.slice(0, -4);
|
|
430
|
+
var table = Internal.makeCacheTable(effectName);
|
|
431
|
+
return sql.unsafe(makeCreateTableQuery(table, pgSchema)).then(function () {
|
|
432
|
+
var inputFile = Path.join(cacheDirPath, entry);
|
|
433
|
+
var command = psqlExec$1 + " -c 'COPY \"" + pgSchema + "\".\"" + table.tableName + "\" FROM STDIN WITH (FORMAT text, HEADER);' < " + inputFile;
|
|
434
|
+
return new Promise((function (resolve, reject) {
|
|
435
|
+
Child_process.exec(command, psqlExecOptions, (function (error, stdout, param) {
|
|
436
|
+
if (error === null) {
|
|
437
|
+
return resolve(stdout);
|
|
438
|
+
} else {
|
|
439
|
+
return reject(error);
|
|
440
|
+
}
|
|
441
|
+
}));
|
|
442
|
+
}));
|
|
443
|
+
});
|
|
444
|
+
}));
|
|
445
|
+
Logging.info("Successfully uploaded cache.");
|
|
446
|
+
} else {
|
|
447
|
+
message = match[1]._0;
|
|
448
|
+
exit = 1;
|
|
449
|
+
}
|
|
450
|
+
} else {
|
|
451
|
+
message = entries._0;
|
|
452
|
+
exit = 1;
|
|
453
|
+
}
|
|
454
|
+
if (exit === 1) {
|
|
455
|
+
if (message === nothingToUploadErrorMessage) {
|
|
456
|
+
Logging.info("No cache found to upload.");
|
|
457
|
+
} else {
|
|
458
|
+
Logging.error("Failed to upload cache, continuing without it. " + message);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
var cacheTableInfo = await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema));
|
|
464
|
+
if (withUpload && Utils.$$Array.notEmpty(cacheTableInfo) && onNewTables !== undefined) {
|
|
465
|
+
await onNewTables(cacheTableInfo.map(function (info) {
|
|
466
|
+
return info.table_name;
|
|
467
|
+
}));
|
|
468
|
+
}
|
|
469
|
+
var cache = {};
|
|
470
|
+
cacheTableInfo.forEach(function (param) {
|
|
471
|
+
var effectName = param.table_name.slice(cacheTablePrefixLength);
|
|
472
|
+
cache[effectName] = {
|
|
473
|
+
effectName: effectName,
|
|
474
|
+
count: param.count
|
|
475
|
+
};
|
|
476
|
+
});
|
|
477
|
+
return cache;
|
|
478
|
+
};
|
|
479
|
+
var initialize = async function (chainConfigsOpt, entitiesOpt, enumsOpt) {
|
|
480
|
+
var chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
|
|
377
481
|
var entities = entitiesOpt !== undefined ? entitiesOpt : [];
|
|
378
|
-
var generalTables = generalTablesOpt !== undefined ? generalTablesOpt : [];
|
|
379
482
|
var enums = enumsOpt !== undefined ? enumsOpt : [];
|
|
380
483
|
var schemaTableNames = await sql.unsafe(makeSchemaTableNamesQuery(pgSchema));
|
|
381
484
|
if (Utils.$$Array.notEmpty(schemaTableNames) && !schemaTableNames.some(function (table) {
|
|
382
|
-
return table.table_name ===
|
|
485
|
+
return table.table_name === InternalTable.EventSyncState.table.tableName;
|
|
383
486
|
})) {
|
|
384
487
|
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.");
|
|
385
488
|
}
|
|
386
|
-
var queries = makeInitializeTransaction(pgSchema, pgUser,
|
|
489
|
+
var queries = makeInitializeTransaction(pgSchema, pgUser, chainConfigs, entities, enums, Utils.$$Array.isEmpty(schemaTableNames));
|
|
387
490
|
await sql.begin(function (sql) {
|
|
388
|
-
return queries.map(function (query) {
|
|
389
|
-
|
|
390
|
-
|
|
491
|
+
return Promise.all(queries.map(function (query) {
|
|
492
|
+
return sql.unsafe(query);
|
|
493
|
+
}));
|
|
391
494
|
});
|
|
495
|
+
var cache = await restoreEffectCache(true);
|
|
392
496
|
if (onInitialize !== undefined) {
|
|
393
|
-
|
|
497
|
+
await onInitialize();
|
|
394
498
|
}
|
|
395
|
-
|
|
499
|
+
return {
|
|
500
|
+
cleanRun: true,
|
|
501
|
+
cache: cache,
|
|
502
|
+
chains: chainConfigs.map(InternalTable.Chains.initialFromConfig)
|
|
503
|
+
};
|
|
396
504
|
};
|
|
397
505
|
var loadByIdsOrThrow = async function (ids, table, rowsSchema) {
|
|
398
506
|
var rows;
|
|
@@ -526,90 +634,26 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, onI
|
|
|
526
634
|
return Logging.errorWithExn(Utils.prettifyExn(exn$1), "Failed to dump cache.");
|
|
527
635
|
}
|
|
528
636
|
};
|
|
529
|
-
var
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return Promise.resolve({
|
|
540
|
-
TAG: "Error",
|
|
541
|
-
_0: nothingToUploadErrorMessage
|
|
542
|
-
});
|
|
543
|
-
})),
|
|
544
|
-
getConnectedPsqlExec(pgUser, pgHost, pgDatabase, pgPort)
|
|
545
|
-
]);
|
|
546
|
-
var exit = 0;
|
|
547
|
-
var message;
|
|
548
|
-
var entries = match[0];
|
|
549
|
-
if (entries.TAG === "Ok") {
|
|
550
|
-
var psqlExec = match[1];
|
|
551
|
-
if (psqlExec.TAG === "Ok") {
|
|
552
|
-
var psqlExec$1 = psqlExec._0;
|
|
553
|
-
var cacheFiles = entries._0.filter(function (entry) {
|
|
554
|
-
return entry.endsWith(".tsv");
|
|
555
|
-
});
|
|
556
|
-
await Promise.all(cacheFiles.map(function (entry) {
|
|
557
|
-
var effectName = entry.slice(0, -4);
|
|
558
|
-
var table = Internal.makeCacheTable(effectName);
|
|
559
|
-
return sql.unsafe(makeCreateTableQuery(table, pgSchema)).then(function () {
|
|
560
|
-
var inputFile = Path.join(cacheDirPath, entry);
|
|
561
|
-
var command = psqlExec$1 + " -c 'COPY \"" + pgSchema + "\".\"" + table.tableName + "\" FROM STDIN WITH (FORMAT text, HEADER);' < " + inputFile;
|
|
562
|
-
return new Promise((function (resolve, reject) {
|
|
563
|
-
Child_process.exec(command, psqlExecOptions, (function (error, stdout, param) {
|
|
564
|
-
if (error === null) {
|
|
565
|
-
return resolve(stdout);
|
|
566
|
-
} else {
|
|
567
|
-
return reject(error);
|
|
568
|
-
}
|
|
569
|
-
}));
|
|
570
|
-
}));
|
|
571
|
-
});
|
|
572
|
-
}));
|
|
573
|
-
Logging.info("Successfully uploaded cache.");
|
|
574
|
-
} else {
|
|
575
|
-
message = match[1]._0;
|
|
576
|
-
exit = 1;
|
|
577
|
-
}
|
|
578
|
-
} else {
|
|
579
|
-
message = entries._0;
|
|
580
|
-
exit = 1;
|
|
581
|
-
}
|
|
582
|
-
if (exit === 1) {
|
|
583
|
-
if (message === nothingToUploadErrorMessage) {
|
|
584
|
-
Logging.info("No cache found to upload.");
|
|
585
|
-
} else {
|
|
586
|
-
Logging.error("Failed to upload cache, continuing without it. " + message);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
var cacheTableInfo = await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema));
|
|
592
|
-
if (withUpload && Utils.$$Array.notEmpty(cacheTableInfo) && onNewTables !== undefined) {
|
|
593
|
-
await onNewTables(cacheTableInfo.map(function (info) {
|
|
594
|
-
return info.table_name;
|
|
595
|
-
}));
|
|
596
|
-
}
|
|
597
|
-
return cacheTableInfo.map(function (info) {
|
|
598
|
-
return {
|
|
599
|
-
effectName: info.table_name.slice(cacheTablePrefixLength),
|
|
600
|
-
count: info.count
|
|
601
|
-
};
|
|
602
|
-
});
|
|
637
|
+
var loadInitialState = async function () {
|
|
638
|
+
var match = await Promise.all([
|
|
639
|
+
restoreEffectCache(false),
|
|
640
|
+
sql.unsafe(makeLoadAllQuery(pgSchema, InternalTable.Chains.table.tableName))
|
|
641
|
+
]);
|
|
642
|
+
return {
|
|
643
|
+
cleanRun: false,
|
|
644
|
+
cache: match[0],
|
|
645
|
+
chains: match[1]
|
|
646
|
+
};
|
|
603
647
|
};
|
|
604
648
|
return {
|
|
605
649
|
isInitialized: isInitialized,
|
|
606
650
|
initialize: initialize,
|
|
651
|
+
loadInitialState: loadInitialState,
|
|
607
652
|
loadByIdsOrThrow: loadByIdsOrThrow,
|
|
608
653
|
loadByFieldOrThrow: loadByFieldOrThrow,
|
|
609
654
|
setOrThrow: setOrThrow$1,
|
|
610
655
|
setEffectCacheOrThrow: setEffectCacheOrThrow,
|
|
611
|
-
dumpEffectCache: dumpEffectCache
|
|
612
|
-
restoreEffectCache: restoreEffectCache
|
|
656
|
+
dumpEffectCache: dumpEffectCache
|
|
613
657
|
};
|
|
614
658
|
}
|
|
615
659
|
|
|
@@ -623,10 +667,9 @@ exports.makeInitializeTransaction = makeInitializeTransaction;
|
|
|
623
667
|
exports.makeLoadByIdQuery = makeLoadByIdQuery;
|
|
624
668
|
exports.makeLoadByFieldQuery = makeLoadByFieldQuery;
|
|
625
669
|
exports.makeLoadByIdsQuery = makeLoadByIdsQuery;
|
|
670
|
+
exports.makeLoadAllQuery = makeLoadAllQuery;
|
|
626
671
|
exports.makeInsertUnnestSetQuery = makeInsertUnnestSetQuery;
|
|
627
672
|
exports.makeInsertValuesSetQuery = makeInsertValuesSetQuery;
|
|
628
|
-
exports.rawEventsTableName = rawEventsTableName;
|
|
629
|
-
exports.eventSyncStateTableName = eventSyncStateTableName;
|
|
630
673
|
exports.maxItemsPerQuery = maxItemsPerQuery;
|
|
631
674
|
exports.makeTableBatchSetQuery = makeTableBatchSetQuery;
|
|
632
675
|
exports.chunkArray = chunkArray;
|
package/src/Prometheus.res
CHANGED
|
@@ -213,9 +213,9 @@ let incrementExecuteBatchDurationCounter = (~duration) => {
|
|
|
213
213
|
executeBatchDurationCounter->PromClient.Counter.incMany(duration)
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
let setSourceChainHeight = (~blockNumber, ~
|
|
216
|
+
let setSourceChainHeight = (~blockNumber, ~chainId) => {
|
|
217
217
|
sourceChainHeight
|
|
218
|
-
->PromClient.Gauge.labels({"chainId":
|
|
218
|
+
->PromClient.Gauge.labels({"chainId": chainId})
|
|
219
219
|
->PromClient.Gauge.set(blockNumber)
|
|
220
220
|
}
|
|
221
221
|
|
package/src/Prometheus.res.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
var Utils = require("./Utils.res.js");
|
|
5
5
|
var Hrtime = require("./bindings/Hrtime.res.js");
|
|
6
6
|
var Js_exn = require("rescript/lib/js/js_exn.js");
|
|
7
|
-
var ChainMap = require("./ChainMap.res.js");
|
|
8
7
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
9
8
|
var Belt_Result = require("rescript/lib/js/belt_Result.js");
|
|
10
9
|
var PromClient = require("prom-client");
|
|
@@ -315,9 +314,9 @@ function incrementExecuteBatchDurationCounter(duration) {
|
|
|
315
314
|
executeBatchDurationCounter.inc(duration);
|
|
316
315
|
}
|
|
317
316
|
|
|
318
|
-
function setSourceChainHeight(blockNumber,
|
|
317
|
+
function setSourceChainHeight(blockNumber, chainId) {
|
|
319
318
|
sourceChainHeight.labels({
|
|
320
|
-
chainId:
|
|
319
|
+
chainId: chainId
|
|
321
320
|
}).set(blockNumber);
|
|
322
321
|
}
|
|
323
322
|
|
package/src/bindings/Pino.res
CHANGED
package/src/bindings/Pino.res.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var Pino = require("pino");
|
|
5
|
+
var Utils = require("../Utils.res.js");
|
|
5
6
|
var Caml_obj = require("rescript/lib/js/caml_obj.js");
|
|
6
7
|
var Belt_Array = require("rescript/lib/js/belt_Array.js");
|
|
7
8
|
var Belt_Option = require("rescript/lib/js/belt_Option.js");
|
|
@@ -14,7 +15,7 @@ function createPinoMessage(message) {
|
|
|
14
15
|
function createPinoMessageWithError(message, err) {
|
|
15
16
|
return {
|
|
16
17
|
msg: message,
|
|
17
|
-
err: err
|
|
18
|
+
err: Utils.prettifyExn(err)
|
|
18
19
|
};
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -89,7 +89,7 @@ type poolConfig = {
|
|
|
89
89
|
@module
|
|
90
90
|
external makeSql: (~config: poolConfig) => sql = "postgres"
|
|
91
91
|
|
|
92
|
-
@send external beginSql: (sql, sql =>
|
|
92
|
+
@send external beginSql: (sql, sql => promise<'result>) => promise<'result> = "begin"
|
|
93
93
|
|
|
94
94
|
// TODO: can explore this approach (https://forum.rescript-lang.org/t/rfc-support-for-tagged-template-literals/3744)
|
|
95
95
|
// @send @variadic
|
package/src/db/EntityHistory.res
CHANGED
|
@@ -141,7 +141,7 @@ let makeHistoryRowSchema: S.t<'entity> => S.t<historyRow<'entity>> = entitySchem
|
|
|
141
141
|
|
|
142
142
|
type t<'entity> = {
|
|
143
143
|
table: table,
|
|
144
|
-
|
|
144
|
+
makeInsertFnQuery: (~pgSchema: string) => string,
|
|
145
145
|
schema: S.t<historyRow<'entity>>,
|
|
146
146
|
// Used for parsing
|
|
147
147
|
schemaRows: S.t<array<historyRow<'entity>>>,
|
|
@@ -153,7 +153,7 @@ type entityInternal
|
|
|
153
153
|
external castInternal: t<'entity> => t<entityInternal> = "%identity"
|
|
154
154
|
external eval: string => 'a = "eval"
|
|
155
155
|
|
|
156
|
-
let fromTable = (table: table, ~
|
|
156
|
+
let fromTable = (table: table, ~schema: S.t<'entity>): t<'entity> => {
|
|
157
157
|
let entity_history_block_timestamp = "entity_history_block_timestamp"
|
|
158
158
|
let entity_history_chain_id = "entity_history_chain_id"
|
|
159
159
|
let entity_history_block_number = "entity_history_block_number"
|
|
@@ -227,19 +227,6 @@ let fromTable = (table: table, ~pgSchema, ~schema: S.t<'entity>): t<'entity> =>
|
|
|
227
227
|
)
|
|
228
228
|
|
|
229
229
|
let insertFnName = `"insert_${table.tableName}"`
|
|
230
|
-
let historyRowArg = "history_row"
|
|
231
|
-
let historyTablePath = `"${pgSchema}"."${historyTableName}"`
|
|
232
|
-
let originTablePath = `"${pgSchema}"."${originTableName}"`
|
|
233
|
-
|
|
234
|
-
let previousHistoryFieldsAreNullStr =
|
|
235
|
-
previousChangeFieldNames
|
|
236
|
-
->Belt.Array.map(fieldName => `${historyRowArg}.${fieldName} IS NULL`)
|
|
237
|
-
->Js.Array2.joinWith(" OR ")
|
|
238
|
-
|
|
239
|
-
let currentChangeFieldNamesCommaSeparated = currentChangeFieldNames->Js.Array2.joinWith(", ")
|
|
240
|
-
|
|
241
|
-
let dataFieldNamesDoubleQuoted = dataFieldNames->Belt.Array.map(fieldName => `"${fieldName}"`)
|
|
242
|
-
let dataFieldNamesCommaSeparated = dataFieldNamesDoubleQuoted->Js.Array2.joinWith(", ")
|
|
243
230
|
|
|
244
231
|
let allFieldNamesDoubleQuoted =
|
|
245
232
|
Belt.Array.concatMany([
|
|
@@ -249,7 +236,21 @@ let fromTable = (table: table, ~pgSchema, ~schema: S.t<'entity>): t<'entity> =>
|
|
|
249
236
|
[actionFieldName],
|
|
250
237
|
])->Belt.Array.map(fieldName => `"${fieldName}"`)
|
|
251
238
|
|
|
252
|
-
let
|
|
239
|
+
let makeInsertFnQuery = (~pgSchema) => {
|
|
240
|
+
let historyRowArg = "history_row"
|
|
241
|
+
let historyTablePath = `"${pgSchema}"."${historyTableName}"`
|
|
242
|
+
let originTablePath = `"${pgSchema}"."${originTableName}"`
|
|
243
|
+
|
|
244
|
+
let previousHistoryFieldsAreNullStr =
|
|
245
|
+
previousChangeFieldNames
|
|
246
|
+
->Belt.Array.map(fieldName => `${historyRowArg}.${fieldName} IS NULL`)
|
|
247
|
+
->Js.Array2.joinWith(" OR ")
|
|
248
|
+
|
|
249
|
+
let currentChangeFieldNamesCommaSeparated = currentChangeFieldNames->Js.Array2.joinWith(", ")
|
|
250
|
+
|
|
251
|
+
let dataFieldNamesDoubleQuoted = dataFieldNames->Belt.Array.map(fieldName => `"${fieldName}"`)
|
|
252
|
+
let dataFieldNamesCommaSeparated = dataFieldNamesDoubleQuoted->Js.Array2.joinWith(", ")
|
|
253
|
+
|
|
253
254
|
`CREATE OR REPLACE FUNCTION ${insertFnName}(${historyRowArg} ${historyTablePath}, should_copy_current_entity BOOLEAN)
|
|
254
255
|
RETURNS void AS $$
|
|
255
256
|
DECLARE
|
|
@@ -315,7 +316,7 @@ $$ LANGUAGE plpgsql;`
|
|
|
315
316
|
|
|
316
317
|
let schema = makeHistoryRowSchema(schema)
|
|
317
318
|
|
|
318
|
-
{table,
|
|
319
|
+
{table, makeInsertFnQuery, schema, schemaRows: S.array(schema), insertFn}
|
|
319
320
|
}
|
|
320
321
|
|
|
321
322
|
type safeReorgBlocks = {
|
|
@@ -157,7 +157,7 @@ function makeHistoryRowSchema(entitySchema) {
|
|
|
157
157
|
}));
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
function fromTable(table,
|
|
160
|
+
function fromTable(table, schema) {
|
|
161
161
|
var currentChangeFieldNames = [
|
|
162
162
|
"entity_history_block_timestamp",
|
|
163
163
|
"entity_history_chain_id",
|
|
@@ -233,17 +233,6 @@ function fromTable(table, pgSchema, schema) {
|
|
|
233
233
|
]
|
|
234
234
|
]));
|
|
235
235
|
var insertFnName = "\"insert_" + table$1.tableName + "\"";
|
|
236
|
-
var historyRowArg = "history_row";
|
|
237
|
-
var historyTablePath = "\"" + pgSchema + "\".\"" + historyTableName + "\"";
|
|
238
|
-
var originTablePath = "\"" + pgSchema + "\".\"" + originTableName + "\"";
|
|
239
|
-
var previousHistoryFieldsAreNullStr = Belt_Array.map(previousChangeFieldNames, (function (fieldName) {
|
|
240
|
-
return historyRowArg + "." + fieldName + " IS NULL";
|
|
241
|
-
})).join(" OR ");
|
|
242
|
-
var currentChangeFieldNamesCommaSeparated = currentChangeFieldNames.join(", ");
|
|
243
|
-
var dataFieldNamesDoubleQuoted = Belt_Array.map(dataFieldNames, (function (fieldName) {
|
|
244
|
-
return "\"" + fieldName + "\"";
|
|
245
|
-
}));
|
|
246
|
-
var dataFieldNamesCommaSeparated = dataFieldNamesDoubleQuoted.join(", ");
|
|
247
236
|
var allFieldNamesDoubleQuoted = Belt_Array.map(Belt_Array.concatMany([
|
|
248
237
|
currentChangeFieldNames,
|
|
249
238
|
previousChangeFieldNames,
|
|
@@ -252,19 +241,32 @@ function fromTable(table, pgSchema, schema) {
|
|
|
252
241
|
]), (function (fieldName) {
|
|
253
242
|
return "\"" + fieldName + "\"";
|
|
254
243
|
}));
|
|
255
|
-
var
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
return
|
|
265
|
-
}))
|
|
266
|
-
|
|
267
|
-
|
|
244
|
+
var makeInsertFnQuery = function (pgSchema) {
|
|
245
|
+
var historyRowArg = "history_row";
|
|
246
|
+
var historyTablePath = "\"" + pgSchema + "\".\"" + historyTableName + "\"";
|
|
247
|
+
var originTablePath = "\"" + pgSchema + "\".\"" + originTableName + "\"";
|
|
248
|
+
var previousHistoryFieldsAreNullStr = Belt_Array.map(previousChangeFieldNames, (function (fieldName) {
|
|
249
|
+
return historyRowArg + "." + fieldName + " IS NULL";
|
|
250
|
+
})).join(" OR ");
|
|
251
|
+
var currentChangeFieldNamesCommaSeparated = currentChangeFieldNames.join(", ");
|
|
252
|
+
var dataFieldNamesDoubleQuoted = Belt_Array.map(dataFieldNames, (function (fieldName) {
|
|
253
|
+
return "\"" + fieldName + "\"";
|
|
254
|
+
}));
|
|
255
|
+
var dataFieldNamesCommaSeparated = dataFieldNamesDoubleQuoted.join(", ");
|
|
256
|
+
return "CREATE OR REPLACE FUNCTION " + insertFnName + "(" + historyRowArg + " " + historyTablePath + ", should_copy_current_entity BOOLEAN)\nRETURNS void AS $$\nDECLARE\n v_previous_record RECORD;\n v_origin_record RECORD;\nBEGIN\n -- Check if previous values are not provided\n IF " + previousHistoryFieldsAreNullStr + " THEN\n -- Find the most recent record for the same id\n SELECT " + currentChangeFieldNamesCommaSeparated + " INTO v_previous_record\n FROM " + historyTablePath + "\n WHERE " + id + " = " + historyRowArg + "." + id + "\n ORDER BY " + Belt_Array.map(currentChangeFieldNames, (function (fieldName) {
|
|
257
|
+
return fieldName + " DESC";
|
|
258
|
+
})).join(", ") + "\n LIMIT 1;\n\n -- If a previous record exists, use its values\n IF FOUND THEN\n " + Belt_Array.map(Belt_Array.zip(currentChangeFieldNames, previousChangeFieldNames), (function (param) {
|
|
259
|
+
return historyRowArg + "." + param[1] + " := v_previous_record." + param[0] + ";";
|
|
260
|
+
})).join(" ") + "\n ElSIF should_copy_current_entity THEN\n -- Check if a value for the id exists in the origin table and if so, insert a history row for it.\n SELECT " + dataFieldNamesCommaSeparated + " FROM " + originTablePath + " WHERE id = " + historyRowArg + "." + id + " INTO v_origin_record;\n IF FOUND THEN\n INSERT INTO " + historyTablePath + " (" + currentChangeFieldNamesCommaSeparated + ", " + dataFieldNamesCommaSeparated + ", \"" + actionFieldName + "\")\n -- SET the current change data fields to 0 since we don't know what they were\n -- and it doesn't matter provided they are less than any new values\n VALUES (" + Belt_Array.map(currentChangeFieldNames, (function (param) {
|
|
261
|
+
return "0";
|
|
262
|
+
})).join(", ") + ", " + Belt_Array.map(dataFieldNames, (function (fieldName) {
|
|
263
|
+
return "v_origin_record.\"" + fieldName + "\"";
|
|
264
|
+
})).join(", ") + ", 'SET');\n\n " + Belt_Array.map(previousChangeFieldNames, (function (previousFieldName) {
|
|
265
|
+
return historyRowArg + "." + previousFieldName + " := 0;";
|
|
266
|
+
})).join(" ") + "\n END IF;\n END IF;\n END IF;\n\n INSERT INTO " + historyTablePath + " (" + allFieldNamesDoubleQuoted.join(", ") + ")\n VALUES (" + Belt_Array.map(allFieldNamesDoubleQuoted, (function (fieldName) {
|
|
267
|
+
return historyRowArg + "." + fieldName;
|
|
268
|
+
})).join(", ") + ");\nEND;\n$$ LANGUAGE plpgsql;";
|
|
269
|
+
};
|
|
268
270
|
var insertFnString = "(sql, rowArgs, shouldCopyCurrentEntity) =>\n sql\`select " + insertFnName + "(ROW(" + Belt_Array.map(allFieldNamesDoubleQuoted, (function (fieldNameDoubleQuoted) {
|
|
269
271
|
return "\${rowArgs[" + fieldNameDoubleQuoted + "]\}";
|
|
270
272
|
})).join(", ") + ", NULL), --NULL argument for SERIAL field\n \${shouldCopyCurrentEntity});\`";
|
|
@@ -272,7 +274,7 @@ function fromTable(table, pgSchema, schema) {
|
|
|
272
274
|
var schema$1 = makeHistoryRowSchema(schema);
|
|
273
275
|
return {
|
|
274
276
|
table: table$1,
|
|
275
|
-
|
|
277
|
+
makeInsertFnQuery: makeInsertFnQuery,
|
|
276
278
|
schema: schema$1,
|
|
277
279
|
schemaRows: S$RescriptSchema.array(schema$1),
|
|
278
280
|
insertFn: insertFn
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* TypeScript file generated from InternalTable.res by genType. */
|
|
2
|
+
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
/* tslint:disable */
|
|
5
|
+
|
|
6
|
+
import type {Json_t as Js_Json_t} from '../../src/Js.shim';
|
|
7
|
+
|
|
8
|
+
import type {t as Address_t} from '../../src/Address.gen';
|
|
9
|
+
|
|
10
|
+
export type EventSyncState_t = {
|
|
11
|
+
readonly chain_id: number;
|
|
12
|
+
readonly block_number: number;
|
|
13
|
+
readonly log_index: number;
|
|
14
|
+
readonly block_timestamp: number
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type RawEvents_t = {
|
|
18
|
+
readonly chain_id: number;
|
|
19
|
+
readonly event_id: bigint;
|
|
20
|
+
readonly event_name: string;
|
|
21
|
+
readonly contract_name: string;
|
|
22
|
+
readonly block_number: number;
|
|
23
|
+
readonly log_index: number;
|
|
24
|
+
readonly src_address: Address_t;
|
|
25
|
+
readonly block_hash: string;
|
|
26
|
+
readonly block_timestamp: number;
|
|
27
|
+
readonly block_fields: Js_Json_t;
|
|
28
|
+
readonly transaction_fields: Js_Json_t;
|
|
29
|
+
readonly params: Js_Json_t
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type DynamicContractRegistry_t = {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly chain_id: number;
|
|
35
|
+
readonly registering_event_block_number: number;
|
|
36
|
+
readonly registering_event_log_index: number;
|
|
37
|
+
readonly registering_event_block_timestamp: number;
|
|
38
|
+
readonly registering_event_contract_name: string;
|
|
39
|
+
readonly registering_event_name: string;
|
|
40
|
+
readonly registering_event_src_address: Address_t;
|
|
41
|
+
readonly contract_address: Address_t;
|
|
42
|
+
readonly contract_name: string
|
|
43
|
+
};
|