envio 3.15.0 → 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 (186) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +11 -2
  3. package/fuel.schema.json +10 -1
  4. package/index.d.ts +6 -0
  5. package/licenses/README.md +1 -1
  6. package/package.json +10 -9
  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 +7 -0
  11. package/src/Bin.res.mjs +8 -0
  12. package/src/ChainFetching.res +450 -16
  13. package/src/ChainFetching.res.mjs +403 -32
  14. package/src/ChainState.res +124 -7
  15. package/src/ChainState.res.mjs +128 -67
  16. package/src/ChainState.resi +26 -0
  17. package/src/Clock.res +57 -0
  18. package/src/Clock.res.mjs +72 -0
  19. package/src/Config.res +31 -3
  20. package/src/Config.res.mjs +15 -4
  21. package/src/ContractRegisterContext.res +3 -6
  22. package/src/ContractRegisterContext.res.mjs +4 -2
  23. package/src/Core.res +95 -36
  24. package/src/Core.res.mjs +90 -1
  25. package/src/CrossChainState.res +12 -2
  26. package/src/CrossChainState.res.mjs +3 -3
  27. package/src/Ecosystem.res +7 -4
  28. package/src/Ecosystem.res.mjs +8 -8
  29. package/src/EffectCacheLookup.res +98 -0
  30. package/src/EffectCacheLookup.res.mjs +116 -0
  31. package/src/EffectState.res +10 -2
  32. package/src/EffectState.res.mjs +8 -4
  33. package/src/EffectState.resi +3 -1
  34. package/src/EntityId.res +2 -7
  35. package/src/EntityId.res.mjs +1 -8
  36. package/src/EntityTables.res +4 -1
  37. package/src/EntityTables.res.mjs +1 -1
  38. package/src/Env.res +20 -0
  39. package/src/Env.res.mjs +16 -0
  40. package/src/EventProcessing.res +38 -1
  41. package/src/EventProcessing.res.mjs +28 -1
  42. package/src/FetchState.res +408 -73
  43. package/src/FetchState.res.mjs +361 -91
  44. package/src/FinalizeBackfill.res +2 -4
  45. package/src/FinalizeBackfill.res.mjs +3 -4
  46. package/src/HandlerLoader.res +39 -15
  47. package/src/HandlerLoader.res.mjs +27 -8
  48. package/src/HandlerRegister.res +4 -0
  49. package/src/HandlerRegister.res.mjs +5 -2
  50. package/src/HandlerRegister.resi +2 -0
  51. package/src/InMemoryTable.res +17 -16
  52. package/src/InMemoryTable.res.mjs +14 -15
  53. package/src/IndexerState.res +28 -4
  54. package/src/IndexerState.res.mjs +19 -6
  55. package/src/IndexerState.resi +4 -0
  56. package/src/Internal.res +61 -49
  57. package/src/Internal.res.mjs +36 -80
  58. package/src/LoadLayer.res +54 -15
  59. package/src/LoadLayer.res.mjs +75 -45
  60. package/src/LoadLayer.resi +26 -0
  61. package/src/Main.res +14 -1
  62. package/src/Main.res.mjs +4 -3
  63. package/src/Persistence.res +3 -23
  64. package/src/Persistence.res.mjs +3 -3
  65. package/src/PreloadLookahead.res +202 -0
  66. package/src/PreloadLookahead.res.mjs +218 -0
  67. package/src/Rollback.res +0 -1
  68. package/src/Rollback.res.mjs +1 -1
  69. package/src/RunScope.res +3 -0
  70. package/src/SafeCheckpointTracking.res +4 -4
  71. package/src/SafeCheckpointTracking.res.mjs +1 -1
  72. package/src/SimulateItems.res +42 -26
  73. package/src/SimulateItems.res.mjs +40 -16
  74. package/src/StagedRows.res +106 -0
  75. package/src/StagedRows.res.mjs +102 -0
  76. package/src/Staging.res +32 -14
  77. package/src/Staging.res.mjs +17 -20
  78. package/src/Storage.res +303 -948
  79. package/src/Storage.res.mjs +229 -708
  80. package/src/SubgraphLog.res +19 -0
  81. package/src/SubgraphLog.res.mjs +26 -0
  82. package/src/Supervisor.res +75 -56
  83. package/src/Supervisor.res.mjs +55 -26
  84. package/src/SyncWrites.res +107 -0
  85. package/src/SyncWrites.res.mjs +98 -0
  86. package/src/TestIndexer.res +22 -27
  87. package/src/TestIndexer.res.mjs +20 -17
  88. package/src/Throttler.res +15 -8
  89. package/src/Throttler.res.mjs +9 -6
  90. package/src/Throttler.resi +1 -1
  91. package/src/UserContext.res +419 -46
  92. package/src/UserContext.res.mjs +318 -30
  93. package/src/Utils.res +17 -6
  94. package/src/Utils.res.mjs +12 -6
  95. package/src/Writing.res +0 -1
  96. package/src/Writing.res.mjs +1 -1
  97. package/src/bindings/ClickHouse.res +0 -322
  98. package/src/bindings/ClickHouse.res.mjs +0 -338
  99. package/src/bindings/StorageClient.res +108 -174
  100. package/src/bindings/StorageClient.res.mjs +19 -8
  101. package/src/bindings/Vitest.res +0 -26
  102. package/src/bindings/Vitest.res.mjs +0 -3
  103. package/src/db/Table.res +24 -150
  104. package/src/db/Table.res.mjs +38 -272
  105. package/src/sources/AddressSet.res +2 -0
  106. package/src/sources/AddressStore.res +3 -0
  107. package/src/sources/CallSource.res +274 -0
  108. package/src/sources/CallSource.res.mjs +196 -0
  109. package/src/sources/ChainSources.res +2 -0
  110. package/src/sources/ChainSources.res.mjs +2 -2
  111. package/src/sources/EvmChain.res +10 -1
  112. package/src/sources/EvmChain.res.mjs +6 -3
  113. package/src/sources/EvmHyperSyncSource.res +2 -2
  114. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  115. package/src/sources/EvmRpcClient.res +13 -3
  116. package/src/sources/EvmRpcClient.res.mjs +4 -3
  117. package/src/sources/EvmRpcWs.res +4 -3
  118. package/src/sources/EvmRpcWs.res.mjs +2 -2
  119. package/src/sources/HeightFeed.res +31 -10
  120. package/src/sources/HeightFeed.res.mjs +10 -6
  121. package/src/sources/HeightStream.res +32 -17
  122. package/src/sources/HeightStream.res.mjs +10 -10
  123. package/src/sources/HyperSync.res +2 -1
  124. package/src/sources/HyperSync.res.mjs +2 -1
  125. package/src/sources/HyperSyncSSE.res +4 -6
  126. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  127. package/src/sources/RpcSource.res +10 -1
  128. package/src/sources/RpcSource.res.mjs +4 -3
  129. package/src/sources/Source.res +3 -0
  130. package/src/sources/SourceManager.res +84 -77
  131. package/src/sources/SourceManager.res.mjs +17 -20
  132. package/src/sources/SourceManager.resi +3 -4
  133. package/src/sources/StartBlockResolver.res +1 -0
  134. package/src/sources/StartBlockResolver.res.mjs +3 -2
  135. package/src/sources/SvmHyperSyncSource.res +2 -2
  136. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  137. package/src/subgraph/abi-types.ts +84 -0
  138. package/src/subgraph/aggregations.ts +745 -0
  139. package/src/subgraph/as-package.ts +143 -0
  140. package/src/subgraph/assemblyscript-regex.ts +67 -0
  141. package/src/subgraph/assemblyscript.ts +731 -0
  142. package/src/subgraph/blocks.ts +398 -0
  143. package/src/subgraph/calls-source.ts +702 -0
  144. package/src/subgraph/calls.ts +258 -0
  145. package/src/subgraph/conformance.ts +106 -0
  146. package/src/subgraph/errors.ts +85 -0
  147. package/src/subgraph/graft.ts +73 -0
  148. package/src/subgraph/graph-cli-worker.mjs +35 -0
  149. package/src/subgraph/graph-cli.ts +900 -0
  150. package/src/subgraph/graph-node-decimal.ts +199 -0
  151. package/src/subgraph/graph-ts-enums.ts +28 -0
  152. package/src/subgraph/graph-ts-types/VERSION +2 -0
  153. package/src/subgraph/graph-ts-types/chain/arweave.d.ts +70 -0
  154. package/src/subgraph/graph-ts-types/chain/cosmos.d.ts +327 -0
  155. package/src/subgraph/graph-ts-types/chain/ethereum.d.ts +233 -0
  156. package/src/subgraph/graph-ts-types/chain/near.d.ts +253 -0
  157. package/src/subgraph/graph-ts-types/chain/starknet.d.ts +32 -0
  158. package/src/subgraph/graph-ts-types/common/collections.d.ts +136 -0
  159. package/src/subgraph/graph-ts-types/common/conversion.d.ts +11 -0
  160. package/src/subgraph/graph-ts-types/common/datasource.d.ts +30 -0
  161. package/src/subgraph/graph-ts-types/common/eager-offset.d.ts +0 -0
  162. package/src/subgraph/graph-ts-types/common/json.d.ts +17 -0
  163. package/src/subgraph/graph-ts-types/common/numbers.d.ts +120 -0
  164. package/src/subgraph/graph-ts-types/common/value.d.ts +120 -0
  165. package/src/subgraph/graph-ts-types/common/yaml.d.ts +90 -0
  166. package/src/subgraph/graph-ts-types/global/global.d.ts +194 -0
  167. package/src/subgraph/graph-ts-types/helper-functions.d.ts +22 -0
  168. package/src/subgraph/graph-ts-types/index.d.ts +102 -0
  169. package/src/subgraph/graph-ts.ts +4339 -0
  170. package/src/subgraph/hosts.ts +554 -0
  171. package/src/subgraph/log.ts +28 -0
  172. package/src/subgraph/receipts.ts +184 -0
  173. package/src/subgraph/register-slots.ts +93 -0
  174. package/src/subgraph/rollup.ts +109 -0
  175. package/src/subgraph/rpc.ts +337 -0
  176. package/src/subgraph/runtime.ts +2059 -0
  177. package/src/subgraph/scope.ts +176 -0
  178. package/src/subgraph/stats.ts +42 -0
  179. package/src/subgraph/template-instances.ts +66 -0
  180. package/src/subgraph/toolchain.ts +327 -0
  181. package/src/subgraph/transient.ts +176 -0
  182. package/svm.schema.json +11 -2
  183. package/src/PgWriting.res +0 -36
  184. package/src/PgWriting.res.mjs +0 -34
  185. package/src/db/IndexDefinition.res +0 -47
  186. package/src/db/IndexDefinition.res.mjs +0 -67
@@ -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,288 +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
- all.push(IndexDefinition.single(derivedFromField.derivedFromEntity, column));
194
- });
195
- });
196
- let seen = new Set();
197
- let entityByTableName = {};
198
- entities.forEach(entityConfig => {
199
- entityByTableName[entityConfig.table.tableName] = entityConfig;
200
- });
201
- return all.filter(definition => {
202
- let identity = IndexDefinition.describe(definition);
203
- if (seen.has(identity)) {
204
- return false;
205
- } else {
206
- seen.add(identity);
207
- return true;
208
- }
209
- }).flatMap(definition => indexTableNames(Stdlib_Option.getOrThrow(entityByTableName[definition.tableName], undefined), partitionChainIds).map(tableName => ({
210
- tableName: tableName,
211
- columns: definition.columns,
212
- method: definition.method
213
- })));
214
- }
215
-
216
- function pgColumnInput(field) {
217
- let match = Table.pgFieldTypeParts(field.fieldType);
218
- return {
219
- name: Table.getPgDbFieldName(field),
220
- fieldType: match[0],
221
- isArray: field.isArray,
222
- isNullable: field.isNullable,
223
- isPrimaryKey: field.isPrimaryKey,
224
- defaultValue: field.defaultValue,
225
- precision: match[1],
226
- scale: match[2],
227
- enumName: match[3]
228
- };
229
- }
230
-
231
- let rowSchemaCache = new WeakMap();
232
-
233
- function getRowSchema(entityConfig) {
234
- let cached = rowSchemaCache.get(entityConfig);
235
- if (cached !== undefined) {
236
- return Primitive_option.valFromOption(cached);
237
- }
238
- let chainIdField = Table.getChainIdField(entityConfig.table);
239
- let schema = chainIdField !== undefined ? S$RescriptSchema.schema(s => {
240
- let dict = {};
241
- let match = entityConfig.schema.t;
242
- let exit = 0;
243
- if (typeof match !== "object" || match.TAG !== "object") {
244
- exit = 1;
245
- } else {
246
- match.items.forEach(param => {
247
- dict[param.location] = s.m(param.schema);
248
- });
249
- }
250
- if (exit === 1) {
251
- Stdlib_JsError.throwWithMessage(`Unexpected non-object schema for entity "` + entityConfig.name + `".`);
252
- }
253
- dict[chainIdField.fieldName] = s.m(ChainId.schema);
254
- return dict;
255
- }) : entityConfig.schema;
256
- rowSchemaCache.set(entityConfig, schema);
257
- return schema;
258
- }
259
-
260
- function register(client, table, itemSchema, postgresOpt, clickhouse, appendOnlyOpt, history) {
261
- let postgres = postgresOpt !== undefined ? postgresOpt : true;
262
- let appendOnly = appendOnlyOpt !== undefined ? appendOnlyOpt : false;
263
- let fields = Table.schemaOrderedFields(table, itemSchema);
264
- let chainIdField = Table.getChainIdField(table);
265
- let registered = client.registerTable({
266
- name: table.tableName,
267
- postgres: postgres ? ({
268
- columns: Table.getFields(table).map(pgColumnInput),
269
- writeColumns: fields.map(Table.getPgDbFieldName),
270
- partitionByColumn: Stdlib_Option.map(chainIdField, Table.getPgDbFieldName),
271
- appendOnly: appendOnly,
272
- historyTable: history,
273
- chainIdColumn: history !== undefined ? Stdlib_Option.map(chainIdField, Table.getPgDbFieldName) : undefined
274
- }) : undefined,
275
- clickhouse: clickhouse
276
- });
277
- return {
278
- handle: registered.handle,
279
- home: registered.home,
280
- table: table,
281
- fields: fields,
282
- postgres: Stdlib_Option.map(registered.postgres, param => ({
283
- staged: Stdlib_Option.map(param.kinds, kinds => PgWriting.columns(fields, kinds.map(Staging.kindOfOrdinal)))
284
- })),
285
- clickhouse: Stdlib_Option.map(registered.clickhouse, __x => ClickHouse.makeTable(registered.handle, Stdlib_Option.getOr(history, table.tableName), __x))
286
- };
287
- }
288
-
289
- function registerEntity(client, entityConfig) {
290
- return register(client, entityConfig.table, getRowSchema(entityConfig), entityConfig.storage.postgres, entityConfig.storage.clickhouse ? ClickHouse.entityTable(entityConfig) : undefined, undefined, EntityHistory.historyTableName(entityConfig.name, entityConfig.index));
291
- }
292
-
293
- function renderDocument(value, isNullable) {
294
- if (value == null) {
295
- if (value === null && !isNullable) {
296
- return "null";
297
- } else {
298
- return value;
299
- }
300
- } else {
301
- return Sql.stringifyDocument(value);
302
- }
303
- }
304
-
305
- let arenaConverters = new WeakMap();
306
-
307
- let cellConverters = new WeakMap();
308
-
309
- function converterOf(registered, forArena, itemSchema) {
310
- let converters = forArena ? arenaConverters : cellConverters;
311
- let convert = converters.get(itemSchema);
312
- if (convert !== undefined) {
313
- return convert;
314
- }
315
- let documents = Stdlib_Array.filterMapWithIndex(registered.fields, (field, index) => {
316
- if (field.fieldType === "Json") {
317
- return [
318
- index,
319
- field
320
- ];
321
- }
322
- });
323
- let schema = forArena ? Table.toDbSchema(registered.table, itemSchema) : itemSchema;
324
- let convert$1 = S$RescriptSchema.compile(S$RescriptSchema.preprocess(S$RescriptSchema.unnest(schema), param => ({
325
- s: columns => {
326
- documents.forEach(param => {
327
- let field = param[1];
328
- let values = columns[param[0]];
329
- for (let row = 0, row_finish = values.length; row < row_finish; ++row) {
330
- let value = values[row];
331
- values[row] = !(value == null) && field.isArray ? value.map(document => renderDocument(document, true)) : renderDocument(value, field.isNullable);
332
- }
333
- });
334
- return columns;
335
- }
336
- })), "Output", "Input", "Sync", false);
337
- converters.set(itemSchema, convert$1);
338
- return convert$1;
339
- }
340
-
341
- function refuseNonFinite(values, fields) {
342
- fields.forEach((field, index) => {
343
- if (field.fieldType !== "Number") {
344
- return;
345
- }
346
- let column = Table.getPgDbFieldName(field);
347
- let check = value => {
348
- if (value == null) {
349
- return;
350
- }
351
- Staging.finiteOrThrow(value, column);
352
- };
353
- values[index].forEach(value => {
354
- if (!field.isArray) {
355
- return check(value);
356
- }
357
- if (value == null) {
358
- return;
359
- }
360
- value.forEach(check);
361
- });
362
- });
363
- }
364
-
365
- function stagedFor(staged, store, stage) {
366
- let started = Performance.now();
367
- let result = stage();
368
- let name = storeName(store);
369
- staged.seconds[name] = Stdlib_Option.getOr(staged.seconds[name], 0) + Performance.secondsSince(started);
370
- return result;
371
- }
372
-
373
- function rowsOrThrow(client, registered, itemSchema, items, staged) {
374
- return stagedFor(staged, "Postgres", () => {
375
- let rows = items.length;
376
- try {
377
- let match = registered.postgres;
378
- if (match === undefined) {
379
- return Stdlib_JsError.throwWithMessage(`Postgres doesn't keep "` + registered.table.tableName + `"`);
380
- }
381
- let columns = match.staged;
382
- if (columns !== undefined) {
383
- let values = converterOf(registered, true, itemSchema)(items);
384
- let handle = PgWriting.stage(StorageClient.arena(client, "Postgres"), registered.handle, columns, values, rows);
385
- staged.handles.push(handle);
386
- return {
387
- staged: handle,
388
- rows: rows
389
- };
390
- }
391
- let values$1 = converterOf(registered, false, itemSchema)(items);
392
- refuseNonFinite(values$1, registered.fields);
393
- return {
394
- cells: Sql.params(values$1.flat(1)),
395
- rows: rows
396
- };
397
- } catch (raw_exn) {
398
- let exn = Primitive_exceptions.internalToException(raw_exn);
399
- if (exn.RE_EXN_ID === S$RescriptSchema.Raised) {
400
- throw {
401
- RE_EXN_ID: Persistence.StorageError,
402
- message: `Failed to convert items for table "` + registered.table.tableName + `"`,
403
- reason: exn,
404
- Error: new Error()
405
- };
406
- }
407
- throw {
408
- RE_EXN_ID: Persistence.StorageError,
409
- message: `Failed to insert items into table "` + registered.table.tableName + `"`,
410
- reason: Utils.prettifyExn(exn),
411
- Error: new Error()
412
- };
413
- }
414
- });
415
- }
416
-
417
- function renderIds(table, ids) {
418
- return Table.encodeIdsToJson(table, ids).map(Sql.render);
72
+ }, Stdlib_Option.map(config, config => JSON.stringify(config.envioInfo)), logger);
419
73
  }
420
74
 
421
75
  function bounds(param) {
422
- let match = Frontier.unnestParams(param.byChain);
76
+ let byChain = param.byChain;
423
77
  return {
424
- sequence: param.sequence,
425
- chainIds: match[0],
426
- checkpointIds: match[1]
78
+ chainIds: Frontier.chainIds(byChain),
79
+ checkpointIds: Frontier.chainIds(byChain).map(chainId => Frontier.get(byChain, chainId))
427
80
  };
428
81
  }
429
82
 
@@ -474,154 +127,117 @@ function storageErrorOf(exn) {
474
127
  }
475
128
  }
476
129
 
477
- let rollbackRowStateSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.object(s => [
478
- s.f(Table.idFieldName, Table.getIdSchema(table)),
479
- s.f(EntityHistory.changeFieldName, EntityHistory.RowAction.schema)
480
- ]));
481
-
482
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))));
483
131
 
484
132
  let rollbackRemovedIdSchema = Utils.$$WeakMap.memoize(table => S$RescriptSchema.object(s => s.f(Table.idFieldName, Table.getIdSchema(table))));
485
133
 
486
- function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onInitialize) {
487
- let entities = entitiesOpt !== undefined ? entitiesOpt : [];
488
- let isolated = isolatedOpt !== undefined ? isolatedOpt : false;
489
- let cacheDirPath = cacheDir !== undefined ? Primitive_option.valFromOption(cacheDir) : Path.resolve(".envio", "cache");
490
- let registry = {};
491
- let registered = (table, register) => {
492
- let registered$1 = registry[table.tableName];
493
- if (registered$1 !== undefined) {
494
- return registered$1;
495
- }
496
- let registered$2 = register();
497
- registry[table.tableName] = registered$2;
498
- return registered$2;
499
- };
500
- let entityTable = entityConfig => registered(entityConfig.table, () => registerEntity(client, entityConfig));
501
- let ownTable = (table, itemSchema, appendOnly) => registered(table, () => register(client, table, itemSchema, undefined, undefined, appendOnly, undefined));
502
- let rawEventsTable = () => ownTable(InternalTable.RawEvents.table, InternalTable.RawEvents.schema, true);
503
- entities.forEach(entityConfig => {
504
- 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
+ });
505
163
  });
506
- let tableOf = table => {
507
- let registered = registry[table.tableName];
508
- if (registered !== undefined) {
509
- return registered;
510
- } else if (Stdlib_Option.isSome(Internal.EffectCache.fromTableName(table.tableName))) {
511
- return ownTable(table, Internal.cacheItemSchema, undefined);
512
- } else {
513
- return Stdlib_JsError.throwWithMessage(`The storage has no table "` + table.tableName + `".`);
514
- }
515
- };
516
- let partitions = (entities, chainIds) => entities.filter(entityConfig => {
517
- if (entityConfig.storage.postgres) {
518
- return Stdlib_Option.isSome(Table.getChainIdField(entityConfig.table));
519
- } else {
520
- return false;
521
- }
522
- }).flatMap(entityConfig => chainIds.map(chainId => ({
523
- table: entityTable(entityConfig).handle,
524
- chainId: chainId,
525
- name: partitionTableName(entityConfig, chainId)
526
- })));
527
- let holding = () => client.holding();
528
- let scanCacheDir = async () => {
529
- let topEntries;
530
- try {
531
- topEntries = await Fs.promises.readdir(cacheDirPath);
532
- } catch (exn) {
533
- topEntries = [];
534
- }
535
- let result = [];
536
- await Promise.all(topEntries.map(async entry => {
537
- let entryPath = Path.join(cacheDirPath, entry);
538
- let isDir = (await Fs.promises.stat(entryPath)).isDirectory();
539
- if (isDir) {
540
- let subEntries = await Fs.promises.readdir(entryPath);
541
- let tsvs = subEntries.filter(sub => sub.endsWith(".tsv"));
542
- let chainId = Internal.EffectCache.parseChainId(entry);
543
- if (chainId === undefined) {
544
- if (Utils.$$Array.notEmpty(tsvs)) {
545
- 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);
546
181
  } else {
547
- return;
182
+ return Staging.writeDeletedValue(stage, column, row, undefined);
548
183
  }
549
- }
550
- let chainId$1 = Primitive_option.valFromOption(chainId);
551
- tsvs.forEach(sub => {
552
- let effectName = sub.slice(0, -4);
553
- let table = Internal.makeCacheTable(effectName, chainId$1);
554
- result.push([
555
- table,
556
- Path.join(entryPath, sub)
557
- ]);
558
184
  });
559
- return;
560
- }
561
- if (!entry.endsWith(".tsv")) {
562
- return;
563
185
  }
564
- let effectName = entry.slice(0, -4);
565
- let table = Internal.makeCacheTable(effectName, "crossChain");
566
- result.push([
567
- table,
568
- entryPath
569
- ]);
570
- }));
571
- return result;
572
- };
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 eagerSchemaIndexes = Env.subgraphMode.contents;
196
+ let keptEffectCaches = Env.subgraphMode.contents ? [
197
+ "envio_subgraph_eth_call",
198
+ "envio_subgraph_eth_balance",
199
+ "envio_subgraph_has_code",
200
+ "envio_subgraph_file",
201
+ "envio_subgraph_ipfs_cat",
202
+ "envio_subgraph_arweave"
203
+ ] : undefined;
204
+ let cacheDirPath = cacheDir !== undefined ? Primitive_option.valFromOption(cacheDir) : Path.resolve(".envio", "cache");
205
+ let layouts = client.layouts();
206
+ let entityIndexByName = {};
207
+ layouts.entities.forEach((layout, index) => {
208
+ entityIndexByName[layout.name] = index;
209
+ });
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);
213
+ let holding = () => client.holding();
573
214
  let restoreEffectCache = async withUpload => {
574
- if (withUpload) {
575
- let entries = await scanCacheDir();
576
- if (entries.length !== 0) {
577
- try {
578
- await client.uploadEffectCache(entries.map(param => ({
579
- table: ownTable(param[0], Internal.cacheItemSchema, undefined).handle,
580
- path: param[1]
581
- })));
582
- Logger.info(logger, "Successfully uploaded cache.", undefined);
583
- } catch (raw_exn) {
584
- let exn = Primitive_exceptions.internalToException(raw_exn);
585
- Logger.errorWithExn(logger, "Failed to upload cache, continuing without it.", exn);
586
- }
587
- } else {
588
- Logger.info(logger, "No saved effect cache to load from .envio/cache.", undefined);
589
- }
590
- }
591
215
  let cache = {};
592
- (await client.effectCacheTables()).forEach(param => {
216
+ (await client.restoreEffectCache(cacheDirPath, withUpload)).forEach(param => {
593
217
  let tableName = param.tableName;
594
- let match = Internal.EffectCache.fromTableName(tableName);
595
- if (match !== undefined) {
596
- cache[tableName] = {
597
- effectName: match[0],
598
- scope: match[1],
599
- tableName: tableName,
600
- count: param.rows
601
- };
602
- return;
603
- }
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
+ };
604
225
  });
605
226
  return cache;
606
227
  };
607
- let initialize = async (chainConfigsOpt, entitiesOpt, enumsOpt, contractMapping, envioInfo) => {
228
+ let initialize = async (chainConfigsOpt, contractMapping, envioInfo) => {
608
229
  let chainConfigs = chainConfigsOpt !== undefined ? chainConfigsOpt : [];
609
- let entities = entitiesOpt !== undefined ? entitiesOpt : [];
610
- let enums = enumsOpt !== undefined ? enumsOpt : [];
611
230
  let rowsByChain = chainConfigs.map(chainConfig => ChainState.configStorageRows(chainConfig, ecosystem, contractMapping));
612
231
  await client.initialize({
613
- sequence: CheckpointSequence.fromEntities(entities),
614
- tables: [rawEventsTable().handle].concat(entities.map(entityConfig => entityTable(entityConfig).handle)),
615
- partitions: partitions(entities, chainConfigs.map(chainConfig => chainConfig.id)),
616
- enums: enums.map(enumConfig => ({
617
- name: enumConfig.name,
618
- variants: enumConfig.variants
619
- })),
620
232
  chains: chainConfigs.map(toChainConfig),
621
233
  envioInfo: JSON.stringify(envioInfo),
622
234
  contractNames: ContractMapping.names(contractMapping),
623
- addresses: addressColumns(rowsByChain.flat())
235
+ addresses: addressColumns(rowsByChain.flat()),
236
+ keptEffectCaches: keptEffectCaches
624
237
  });
238
+ if (eagerSchemaIndexes) {
239
+ await client.ensureSchemaIndexes(chainConfigs.map(chainConfig => chainConfig.id));
240
+ }
625
241
  let cache = await restoreEffectCache(true);
626
242
  if (onInitialize !== undefined) {
627
243
  await onInitialize();
@@ -649,9 +265,11 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
649
265
  };
650
266
  let loadOrThrow = async (filter, table) => {
651
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);
652
270
  let rows;
653
271
  try {
654
- rows = await StorageClient.loadWhere(client, tableOf(table).handle, conditions);
272
+ rows = await loading;
655
273
  } catch (raw_exn) {
656
274
  let exn = Primitive_exceptions.internalToException(raw_exn);
657
275
  throw {
@@ -691,50 +309,17 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
691
309
  }));
692
310
  return columns;
693
311
  };
694
- let partitionChainIds = chainIds => {
695
- if (isolated) {
696
- return Primitive_option.some(chainIds);
697
- }
698
- };
699
- let queryTableName = (entityConfig, scope) => {
700
- if (scope === "crossChain") {
701
- return entityConfig.table.tableName;
702
- } else {
703
- return indexTableNames(entityConfig, partitionChainIds([scope]))[0];
704
- }
705
- };
706
312
  let ensureQueryIndexes = async (entityConfig, scope, filters) => {
707
- 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));
708
314
  if (building === null) {
709
315
  return;
710
316
  } else {
711
317
  return await building;
712
318
  }
713
319
  };
714
- let schemaIndexes = (entities, chainIds) => getSchemaIndexes(entities.filter(e => e.storage.postgres), partitionChainIds(chainIds)).map(IndexDefinition.toInput);
715
- let ensureSchemaIndexes = (entities, chainIds) => client.ensureSchemaIndexes(schemaIndexes(entities, chainIds));
716
- let finalizeBackfill = (entities, chainIds, readyAt) => client.finalizeBackfill(schemaIndexes(entities, chainIds), chainIds, readyAt.getTime());
717
- let dumpEffectCache = async () => {
718
- try {
719
- let tables = (await client.effectCacheTables()).filter(param => param.rows > 0);
720
- if (Utils.$$Array.notEmpty(tables)) {
721
- Logger.info(logger, `Dumping cache: ` + tables.map(param => param.tableName + " (" + param.rows.toString() + " rows)").join(", "), undefined);
722
- await client.dumpEffectCache(Stdlib_Array.filterMap(tables, param => {
723
- let tableName = param.tableName;
724
- return Stdlib_Option.map(Internal.EffectCache.fromTableName(tableName), param => ({
725
- tableName: tableName,
726
- path: Path.join(cacheDirPath, Internal.EffectCache.toCachePath(param[0], param[1]))
727
- }));
728
- }));
729
- return Logger.info(logger, `Successfully dumped cache to ` + cacheDirPath, undefined);
730
- } else {
731
- return;
732
- }
733
- } catch (raw_exn) {
734
- let exn = Primitive_exceptions.internalToException(raw_exn);
735
- return Logger.errorWithExn(logger, `Failed to dump cache.`, exn);
736
- }
737
- };
320
+ let ensureSchemaIndexes = chainIds => client.ensureSchemaIndexes(chainIds);
321
+ let finalizeBackfill = (chainIds, readyAt) => client.finalizeBackfill(chainIds, readyAt.getTime());
322
+ let dumpEffectCache = () => client.dumpEffectCache(cacheDirPath);
738
323
  let readStoredConfig = async () => {
739
324
  let stored = await client.readStoredConfig();
740
325
  let configAddresses = StorageClient.read(client, stored.configAddresses);
@@ -772,19 +357,14 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
772
357
  contractMapping: ContractMapping.fromStoredNames(match$1)
773
358
  };
774
359
  };
775
- let addChain = (chainConfig, entities, contractMapping) => client.addChain({
360
+ let addChain = (chainConfig, contractMapping) => client.addChain({
776
361
  chain: toChainConfig(chainConfig),
777
- partitions: partitions(entities, [chainConfig.id]),
778
362
  addresses: addressColumns(ChainState.configStorageRows(chainConfig, ecosystem, contractMapping))
779
363
  });
780
- let resumeInitialState = async (entities, chainIds, contractMapping) => {
364
+ let resumeInitialState = async (chainIds, contractMapping) => {
781
365
  let match = await Promise.all([
782
366
  restoreEffectCache(false),
783
- client.resume({
784
- sequence: CheckpointSequence.fromEntities(entities),
785
- tables: entities.map(entityConfig => entityTable(entityConfig).handle),
786
- chainIds: chainIds
787
- })
367
+ client.resume(chainIds)
788
368
  ]);
789
369
  let resumed = match[1];
790
370
  let addressRowsByChainId = AddressRows.group(StorageClient.read(client, resumed.addresses));
@@ -811,10 +391,10 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
811
391
  });
812
392
  let checkpointFrontier = Frontier.fromEntries(stored.map(param => [
813
393
  param[0],
814
- BigInt(param[1].checkpointId)
394
+ param[1].checkpointId
815
395
  ]));
816
396
  let reorgCheckpoints = resumed.reorgCheckpoints.map(checkpoint => ({
817
- id: BigInt(checkpoint.id),
397
+ id: checkpoint.id,
818
398
  chain_id: ChainId.normalizeOrThrow(checkpoint.chainId),
819
399
  block_number: checkpoint.blockNumber,
820
400
  block_hash: checkpoint.blockHash
@@ -841,15 +421,15 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
841
421
  });
842
422
  let setChainMeta = chainsData => client.setChainMeta(chainMeta(chainsData)).then(() => (undefined));
843
423
  let pruneStaleCheckpoints = safeCheckpoints => client.pruneCheckpoints(bounds(safeCheckpoints));
844
- let pruneStaleEntityHistory = (entityConfig, safeCheckpoints) => client.pruneHistory(entityTable(entityConfig).handle, bounds(safeCheckpoints));
845
- 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));
846
426
  let getRollbackProgressDiff = async floors => (await client.rollbackProgressDiff(bounds(floors.checkpointBounds))).map(diff => ({
847
427
  chain_id: ChainId.normalizeOrThrow(diff.chainId),
848
428
  events_processed_diff: diff.eventsProcessed,
849
429
  new_progress_block_number: diff.progressBlock
850
430
  }));
851
431
  let getRollbackData = async (entityConfig, floors) => {
852
- let match = await client.rollbackData(entityTable(entityConfig).handle, bounds(floors.checkpointBounds));
432
+ let match = await client.rollbackData(entityConfig.index, bounds(floors.checkpointBounds));
853
433
  let restored = match.restored;
854
434
  let removedIdRows;
855
435
  try {
@@ -867,29 +447,28 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
867
447
  return "crossChain";
868
448
  }
869
449
  };
870
- let removals = removedIdRows.map(row => ({
871
- entityId: S$RescriptSchema.parseOrThrow(row, rollbackRemovedIdSchema(entityConfig.table)),
872
- scope: scopeOf(row)
873
- }));
874
- let restoredEntitiesResult = [];
875
- rollbackRows.forEach(row => {
876
- let match = S$RescriptSchema.parseOrThrow(row, rollbackRowStateSchema(entityConfig.table));
877
- if (match[1] === "SET") {
878
- restoredEntitiesResult.push(row);
879
- return;
880
- }
881
- removals.push({
882
- entityId: match[0],
883
- scope: scopeOf(row)
884
- });
885
- });
886
450
  return [
887
- removals,
888
- 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))
889
456
  ];
890
457
  };
891
- let writeBatch = async (batch, rollback, config, allEntities, updatedEffectsCache, updatedEntities, registeredAddresses, chainMetaData, onWrite) => {
892
- 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));
893
472
  let rawEvents;
894
473
  if (config.enableRawEvents) {
895
474
  let seenLogCoordinates = new Set();
@@ -908,21 +487,35 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
908
487
  } else {
909
488
  rawEvents = [];
910
489
  }
911
- let staged_handles = [];
912
- let staged_seconds = {};
913
- let staged = {
914
- handles: staged_handles,
915
- 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
916
501
  };
917
502
  let input;
918
503
  try {
919
504
  let tmp;
920
505
  if (Utils.$$Array.notEmpty(rawEvents)) {
921
- let table = rawEventsTable();
922
- tmp = {
923
- table: table.handle,
924
- rows: rowsOrThrow(client, table, InternalTable.RawEvents.schema, rawEvents, staged)
925
- };
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;
926
519
  } else {
927
520
  tmp = undefined;
928
521
  }
@@ -931,7 +524,6 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
931
524
  let rolledBackAddresses = param.rolledBackAddresses;
932
525
  return {
933
526
  bounds: bounds(param.floors.checkpointBounds),
934
- tables: allEntities.map(entityConfig => entityTable(entityConfig).handle),
935
527
  progress: param.progressedChains.map(progress),
936
528
  removedAddresses: {
937
529
  chainIds: rolledBackAddresses.map(key => key.chainId),
@@ -940,7 +532,7 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
940
532
  },
941
533
  diffCheckpoints: param.diffCheckpoints.map(diff => ({
942
534
  chainId: diff.chainId,
943
- checkpointId: diff.checkpointId.toString(),
535
+ checkpointId: diff.checkpointId,
944
536
  blockNumber: diff.blockNumber
945
537
  }))
946
538
  };
@@ -953,124 +545,41 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
953
545
  totalEventsProcessed: chainAfterBatch.totalEventsProcessed
954
546
  })),
955
547
  rawEvents: tmp,
956
- entities: updatedEntities.map(update => {
957
- let shouldSaveHistory = update.shouldSaveHistory;
958
- let changes = update.changes;
959
- let scope = update.scope;
960
- let entityConfig = update.entityConfig;
961
- let table = entityTable(entityConfig);
962
- let match = Table.getChainIdField(entityConfig.table);
963
- let chainIdStamp = match !== undefined && scope !== "crossChain" ? [
964
- match,
965
- scope
966
- ] : undefined;
967
- let postgresWrite = () => {
968
- let stamped;
969
- if (chainIdStamp !== undefined) {
970
- let chainId = chainIdStamp[1];
971
- let field = chainIdStamp[0];
972
- stamped = changes.map(change => {
973
- if (change.type === "SET") {
974
- return {
975
- type: "SET",
976
- entityId: change.entityId,
977
- entity: Internal.stampChainId(change.entity, field.fieldName, chainId),
978
- checkpointId: change.checkpointId
979
- };
980
- } else {
981
- return change;
982
- }
983
- });
984
- } else {
985
- stamped = changes;
986
- }
987
- let diffCheckpointId = Stdlib_Option.flatMap(rollback, r => CheckpointSequence.findForScope(config.checkpointSequence, r.diffFrontier, scope));
988
- let historySets = [];
989
- let historySetCheckpointIds = [];
990
- let historyDeleteIds = [];
991
- let historyDeleteCheckpointIds = [];
992
- let idsWithDiff = new Set();
993
- let latestChangeById = {};
994
- let orderedIds = [];
995
- stamped.forEach(change => {
996
- let entityId = change.entityId;
997
- let entityKey = EntityId.toKey(entityId);
998
- if (Stdlib_Option.isNone(latestChangeById[entityKey])) {
999
- orderedIds.push(entityId);
1000
- }
1001
- latestChangeById[entityKey] = change;
1002
- if (!shouldSaveHistory) {
1003
- return;
1004
- }
1005
- if (change.checkpointId === diffCheckpointId) {
1006
- idsWithDiff.add(entityKey);
1007
- return;
1008
- }
1009
- if (change.type === "SET") {
1010
- historySets.push(change.entity);
1011
- historySetCheckpointIds.push(change.checkpointId.toString());
1012
- return;
1013
- }
1014
- historyDeleteIds.push(change.entityId);
1015
- historyDeleteCheckpointIds.push(change.checkpointId.toString());
1016
- });
1017
- let sets = [];
1018
- let deletes = [];
1019
- let backfill = [];
1020
- orderedIds.forEach(entityId => {
1021
- let entityKey = EntityId.toKey(entityId);
1022
- let match = latestChangeById[entityKey];
1023
- if (match.type === "SET") {
1024
- sets.push(match.entity);
1025
- } else {
1026
- deletes.push(match.entityId);
1027
- }
1028
- if (shouldSaveHistory && !idsWithDiff.has(entityKey)) {
1029
- backfill.push(entityId);
1030
- return;
1031
- }
1032
- });
1033
- let rowsOf = entities => {
1034
- if (Utils.$$Array.notEmpty(entities)) {
1035
- return rowsOrThrow(client, table, getRowSchema(entityConfig), entities, staged);
1036
- }
1037
- };
1038
- return {
1039
- sets: rowsOf(sets),
1040
- deletes: renderIds(entityConfig.table, deletes),
1041
- history: shouldSaveHistory ? ({
1042
- backfill: renderIds(entityConfig.table, backfill),
1043
- sets: rowsOf(historySets),
1044
- setCheckpointIds: historySetCheckpointIds,
1045
- deleteIds: renderIds(entityConfig.table, historyDeleteIds),
1046
- deleteCheckpointIds: historyDeleteCheckpointIds
1047
- }) : undefined
1048
- };
1049
- };
1050
- let match$1 = table.clickhouse;
1051
- let tmp;
1052
- if (changes.length !== 0 && match$1 !== undefined) {
1053
- let handle = stagedFor(staged, "ClickHouse", () => ClickHouse.stageChangesOrThrow(StorageClient.arena(client, "ClickHouse"), match$1, entityConfig, scope, changes));
1054
- staged_handles.push(handle);
1055
- tmp = handle;
1056
- } else {
1057
- 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;
1058
567
  }
1059
568
  return {
1060
- table: table.handle,
1061
- chainId: Stdlib_Option.map(chainIdStamp, param => param[1]),
1062
- postgres: Stdlib_Option.map(table.postgres, param => postgresWrite()),
1063
- clickhouse: tmp
569
+ entity: update.entityConfig.index,
570
+ chainId: Internal.chainScopeChainId(update.scope),
571
+ keepsHistory: update.shouldSaveHistory,
572
+ changes: handle
1064
573
  };
1065
574
  }),
1066
575
  chainMeta: Stdlib_Option.mapOr(chainMetaData, [], chainMeta),
1067
576
  addresses: addressColumns(registeredAddresses.map(staged => staged.row)),
1068
577
  frontier: {
1069
- chainIds: match[0],
1070
- checkpointIds: match[1]
578
+ chainIds: chainIds,
579
+ checkpointIds: frontierCheckpointIds
1071
580
  },
1072
581
  checkpoints: {
1073
- ids: batch.checkpointIds.map(id => id.toString()),
582
+ ids: batch.checkpointIds,
1074
583
  chainIds: batch.checkpointChainIds,
1075
584
  blockNumbers: batch.checkpointBlockNumbers,
1076
585
  blockHashes: batch.checkpointBlockHashes,
@@ -1078,35 +587,59 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1078
587
  keepsHistory: batch.checkpointChainIds.map(chainId => HistoryPolicy.forChain(batch.history, chainId))
1079
588
  },
1080
589
  effectCaches: updatedEffectsCache.map(param => {
1081
- 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
+ }
1082
612
  return {
1083
- table: registered.handle,
613
+ table: table.tableName,
1084
614
  create: param.shouldInitialize,
1085
- rows: rowsOrThrow(client, registered, param.itemSchema, param.items, staged)
615
+ rows: tmp
1086
616
  };
1087
617
  })
1088
618
  };
1089
- } catch (exn) {
1090
- client.discardStaged(staged_handles);
1091
- throw exn;
619
+ } catch (exn$1) {
620
+ client.discardStaged(handles);
621
+ throw exn$1;
1092
622
  }
623
+ let postgresStagingSeconds = Performance.secondsSince(stagingStarted) - clickHouseOnlyStagingSeconds.contents;
1093
624
  let timings;
1094
625
  try {
1095
626
  timings = await client.writeBatch(input);
1096
- } catch (raw_exn) {
1097
- let exn$1 = Primitive_exceptions.internalToException(raw_exn);
1098
- client.discardStaged(staged_handles);
1099
- 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);
1100
631
  }
1101
632
  timings.forEach(param => {
1102
- let name = storeName(param.store);
1103
- 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);
1104
637
  });
1105
638
  };
1106
639
  let close = () => client.close();
1107
640
  return {
1108
641
  name: postgresName,
1109
- entityStoreName: entityConfig => storeName(entityTable(entityConfig).home),
642
+ entityStoreName: entityConfig => Stdlib_Option.mapOr(layouts.entities[entityConfig.index].home, postgresName, storeName),
1110
643
  holding: holding,
1111
644
  initialize: initialize,
1112
645
  readStoredConfig: readStoredConfig,
@@ -1131,13 +664,13 @@ function make(client, logger, entitiesOpt, cacheDir, ecosystem, isolatedOpt, onI
1131
664
 
1132
665
  function clientFromEnv(config, logger, pgSchemaOpt, isHasuraEnabled, maxConnections) {
1133
666
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1134
- 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);
1135
668
  }
1136
669
 
1137
670
  function makeStorageFromEnv(config, logger, pgSchemaOpt, isHasuraEnabledOpt, maxConnections, cacheDir) {
1138
671
  let pgSchema = pgSchemaOpt !== undefined ? pgSchemaOpt : Env.Db.publicSchema;
1139
672
  let isHasuraEnabled = isHasuraEnabledOpt !== undefined ? isHasuraEnabledOpt : Env.Hasura.enabled;
1140
- 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, {
1141
674
  role: Env.Hasura.role,
1142
675
  secret: Env.Hasura.secret
1143
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);
@@ -1149,36 +682,24 @@ function makePersistenceFromConfig(config, logger, storageOpt) {
1149
682
  }
1150
683
 
1151
684
  export {
1152
- formatSeconds,
1153
- slowOnLargeDatabaseNotice,
1154
685
  storeName,
1155
686
  postgresName,
1156
- logIndexEvent,
1157
687
  postgresOptions,
1158
688
  makeClient,
1159
- partitionTableName,
1160
- indexTableNames,
1161
- getSchemaIndexes,
1162
- pgColumnInput,
1163
- rowSchemaCache,
1164
- getRowSchema,
1165
- registerEntity,
1166
- arenaConverters,
1167
- cellConverters,
1168
- converterOf,
1169
- stagedFor,
1170
- renderIds,
1171
689
  bounds,
1172
690
  progress,
1173
691
  addressColumns,
1174
692
  toChainConfig,
1175
693
  storageErrorOf,
1176
- rollbackRowStateSchema,
1177
694
  rollbackChainIdSchema,
1178
695
  rollbackRemovedIdSchema,
696
+ changeColumns,
697
+ stageOrThrow,
698
+ stageRowsOrThrow,
699
+ stageChangesOrThrow,
1179
700
  make,
1180
701
  clientFromEnv,
1181
702
  makeStorageFromEnv,
1182
703
  makePersistenceFromConfig,
1183
704
  }
1184
- /* rowSchemaCache Not a pure module */
705
+ /* rollbackChainIdSchema Not a pure module */