envio 3.15.0-subgraph → 3.16.0

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 (186) 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 +9 -10
  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/Bin.res +0 -7
  11. package/src/Bin.res.mjs +0 -8
  12. package/src/ChainFetching.res +17 -456
  13. package/src/ChainFetching.res.mjs +33 -404
  14. package/src/ChainState.res +48 -83
  15. package/src/ChainState.res.mjs +83 -115
  16. package/src/ChainState.resi +0 -26
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +7 -16
  20. package/src/Config.res.mjs +4 -11
  21. package/src/ContractRegisterContext.res +6 -3
  22. package/src/ContractRegisterContext.res.mjs +2 -4
  23. package/src/Core.res +5 -136
  24. package/src/Core.res.mjs +1 -90
  25. package/src/CrossChainState.res +2 -8
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +4 -7
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectState.res +10 -2
  30. package/src/EffectState.res.mjs +8 -4
  31. package/src/EffectState.resi +3 -1
  32. package/src/EntityId.res +2 -7
  33. package/src/EntityId.res.mjs +1 -8
  34. package/src/EntityTables.res +4 -1
  35. package/src/EntityTables.res.mjs +1 -1
  36. package/src/Env.res +0 -16
  37. package/src/Env.res.mjs +0 -11
  38. package/src/EventProcessing.res +1 -38
  39. package/src/EventProcessing.res.mjs +1 -28
  40. package/src/FetchState.res +160 -319
  41. package/src/FetchState.res.mjs +182 -292
  42. package/src/FinalizeBackfill.res +2 -4
  43. package/src/FinalizeBackfill.res.mjs +3 -4
  44. package/src/HandlerLoader.res +15 -39
  45. package/src/HandlerLoader.res.mjs +8 -27
  46. package/src/HandlerRegister.res +0 -4
  47. package/src/HandlerRegister.res.mjs +2 -5
  48. package/src/HandlerRegister.resi +0 -2
  49. package/src/InMemoryTable.res +17 -16
  50. package/src/InMemoryTable.res.mjs +14 -15
  51. package/src/IndexerState.res +28 -4
  52. package/src/IndexerState.res.mjs +19 -6
  53. package/src/IndexerState.resi +4 -0
  54. package/src/Internal.res +0 -110
  55. package/src/Internal.res.mjs +1 -115
  56. package/src/LoadLayer.res +21 -47
  57. package/src/LoadLayer.res.mjs +47 -72
  58. package/src/LoadLayer.resi +0 -26
  59. package/src/Main.res +1 -14
  60. package/src/Main.res.mjs +3 -4
  61. package/src/Persistence.res +3 -23
  62. package/src/Persistence.res.mjs +3 -3
  63. package/src/Rollback.res +0 -1
  64. package/src/Rollback.res.mjs +1 -1
  65. package/src/RunScope.res +0 -3
  66. package/src/SafeCheckpointTracking.res +4 -4
  67. package/src/SafeCheckpointTracking.res.mjs +1 -1
  68. package/src/SimulateItems.res +26 -42
  69. package/src/SimulateItems.res.mjs +16 -40
  70. package/src/StagedRows.res +106 -0
  71. package/src/StagedRows.res.mjs +102 -0
  72. package/src/Staging.res +32 -14
  73. package/src/Staging.res.mjs +17 -20
  74. package/src/Storage.res +277 -998
  75. package/src/Storage.res.mjs +216 -731
  76. package/src/Supervisor.res +75 -56
  77. package/src/Supervisor.res.mjs +55 -26
  78. package/src/TestIndexer.res +22 -27
  79. package/src/TestIndexer.res.mjs +20 -17
  80. package/src/Throttler.res +15 -8
  81. package/src/Throttler.res.mjs +9 -6
  82. package/src/Throttler.resi +1 -1
  83. package/src/UserContext.res +46 -410
  84. package/src/UserContext.res.mjs +30 -318
  85. package/src/Utils.res +0 -23
  86. package/src/Utils.res.mjs +1 -17
  87. package/src/Writing.res +0 -1
  88. package/src/Writing.res.mjs +1 -1
  89. package/src/bindings/ClickHouse.res +0 -322
  90. package/src/bindings/ClickHouse.res.mjs +0 -338
  91. package/src/bindings/StorageClient.res +107 -175
  92. package/src/bindings/StorageClient.res.mjs +19 -8
  93. package/src/bindings/Vitest.res +0 -26
  94. package/src/bindings/Vitest.res.mjs +0 -3
  95. package/src/db/Table.res +24 -150
  96. package/src/db/Table.res.mjs +38 -272
  97. package/src/sources/AddressSet.res +0 -2
  98. package/src/sources/AddressStore.res +0 -3
  99. package/src/sources/ChainSources.res +2 -0
  100. package/src/sources/ChainSources.res.mjs +2 -2
  101. package/src/sources/EvmChain.res +4 -7
  102. package/src/sources/EvmChain.res.mjs +5 -4
  103. package/src/sources/EvmHyperSyncSource.res +2 -2
  104. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  105. package/src/sources/EvmRpcClient.res +13 -3
  106. package/src/sources/EvmRpcClient.res.mjs +4 -3
  107. package/src/sources/EvmRpcWs.res +4 -3
  108. package/src/sources/EvmRpcWs.res.mjs +2 -2
  109. package/src/sources/HeightFeed.res +31 -10
  110. package/src/sources/HeightFeed.res.mjs +10 -6
  111. package/src/sources/HeightStream.res +32 -17
  112. package/src/sources/HeightStream.res.mjs +10 -10
  113. package/src/sources/HyperSync.res +1 -2
  114. package/src/sources/HyperSync.res.mjs +1 -2
  115. package/src/sources/HyperSyncSSE.res +4 -6
  116. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  117. package/src/sources/RpcSource.res +10 -1
  118. package/src/sources/RpcSource.res.mjs +4 -3
  119. package/src/sources/Source.res +3 -0
  120. package/src/sources/SourceManager.res +85 -104
  121. package/src/sources/SourceManager.res.mjs +18 -37
  122. package/src/sources/SourceManager.resi +3 -5
  123. package/src/sources/StartBlockResolver.res +1 -0
  124. package/src/sources/StartBlockResolver.res.mjs +4 -3
  125. package/src/sources/SvmHyperSyncSource.res +2 -2
  126. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  127. package/svm.schema.json +3 -3
  128. package/src/EffectCacheLookup.res +0 -98
  129. package/src/EffectCacheLookup.res.mjs +0 -116
  130. package/src/PgWriting.res +0 -36
  131. package/src/PgWriting.res.mjs +0 -34
  132. package/src/PreloadLookahead.res +0 -184
  133. package/src/PreloadLookahead.res.mjs +0 -197
  134. package/src/SubgraphLog.res +0 -19
  135. package/src/SubgraphLog.res.mjs +0 -26
  136. package/src/SyncWrites.res +0 -101
  137. package/src/SyncWrites.res.mjs +0 -98
  138. package/src/db/IndexDefinition.res +0 -47
  139. package/src/db/IndexDefinition.res.mjs +0 -60
  140. package/src/sources/CallSource.res +0 -274
  141. package/src/sources/CallSource.res.mjs +0 -196
  142. package/src/subgraph/abi-types.ts +0 -84
  143. package/src/subgraph/aggregations.ts +0 -745
  144. package/src/subgraph/as-package.ts +0 -143
  145. package/src/subgraph/assemblyscript-regex.ts +0 -67
  146. package/src/subgraph/assemblyscript.ts +0 -731
  147. package/src/subgraph/blocks.ts +0 -398
  148. package/src/subgraph/calls-source.ts +0 -702
  149. package/src/subgraph/calls.ts +0 -258
  150. package/src/subgraph/conformance.ts +0 -106
  151. package/src/subgraph/errors.ts +0 -85
  152. package/src/subgraph/graft.ts +0 -73
  153. package/src/subgraph/graph-cli-worker.mjs +0 -35
  154. package/src/subgraph/graph-cli.ts +0 -900
  155. package/src/subgraph/graph-node-decimal.ts +0 -199
  156. package/src/subgraph/graph-ts-enums.ts +0 -28
  157. package/src/subgraph/graph-ts-types/VERSION +0 -2
  158. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +0 -70
  159. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +0 -327
  160. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +0 -233
  161. package/src/subgraph/graph-ts-types/chain/near.d.ts +0 -253
  162. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +0 -32
  163. package/src/subgraph/graph-ts-types/common/collections.d.ts +0 -136
  164. package/src/subgraph/graph-ts-types/common/conversion.d.ts +0 -11
  165. package/src/subgraph/graph-ts-types/common/datasource.d.ts +0 -30
  166. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  167. package/src/subgraph/graph-ts-types/common/json.d.ts +0 -17
  168. package/src/subgraph/graph-ts-types/common/numbers.d.ts +0 -120
  169. package/src/subgraph/graph-ts-types/common/value.d.ts +0 -120
  170. package/src/subgraph/graph-ts-types/common/yaml.d.ts +0 -90
  171. package/src/subgraph/graph-ts-types/global/global.d.ts +0 -194
  172. package/src/subgraph/graph-ts-types/helper-functions.d.ts +0 -22
  173. package/src/subgraph/graph-ts-types/index.d.ts +0 -102
  174. package/src/subgraph/graph-ts.ts +0 -4280
  175. package/src/subgraph/hosts.ts +0 -554
  176. package/src/subgraph/log.ts +0 -28
  177. package/src/subgraph/receipts.ts +0 -184
  178. package/src/subgraph/register-slots.ts +0 -93
  179. package/src/subgraph/rollup.ts +0 -109
  180. package/src/subgraph/rpc.ts +0 -337
  181. package/src/subgraph/runtime.ts +0 -2060
  182. package/src/subgraph/scope.ts +0 -177
  183. package/src/subgraph/stats.ts +0 -42
  184. package/src/subgraph/template-instances.ts +0 -66
  185. package/src/subgraph/toolchain.ts +0 -327
  186. package/src/subgraph/transient.ts +0 -176
@@ -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,173 +127,104 @@ 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;
499
- let eagerSchemaIndexes = Env.subgraphMode.contents;
500
- let keptEffectCaches = Env.subgraphMode.contents ? [
501
- "envio_subgraph_eth_call",
502
- "envio_subgraph_eth_balance",
503
- "envio_subgraph_has_code",
504
- "envio_subgraph_file",
505
- "envio_subgraph_ipfs_cat",
506
- "envio_subgraph_arweave"
507
- ] : undefined;
508
- 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);
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
+ });
524
163
  });
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
- })));
546
- 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(", ") + `.`);
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);
565
181
  } else {
566
- return;
182
+ return Staging.writeDeletedValue(stage, column, row, undefined);
567
183
  }
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
184
  });
578
- return;
579
185
  }
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
- };
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) {
195
+ let cacheDirPath = cacheDir !== undefined ? Primitive_option.valFromOption(cacheDir) : Path.resolve(".envio", "cache");
196
+ let layouts = client.layouts();
197
+ let entityIndexByName = {};
198
+ layouts.entities.forEach((layout, index) => {
199
+ entityIndexByName[layout.name] = index;
200
+ });
201
+ let entityWriters = layouts.entities.map(layout => StagedRows.writersOf(layout.fields));
202
+ let rawEventWriters = StagedRows.writersOf(layouts.rawEvents);
203
+ let effectCacheWriters = StagedRows.writersOf(layouts.effectCache);
204
+ let holding = () => client.holding();
592
205
  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
206
  let cache = {};
611
- (await client.effectCacheTables()).forEach(param => {
207
+ (await client.restoreEffectCache(cacheDirPath, withUpload)).forEach(param => {
612
208
  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
- }
209
+ let chainId = param.chainId;
210
+ cache[tableName] = {
211
+ effectName: param.effectName,
212
+ scope: chainId !== undefined ? Primitive_option.valFromOption(chainId) : "crossChain",
213
+ tableName: tableName,
214
+ count: param.rows
215
+ };
623
216
  });
624
217
  return cache;
625
218
  };
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) => {
219
+ let initialize = async (chainConfigsOpt, contractMapping, envioInfo) => {
633
220
  let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
634
- let entities = entitiesOpt !== undefined ? entitiesOpt : [];
635
- let enums = enumsOpt !== undefined ? enumsOpt : [];
636
221
  let rowsByChain = chainConfigs.map(chainConfig => ChainState.configStorageRows(chainConfig, ecosystem, contractMapping));
637
222
  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
223
  chains: chainConfigs.map(toChainConfig),
646
224
  envioInfo: JSON.stringify(envioInfo),
647
225
  contractNames: ContractMapping.names(contractMapping),
648
- addresses: addressColumns(rowsByChain.flat()),
649
- keptEffectCaches: keptEffectCaches
226
+ addresses: addressColumns(rowsByChain.flat())
650
227
  });
651
- if (eagerSchemaIndexes) {
652
- await client.ensureSchemaIndexes(schemaIndexes(entities, chainConfigs.map(chainConfig => chainConfig.id)));
653
- }
654
228
  let cache = await restoreEffectCache(true);
655
229
  if (onInitialize !== undefined) {
656
230
  await onInitialize();
@@ -678,9 +252,11 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
678
252
  };
679
253
  let loadOrThrow = async (filter, table) => {
680
254
  let conditions = LoadFilter.make(filter, table, field => field.pgDbFieldName);
255
+ let entity = entityIndexByName[table.tableName];
256
+ let loading = entity !== undefined ? StorageClient.loadWhere(client, entity, conditions) : StorageClient.loadEffectCache(client, table.tableName, conditions);
681
257
  let rows;
682
258
  try {
683
- rows = await StorageClient.loadWhere(client, tableOf(table).handle, conditions);
259
+ rows = await loading;
684
260
  } catch (raw_exn) {
685
261
  let exn = Primitive_exceptions.internalToException(raw_exn);
686
262
  throw {
@@ -720,44 +296,17 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
720
296
  }));
721
297
  return columns;
722
298
  };
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
299
  let ensureQueryIndexes = async (entityConfig, scope, filters) => {
731
- let building = client.ensureQueryIndexes(entityTable(entityConfig).handle, queryTableName(entityConfig, scope), filterColumns(entityConfig.table, filters));
300
+ let building = client.ensureQueryIndexes(entityConfig.index, Stdlib_Null.fromOption(Internal.chainScopeChainId(scope)), filterColumns(entityConfig.table, filters));
732
301
  if (building === null) {
733
302
  return;
734
303
  } else {
735
304
  return await building;
736
305
  }
737
306
  };
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
- };
307
+ let ensureSchemaIndexes = chainIds => client.ensureSchemaIndexes(chainIds);
308
+ let finalizeBackfill = (chainIds, readyAt) => client.finalizeBackfill(chainIds, readyAt.getTime());
309
+ let dumpEffectCache = () => client.dumpEffectCache(cacheDirPath);
761
310
  let readStoredConfig = async () => {
762
311
  let stored = await client.readStoredConfig();
763
312
  let configAddresses = StorageClient.read(client, stored.configAddresses);
@@ -795,19 +344,14 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
795
344
  contractMapping: ContractMapping.fromStoredNames(match$1)
796
345
  };
797
346
  };
798
- let addChain = (chainConfig, entities, contractMapping) => client.addChain({
347
+ let addChain = (chainConfig, contractMapping) => client.addChain({
799
348
  chain: toChainConfig(chainConfig),
800
- partitions: partitions(entities, [chainConfig.id]),
801
349
  addresses: addressColumns(ChainState.configStorageRows(chainConfig, ecosystem, contractMapping))
802
350
  });
803
- let resumeInitialState = async (entities, chainIds, contractMapping) => {
351
+ let resumeInitialState = async (chainIds, contractMapping) => {
804
352
  let match = await Promise.all([
805
353
  restoreEffectCache(false),
806
- client.resume({
807
- sequence: CheckpointSequence.fromEntities(entities),
808
- tables: entities.map(entityConfig => entityTable(entityConfig).handle),
809
- chainIds: chainIds
810
- })
354
+ client.resume(chainIds)
811
355
  ]);
812
356
  let resumed = match[1];
813
357
  let addressRowsByChainId = AddressRows.group(StorageClient.read(client, resumed.addresses));
@@ -834,10 +378,10 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
834
378
  });
835
379
  let checkpointFrontier = Frontier.fromEntries(stored.map(param => [
836
380
  param[0],
837
- BigInt(param[1].checkpointId)
381
+ param[1].checkpointId
838
382
  ]));
839
383
  let reorgCheckpoints = resumed.reorgCheckpoints.map(checkpoint => ({
840
- id: BigInt(checkpoint.id),
384
+ id: checkpoint.id,
841
385
  chain_id: ChainId.normalizeOrThrow(checkpoint.chainId),
842
386
  block_number: checkpoint.blockNumber,
843
387
  block_hash: checkpoint.blockHash
@@ -864,15 +408,15 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
864
408
  });
865
409
  let setChainMeta = chainsData => client.setChainMeta(chainMeta(chainsData)).then(() => (undefined));
866
410
  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));
411
+ let pruneStaleEntityHistory = (entityConfig, safeCheckpoints) => client.pruneHistory(entityConfig.index, bounds(safeCheckpoints));
412
+ let getRollbackTargetCheckpoint = async (reorgChainId, lastKnownValidBlockNumber) => Primitive_option.fromNullable(await client.rollbackTargetCheckpoint(reorgChainId, lastKnownValidBlockNumber));
869
413
  let getRollbackProgressDiff = async floors => (await client.rollbackProgressDiff(bounds(floors.checkpointBounds))).map(diff => ({
870
414
  chain_id: ChainId.normalizeOrThrow(diff.chainId),
871
415
  events_processed_diff: diff.eventsProcessed,
872
416
  new_progress_block_number: diff.progressBlock
873
417
  }));
874
418
  let getRollbackData = async (entityConfig, floors) => {
875
- let match = await client.rollbackData(entityTable(entityConfig).handle, bounds(floors.checkpointBounds));
419
+ let match = await client.rollbackData(entityConfig.index, bounds(floors.checkpointBounds));
876
420
  let restored = match.restored;
877
421
  let removedIdRows;
878
422
  try {
@@ -890,29 +434,28 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
890
434
  return "crossChain";
891
435
  }
892
436
  };
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
437
  return [
910
- removals,
911
- S$RescriptSchema.parseOrThrow(restoredEntitiesResult, Table.pgRowsSchema(entityConfig.table))
438
+ removedIdRows.map(row => ({
439
+ entityId: S$RescriptSchema.parseOrThrow(row, rollbackRemovedIdSchema(entityConfig.table)),
440
+ scope: scopeOf(row)
441
+ })),
442
+ S$RescriptSchema.parseOrThrow(rollbackRows, Table.pgRowsSchema(entityConfig.table))
912
443
  ];
913
444
  };
914
- let writeBatch = async (batch, rollback, config, allEntities, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
915
- let match = Frontier.unnestParams(Persistence.writtenFrontier(batch, rollback));
445
+ let stageRows = (table, writers, items) => stageRowsOrThrow(StorageClient.arena(client, rows => client.beginRows(table, rows)), writers, items);
446
+ let stageChanges = param => {
447
+ let entityConfig = param.entityConfig;
448
+ return stageChangesOrThrow(StorageClient.arena(client, rows => client.beginChanges(entityConfig.index, rows)), entityWriters[entityConfig.index], param.changes);
449
+ };
450
+ let changesErrorOf = (entityConfig, exn) => ({
451
+ RE_EXN_ID: Persistence.StorageError,
452
+ 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) + `"`,
453
+ reason: Utils.prettifyExn(exn)
454
+ });
455
+ let writeBatch = async (batch, rollback, config, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
456
+ let frontier = Persistence.writtenFrontier(batch, rollback);
457
+ let chainIds = Frontier.chainIds(frontier);
458
+ let frontierCheckpointIds = chainIds.map(chainId => Frontier.get(frontier, chainId));
916
459
  let rawEvents;
917
460
  if (config.enableRawEvents) {
918
461
  let seenLogCoordinates = new Set();
@@ -931,21 +474,35 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
931
474
  } else {
932
475
  rawEvents = [];
933
476
  }
934
- let staged_handles = [];
935
- let staged_seconds = {};
936
- let staged = {
937
- handles: staged_handles,
938
- seconds: staged_seconds
477
+ let handles = [];
478
+ let staged = handle => {
479
+ handles.push(handle);
480
+ return handle;
481
+ };
482
+ let stagingStarted = Performance.now();
483
+ let clickHouseStagingSeconds = {
484
+ contents: 0
485
+ };
486
+ let clickHouseOnlyStagingSeconds = {
487
+ contents: 0
939
488
  };
940
489
  let input;
941
490
  try {
942
491
  let tmp;
943
492
  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
- };
493
+ let tmp$1;
494
+ try {
495
+ tmp$1 = staged(stageRows("RawEvents", rawEventWriters, rawEvents));
496
+ } catch (raw_exn) {
497
+ let exn = Primitive_exceptions.internalToException(raw_exn);
498
+ throw {
499
+ RE_EXN_ID: Persistence.StorageError,
500
+ message: `Failed to insert items into table "` + InternalTable.RawEvents.table.tableName + `"`,
501
+ reason: Utils.prettifyExn(exn),
502
+ Error: new Error()
503
+ };
504
+ }
505
+ tmp = tmp$1;
949
506
  } else {
950
507
  tmp = undefined;
951
508
  }
@@ -954,7 +511,6 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
954
511
  let rolledBackAddresses = param.rolledBackAddresses;
955
512
  return {
956
513
  bounds: bounds(param.floors.checkpointBounds),
957
- tables: allEntities.map(entityConfig => entityTable(entityConfig).handle),
958
514
  progress: param.progressedChains.map(progress),
959
515
  removedAddresses: {
960
516
  chainIds: rolledBackAddresses.map(key => key.chainId),
@@ -963,7 +519,7 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
963
519
  },
964
520
  diffCheckpoints: param.diffCheckpoints.map(diff => ({
965
521
  chainId: diff.chainId,
966
- checkpointId: diff.checkpointId.toString(),
522
+ checkpointId: diff.checkpointId,
967
523
  blockNumber: diff.blockNumber
968
524
  }))
969
525
  };
@@ -976,124 +532,41 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
976
532
  totalEventsProcessed: chainAfterBatch.totalEventsProcessed
977
533
  })),
978
534
  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;
535
+ changes: Stdlib_Array.filterMap(updatedEntities, update => {
536
+ let match = update.changes;
537
+ if (match.length === 0) {
538
+ return;
539
+ }
540
+ let started = Performance.now();
541
+ let handle;
542
+ try {
543
+ handle = staged(stageChanges(update));
544
+ } catch (raw_exn) {
545
+ let exn = Primitive_exceptions.internalToException(raw_exn);
546
+ throw changesErrorOf(update.entityConfig, exn);
547
+ }
548
+ let seconds = Performance.secondsSince(started);
549
+ if (update.entityConfig.storage.clickhouse) {
550
+ clickHouseStagingSeconds.contents = clickHouseStagingSeconds.contents + seconds;
551
+ }
552
+ if (!update.entityConfig.storage.postgres) {
553
+ clickHouseOnlyStagingSeconds.contents = clickHouseOnlyStagingSeconds.contents + seconds;
1081
554
  }
1082
555
  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
556
+ entity: update.entityConfig.index,
557
+ chainId: Internal.chainScopeChainId(update.scope),
558
+ keepsHistory: update.shouldSaveHistory,
559
+ changes: handle
1087
560
  };
1088
561
  }),
1089
562
  chainMeta: Stdlib_Option.mapOr(chainMetaData, [], chainMeta),
1090
563
  addresses: addressColumns(registeredAddresses.map(staged => staged.row)),
1091
564
  frontier: {
1092
- chainIds: match[0],
1093
- checkpointIds: match[1]
565
+ chainIds: chainIds,
566
+ checkpointIds: frontierCheckpointIds
1094
567
  },
1095
568
  checkpoints: {
1096
- ids: batch.checkpointIds.map(id => id.toString()),
569
+ ids: batch.checkpointIds,
1097
570
  chainIds: batch.checkpointChainIds,
1098
571
  blockNumbers: batch.checkpointBlockNumbers,
1099
572
  blockHashes: batch.checkpointBlockHashes,
@@ -1101,35 +574,59 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1101
574
  keepsHistory: batch.checkpointChainIds.map(chainId => HistoryPolicy.forChain(batch.history, chainId))
1102
575
  },
1103
576
  effectCaches: updatedEffectsCache.map(param => {
1104
- let registered = ownTable(param.table, Internal.cacheItemSchema, undefined);
577
+ let itemSchema = param.itemSchema;
578
+ let table = param.table;
579
+ let tmp;
580
+ try {
581
+ tmp = staged(stageRows("EffectCache", effectCacheWriters, param.items.map(item => S$RescriptSchema.reverseConvertOrThrow(item, itemSchema))));
582
+ } catch (raw_exn) {
583
+ let exn = Primitive_exceptions.internalToException(raw_exn);
584
+ if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
585
+ throw {
586
+ RE_EXN_ID: Persistence.StorageError,
587
+ message: `Failed to convert items for table "` + table.tableName + `"`,
588
+ reason: exn,
589
+ Error: new Error()
590
+ };
591
+ }
592
+ throw {
593
+ RE_EXN_ID: Persistence.StorageError,
594
+ message: `Failed to insert items into table "` + table.tableName + `"`,
595
+ reason: Utils.prettifyExn(exn),
596
+ Error: new Error()
597
+ };
598
+ }
1105
599
  return {
1106
- table: registered.handle,
600
+ table: table.tableName,
1107
601
  create: param.shouldInitialize,
1108
- rows: rowsOrThrow(client, registered, param.itemSchema, param.items, staged)
602
+ rows: tmp
1109
603
  };
1110
604
  })
1111
605
  };
1112
- } catch (exn) {
1113
- client.discardStaged(staged_handles);
1114
- throw exn;
606
+ } catch (exn$1) {
607
+ client.discardStaged(handles);
608
+ throw exn$1;
1115
609
  }
610
+ let postgresStagingSeconds = Performance.secondsSince(stagingStarted) - clickHouseOnlyStagingSeconds.contents;
1116
611
  let timings;
1117
612
  try {
1118
613
  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);
614
+ } catch (raw_exn$1) {
615
+ let exn$2 = Primitive_exceptions.internalToException(raw_exn$1);
616
+ client.discardStaged(handles);
617
+ throw storageErrorOf(exn$2);
1123
618
  }
1124
619
  timings.forEach(param => {
1125
- let name = storeName(param.store);
1126
- onWrite(name, param.seconds + Stdlib_Option.getOr(staged_seconds[name], 0));
620
+ let store = param.store;
621
+ let tmp;
622
+ tmp = store === "Postgres" ? postgresStagingSeconds : clickHouseStagingSeconds.contents;
623
+ onWrite(storeName(store), param.seconds + tmp);
1127
624
  });
1128
625
  };
1129
626
  let close = () => client.close();
1130
627
  return {
1131
628
  name: postgresName,
1132
- entityStoreName: entityConfig => storeName(entityTable(entityConfig).home),
629
+ entityStoreName: entityConfig => Stdlib_Option.mapOr(layouts.entities[entityConfig.index].home, postgresName, storeName),
1133
630
  holding: holding,
1134
631
  initialize: initialize,
1135
632
  readStoredConfig: readStoredConfig,
@@ -1154,13 +651,13 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1154
651
 
1155
652
  function clientFromEnv(config, logger, pgSchemaOpt, isHasuraEnabled, maxConnections) {
1156
653
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1157
- return makeClient(logger, config.chainIdMode, postgresOptions(pgSchema, isHasuraEnabled, maxConnections), config.storage.clickhouse ? ClickHouse.optionsFromEnvOrThrow() : undefined);
654
+ return makeClient(logger, config, postgresOptions(pgSchema, isHasuraEnabled, maxConnections, config.isolated), config.storage.clickhouse ? ClickHouse.optionsFromEnvOrThrow() : undefined);
1158
655
  }
1159
656
 
1160
657
  function makeStorageFromEnv(config, logger, pgSchemaOpt, isHasuraEnabledOpt, maxConnections, cacheDir) {
1161
658
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1162
659
  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, {
660
+ return make(clientFromEnv(config, logger, pgSchema, isHasuraEnabled, maxConnections), cacheDir, config.ecosystem.name, isHasuraEnabled ? () => Stdlib_Promise.$$catch(Hasura.trackDatabase(logger, Env.Hasura.graphqlEndpoint, {
1164
661
  role: Env.Hasura.role,
1165
662
  secret: Env.Hasura.secret
1166
663
  }, 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 +669,24 @@ function makePersistenceFromConfig(config, logger, storageOpt) {
1172
669
  }
1173
670
 
1174
671
  export {
1175
- formatSeconds,
1176
- slowOnLargeDatabaseNotice,
1177
672
  storeName,
1178
673
  postgresName,
1179
- logIndexEvent,
1180
674
  postgresOptions,
1181
675
  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
676
  bounds,
1195
677
  progress,
1196
678
  addressColumns,
1197
679
  toChainConfig,
1198
680
  storageErrorOf,
1199
- rollbackRowStateSchema,
1200
681
  rollbackChainIdSchema,
1201
682
  rollbackRemovedIdSchema,
683
+ changeColumns,
684
+ stageOrThrow,
685
+ stageRowsOrThrow,
686
+ stageChangesOrThrow,
1202
687
  make,
1203
688
  clientFromEnv,
1204
689
  makeStorageFromEnv,
1205
690
  makePersistenceFromConfig,
1206
691
  }
1207
- /* rowSchemaCache Not a pure module */
692
+ /* rollbackChainIdSchema Not a pure module */