envio 3.15.0-subgraph → 3.16.0-subgraph

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 (114) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +3 -3
  3. package/fuel.schema.json +2 -2
  4. package/index.d.ts +3 -3
  5. package/licenses/README.md +1 -1
  6. package/package.json +8 -8
  7. package/src/Batch.res.mjs +5 -5
  8. package/src/BatchProcessing.res +1 -0
  9. package/src/BatchProcessing.res.mjs +1 -0
  10. package/src/ChainFetching.res +1 -6
  11. package/src/ChainFetching.res.mjs +1 -1
  12. package/src/ChainState.res +48 -7
  13. package/src/ChainState.res.mjs +21 -8
  14. package/src/Clock.res +57 -0
  15. package/src/Clock.res.mjs +72 -0
  16. package/src/Config.res +16 -4
  17. package/src/Config.res.mjs +5 -3
  18. package/src/Core.res +4 -40
  19. package/src/CrossChainState.res +10 -6
  20. package/src/CrossChainState.res.mjs +1 -1
  21. package/src/EffectState.res +10 -2
  22. package/src/EffectState.res.mjs +8 -4
  23. package/src/EffectState.resi +3 -1
  24. package/src/EntityId.res +2 -7
  25. package/src/EntityId.res.mjs +1 -8
  26. package/src/EntityTables.res +4 -1
  27. package/src/EntityTables.res.mjs +1 -1
  28. package/src/Env.res +4 -0
  29. package/src/Env.res.mjs +5 -0
  30. package/src/FetchState.res +157 -69
  31. package/src/FetchState.res.mjs +112 -47
  32. package/src/FinalizeBackfill.res +2 -4
  33. package/src/FinalizeBackfill.res.mjs +3 -4
  34. package/src/InMemoryTable.res +17 -16
  35. package/src/InMemoryTable.res.mjs +14 -15
  36. package/src/IndexerState.res +28 -4
  37. package/src/IndexerState.res.mjs +19 -6
  38. package/src/IndexerState.resi +4 -0
  39. package/src/Internal.res +0 -49
  40. package/src/Internal.res.mjs +1 -80
  41. package/src/LoadLayer.res +17 -10
  42. package/src/LoadLayer.res.mjs +11 -8
  43. package/src/Main.res.mjs +1 -1
  44. package/src/Persistence.res +3 -23
  45. package/src/Persistence.res.mjs +3 -3
  46. package/src/PreloadLookahead.res +42 -24
  47. package/src/PreloadLookahead.res.mjs +51 -30
  48. package/src/Rollback.res +0 -1
  49. package/src/Rollback.res.mjs +1 -1
  50. package/src/SafeCheckpointTracking.res +4 -4
  51. package/src/SafeCheckpointTracking.res.mjs +1 -1
  52. package/src/StagedRows.res +106 -0
  53. package/src/StagedRows.res.mjs +102 -0
  54. package/src/Staging.res +32 -14
  55. package/src/Staging.res.mjs +17 -20
  56. package/src/Storage.res +278 -973
  57. package/src/Storage.res.mjs +218 -720
  58. package/src/Supervisor.res +75 -56
  59. package/src/Supervisor.res.mjs +55 -26
  60. package/src/SyncWrites.res +24 -18
  61. package/src/SyncWrites.res.mjs +11 -11
  62. package/src/TestIndexer.res +22 -27
  63. package/src/TestIndexer.res.mjs +20 -17
  64. package/src/Throttler.res +15 -8
  65. package/src/Throttler.res.mjs +9 -6
  66. package/src/Throttler.resi +1 -1
  67. package/src/UserContext.res +13 -4
  68. package/src/UserContext.res.mjs +5 -5
  69. package/src/Utils.res +0 -6
  70. package/src/Utils.res.mjs +0 -5
  71. package/src/Writing.res +0 -1
  72. package/src/Writing.res.mjs +1 -1
  73. package/src/bindings/ClickHouse.res +0 -322
  74. package/src/bindings/ClickHouse.res.mjs +0 -338
  75. package/src/bindings/StorageClient.res +107 -174
  76. package/src/bindings/StorageClient.res.mjs +19 -8
  77. package/src/bindings/Vitest.res +0 -26
  78. package/src/bindings/Vitest.res.mjs +0 -3
  79. package/src/db/Table.res +24 -150
  80. package/src/db/Table.res.mjs +38 -272
  81. package/src/sources/ChainSources.res +2 -0
  82. package/src/sources/ChainSources.res.mjs +2 -2
  83. package/src/sources/EvmChain.res +3 -0
  84. package/src/sources/EvmChain.res.mjs +4 -2
  85. package/src/sources/EvmHyperSyncSource.res +2 -2
  86. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  87. package/src/sources/EvmRpcClient.res +13 -3
  88. package/src/sources/EvmRpcClient.res.mjs +4 -3
  89. package/src/sources/EvmRpcWs.res +4 -3
  90. package/src/sources/EvmRpcWs.res.mjs +2 -2
  91. package/src/sources/HeightFeed.res +31 -10
  92. package/src/sources/HeightFeed.res.mjs +10 -6
  93. package/src/sources/HeightStream.res +32 -17
  94. package/src/sources/HeightStream.res.mjs +10 -10
  95. package/src/sources/HyperSyncSSE.res +4 -6
  96. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  97. package/src/sources/RpcSource.res +10 -1
  98. package/src/sources/RpcSource.res.mjs +4 -3
  99. package/src/sources/Source.res +3 -0
  100. package/src/sources/SourceManager.res +85 -104
  101. package/src/sources/SourceManager.res.mjs +18 -37
  102. package/src/sources/SourceManager.resi +3 -5
  103. package/src/sources/StartBlockResolver.res +1 -0
  104. package/src/sources/StartBlockResolver.res.mjs +4 -3
  105. package/src/sources/SvmHyperSyncSource.res +2 -2
  106. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  107. package/src/subgraph/graph-ts.ts +87 -28
  108. package/src/subgraph/runtime.ts +0 -1
  109. package/src/subgraph/scope.ts +0 -1
  110. package/svm.schema.json +3 -3
  111. package/src/PgWriting.res +0 -36
  112. package/src/PgWriting.res.mjs +0 -34
  113. package/src/db/IndexDefinition.res +0 -47
  114. package/src/db/IndexDefinition.res.mjs +0 -60
@@ -1,6 +1,5 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as Fs from "fs";
4
3
  import * as Env from "./Env.res.mjs";
5
4
  import * as Sql from "./db/Sql.res.mjs";
6
5
  import * as Path from "path";
@@ -12,16 +11,16 @@ import * as Logger from "./Logger.res.mjs";
12
11
  import * as Schema from "./db/Schema.res.mjs";
13
12
  import * as ChainId from "./ChainId.res.mjs";
14
13
  import * as Staging from "./Staging.res.mjs";
15
- import * as EntityId from "./EntityId.res.mjs";
16
14
  import * as Frontier from "./db/Frontier.res.mjs";
17
15
  import * as Internal from "./Internal.res.mjs";
18
- import * as PgWriting from "./PgWriting.res.mjs";
19
16
  import * as ChainState from "./ChainState.res.mjs";
20
17
  import * as ClickHouse from "./bindings/ClickHouse.res.mjs";
21
18
  import * as LoadFilter from "./db/LoadFilter.res.mjs";
19
+ import * as StagedRows from "./StagedRows.res.mjs";
22
20
  import * as AddressRows from "./AddressRows.res.mjs";
23
21
  import * as Performance from "./bindings/Performance.res.mjs";
24
22
  import * as Persistence from "./Persistence.res.mjs";
23
+ import * as Stdlib_Null from "@rescript/runtime/lib/es6/Stdlib_Null.js";
25
24
  import * as EntityFilter from "./db/EntityFilter.res.mjs";
26
25
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
27
26
  import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
@@ -30,21 +29,12 @@ import * as HistoryPolicy from "./HistoryPolicy.res.mjs";
30
29
  import * as InternalTable from "./db/InternalTable.res.mjs";
31
30
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
32
31
  import * as StorageClient from "./bindings/StorageClient.res.mjs";
33
- import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
34
32
  import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
35
33
  import * as ContractMapping from "./ContractMapping.res.mjs";
36
- import * as IndexDefinition from "./db/IndexDefinition.res.mjs";
37
34
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
38
35
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
39
- import * as CheckpointSequence from "./db/CheckpointSequence.res.mjs";
40
36
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
41
37
 
42
- function formatSeconds(seconds) {
43
- return (Math.round(seconds * 100) / 100).toString();
44
- }
45
-
46
- let slowOnLargeDatabaseNotice = "This can take a long time on a large database.";
47
-
48
38
  function storeName(store) {
49
39
  if (store === "Postgres") {
50
40
  return "postgres";
@@ -55,83 +45,11 @@ function storeName(store) {
55
45
 
56
46
  let postgresName = "postgres";
57
47
 
58
- function logIndexEvent(logger, pgSchema, event) {
59
- switch (event.kind) {
60
- case "Invalid" :
61
- return Logger.warn(logger, `Ignoring invalid PostgreSQL indexes in schema "` + pgSchema + `". They can't serve queries, so the indexer builds its own alongside them.`, {
62
- storage: postgresName,
63
- indexes: event.names
64
- });
65
- case "Planned" :
66
- let rebuilt = event.rebuilt;
67
- let missing = event.missing;
68
- if (Utils.$$Array.notEmpty(rebuilt)) {
69
- Logger.warn(logger, `PostgreSQL reports ` + rebuilt.length.toString() + ` of the indexer's own indexes as invalid, so they can't serve queries. Rebuilding them.`, {
70
- storage: postgresName,
71
- indexes: rebuilt
72
- });
73
- }
74
- if (missing.length !== 0) {
75
- return Logger.info(logger, `Creating the ` + missing.length.toString() + ` remaining schema indexes before the indexer reports ready. Writes are paused until they are committed. ` + slowOnLargeDatabaseNotice, {
76
- storage: postgresName,
77
- indexes: missing
78
- });
79
- } else {
80
- return Logger.info(logger, `All ` + event.declared.toString() + ` schema indexes are already in place. Marking the indexer ready.`, {
81
- storage: postgresName
82
- });
83
- }
84
- case "Building" :
85
- if (event.purpose === "Query") {
86
- return Logger.info(logger, (
87
- event.isRebuild ? "Rebuilding unusable index" : "Creating index"
88
- ) + ` "` + event.name + `" to serve a getWhere query on "` + event.tableName + `". Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice, {
89
- storage: postgresName
90
- });
91
- } else {
92
- return Logger.info(logger, (
93
- event.isRebuild ? "Rebuilding unusable index" : "Creating missing index"
94
- ) + ` "` + event.name + `" the schema promises but the database no longer has. Writes to the table are paused until it completes. ` + slowOnLargeDatabaseNotice, {
95
- storage: postgresName
96
- });
97
- }
98
- case "Built" :
99
- let tmp;
100
- tmp = event.purpose === "Query" ? " Resuming indexing." : "";
101
- return Logger.info(logger, `Index "` + event.name + `" is ready after ` + formatSeconds(event.seconds) + `s.` + tmp, {
102
- storage: postgresName
103
- });
104
- case "Failed" :
105
- if (event.purpose === "Query") {
106
- return Logger.warn(logger, `Failed to create an index on "` + event.tableName + `"(` + event.columns.map(column => `"` + column + `"`).join(", ") + `) for a getWhere query. The query runs without it.`, {
107
- storage: postgresName,
108
- err: event.error,
109
- code: event.code
110
- });
111
- } else {
112
- return Logger.warn(logger, `Failed to restore the schema index "` + event.name + `". Queries relying on it run unindexed until the next restart.`, {
113
- storage: postgresName,
114
- err: event.error,
115
- code: event.code
116
- });
117
- }
118
- case "ResyncFailed" :
119
- return Logger.trace(logger, `Could not re-read the index "` + event.name + `" after a failed build. The next attempt reads it again.`, {
120
- storage: postgresName,
121
- err: event.error,
122
- code: event.code
123
- });
124
- case "Committed" :
125
- return Logger.info(logger, `Committed ` + event.count.toString() + ` schema indexes and the ready timestamp in ` + formatSeconds(event.seconds) + `s.`, {
126
- storage: postgresName
127
- });
128
- }
129
- }
130
-
131
- function postgresOptions(pgSchemaOpt, isHasuraEnabledOpt, maxConnectionsOpt) {
48
+ function postgresOptions(pgSchemaOpt, isHasuraEnabledOpt, maxConnectionsOpt, isolatedOpt) {
132
49
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
133
50
  let isHasuraEnabled = isHasuraEnabledOpt !== undefined ? isHasuraEnabledOpt : false;
134
51
  let maxConnections = maxConnectionsOpt !== undefined ? maxConnectionsOpt : Env.Db.maxConnections;
52
+ let isolated = isolatedOpt !== undefined ? isolatedOpt : false;
135
53
  return {
136
54
  host: Env.Db.host,
137
55
  port: Env.Db.port,
@@ -142,298 +60,23 @@ function postgresOptions(pgSchemaOpt, isHasuraEnabledOpt, maxConnectionsOpt) {
142
60
  maxConnections: maxConnections,
143
61
  applicationName: `hyperindex/` + Utils.EnvioPackage.value.version,
144
62
  pgSchema: pgSchema,
145
- isHasuraEnabled: isHasuraEnabled
63
+ isHasuraEnabled: isHasuraEnabled,
64
+ isolated: isolated
146
65
  };
147
66
  }
148
67
 
149
- function makeClient(logger, chainIdModeOpt, postgres, clickhouse) {
150
- let chainIdMode = chainIdModeOpt !== undefined ? chainIdModeOpt : "int32";
68
+ function makeClient(logger, config, postgres, clickhouse) {
151
69
  return StorageClient.make({
152
- chainIdMode: chainIdMode,
153
70
  postgres: postgres,
154
71
  clickhouse: clickhouse
155
- }, event => logIndexEvent(logger, postgres.pgSchema, event), message => Logger.warn(logger, message, {
156
- storage: "clickhouse"
157
- }));
158
- }
159
-
160
- function partitionTableName(entityConfig, chainId) {
161
- let chainIdStr = ChainId.toString(chainId);
162
- return Table.fitPgTableName(entityConfig.table.tableName + `$` + chainIdStr, `$` + entityConfig.index.toString() + `$` + chainIdStr);
163
- }
164
-
165
- function indexTableNames(entityConfig, partitionChainIds) {
166
- let match = Table.getChainIdField(entityConfig.table);
167
- if (match !== undefined) {
168
- if (partitionChainIds !== undefined) {
169
- return partitionChainIds.map(chainId => partitionTableName(entityConfig, chainId));
170
- } else {
171
- return [entityConfig.table.tableName];
172
- }
173
- } else {
174
- return [entityConfig.table.tableName];
175
- }
176
- }
177
-
178
- function getSchemaIndexes(entities, partitionChainIds) {
179
- let derivedSchema = Schema.make(entities.map(e => e.table));
180
- let all = [];
181
- entities.forEach(param => {
182
- let table = param.table;
183
- Table.getSingleIndexes(table).forEach(column => {
184
- all.push(IndexDefinition.single(table.tableName, column));
185
- });
186
- Table.getCompositeIndexes(table).forEach(indexFields => {
187
- all.push(IndexDefinition.fromIndexFields(table.tableName, indexFields));
188
- });
189
- });
190
- entities.forEach(param => {
191
- Table.getDerivedFromFields(param.table).forEach(derivedFromField => {
192
- let column = Utils.unwrapResultExn(Schema.getDerivedFromPgFieldName(derivedSchema, derivedFromField));
193
- let isList = Stdlib_Option.mapOr(Stdlib_Option.flatMap(derivedSchema[derivedFromField.derivedFromEntity], table => Table.getFieldByName(table, derivedFromField.derivedFromField)), false, field => {
194
- if (field.TAG === "Field") {
195
- return field._0.isArray;
196
- } else {
197
- return false;
198
- }
199
- });
200
- all.push(IndexDefinition.make(derivedFromField.derivedFromEntity, [{
201
- name: column,
202
- direction: "Asc"
203
- }], isList ? "gin" : undefined));
204
- });
205
- });
206
- let seen = new Set();
207
- let entityByTableName = {};
208
- entities.forEach(entityConfig => {
209
- entityByTableName[entityConfig.table.tableName] = entityConfig;
210
- });
211
- return all.filter(definition => {
212
- let identity = IndexDefinition.describe(definition);
213
- if (seen.has(identity)) {
214
- return false;
215
- } else {
216
- seen.add(identity);
217
- return true;
218
- }
219
- }).flatMap(definition => indexTableNames(Stdlib_Option.getOrThrow(entityByTableName[definition.tableName], undefined), partitionChainIds).map(tableName => ({
220
- tableName: tableName,
221
- columns: definition.columns,
222
- method: definition.method
223
- })));
224
- }
225
-
226
- function pgColumnInput(field) {
227
- let match = Table.pgFieldTypeParts(field.fieldType);
228
- return {
229
- name: Table.getPgDbFieldName(field),
230
- fieldType: match[0],
231
- isArray: field.isArray,
232
- isNullable: field.isNullable,
233
- isPrimaryKey: field.isPrimaryKey,
234
- defaultValue: field.defaultValue,
235
- precision: match[1],
236
- scale: match[2],
237
- enumName: match[3]
238
- };
239
- }
240
-
241
- let rowSchemaCache = new WeakMap();
242
-
243
- function getRowSchema(entityConfig) {
244
- let cached = rowSchemaCache.get(entityConfig);
245
- if (cached !== undefined) {
246
- return Primitive_option.valFromOption(cached);
247
- }
248
- let chainIdField = Table.getChainIdField(entityConfig.table);
249
- let schema = chainIdField !== undefined ? S$RescriptSchema.schema(s => {
250
- let dict = {};
251
- let match = entityConfig.schema.t;
252
- let exit = 0;
253
- if (typeof match !== "object" || match.TAG !== "object") {
254
- exit = 1;
255
- } else {
256
- match.items.forEach(param => {
257
- dict[param.location] = s.m(param.schema);
258
- });
259
- }
260
- if (exit === 1) {
261
- Stdlib_JsError.throwWithMessage(`Unexpected non-object schema for entity "` + entityConfig.name + `".`);
262
- }
263
- dict[chainIdField.fieldName] = s.m(ChainId.schema);
264
- return dict;
265
- }) : entityConfig.schema;
266
- rowSchemaCache.set(entityConfig, schema);
267
- return schema;
268
- }
269
-
270
- function register(client, table, itemSchema, postgresOpt, clickhouse, appendOnlyOpt, history) {
271
- let postgres = postgresOpt !== undefined ? postgresOpt : true;
272
- let appendOnly = appendOnlyOpt !== undefined ? appendOnlyOpt : false;
273
- let fields = Table.schemaOrderedFields(table, itemSchema);
274
- let chainIdField = Table.getChainIdField(table);
275
- let registered = client.registerTable({
276
- name: table.tableName,
277
- postgres: postgres ? ({
278
- columns: Table.getFields(table).map(pgColumnInput),
279
- writeColumns: fields.map(Table.getPgDbFieldName),
280
- partitionByColumn: Stdlib_Option.map(chainIdField, Table.getPgDbFieldName),
281
- appendOnly: appendOnly,
282
- historyTable: history,
283
- chainIdColumn: history !== undefined ? Stdlib_Option.map(chainIdField, Table.getPgDbFieldName) : undefined
284
- }) : undefined,
285
- clickhouse: clickhouse
286
- });
287
- return {
288
- handle: registered.handle,
289
- home: registered.home,
290
- table: table,
291
- fields: fields,
292
- postgres: Stdlib_Option.map(registered.postgres, param => ({
293
- staged: Stdlib_Option.map(param.kinds, kinds => PgWriting.columns(fields, kinds.map(Staging.kindOfOrdinal)))
294
- })),
295
- clickhouse: Stdlib_Option.map(registered.clickhouse, __x => ClickHouse.makeTable(registered.handle, Stdlib_Option.getOr(history, table.tableName), __x))
296
- };
297
- }
298
-
299
- function registerEntity(client, entityConfig) {
300
- return register(client, entityConfig.table, getRowSchema(entityConfig), entityConfig.storage.postgres, entityConfig.storage.clickhouse ? ClickHouse.entityTable(entityConfig) : undefined, undefined, EntityHistory.historyTableName(entityConfig.name, entityConfig.index));
301
- }
302
-
303
- function renderDocument(value, isNullable) {
304
- if (value == null) {
305
- if (value === null && !isNullable) {
306
- return "null";
307
- } else {
308
- return value;
309
- }
310
- } else {
311
- return Sql.stringifyDocument(value);
312
- }
313
- }
314
-
315
- let arenaConverters = new WeakMap();
316
-
317
- let cellConverters = new WeakMap();
318
-
319
- function converterOf(registered, forArena, itemSchema) {
320
- let converters = forArena ? arenaConverters : cellConverters;
321
- let convert = converters.get(itemSchema);
322
- if (convert !== undefined) {
323
- return convert;
324
- }
325
- let documents = Stdlib_Array.filterMapWithIndex(registered.fields, (field, index) => {
326
- if (field.fieldType === "Json") {
327
- return [
328
- index,
329
- field
330
- ];
331
- }
332
- });
333
- let schema = forArena ? Table.toDbSchema(registered.table, itemSchema) : itemSchema;
334
- let convert$1 = S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(schema), param => ({
335
- s: columns => {
336
- documents.forEach(param => {
337
- let field = param[1];
338
- let values = columns[param[0]];
339
- for (let row = 0, row_finish = values.length; row < row_finish; ++row) {
340
- let value = values[row];
341
- values[row] = !(value == null) && field.isArray ? value.map(document => renderDocument(document, true)) : renderDocument(value, field.isNullable);
342
- }
343
- });
344
- return columns;
345
- }
346
- })), "Output", "Input", "Sync", false);
347
- converters.set(itemSchema, convert$1);
348
- return convert$1;
349
- }
350
-
351
- function refuseNonFinite(values, fields) {
352
- fields.forEach((field, index) => {
353
- if (field.fieldType !== "Number") {
354
- return;
355
- }
356
- let column = Table.getPgDbFieldName(field);
357
- let check = value => {
358
- if (value == null) {
359
- return;
360
- }
361
- Staging.finiteOrThrow(value, column);
362
- };
363
- values[index].forEach(value => {
364
- if (!field.isArray) {
365
- return check(value);
366
- }
367
- if (value == null) {
368
- return;
369
- }
370
- value.forEach(check);
371
- });
372
- });
373
- }
374
-
375
- function stagedFor(staged, store, stage) {
376
- let started = Performance.now();
377
- let result = stage();
378
- let name = storeName(store);
379
- staged.seconds[name] = Stdlib_Option.getOr(staged.seconds[name], 0) + Performance.secondsSince(started);
380
- return result;
381
- }
382
-
383
- function rowsOrThrow(client, registered, itemSchema, items, staged) {
384
- return stagedFor(staged, "Postgres", () => {
385
- let rows = items.length;
386
- try {
387
- let match = registered.postgres;
388
- if (match === undefined) {
389
- return Stdlib_JsError.throwWithMessage(`Postgres doesn't keep "` + registered.table.tableName + `"`);
390
- }
391
- let columns = match.staged;
392
- if (columns !== undefined) {
393
- let values = converterOf(registered, true, itemSchema)(items);
394
- let handle = PgWriting.stage(StorageClient.arena(client, "Postgres"), registered.handle, columns, values, rows);
395
- staged.handles.push(handle);
396
- return {
397
- staged: handle,
398
- rows: rows
399
- };
400
- }
401
- let values$1 = converterOf(registered, false, itemSchema)(items);
402
- refuseNonFinite(values$1, registered.fields);
403
- return {
404
- cells: Sql.params(values$1.flat(1)),
405
- rows: rows
406
- };
407
- } catch (raw_exn) {
408
- let exn = Primitive_exceptions.internalToException(raw_exn);
409
- if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
410
- throw {
411
- RE_EXN_ID: Persistence.StorageError,
412
- message: `Failed to convert items for table "` + registered.table.tableName + `"`,
413
- reason: exn,
414
- Error: new Error()
415
- };
416
- }
417
- throw {
418
- RE_EXN_ID: Persistence.StorageError,
419
- message: `Failed to insert items into table "` + registered.table.tableName + `"`,
420
- reason: Utils.prettifyExn(exn),
421
- Error: new Error()
422
- };
423
- }
424
- });
425
- }
426
-
427
- function renderIds(table, ids) {
428
- return Table.encodeIdsToJson(table, ids).map(Sql.render);
72
+ }, Stdlib_Option.map(config, config => JSON.stringify(config.envioInfo)), logger);
429
73
  }
430
74
 
431
75
  function bounds(param) {
432
- let match = Frontier.unnestParams(param.byChain);
76
+ let byChain = param.byChain;
433
77
  return {
434
- sequence: param.sequence,
435
- chainIds: match[0],
436
- checkpointIds: match[1]
78
+ chainIds: Frontier.chainIds(byChain),
79
+ checkpointIds: Frontier.chainIds(byChain).map(chainId => Frontier.get(byChain, chainId))
437
80
  };
438
81
  }
439
82
 
@@ -484,18 +127,71 @@ function storageErrorOf(exn) {
484
127
  }
485
128
  }
486
129
 
487
- let rollbackRowStateSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.object(s => [
488
- s.f(Table.idFieldName, Table.getIdSchema(table)),
489
- s.f(EntityHistory.changeFieldName, EntityHistory.RowAction.schema)
490
- ]));
491
-
492
130
  let rollbackChainIdSchema = Utils.$$WeakMap.memoize(table => Stdlib_Option.map(Table.getChainIdField(table), field => S$RescriptSchema.object(s => s.f(Table.getPgDbFieldName(field), ChainId.schema))));
493
131
 
494
132
  let rollbackRemovedIdSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.object(s => s.f(Table.idFieldName, Table.getIdSchema(table))));
495
133
 
496
- function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onInitialize) {
497
- let entities = entitiesOpt !== undefined ? entitiesOpt : [];
498
- let isolated = isolatedOpt !== undefined ? isolatedOpt : false;
134
+ let changeColumns = [
135
+ {
136
+ name: EntityHistory.checkpointIdFieldName,
137
+ kind: 2,
138
+ isNullable: false
139
+ },
140
+ {
141
+ name: EntityHistory.changeFieldName,
142
+ kind: 0,
143
+ isNullable: false
144
+ }
145
+ ];
146
+
147
+ function stageOrThrow(arena, columns, rows, fill) {
148
+ let stage = Staging.begin(arena, rows, columns);
149
+ try {
150
+ fill(stage);
151
+ return Staging.commit(stage);
152
+ } catch (exn) {
153
+ Staging.abort(stage);
154
+ throw exn;
155
+ }
156
+ }
157
+
158
+ function stageRowsOrThrow(arena, writers, items) {
159
+ return stageOrThrow(arena, StagedRows.columnsOf(writers), items.length, stage => {
160
+ items.forEach((item, row) => {
161
+ writers.forEach((param, column) => StagedRows.writeField(stage, writers, column, row, item[param.field.name]));
162
+ });
163
+ });
164
+ }
165
+
166
+ function stageChangesOrThrow(arena, writers, changes) {
167
+ let fields = writers.length;
168
+ return stageOrThrow(arena, StagedRows.columnsOf(writers).concat(changeColumns), changes.length, stage => {
169
+ changes.forEach((change, row) => {
170
+ let entityId = change.entityId;
171
+ if (change.type === "SET") {
172
+ let entity = change.entity;
173
+ writers.forEach((param, column) => {
174
+ let field = param.field;
175
+ StagedRows.writeField(stage, writers, column, row, field.name === Table.idFieldName ? entityId : entity[field.name]);
176
+ });
177
+ } else {
178
+ writers.forEach((param, column) => {
179
+ if (param.field.name === Table.idFieldName) {
180
+ return StagedRows.writeField(stage, writers, column, row, entityId);
181
+ } else {
182
+ return Staging.writeDeletedValue(stage, column, row, undefined);
183
+ }
184
+ });
185
+ }
186
+ Staging.writeValue(stage, fields, row, change.checkpointId);
187
+ let tmp;
188
+ tmp = change.type === "SET" ? 0 : 1;
189
+ Staging.writeValue(stage, fields + 1 | 0, row, tmp);
190
+ });
191
+ });
192
+ }
193
+
194
+ function make(client, cacheDir, ecosystem, onInitialize) {
499
195
  let eagerSchemaIndexes = Env.subgraphMode.contents;
500
196
  let keptEffectCaches = Env.subgraphMode.contents ? [
501
197
  "envio_subgraph_eth_call",
@@ -506,142 +202,33 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
506
202
  "envio_subgraph_arweave"
507
203
  ] : undefined;
508
204
  let cacheDirPath = cacheDir !== undefined ? Primitive_option.valFromOption(cacheDir) : Path.resolve(".envio", "cache");
509
- let registry = {};
510
- let registered = (table, register) => {
511
- let registered$1 = registry[table.tableName];
512
- if (registered$1 !== undefined) {
513
- return registered$1;
514
- }
515
- let registered$2 = register();
516
- registry[table.tableName] = registered$2;
517
- return registered$2;
518
- };
519
- let entityTable = entityConfig => registered(entityConfig.table, () => registerEntity(client, entityConfig));
520
- let ownTable = (table, itemSchema, appendOnly) => registered(table, () => register(client, table, itemSchema, undefined, undefined, appendOnly, undefined));
521
- let rawEventsTable = () => ownTable(InternalTable.RawEvents.table, InternalTable.RawEvents.schema, true);
522
- entities.forEach(entityConfig => {
523
- entityTable(entityConfig);
205
+ let layouts = client.layouts();
206
+ let entityIndexByName = {};
207
+ layouts.entities.forEach((layout, index) => {
208
+ entityIndexByName[layout.name] = index;
524
209
  });
525
- let tableOf = table => {
526
- let registered = registry[table.tableName];
527
- if (registered !== undefined) {
528
- return registered;
529
- } else if (Stdlib_Option.isSome(Internal.EffectCache.fromTableName(table.tableName))) {
530
- return ownTable(table, Internal.cacheItemSchema, undefined);
531
- } else {
532
- return Stdlib_JsError.throwWithMessage(`The storage has no table "` + table.tableName + `".`);
533
- }
534
- };
535
- let partitions = (entities, chainIds) => entities.filter(entityConfig => {
536
- if (entityConfig.storage.postgres) {
537
- return Stdlib_Option.isSome(Table.getChainIdField(entityConfig.table));
538
- } else {
539
- return false;
540
- }
541
- }).flatMap(entityConfig => chainIds.map(chainId => ({
542
- table: entityTable(entityConfig).handle,
543
- chainId: chainId,
544
- name: partitionTableName(entityConfig, chainId)
545
- })));
210
+ let entityWriters = layouts.entities.map(layout => StagedRows.writersOf(layout.fields));
211
+ let rawEventWriters = StagedRows.writersOf(layouts.rawEvents);
212
+ let effectCacheWriters = StagedRows.writersOf(layouts.effectCache);
546
213
  let holding = () => client.holding();
547
- let scanCacheDir = async () => {
548
- let topEntries;
549
- try {
550
- topEntries = await Fs.promises.readdir(cacheDirPath);
551
- } catch (exn) {
552
- topEntries = [];
553
- }
554
- let result = [];
555
- await Promise.all(topEntries.map(async entry => {
556
- let entryPath = Path.join(cacheDirPath, entry);
557
- let isDir = (await Fs.promises.stat(entryPath)).isDirectory();
558
- if (isDir) {
559
- let subEntries = await Fs.promises.readdir(entryPath);
560
- let tsvs = subEntries.filter(sub => sub.endsWith(".tsv"));
561
- let chainId = Internal.EffectCache.parseChainId(entry);
562
- if (chainId === undefined) {
563
- if (Utils.$$Array.notEmpty(tsvs)) {
564
- return Stdlib_JsError.throwWithMessage(`Invalid effect cache directory ".envio/cache/` + entry + `". Chain cache directories must be named by a numeric chain id (e.g. "1"). Found cache files: ` + tsvs.join(", ") + `.`);
565
- } else {
566
- return;
567
- }
568
- }
569
- let chainId$1 = Primitive_option.valFromOption(chainId);
570
- tsvs.forEach(sub => {
571
- let effectName = sub.slice(0, -4);
572
- let table = Internal.makeCacheTable(effectName, chainId$1);
573
- result.push([
574
- table,
575
- Path.join(entryPath, sub)
576
- ]);
577
- });
578
- return;
579
- }
580
- if (!entry.endsWith(".tsv")) {
581
- return;
582
- }
583
- let effectName = entry.slice(0, -4);
584
- let table = Internal.makeCacheTable(effectName, "crossChain");
585
- result.push([
586
- table,
587
- entryPath
588
- ]);
589
- }));
590
- return result;
591
- };
592
214
  let restoreEffectCache = async withUpload => {
593
- if (withUpload) {
594
- let entries = await scanCacheDir();
595
- if (entries.length !== 0) {
596
- try {
597
- await client.uploadEffectCache(entries.map(param => ({
598
- table: ownTable(param[0], Internal.cacheItemSchema, undefined).handle,
599
- path: param[1]
600
- })));
601
- Logger.info(logger, "Successfully uploaded cache.", undefined);
602
- } catch (raw_exn) {
603
- let exn = Primitive_exceptions.internalToException(raw_exn);
604
- Logger.errorWithExn(logger, "Failed to upload cache, continuing without it.", exn);
605
- }
606
- } else {
607
- Logger.info(logger, "No saved effect cache to load from .envio/cache.", undefined);
608
- }
609
- }
610
215
  let cache = {};
611
- (await client.effectCacheTables()).forEach(param => {
216
+ (await client.restoreEffectCache(cacheDirPath, withUpload)).forEach(param => {
612
217
  let tableName = param.tableName;
613
- let match = Internal.EffectCache.fromTableName(tableName);
614
- if (match !== undefined) {
615
- cache[tableName] = {
616
- effectName: match[0],
617
- scope: match[1],
618
- tableName: tableName,
619
- count: param.rows
620
- };
621
- return;
622
- }
218
+ let chainId = param.chainId;
219
+ cache[tableName] = {
220
+ effectName: param.effectName,
221
+ scope: chainId !== undefined ? Primitive_option.valFromOption(chainId) : "crossChain",
222
+ tableName: tableName,
223
+ count: param.rows
224
+ };
623
225
  });
624
226
  return cache;
625
227
  };
626
- let partitionChainIds = chainIds => {
627
- if (isolated) {
628
- return Primitive_option.some(chainIds);
629
- }
630
- };
631
- let schemaIndexes = (entities, chainIds) => getSchemaIndexes(entities.filter(e => e.storage.postgres), partitionChainIds(chainIds)).map(IndexDefinition.toInput);
632
- let initialize = async (chainConfigsOpt, entitiesOpt, enumsOpt, contractMapping, envioInfo) => {
228
+ let initialize = async (chainConfigsOpt, contractMapping, envioInfo) => {
633
229
  let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
634
- let entities = entitiesOpt !== undefined ? entitiesOpt : [];
635
- let enums = enumsOpt !== undefined ? enumsOpt : [];
636
230
  let rowsByChain = chainConfigs.map(chainConfig => ChainState.configStorageRows(chainConfig, ecosystem, contractMapping));
637
231
  await client.initialize({
638
- sequence: CheckpointSequence.fromEntities(entities),
639
- tables: [rawEventsTable().handle].concat(entities.map(entityConfig => entityTable(entityConfig).handle)),
640
- partitions: partitions(entities, chainConfigs.map(chainConfig => chainConfig.id)),
641
- enums: enums.map(enumConfig => ({
642
- name: enumConfig.name,
643
- variants: enumConfig.variants
644
- })),
645
232
  chains: chainConfigs.map(toChainConfig),
646
233
  envioInfo: JSON.stringify(envioInfo),
647
234
  contractNames: ContractMapping.names(contractMapping),
@@ -649,7 +236,7 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
649
236
  keptEffectCaches: keptEffectCaches
650
237
  });
651
238
  if (eagerSchemaIndexes) {
652
- await client.ensureSchemaIndexes(schemaIndexes(entities, chainConfigs.map(chainConfig => chainConfig.id)));
239
+ await client.ensureSchemaIndexes(chainConfigs.map(chainConfig => chainConfig.id));
653
240
  }
654
241
  let cache = await restoreEffectCache(true);
655
242
  if (onInitialize !== undefined) {
@@ -678,9 +265,11 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
678
265
  };
679
266
  let loadOrThrow = async (filter, table) => {
680
267
  let conditions = LoadFilter.make(filter, table, field => field.pgDbFieldName);
268
+ let entity = entityIndexByName[table.tableName];
269
+ let loading = entity !== undefined ? StorageClient.loadWhere(client, entity, conditions) : StorageClient.loadEffectCache(client, table.tableName, conditions);
681
270
  let rows;
682
271
  try {
683
- rows = await StorageClient.loadWhere(client, tableOf(table).handle, conditions);
272
+ rows = await loading;
684
273
  } catch (raw_exn) {
685
274
  let exn = Primitive_exceptions.internalToException(raw_exn);
686
275
  throw {
@@ -720,44 +309,17 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
720
309
  }));
721
310
  return columns;
722
311
  };
723
- let queryTableName = (entityConfig, scope) => {
724
- if (scope === "crossChain") {
725
- return entityConfig.table.tableName;
726
- } else {
727
- return indexTableNames(entityConfig, partitionChainIds([scope]))[0];
728
- }
729
- };
730
312
  let ensureQueryIndexes = async (entityConfig, scope, filters) => {
731
- let building = client.ensureQueryIndexes(entityTable(entityConfig).handle, queryTableName(entityConfig, scope), filterColumns(entityConfig.table, filters));
313
+ let building = client.ensureQueryIndexes(entityConfig.index, Stdlib_Null.fromOption(Internal.chainScopeChainId(scope)), filterColumns(entityConfig.table, filters));
732
314
  if (building === null) {
733
315
  return;
734
316
  } else {
735
317
  return await building;
736
318
  }
737
319
  };
738
- let ensureSchemaIndexes = (entities, chainIds) => client.ensureSchemaIndexes(schemaIndexes(entities, chainIds));
739
- let finalizeBackfill = (entities, chainIds, readyAt) => client.finalizeBackfill(schemaIndexes(entities, chainIds), chainIds, readyAt.getTime());
740
- let dumpEffectCache = async () => {
741
- try {
742
- let tables = (await client.effectCacheTables()).filter(param => param.rows > 0);
743
- if (Utils.$$Array.notEmpty(tables)) {
744
- Logger.info(logger, `Dumping cache: ` + tables.map(param => param.tableName + " (" + param.rows.toString() + " rows)").join(", "), undefined);
745
- await client.dumpEffectCache(Stdlib_Array.filterMap(tables, param => {
746
- let tableName = param.tableName;
747
- return Stdlib_Option.map(Internal.EffectCache.fromTableName(tableName), param => ({
748
- tableName: tableName,
749
- path: Path.join(cacheDirPath, Internal.EffectCache.toCachePath(param[0], param[1]))
750
- }));
751
- }));
752
- return Logger.info(logger, `Successfully dumped cache to ` + cacheDirPath, undefined);
753
- } else {
754
- return;
755
- }
756
- } catch (raw_exn) {
757
- let exn = Primitive_exceptions.internalToException(raw_exn);
758
- return Logger.errorWithExn(logger, `Failed to dump cache.`, exn);
759
- }
760
- };
320
+ let ensureSchemaIndexes = chainIds => client.ensureSchemaIndexes(chainIds);
321
+ let finalizeBackfill = (chainIds, readyAt) => client.finalizeBackfill(chainIds, readyAt.getTime());
322
+ let dumpEffectCache = () => client.dumpEffectCache(cacheDirPath);
761
323
  let readStoredConfig = async () => {
762
324
  let stored = await client.readStoredConfig();
763
325
  let configAddresses = StorageClient.read(client, stored.configAddresses);
@@ -795,19 +357,14 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
795
357
  contractMapping: ContractMapping.fromStoredNames(match$1)
796
358
  };
797
359
  };
798
- let addChain = (chainConfig, entities, contractMapping) => client.addChain({
360
+ let addChain = (chainConfig, contractMapping) => client.addChain({
799
361
  chain: toChainConfig(chainConfig),
800
- partitions: partitions(entities, [chainConfig.id]),
801
362
  addresses: addressColumns(ChainState.configStorageRows(chainConfig, ecosystem, contractMapping))
802
363
  });
803
- let resumeInitialState = async (entities, chainIds, contractMapping) => {
364
+ let resumeInitialState = async (chainIds, contractMapping) => {
804
365
  let match = await Promise.all([
805
366
  restoreEffectCache(false),
806
- client.resume({
807
- sequence: CheckpointSequence.fromEntities(entities),
808
- tables: entities.map(entityConfig => entityTable(entityConfig).handle),
809
- chainIds: chainIds
810
- })
367
+ client.resume(chainIds)
811
368
  ]);
812
369
  let resumed = match[1];
813
370
  let addressRowsByChainId = AddressRows.group(StorageClient.read(client, resumed.addresses));
@@ -834,10 +391,10 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
834
391
  });
835
392
  let checkpointFrontier = Frontier.fromEntries(stored.map(param => [
836
393
  param[0],
837
- BigInt(param[1].checkpointId)
394
+ param[1].checkpointId
838
395
  ]));
839
396
  let reorgCheckpoints = resumed.reorgCheckpoints.map(checkpoint => ({
840
- id: BigInt(checkpoint.id),
397
+ id: checkpoint.id,
841
398
  chain_id: ChainId.normalizeOrThrow(checkpoint.chainId),
842
399
  block_number: checkpoint.blockNumber,
843
400
  block_hash: checkpoint.blockHash
@@ -864,15 +421,15 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
864
421
  });
865
422
  let setChainMeta = chainsData => client.setChainMeta(chainMeta(chainsData)).then(() => (undefined));
866
423
  let pruneStaleCheckpoints = safeCheckpoints => client.pruneCheckpoints(bounds(safeCheckpoints));
867
- let pruneStaleEntityHistory = (entityConfig, safeCheckpoints) => client.pruneHistory(entityTable(entityConfig).handle, bounds(safeCheckpoints));
868
- let getRollbackTargetCheckpoint = async (reorgChainId, lastKnownValidBlockNumber, sequence) => Stdlib_Option.map(Primitive_option.fromNullable(await client.rollbackTargetCheckpoint(reorgChainId, lastKnownValidBlockNumber, sequence)), prim => BigInt(prim));
424
+ let pruneStaleEntityHistory = (entityConfig, safeCheckpoints) => client.pruneHistory(entityConfig.index, bounds(safeCheckpoints));
425
+ let getRollbackTargetCheckpoint = async (reorgChainId, lastKnownValidBlockNumber) => Primitive_option.fromNullable(await client.rollbackTargetCheckpoint(reorgChainId, lastKnownValidBlockNumber));
869
426
  let getRollbackProgressDiff = async floors => (await client.rollbackProgressDiff(bounds(floors.checkpointBounds))).map(diff => ({
870
427
  chain_id: ChainId.normalizeOrThrow(diff.chainId),
871
428
  events_processed_diff: diff.eventsProcessed,
872
429
  new_progress_block_number: diff.progressBlock
873
430
  }));
874
431
  let getRollbackData = async (entityConfig, floors) => {
875
- let match = await client.rollbackData(entityTable(entityConfig).handle, bounds(floors.checkpointBounds));
432
+ let match = await client.rollbackData(entityConfig.index, bounds(floors.checkpointBounds));
876
433
  let restored = match.restored;
877
434
  let removedIdRows;
878
435
  try {
@@ -890,29 +447,28 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
890
447
  return "crossChain";
891
448
  }
892
449
  };
893
- let removals = removedIdRows.map(row => ({
894
- entityId: S$RescriptSchema.parseOrThrow(row, rollbackRemovedIdSchema(entityConfig.table)),
895
- scope: scopeOf(row)
896
- }));
897
- let restoredEntitiesResult = [];
898
- rollbackRows.forEach(row => {
899
- let match = S$RescriptSchema.parseOrThrow(row, rollbackRowStateSchema(entityConfig.table));
900
- if (match[1] === "SET") {
901
- restoredEntitiesResult.push(row);
902
- return;
903
- }
904
- removals.push({
905
- entityId: match[0],
906
- scope: scopeOf(row)
907
- });
908
- });
909
450
  return [
910
- removals,
911
- S$RescriptSchema.parseOrThrow(restoredEntitiesResult, Table.pgRowsSchema(entityConfig.table))
451
+ removedIdRows.map(row => ({
452
+ entityId: S$RescriptSchema.parseOrThrow(row, rollbackRemovedIdSchema(entityConfig.table)),
453
+ scope: scopeOf(row)
454
+ })),
455
+ S$RescriptSchema.parseOrThrow(rollbackRows, Table.pgRowsSchema(entityConfig.table))
912
456
  ];
913
457
  };
914
- let writeBatch = async (batch, rollback, config, allEntities, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
915
- let match = Frontier.unnestParams(Persistence.writtenFrontier(batch, rollback));
458
+ let stageRows = (table, writers, items) => stageRowsOrThrow(StorageClient.arena(client, rows => client.beginRows(table, rows)), writers, items);
459
+ let stageChanges = param => {
460
+ let entityConfig = param.entityConfig;
461
+ return stageChangesOrThrow(StorageClient.arena(client, rows => client.beginChanges(entityConfig.index, rows)), entityWriters[entityConfig.index], param.changes);
462
+ };
463
+ let changesErrorOf = (entityConfig, exn) => ({
464
+ RE_EXN_ID: Persistence.StorageError,
465
+ message: entityConfig.storage.postgres ? `Failed to insert items into table "` + entityConfig.table.tableName + `"` : `Failed to convert items for ClickHouse table "` + EntityHistory.historyTableName(entityConfig.name, entityConfig.index) + `"`,
466
+ reason: Utils.prettifyExn(exn)
467
+ });
468
+ let writeBatch = async (batch, rollback, config, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
469
+ let frontier = Persistence.writtenFrontier(batch, rollback);
470
+ let chainIds = Frontier.chainIds(frontier);
471
+ let frontierCheckpointIds = chainIds.map(chainId => Frontier.get(frontier, chainId));
916
472
  let rawEvents;
917
473
  if (config.enableRawEvents) {
918
474
  let seenLogCoordinates = new Set();
@@ -931,21 +487,35 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
931
487
  } else {
932
488
  rawEvents = [];
933
489
  }
934
- let staged_handles = [];
935
- let staged_seconds = {};
936
- let staged = {
937
- handles: staged_handles,
938
- seconds: staged_seconds
490
+ let handles = [];
491
+ let staged = handle => {
492
+ handles.push(handle);
493
+ return handle;
494
+ };
495
+ let stagingStarted = Performance.now();
496
+ let clickHouseStagingSeconds = {
497
+ contents: 0
498
+ };
499
+ let clickHouseOnlyStagingSeconds = {
500
+ contents: 0
939
501
  };
940
502
  let input;
941
503
  try {
942
504
  let tmp;
943
505
  if (Utils.$$Array.notEmpty(rawEvents)) {
944
- let table = rawEventsTable();
945
- tmp = {
946
- table: table.handle,
947
- rows: rowsOrThrow(client, table, InternalTable.RawEvents.schema, rawEvents, staged)
948
- };
506
+ let tmp$1;
507
+ try {
508
+ tmp$1 = staged(stageRows("RawEvents", rawEventWriters, rawEvents));
509
+ } catch (raw_exn) {
510
+ let exn = Primitive_exceptions.internalToException(raw_exn);
511
+ throw {
512
+ RE_EXN_ID: Persistence.StorageError,
513
+ message: `Failed to insert items into table "` + InternalTable.RawEvents.table.tableName + `"`,
514
+ reason: Utils.prettifyExn(exn),
515
+ Error: new Error()
516
+ };
517
+ }
518
+ tmp = tmp$1;
949
519
  } else {
950
520
  tmp = undefined;
951
521
  }
@@ -954,7 +524,6 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
954
524
  let rolledBackAddresses = param.rolledBackAddresses;
955
525
  return {
956
526
  bounds: bounds(param.floors.checkpointBounds),
957
- tables: allEntities.map(entityConfig => entityTable(entityConfig).handle),
958
527
  progress: param.progressedChains.map(progress),
959
528
  removedAddresses: {
960
529
  chainIds: rolledBackAddresses.map(key => key.chainId),
@@ -963,7 +532,7 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
963
532
  },
964
533
  diffCheckpoints: param.diffCheckpoints.map(diff => ({
965
534
  chainId: diff.chainId,
966
- checkpointId: diff.checkpointId.toString(),
535
+ checkpointId: diff.checkpointId,
967
536
  blockNumber: diff.blockNumber
968
537
  }))
969
538
  };
@@ -976,124 +545,41 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
976
545
  totalEventsProcessed: chainAfterBatch.totalEventsProcessed
977
546
  })),
978
547
  rawEvents: tmp,
979
- entities: updatedEntities.map(update => {
980
- let shouldSaveHistory = update.shouldSaveHistory;
981
- let changes = update.changes;
982
- let scope = update.scope;
983
- let entityConfig = update.entityConfig;
984
- let table = entityTable(entityConfig);
985
- let match = Table.getChainIdField(entityConfig.table);
986
- let chainIdStamp = match !== undefined && scope !== "crossChain" ? [
987
- match,
988
- scope
989
- ] : undefined;
990
- let postgresWrite = () => {
991
- let stamped;
992
- if (chainIdStamp !== undefined) {
993
- let chainId = chainIdStamp[1];
994
- let field = chainIdStamp[0];
995
- stamped = changes.map(change => {
996
- if (change.type === "SET") {
997
- return {
998
- type: "SET",
999
- entityId: change.entityId,
1000
- entity: Internal.stampChainId(change.entity, field.fieldName, chainId),
1001
- checkpointId: change.checkpointId
1002
- };
1003
- } else {
1004
- return change;
1005
- }
1006
- });
1007
- } else {
1008
- stamped = changes;
1009
- }
1010
- let diffCheckpointId = Stdlib_Option.flatMap(rollback, r => CheckpointSequence.findForScope(config.checkpointSequence, r.diffFrontier, scope));
1011
- let historySets = [];
1012
- let historySetCheckpointIds = [];
1013
- let historyDeleteIds = [];
1014
- let historyDeleteCheckpointIds = [];
1015
- let idsWithDiff = new Set();
1016
- let latestChangeById = {};
1017
- let orderedIds = [];
1018
- stamped.forEach(change => {
1019
- let entityId = change.entityId;
1020
- let entityKey = EntityId.toKey(entityId);
1021
- if (Stdlib_Option.isNone(latestChangeById[entityKey])) {
1022
- orderedIds.push(entityId);
1023
- }
1024
- latestChangeById[entityKey] = change;
1025
- if (!shouldSaveHistory) {
1026
- return;
1027
- }
1028
- if (change.checkpointId === diffCheckpointId) {
1029
- idsWithDiff.add(entityKey);
1030
- return;
1031
- }
1032
- if (change.type === "SET") {
1033
- historySets.push(change.entity);
1034
- historySetCheckpointIds.push(change.checkpointId.toString());
1035
- return;
1036
- }
1037
- historyDeleteIds.push(change.entityId);
1038
- historyDeleteCheckpointIds.push(change.checkpointId.toString());
1039
- });
1040
- let sets = [];
1041
- let deletes = [];
1042
- let backfill = [];
1043
- orderedIds.forEach(entityId => {
1044
- let entityKey = EntityId.toKey(entityId);
1045
- let match = latestChangeById[entityKey];
1046
- if (match.type === "SET") {
1047
- sets.push(match.entity);
1048
- } else {
1049
- deletes.push(match.entityId);
1050
- }
1051
- if (shouldSaveHistory && !idsWithDiff.has(entityKey)) {
1052
- backfill.push(entityId);
1053
- return;
1054
- }
1055
- });
1056
- let rowsOf = entities => {
1057
- if (Utils.$$Array.notEmpty(entities)) {
1058
- return rowsOrThrow(client, table, getRowSchema(entityConfig), entities, staged);
1059
- }
1060
- };
1061
- return {
1062
- sets: rowsOf(sets),
1063
- deletes: renderIds(entityConfig.table, deletes),
1064
- history: shouldSaveHistory ? ({
1065
- backfill: renderIds(entityConfig.table, backfill),
1066
- sets: rowsOf(historySets),
1067
- setCheckpointIds: historySetCheckpointIds,
1068
- deleteIds: renderIds(entityConfig.table, historyDeleteIds),
1069
- deleteCheckpointIds: historyDeleteCheckpointIds
1070
- }) : undefined
1071
- };
1072
- };
1073
- let match$1 = table.clickhouse;
1074
- let tmp;
1075
- if (changes.length !== 0 && match$1 !== undefined) {
1076
- let handle = stagedFor(staged, "ClickHouse", () => ClickHouse.stageChangesOrThrow(StorageClient.arena(client, "ClickHouse"), match$1, entityConfig, scope, changes));
1077
- staged_handles.push(handle);
1078
- tmp = handle;
1079
- } else {
1080
- tmp = undefined;
548
+ changes: Stdlib_Array.filterMap(updatedEntities, update => {
549
+ let match = update.changes;
550
+ if (match.length === 0) {
551
+ return;
552
+ }
553
+ let started = Performance.now();
554
+ let handle;
555
+ try {
556
+ handle = staged(stageChanges(update));
557
+ } catch (raw_exn) {
558
+ let exn = Primitive_exceptions.internalToException(raw_exn);
559
+ throw changesErrorOf(update.entityConfig, exn);
560
+ }
561
+ let seconds = Performance.secondsSince(started);
562
+ if (update.entityConfig.storage.clickhouse) {
563
+ clickHouseStagingSeconds.contents = clickHouseStagingSeconds.contents + seconds;
564
+ }
565
+ if (!update.entityConfig.storage.postgres) {
566
+ clickHouseOnlyStagingSeconds.contents = clickHouseOnlyStagingSeconds.contents + seconds;
1081
567
  }
1082
568
  return {
1083
- table: table.handle,
1084
- chainId: Stdlib_Option.map(chainIdStamp, param => param[1]),
1085
- postgres: Stdlib_Option.map(table.postgres, param => postgresWrite()),
1086
- clickhouse: tmp
569
+ entity: update.entityConfig.index,
570
+ chainId: Internal.chainScopeChainId(update.scope),
571
+ keepsHistory: update.shouldSaveHistory,
572
+ changes: handle
1087
573
  };
1088
574
  }),
1089
575
  chainMeta: Stdlib_Option.mapOr(chainMetaData, [], chainMeta),
1090
576
  addresses: addressColumns(registeredAddresses.map(staged => staged.row)),
1091
577
  frontier: {
1092
- chainIds: match[0],
1093
- checkpointIds: match[1]
578
+ chainIds: chainIds,
579
+ checkpointIds: frontierCheckpointIds
1094
580
  },
1095
581
  checkpoints: {
1096
- ids: batch.checkpointIds.map(id => id.toString()),
582
+ ids: batch.checkpointIds,
1097
583
  chainIds: batch.checkpointChainIds,
1098
584
  blockNumbers: batch.checkpointBlockNumbers,
1099
585
  blockHashes: batch.checkpointBlockHashes,
@@ -1101,35 +587,59 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1101
587
  keepsHistory: batch.checkpointChainIds.map(chainId => HistoryPolicy.forChain(batch.history, chainId))
1102
588
  },
1103
589
  effectCaches: updatedEffectsCache.map(param => {
1104
- let registered = ownTable(param.table, Internal.cacheItemSchema, undefined);
590
+ let itemSchema = param.itemSchema;
591
+ let table = param.table;
592
+ let tmp;
593
+ try {
594
+ tmp = staged(stageRows("EffectCache", effectCacheWriters, param.items.map(item => S$RescriptSchema.reverseConvertOrThrow(item, itemSchema))));
595
+ } catch (raw_exn) {
596
+ let exn = Primitive_exceptions.internalToException(raw_exn);
597
+ if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
598
+ throw {
599
+ RE_EXN_ID: Persistence.StorageError,
600
+ message: `Failed to convert items for table "` + table.tableName + `"`,
601
+ reason: exn,
602
+ Error: new Error()
603
+ };
604
+ }
605
+ throw {
606
+ RE_EXN_ID: Persistence.StorageError,
607
+ message: `Failed to insert items into table "` + table.tableName + `"`,
608
+ reason: Utils.prettifyExn(exn),
609
+ Error: new Error()
610
+ };
611
+ }
1105
612
  return {
1106
- table: registered.handle,
613
+ table: table.tableName,
1107
614
  create: param.shouldInitialize,
1108
- rows: rowsOrThrow(client, registered, param.itemSchema, param.items, staged)
615
+ rows: tmp
1109
616
  };
1110
617
  })
1111
618
  };
1112
- } catch (exn) {
1113
- client.discardStaged(staged_handles);
1114
- throw exn;
619
+ } catch (exn$1) {
620
+ client.discardStaged(handles);
621
+ throw exn$1;
1115
622
  }
623
+ let postgresStagingSeconds = Performance.secondsSince(stagingStarted) - clickHouseOnlyStagingSeconds.contents;
1116
624
  let timings;
1117
625
  try {
1118
626
  timings = await client.writeBatch(input);
1119
- } catch (raw_exn) {
1120
- let exn$1 = Primitive_exceptions.internalToException(raw_exn);
1121
- client.discardStaged(staged_handles);
1122
- throw storageErrorOf(exn$1);
627
+ } catch (raw_exn$1) {
628
+ let exn$2 = Primitive_exceptions.internalToException(raw_exn$1);
629
+ client.discardStaged(handles);
630
+ throw storageErrorOf(exn$2);
1123
631
  }
1124
632
  timings.forEach(param => {
1125
- let name = storeName(param.store);
1126
- onWrite(name, param.seconds + Stdlib_Option.getOr(staged_seconds[name], 0));
633
+ let store = param.store;
634
+ let tmp;
635
+ tmp = store === "Postgres" ? postgresStagingSeconds : clickHouseStagingSeconds.contents;
636
+ onWrite(storeName(store), param.seconds + tmp);
1127
637
  });
1128
638
  };
1129
639
  let close = () => client.close();
1130
640
  return {
1131
641
  name: postgresName,
1132
- entityStoreName: entityConfig => storeName(entityTable(entityConfig).home),
642
+ entityStoreName: entityConfig => Stdlib_Option.mapOr(layouts.entities[entityConfig.index].home, postgresName, storeName),
1133
643
  holding: holding,
1134
644
  initialize: initialize,
1135
645
  readStoredConfig: readStoredConfig,
@@ -1154,13 +664,13 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1154
664
 
1155
665
  function clientFromEnv(config, logger, pgSchemaOpt, isHasuraEnabled, maxConnections) {
1156
666
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1157
- return makeClient(logger, config.chainIdMode, postgresOptions(pgSchema, isHasuraEnabled, maxConnections), config.storage.clickhouse ? ClickHouse.optionsFromEnvOrThrow() : undefined);
667
+ return makeClient(logger, config, postgresOptions(pgSchema, isHasuraEnabled, maxConnections, config.isolated), config.storage.clickhouse ? ClickHouse.optionsFromEnvOrThrow() : undefined);
1158
668
  }
1159
669
 
1160
670
  function makeStorageFromEnv(config, logger, pgSchemaOpt, isHasuraEnabledOpt, maxConnections, cacheDir) {
1161
671
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1162
672
  let isHasuraEnabled = isHasuraEnabledOpt !== undefined ? isHasuraEnabledOpt : Env.Hasura.enabled;
1163
- return make(clientFromEnv(config, logger, pgSchema, isHasuraEnabled, maxConnections), logger, config.userEntities, cacheDir, config.ecosystem.name, config.isolated, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(logger, Env.Hasura.graphqlEndpoint, {
673
+ return make(clientFromEnv(config, logger, pgSchema, isHasuraEnabled, maxConnections), cacheDir, config.ecosystem.name, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(logger, Env.Hasura.graphqlEndpoint, {
1164
674
  role: Env.Hasura.role,
1165
675
  secret: Env.Hasura.secret
1166
676
  }, pgSchema, Config.getPgUserEntities(config), Env.Hasura.aggregateEntities, Env.Hasura.responseLimit, Schema.make(config.userEntities.map(e => e.table))), err => Promise.resolve(Logger.errorWithExn(logger, `Error tracking tables`, err))) : undefined);
@@ -1172,36 +682,24 @@ function makePersistenceFromConfig(config, logger, storageOpt) {
1172
682
  }
1173
683
 
1174
684
  export {
1175
- formatSeconds,
1176
- slowOnLargeDatabaseNotice,
1177
685
  storeName,
1178
686
  postgresName,
1179
- logIndexEvent,
1180
687
  postgresOptions,
1181
688
  makeClient,
1182
- partitionTableName,
1183
- indexTableNames,
1184
- getSchemaIndexes,
1185
- pgColumnInput,
1186
- rowSchemaCache,
1187
- getRowSchema,
1188
- registerEntity,
1189
- arenaConverters,
1190
- cellConverters,
1191
- converterOf,
1192
- stagedFor,
1193
- renderIds,
1194
689
  bounds,
1195
690
  progress,
1196
691
  addressColumns,
1197
692
  toChainConfig,
1198
693
  storageErrorOf,
1199
- rollbackRowStateSchema,
1200
694
  rollbackChainIdSchema,
1201
695
  rollbackRemovedIdSchema,
696
+ changeColumns,
697
+ stageOrThrow,
698
+ stageRowsOrThrow,
699
+ stageChangesOrThrow,
1202
700
  make,
1203
701
  clientFromEnv,
1204
702
  makeStorageFromEnv,
1205
703
  makePersistenceFromConfig,
1206
704
  }
1207
- /* rowSchemaCache Not a pure module */
705
+ /* rollbackChainIdSchema Not a pure module */