envio 3.7.0 → 3.9.0-resolvers.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 (118) hide show
  1. package/README.md +2 -2
  2. package/evm.schema.json +7 -0
  3. package/fuel.schema.json +7 -0
  4. package/index.d.ts +674 -161
  5. package/index.js +10 -0
  6. package/package.json +6 -7
  7. package/src/AddressRows.res +121 -0
  8. package/src/AddressRows.res.mjs +143 -0
  9. package/src/Batch.res +11 -0
  10. package/src/Batch.res.mjs +2 -1
  11. package/src/Bin.res +47 -0
  12. package/src/Bin.res.mjs +34 -1
  13. package/src/ChainState.res +108 -98
  14. package/src/ChainState.res.mjs +86 -67
  15. package/src/ChainState.resi +28 -15
  16. package/src/Config.res +61 -131
  17. package/src/Config.res.mjs +47 -79
  18. package/src/ContractMapping.res +66 -0
  19. package/src/ContractMapping.res.mjs +73 -0
  20. package/src/Core.res +24 -0
  21. package/src/Core.res.mjs +4 -0
  22. package/src/Ecosystem.res +7 -2
  23. package/src/Env.res +128 -1
  24. package/src/Env.res.mjs +123 -1
  25. package/src/Envio.res +54 -76
  26. package/src/EventConfigBuilder.res +316 -46
  27. package/src/EventConfigBuilder.res.mjs +231 -28
  28. package/src/FetchState.res +59 -67
  29. package/src/FetchState.res.mjs +34 -44
  30. package/src/HandlerRegister.res +26 -15
  31. package/src/HandlerRegister.res.mjs +27 -7
  32. package/src/Hasura.res +30 -22
  33. package/src/Hasura.res.mjs +11 -5
  34. package/src/InMemoryStore.res +23 -38
  35. package/src/InMemoryStore.res.mjs +13 -27
  36. package/src/IndexerState.res +40 -3
  37. package/src/IndexerState.res.mjs +30 -4
  38. package/src/IndexerState.resi +4 -1
  39. package/src/Internal.res +49 -30
  40. package/src/Internal.res.mjs +12 -16
  41. package/src/Main.res +27 -20
  42. package/src/Main.res.mjs +19 -14
  43. package/src/Metrics.res +15 -1
  44. package/src/Metrics.res.mjs +5 -1
  45. package/src/Persistence.res +46 -21
  46. package/src/Persistence.res.mjs +8 -5
  47. package/src/PgStorage.res +238 -79
  48. package/src/PgStorage.res.mjs +115 -73
  49. package/src/PruneStaleHistory.res +1 -1
  50. package/src/PruneStaleHistory.res.mjs +1 -1
  51. package/src/Rollback.res +62 -41
  52. package/src/Rollback.res.mjs +61 -19
  53. package/src/RollbackCommit.res +7 -9
  54. package/src/RollbackCommit.res.mjs +5 -6
  55. package/src/SimulateItems.res +254 -9
  56. package/src/SimulateItems.res.mjs +214 -47
  57. package/src/Sink.res +35 -26
  58. package/src/Sink.res.mjs +20 -16
  59. package/src/TestIndexer.res +121 -123
  60. package/src/TestIndexer.res.mjs +97 -102
  61. package/src/Utils.res +38 -0
  62. package/src/Utils.res.mjs +39 -2
  63. package/src/Writing.res +4 -2
  64. package/src/Writing.res.mjs +3 -2
  65. package/src/bindings/ClickHouse.res +311 -656
  66. package/src/bindings/ClickHouse.res.mjs +294 -395
  67. package/src/bindings/ClickHouseSink.res +303 -0
  68. package/src/bindings/ClickHouseSink.res.mjs +216 -0
  69. package/src/bindings/NodeJs.res +9 -0
  70. package/src/bindings/NodeJs.res.mjs +8 -1
  71. package/src/bindings/Postgres.res +9 -0
  72. package/src/bindings/Postgres.res.mjs +3 -0
  73. package/src/db/EntityHistory.res +29 -24
  74. package/src/db/EntityHistory.res.mjs +11 -19
  75. package/src/db/InternalTable.res +258 -83
  76. package/src/db/InternalTable.res.mjs +223 -85
  77. package/src/db/RollbackScope.res +29 -0
  78. package/src/db/RollbackScope.res.mjs +31 -0
  79. package/src/db/Table.res +28 -1
  80. package/src/db/Table.res.mjs +26 -2
  81. package/src/resolvers/ResolverProcess.res +809 -0
  82. package/src/resolvers/ResolverProcess.res.mjs +667 -0
  83. package/src/resolvers/ResolverQuery.res +317 -0
  84. package/src/resolvers/ResolverQuery.res.mjs +220 -0
  85. package/src/resolvers/collisions.js +108 -0
  86. package/src/resolvers/db.js +363 -0
  87. package/src/resolvers/dispatch.js +165 -0
  88. package/src/resolvers/errors.js +30 -0
  89. package/src/resolvers/graphqlSelection.js +292 -0
  90. package/src/resolvers/hasuraAction.js +84 -0
  91. package/src/resolvers/hasuraApply.js +323 -0
  92. package/src/resolvers/hasuraMetadata.js +119 -0
  93. package/src/resolvers/index.js +95 -0
  94. package/src/resolvers/manifest.js +370 -0
  95. package/src/resolvers/server.js +270 -0
  96. package/src/sources/AddressSet.res +0 -22
  97. package/src/sources/AddressStore.res +48 -88
  98. package/src/sources/AddressStore.res.mjs +11 -22
  99. package/src/sources/Evm.res +2 -0
  100. package/src/sources/Evm.res.mjs +2 -0
  101. package/src/sources/EvmHyperSyncSource.res +3 -2
  102. package/src/sources/Fuel.res +2 -0
  103. package/src/sources/Fuel.res.mjs +2 -0
  104. package/src/sources/SimulateSource.res +8 -4
  105. package/src/sources/SimulateSource.res.mjs +7 -3
  106. package/src/sources/Svm.res +36 -7
  107. package/src/sources/Svm.res.mjs +34 -4
  108. package/src/sources/SvmHyperSyncClient.res +20 -116
  109. package/src/sources/SvmHyperSyncClient.res.mjs +5 -7
  110. package/src/sources/SvmHyperSyncSource.res +89 -37
  111. package/src/sources/SvmHyperSyncSource.res.mjs +71 -39
  112. package/src/sources/TransactionStore.res +38 -0
  113. package/src/sources/TransactionStore.res.mjs +5 -0
  114. package/src/tui/Tui.res +1 -1
  115. package/src/tui/Tui.res.mjs +1 -1
  116. package/svm.schema.json +44 -156
  117. package/src/MemoryStorage.res +0 -724
  118. package/src/MemoryStorage.res.mjs +0 -601
@@ -1123,25 +1123,16 @@ function warnRejectedRegistration(verdict, chainId, contractAddress, contractNam
1123
1123
  contractName: contractName
1124
1124
  }, `Skipping contract registration: Not a valid address for this chain's ecosystem.`);
1125
1125
  }
1126
- switch (verdict.TAG) {
1127
- case "Added" :
1128
- return;
1129
- case "Duplicate" :
1130
- let existingEffectiveStartBlock = verdict.existingEffectiveStartBlock;
1131
- let effectiveStartBlock = verdict.effectiveStartBlock;
1132
- if (existingEffectiveStartBlock > effectiveStartBlock) {
1133
- return warnAddressRegistration(chainId, contractAddress, {
1134
- existingBlockNumber: existingEffectiveStartBlock,
1135
- newBlockNumber: effectiveStartBlock
1136
- }, `Skipping contract registration: Contract address is already registered at a later block number. Currently registration of the same contract address is not supported by Envio. Reach out to us if it's a problem for you.`);
1137
- } else {
1138
- return;
1139
- }
1140
- case "Conflict" :
1141
- return warnAddressRegistration(chainId, contractAddress, {
1142
- existingContractType: verdict.existingContractName,
1143
- newContractType: contractName
1144
- }, `Skipping contract registration: Contract address is already registered for one contract and cannot be registered for another contract.`);
1126
+ if (verdict.TAG === "Added") {
1127
+ return;
1128
+ }
1129
+ let existingEffectiveStartBlock = verdict.existingEffectiveStartBlock;
1130
+ let effectiveStartBlock = verdict.effectiveStartBlock;
1131
+ if (existingEffectiveStartBlock > effectiveStartBlock) {
1132
+ return warnAddressRegistration(chainId, contractAddress, {
1133
+ existingBlockNumber: existingEffectiveStartBlock,
1134
+ newBlockNumber: effectiveStartBlock
1135
+ }, `Skipping same-contract re-registration: the address is already registered for this contract. The start block does not move earlier.`);
1145
1136
  }
1146
1137
  }
1147
1138
 
@@ -1727,7 +1718,7 @@ function getReadyItemsCount(fetchState, targetSize, fromItem) {
1727
1718
  return acc;
1728
1719
  }
1729
1720
 
1730
- function make$1(startBlock, endBlock, onEventRegistrations, addressStore, addresses, maxAddrInPartition, chainId, maxOnBlockBufferSize, knownHeight, progressBlockNumberOpt, onBlockRegistrationsOpt, blockLagOpt, firstEventBlockOpt, clientFilterAddressThresholdOpt, isResumedOpt) {
1721
+ function make$1(startBlock, endBlock, onEventRegistrations, addressStore, addressRows, maxAddrInPartition, chainId, maxOnBlockBufferSize, knownHeight, progressBlockNumberOpt, onBlockRegistrationsOpt, blockLagOpt, firstEventBlockOpt, clientFilterAddressThresholdOpt, isResumedOpt) {
1731
1722
  let progressBlockNumber = progressBlockNumberOpt !== undefined ? progressBlockNumberOpt : startBlock - 1 | 0;
1732
1723
  let onBlockRegistrations = onBlockRegistrationsOpt !== undefined ? onBlockRegistrationsOpt : [];
1733
1724
  let blockLag = blockLagOpt !== undefined ? blockLagOpt : 0;
@@ -1762,29 +1753,24 @@ function make$1(startBlock, endBlock, onEventRegistrations, addressStore, addres
1762
1753
  });
1763
1754
  }
1764
1755
  let normalSelection = makeSelection(normalRegistrations, true, undefined);
1765
- AddressStore.seedBatch(addressStore, addresses.map(contract => ({
1766
- address: contract.address,
1767
- contractName: contract.contractName,
1768
- registrationBlock: contract.registrationBlock
1769
- }))).forEach((verdict, idx) => {
1770
- let contract = addresses[idx];
1771
- warnRejectedRegistration(verdict, chainId, contract.address, contract.contractName);
1772
- });
1756
+ AddressStore.seedRows(addressStore, addressRows).forEach(rejected => warnAddressRegistration(chainId, rejected.address, {
1757
+ contractName: rejected.contractName,
1758
+ existingBlockNumber: rejected.existingEffectiveStartBlock,
1759
+ newBlockNumber: rejected.effectiveStartBlock
1760
+ }, `Skipping a stored address: it is already registered for this contract.`));
1773
1761
  let dynamicContracts = new Set();
1774
1762
  let clientFilteredContracts = new Set();
1775
1763
  let registeringSetsByContract = {};
1776
- addresses.forEach(contract => {
1777
- let contractName = contract.contractName;
1764
+ Array.from(contractNamesWithNormalEvents).forEach(contractName => {
1765
+ if (addressStore.contractCount(contractName) > 0) {
1766
+ registeringSetsByContract[contractName] = AddressStore.makeSet(addressStore, contractName, undefined);
1767
+ return;
1768
+ }
1769
+ });
1770
+ addressStore.dynamicContractNames().forEach(contractName => {
1778
1771
  if (contractNamesWithNormalEvents.has(contractName)) {
1779
- if (!(contractName in registeringSetsByContract)) {
1780
- registeringSetsByContract[contractName] = AddressStore.makeSet(addressStore, contractName, undefined);
1781
- }
1782
- if (contract.registrationBlock !== -1) {
1783
- dynamicContracts.add(contractName);
1784
- return;
1785
- } else {
1786
- return;
1787
- }
1772
+ dynamicContracts.add(contractName);
1773
+ return;
1788
1774
  }
1789
1775
  });
1790
1776
  if (clientFilterAddressThreshold !== undefined) {
@@ -1797,7 +1783,7 @@ function make$1(startBlock, endBlock, onEventRegistrations, addressStore, addres
1797
1783
  }
1798
1784
  let optimizedPartitions = createPartitions(registeringSetsByContract, addressStore, dynamicContracts, clientFilteredContracts, normalSelection, maxAddrInPartition, partitions.length, partitions, progressBlockNumber, knownHeight);
1799
1785
  if (optimizedPartitions.idsInAscOrder.length === 0 && Utils.$$Array.isEmpty(onBlockRegistrations)) {
1800
- Stdlib_JsError.throwWithMessage(`Invalid configuration: Nothing to fetch on chain ` + ChainId.toString(chainId) + `. ` + (`addresses=` + addresses.length.toString() + `, `) + (`onEventRegistrations=` + onEventRegistrations.length.toString() + `, `) + (`normalRegistrations=` + normalRegistrations.length.toString() + `. `) + `Make sure that you provided at least one contract address to index, or have events with Wildcard mode enabled, or have onBlock handlers.`);
1786
+ Stdlib_JsError.throwWithMessage(`Invalid configuration: Nothing to fetch on chain ` + ChainId.toString(chainId) + `. ` + (`addresses=` + addressRows.addresses.length.toString() + `, `) + (`onEventRegistrations=` + onEventRegistrations.length.toString() + `, `) + (`normalRegistrations=` + normalRegistrations.length.toString() + `. `) + `Make sure that you provided at least one contract address to index, or have events with Wildcard mode enabled, or have onBlock handlers.`);
1801
1787
  }
1802
1788
  let buffer = [];
1803
1789
  let latestOnBlockBlockNumber;
@@ -1861,8 +1847,8 @@ function rollbackPendingQueries(mutPendingQueries, targetBlockNumber) {
1861
1847
  return adjusted;
1862
1848
  }
1863
1849
 
1864
- function rollback(fetchState, addressStore, targetBlockNumber) {
1865
- addressStore.rollback(targetBlockNumber);
1850
+ function rollback(fetchState, rolledBackAddressStore, targetBlockNumber) {
1851
+ let rolledBackAddresses = rolledBackAddressStore.rollback(targetBlockNumber);
1866
1852
  let keptPartitions = [];
1867
1853
  let nextKeptIdRef = 0;
1868
1854
  let registeringSetsByContract = {};
@@ -1921,8 +1907,8 @@ function rollback(fetchState, addressStore, targetBlockNumber) {
1921
1907
  });
1922
1908
  }
1923
1909
  }
1924
- let optimizedPartitions = createPartitions(registeringSetsByContract, addressStore, fetchState.optimizedPartitions.dynamicContracts, fetchState.optimizedPartitions.clientFilteredContracts, fetchState.normalSelection, fetchState.optimizedPartitions.maxAddrInPartition, nextKeptIdRef, keptPartitions, targetBlockNumber, fetchState.knownHeight);
1925
- return updateInternal({
1910
+ let optimizedPartitions = createPartitions(registeringSetsByContract, rolledBackAddressStore, fetchState.optimizedPartitions.dynamicContracts, fetchState.optimizedPartitions.clientFilteredContracts, fetchState.normalSelection, fetchState.optimizedPartitions.maxAddrInPartition, nextKeptIdRef, keptPartitions, targetBlockNumber, fetchState.knownHeight);
1911
+ let rolledBack = updateInternal({
1926
1912
  optimizedPartitions: fetchState.optimizedPartitions,
1927
1913
  startBlock: fetchState.startBlock,
1928
1914
  endBlock: fetchState.endBlock,
@@ -1941,6 +1927,10 @@ function rollback(fetchState, addressStore, targetBlockNumber) {
1941
1927
  tmp = item.kind === 0 ? item.blockNumber : item.blockNumber;
1942
1928
  return tmp <= targetBlockNumber;
1943
1929
  }), true, undefined, undefined);
1930
+ return {
1931
+ fetchState: rolledBack,
1932
+ rolledBackAddresses: rolledBackAddresses
1933
+ };
1944
1934
  }
1945
1935
 
1946
1936
  function resetPendingQueries(fetchState) {
@@ -154,6 +154,8 @@ let buildOnEventRegistrationWith = (
154
154
  ~isWildcard,
155
155
  ~handler,
156
156
  ~contractRegister,
157
+ ~where,
158
+ ~fieldSelection?,
157
159
  ~startBlock?,
158
160
  ) :> Internal.onEventRegistration)
159
161
  | Evm =>
@@ -299,21 +301,29 @@ let addOnEventRegistration = (
299
301
  let fieldSelection = switch eventOptions->Option.flatMap(v => v.fields) {
300
302
  | None => None
301
303
  | Some(fields) =>
302
- // Only EVM resolves a registration selection of its own; Fuel and SVM take
303
- // theirs from the event config, so an inline one would be silently dropped.
304
- if registration.config.ecosystem.name !== Evm {
304
+ switch registration.config.ecosystem.name {
305
+ | Evm =>
306
+ Some(
307
+ EventConfigBuilder.resolveInlineFieldSelection(
308
+ fields,
309
+ ~contractName,
310
+ ~eventName,
311
+ ~enableRawEvents=registration.config.enableRawEvents,
312
+ ),
313
+ )
314
+ | Svm =>
315
+ Some(
316
+ EventConfigBuilder.resolveSvmInlineFieldSelection(
317
+ fields,
318
+ ~contractName,
319
+ ~eventName,
320
+ ),
321
+ )
322
+ | Fuel =>
305
323
  JsError.throwWithMessage(
306
- `The fields option of the "${eventName}" event registration on contract "${contractName}" is only supported on EVM. Select the fields in your config instead.`,
324
+ `The fields option of the "${eventName}" event registration on contract "${contractName}" is not supported on Fuel. Select the fields in your config instead.`,
307
325
  )
308
326
  }
309
- Some(
310
- EventConfigBuilder.resolveInlineFieldSelection(
311
- fields,
312
- ~contractName,
313
- ~eventName,
314
- ~enableRawEvents=registration.config.enableRawEvents,
315
- ),
316
- )
317
327
  }
318
328
  let matched = ref(false)
319
329
  registration.config.chainMap
@@ -350,17 +360,18 @@ let addOnEventRegistration = (
350
360
  if !matched.contents {
351
361
  let (contractNames, eventNames) = registration->describeConfigured(~contractName)
352
362
  let listOr = (names, empty) =>
353
- names->Utils.Array.isEmpty ? empty : names->Array.joinUnsafe(", ")
363
+ names->Utils.Array.isEmpty ? empty : names->Utils.Array.quotedJoin
364
+ let {contractNoun, eventNoun} = registration.config.ecosystem
354
365
  if eventNames->Utils.Array.isEmpty {
355
366
  JsError.throwWithMessage(
356
- `Contract "${contractName}" is not configured on any chain, so its handler for "${eventName}" would never run. Add it to your config, or remove the registration. Configured contracts: ${listOr(
367
+ `${contractNoun->Utils.String.capitalize} "${contractName}" is not configured on any chain, so its handler for "${eventName}" would never run. Add it to your config, or remove the registration. Configured ${contractNoun}s: ${listOr(
357
368
  contractNames,
358
369
  "none",
359
370
  )}.`,
360
371
  )
361
372
  } else {
362
373
  JsError.throwWithMessage(
363
- `Event "${eventName}" is not configured on contract "${contractName}", so its handler would never run. Add it to your config, or remove the registration. Configured events on "${contractName}": ${listOr(
374
+ `${eventNoun->Utils.String.capitalize} "${eventName}" is not configured on ${contractNoun} "${contractName}", so its handler would never run. Add it to your config, or remove the registration. Configured ${eventNoun}s on "${contractName}": ${listOr(
364
375
  eventNames,
365
376
  "none",
366
377
  )}.`,
@@ -102,7 +102,7 @@ function buildOnEventRegistrationWith(config, chainId, eventConfig, isWildcard,
102
102
  case "fuel" :
103
103
  return EventConfigBuilder.buildFuelOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
104
104
  case "svm" :
105
- return EventConfigBuilder.buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, startBlock);
105
+ return EventConfigBuilder.buildSvmOnEventRegistration(eventConfig, isWildcard, handler, contractRegister, where, fieldSelection, startBlock);
106
106
  }
107
107
  }
108
108
 
@@ -200,7 +200,24 @@ function addOnEventRegistration(registration, contractName, eventName, handler,
200
200
  let isWildcard = Stdlib_Option.getOr(Stdlib_Option.flatMap(eventOptions, v => v.wildcard), false);
201
201
  let where = Stdlib_Option.flatMap(eventOptions, v => v.where);
202
202
  let fields = Stdlib_Option.flatMap(eventOptions, v => v.fields);
203
- let fieldSelection = fields !== undefined ? (registration.config.ecosystem.name !== "evm" ? Stdlib_JsError.throwWithMessage(`The fields option of the "` + eventName + `" event registration on contract "` + contractName + `" is only supported on EVM. Select the fields in your config instead.`) : undefined, EventConfigBuilder.resolveInlineFieldSelection(fields, contractName, eventName, registration.config.enableRawEvents)) : undefined;
203
+ let fieldSelection;
204
+ if (fields !== undefined) {
205
+ let fields$1 = Primitive_option.valFromOption(fields);
206
+ let match = registration.config.ecosystem.name;
207
+ switch (match) {
208
+ case "evm" :
209
+ fieldSelection = EventConfigBuilder.resolveInlineFieldSelection(fields$1, contractName, eventName, registration.config.enableRawEvents);
210
+ break;
211
+ case "fuel" :
212
+ fieldSelection = Stdlib_JsError.throwWithMessage(`The fields option of the "` + eventName + `" event registration on contract "` + contractName + `" is not supported on Fuel. Select the fields in your config instead.`);
213
+ break;
214
+ case "svm" :
215
+ fieldSelection = EventConfigBuilder.resolveSvmInlineFieldSelection(fields$1, contractName, eventName);
216
+ break;
217
+ }
218
+ } else {
219
+ fieldSelection = undefined;
220
+ }
204
221
  let matched = {
205
222
  contents: false
206
223
  };
@@ -220,19 +237,22 @@ function addOnEventRegistration(registration, contractName, eventName, handler,
220
237
  if (matched.contents) {
221
238
  return;
222
239
  }
223
- let match = describeConfigured(registration, contractName);
224
- let eventNames = match[1];
240
+ let match$1 = describeConfigured(registration, contractName);
241
+ let eventNames = match$1[1];
225
242
  let listOr = (names, empty) => {
226
243
  if (Utils.$$Array.isEmpty(names)) {
227
244
  return empty;
228
245
  } else {
229
- return names.join(", ");
246
+ return Utils.$$Array.quotedJoin(names);
230
247
  }
231
248
  };
249
+ let match$2 = registration.config.ecosystem;
250
+ let eventNoun = match$2.eventNoun;
251
+ let contractNoun = match$2.contractNoun;
232
252
  if (Utils.$$Array.isEmpty(eventNames)) {
233
- return Stdlib_JsError.throwWithMessage(`Contract "` + contractName + `" is not configured on any chain, so its handler for "` + eventName + `" would never run. Add it to your config, or remove the registration. Configured contracts: ` + listOr(match[0], "none") + `.`);
253
+ return Stdlib_JsError.throwWithMessage(Utils.$$String.capitalize(contractNoun) + ` "` + contractName + `" is not configured on any chain, so its handler for "` + eventName + `" would never run. Add it to your config, or remove the registration. Configured ` + contractNoun + `s: ` + listOr(match$1[0], "none") + `.`);
234
254
  } else {
235
- return Stdlib_JsError.throwWithMessage(`Event "` + eventName + `" is not configured on contract "` + contractName + `", so its handler would never run. Add it to your config, or remove the registration. Configured events on "` + contractName + `": ` + listOr(eventNames, "none") + `.`);
255
+ return Stdlib_JsError.throwWithMessage(Utils.$$String.capitalize(eventNoun) + ` "` + eventName + `" is not configured on ` + contractNoun + ` "` + contractName + `", so its handler would never run. Add it to your config, or remove the registration. Configured ` + eventNoun + `s on "` + contractName + `": ` + listOr(eventNames, "none") + `.`);
236
256
  }
237
257
  }
238
258
 
package/src/Hasura.res CHANGED
@@ -286,9 +286,7 @@ let createSelectPermission = async (
286
286
  // column joins alongside the id — without it the relationship would resolve to
287
287
  // another chain's row with the same id.
288
288
  let makeColumnMapping = (~relationalKey, ~isDerivedFrom, ~chainIdColumn) => {
289
- let pairs = [
290
- isDerivedFrom ? `"id": "${relationalKey}"` : `"${relationalKey}": "id"`,
291
- ]
289
+ let pairs = [isDerivedFrom ? `"id": "${relationalKey}"` : `"${relationalKey}": "id"`]
292
290
  switch chainIdColumn {
293
291
  | Some(column) => pairs->Array.push(`"${column}": "${column}"`)->ignore
294
292
  | None => ()
@@ -309,7 +307,6 @@ let createEntityRelationship = async (
309
307
  ~chainIdColumn: option<string>,
310
308
  ~comment: option<string>=?,
311
309
  ) => {
312
-
313
310
  let tableJson = {
314
311
  "schema": pgSchema,
315
312
  "name": tableName,
@@ -347,15 +344,7 @@ let createEntityRelationship = async (
347
344
  )
348
345
  }
349
346
 
350
- let trackDatabase = async (
351
- ~endpoint,
352
- ~auth,
353
- ~pgSchema,
354
- ~userEntities: array<Internal.entityConfig>,
355
- ~aggregateEntities,
356
- ~responseLimit,
357
- ~schema,
358
- ) => {
347
+ let makeTableConfigs = (~userEntities: array<Internal.entityConfig>) => {
359
348
  let exposedInternalTableConfigs = [
360
349
  {
361
350
  tableName: InternalTable.RawEvents.table.tableName,
@@ -373,12 +362,27 @@ let trackDatabase = async (
373
362
  columnConfigs: dict{},
374
363
  },
375
364
  ]
376
- let userTableConfigs = userEntities->Array.map(entity => {
377
- tableName: entity.table.tableName,
378
- description: entity.table.description,
379
- columnConfigs: entity.table->makeColumnConfigs,
380
- })
381
- let tableConfigs = [exposedInternalTableConfigs, userTableConfigs]->Array.flat
365
+ let userTableConfigs =
366
+ userEntities
367
+ ->Array.filter(entity => !entity.internal)
368
+ ->Array.map(entity => {
369
+ tableName: entity.table.tableName,
370
+ description: entity.table.description,
371
+ columnConfigs: entity.table->makeColumnConfigs,
372
+ })
373
+ [exposedInternalTableConfigs, userTableConfigs]->Array.flat
374
+ }
375
+
376
+ let trackDatabase = async (
377
+ ~endpoint,
378
+ ~auth,
379
+ ~pgSchema,
380
+ ~userEntities: array<Internal.entityConfig>,
381
+ ~aggregateEntities,
382
+ ~responseLimit,
383
+ ~schema,
384
+ ) => {
385
+ let tableConfigs = makeTableConfigs(~userEntities)
382
386
  let tableNames = tableConfigs->Array.map(c => c.tableName)
383
387
 
384
388
  Logging.info("Tracking tables in Hasura")
@@ -414,10 +418,14 @@ let trackDatabase = async (
414
418
  ->Option.flatMap(e => e.table->Table.getChainIdField)
415
419
  ->Option.map(Table.getPgDbFieldName)
416
420
 
417
- for i in 0 to userEntities->Array.length - 1 {
418
- let entityConfig = userEntities->Array.getUnsafe(i)
421
+ // Relationships to an @internal entity can't exist here: codegen rejects a
422
+ // reference from an exposed entity to an @internal one.
423
+ let exposedEntities = userEntities->Array.filter(e => !e.internal)
424
+ for i in 0 to exposedEntities->Array.length - 1 {
425
+ let entityConfig = exposedEntities->Array.getUnsafe(i)
419
426
  let {tableName} = entityConfig.table
420
- let ownChainIdColumn = entityConfig.table->Table.getChainIdField->Option.map(Table.getPgDbFieldName)
427
+ let ownChainIdColumn =
428
+ entityConfig.table->Table.getChainIdField->Option.map(Table.getPgDbFieldName)
421
429
  let sharedChainIdColumn = mappedEntity =>
422
430
  switch (ownChainIdColumn, chainIdColumnOf(mappedEntity)) {
423
431
  | (Some(column), Some(_)) => Some(column)
@@ -285,7 +285,7 @@ async function createEntityRelationship(endpoint, auth, pgSchema, tableName, rel
285
285
  });
286
286
  }
287
287
 
288
- async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEntities, responseLimit, schema) {
288
+ function makeTableConfigs(userEntities) {
289
289
  let exposedInternalTableConfigs = [
290
290
  {
291
291
  tableName: InternalTable.RawEvents.table.tableName,
@@ -303,15 +303,19 @@ async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEn
303
303
  columnConfigs: {}
304
304
  }
305
305
  ];
306
- let userTableConfigs = userEntities.map(entity => ({
306
+ let userTableConfigs = userEntities.filter(entity => !entity.internal).map(entity => ({
307
307
  tableName: entity.table.tableName,
308
308
  description: entity.table.description,
309
309
  columnConfigs: makeColumnConfigs(entity.table)
310
310
  }));
311
- let tableConfigs = [
311
+ return [
312
312
  exposedInternalTableConfigs,
313
313
  userTableConfigs
314
314
  ].flat();
315
+ }
316
+
317
+ async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEntities, responseLimit, schema) {
318
+ let tableConfigs = makeTableConfigs(userEntities);
315
319
  let tableNames = tableConfigs.map(c => c.tableName);
316
320
  Logging.info("Tracking tables in Hasura");
317
321
  await clearHasuraMetadata(endpoint, auth);
@@ -322,8 +326,9 @@ async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEn
322
326
  await createSelectPermission(endpoint, auth, tableName, pgSchema, responseLimit, aggregateEntities);
323
327
  }
324
328
  let chainIdColumnOf = entityName => Stdlib_Option.map(Stdlib_Option.flatMap(userEntities.find(e => e.name === entityName), e => Table.getChainIdField(e.table)), Table.getPgDbFieldName);
325
- for (let i$1 = 0, i_finish$1 = userEntities.length; i$1 < i_finish$1; ++i$1) {
326
- let entityConfig = userEntities[i$1];
329
+ let exposedEntities = userEntities.filter(e => !e.internal);
330
+ for (let i$1 = 0, i_finish$1 = exposedEntities.length; i$1 < i_finish$1; ++i$1) {
331
+ let entityConfig = exposedEntities[i$1];
327
332
  let match = entityConfig.table;
328
333
  let tableName$1 = match.tableName;
329
334
  let ownChainIdColumn = Stdlib_Option.map(Table.getChainIdField(entityConfig.table), Table.getPgDbFieldName);
@@ -365,6 +370,7 @@ export {
365
370
  createSelectPermission,
366
371
  makeColumnMapping,
367
372
  createEntityRelationship,
373
+ makeTableConfigs,
368
374
  trackDatabase,
369
375
  }
370
376
  /* Rest Not a pure module */
@@ -127,14 +127,18 @@ let dropCommittedEffects = (
127
127
 
128
128
  let prepareRollbackDiff = async (
129
129
  state: IndexerState.t,
130
+ ~rollbackScope: RollbackScope.t,
130
131
  ~rollbackTargetCheckpointId,
131
132
  ~rollbackDiffCheckpointId,
132
- ~progressBlockNumberByChainId,
133
+ ~progressedChains,
134
+ ~rolledBackAddresses,
133
135
  ) => {
134
136
  state->IndexerState.beginRollbackDiff(
135
137
  ~targetCheckpointId=rollbackTargetCheckpointId,
136
138
  ~diffCheckpointId=rollbackDiffCheckpointId,
137
- ~progressBlockNumberByChainId,
139
+ ~scope=rollbackScope,
140
+ ~progressedChains,
141
+ ~rolledBackAddresses,
138
142
  )
139
143
  let persistence = state->IndexerState.persistence
140
144
  let committedCheckpointId = state->IndexerState.committedCheckpointId
@@ -148,8 +152,9 @@ let prepareRollbackDiff = async (
148
152
  let _ = await persistence.allEntities
149
153
  ->Array.filter(entityConfig => entityConfig.storage.postgres)
150
154
  ->Array.map(async entityConfig => {
151
- let (removals, restoredEntitiesResult) = await persistence.storage.getRollbackData(
155
+ let (removals, restoredEntities) = await persistence.storage.getRollbackData(
152
156
  ~entityConfig,
157
+ ~scope=rollbackScope,
153
158
  ~rollbackTargetCheckpointId,
154
159
  )
155
160
 
@@ -166,11 +171,6 @@ let prepareRollbackDiff = async (
166
171
  )
167
172
  })
168
173
 
169
- let restoredEntities =
170
- restoredEntitiesResult
171
- ->S.parseOrThrow(entityConfig.table->Table.pgRowsSchema)
172
- ->(Utils.magic: array<unknown> => array<Internal.entity>)
173
-
174
174
  restoredEntities->Array.forEach((entity: Internal.entity) => {
175
175
  let scope = entity->takeRowScope(~entityConfig)
176
176
  setEntities->Utils.Dict.push(entityConfig.name, entity.id)
@@ -199,12 +199,6 @@ let prepareRollbackDiff = async (
199
199
  // registered them: the store is where they already live, and it knows which
200
200
  // ones the database hasn't seen yet.
201
201
  let setBatchDcs = (state: IndexerState.t, ~batch: Batch.t) => {
202
- let inMemTable = state->getInMemTable(
203
- ~entityConfig=InternalTable.EnvioAddresses.entityConfig,
204
- ~scope=CrossChain,
205
- )
206
- let committedCheckpointId = state->IndexerState.committedCheckpointId
207
-
208
202
  batch.progressedChainsById->Utils.Dict.forEach(progressedChain => {
209
203
  let chainId = progressedChain.fetchState.chainId
210
204
  let chainState = state->IndexerState.getChainState(~chainId)
@@ -224,31 +218,22 @@ let setBatchDcs = (state: IndexerState.t, ~batch: Batch.t) => {
224
218
  }
225
219
  }
226
220
 
227
- chainState
228
- ->ChainState.drainAddressesForWrite(
229
- ~toBlockInclusive=progressedChain.progressBlockNumber,
230
- ~checkpointBlockNumbers,
231
- )
232
- ->Array.forEach(dc => {
233
- let entity: InternalTable.EnvioAddresses.t = {
234
- id: InternalTable.EnvioAddresses.makeId(~chainId, ~address=dc.address),
235
- chainId,
236
- contractName: dc.contractName,
237
- registrationBlock: dc.registrationBlock,
238
- // Only ever written, never read back. Kept on the table so the column
239
- // doesn't need a migration.
240
- registrationLogIndex: -1,
241
- }
242
-
243
- inMemTable->InMemoryTable.Entity.set(
244
- ~committedCheckpointId,
245
- Set({
246
- entityId: entity.id->EntityId.unsafeOfString,
247
- checkpointId: checkpointIds->Array.getUnsafe(dc.checkpointIdx),
248
- entity: entity->InternalTable.EnvioAddresses.castToInternal,
249
- }),
221
+ batch.registeredAddresses->Array.pushMany(
222
+ chainState
223
+ ->ChainState.drainAddressesForWrite(
224
+ ~toBlockInclusive=progressedChain.progressBlockNumber,
225
+ ~checkpointBlockNumbers,
250
226
  )
251
- })
227
+ ->Array.map((dc): AddressRows.staged => {
228
+ row: {
229
+ chainId,
230
+ address: dc.address,
231
+ contractId: dc.contractId,
232
+ registrationBlock: dc.registrationBlock,
233
+ },
234
+ checkpointId: checkpointIds->Array.getUnsafe(dc.checkpointIdx),
235
+ }),
236
+ )->ignore
252
237
  }
253
238
  })
254
239
  }
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Table from "./db/Table.res.mjs";
4
4
  import * as Utils from "./Utils.res.mjs";
5
- import * as Config from "./Config.res.mjs";
6
5
  import * as Internal from "./Internal.res.mjs";
7
6
  import * as ChainState from "./ChainState.res.mjs";
8
7
  import * as EffectState from "./EffectState.res.mjs";
@@ -12,7 +11,6 @@ import * as InMemoryTable from "./InMemoryTable.res.mjs";
12
11
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
13
12
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
14
13
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
15
- import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
16
14
 
17
15
  function getInMemTable(state, entityConfig, scope) {
18
16
  let tmp;
@@ -108,14 +106,14 @@ function dropCommittedEffects(inMemTable, committedCheckpointId, keepLoadedFromD
108
106
  inMemTable.changesCount = inMemTable.changesCount - keysToDelete.length;
109
107
  }
110
108
 
111
- async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId) {
112
- IndexerState.beginRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressBlockNumberByChainId);
109
+ async function prepareRollbackDiff(state, rollbackScope, rollbackTargetCheckpointId, rollbackDiffCheckpointId, progressedChains, rolledBackAddresses) {
110
+ IndexerState.beginRollbackDiff(state, rollbackTargetCheckpointId, rollbackDiffCheckpointId, rollbackScope, progressedChains, rolledBackAddresses);
113
111
  let persistence = IndexerState.persistence(state);
114
112
  let committedCheckpointId = IndexerState.committedCheckpointId(state);
115
113
  let deletedEntities = {};
116
114
  let setEntities = {};
117
115
  await Promise.all(persistence.allEntities.filter(entityConfig => entityConfig.storage.postgres).map(async entityConfig => {
118
- let match = await persistence.storage.getRollbackData(entityConfig, rollbackTargetCheckpointId);
116
+ let match = await persistence.storage.getRollbackData(entityConfig, rollbackScope, rollbackTargetCheckpointId);
119
117
  match[0].forEach(param => {
120
118
  let entityId = param.entityId;
121
119
  Utils.Dict.push(deletedEntities, entityConfig.name, entityId);
@@ -125,8 +123,7 @@ async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDi
125
123
  checkpointId: rollbackDiffCheckpointId
126
124
  });
127
125
  });
128
- let restoredEntities = S$RescriptSchema.parseOrThrow(match[1], Table.pgRowsSchema(entityConfig.table));
129
- restoredEntities.forEach(entity => {
126
+ match[1].forEach(entity => {
130
127
  let scope = takeRowScope(entity, entityConfig);
131
128
  Utils.Dict.push(setEntities, entityConfig.name, entity.id);
132
129
  InMemoryTable.Entity.set(getInMemTable(state, entityConfig, scope), committedCheckpointId, {
@@ -144,8 +141,6 @@ async function prepareRollbackDiff(state, rollbackTargetCheckpointId, rollbackDi
144
141
  }
145
142
 
146
143
  function setBatchDcs(state, batch) {
147
- let inMemTable = getInMemTable(state, Config.EnvioAddresses.entityConfig, "crossChain");
148
- let committedCheckpointId = IndexerState.committedCheckpointId(state);
149
144
  Utils.Dict.forEach(batch.progressedChainsById, progressedChain => {
150
145
  let chainId = progressedChain.fetchState.chainId;
151
146
  let chainState = IndexerState.getChainState(state, chainId);
@@ -160,24 +155,15 @@ function setBatchDcs(state, batch) {
160
155
  checkpointBlockNumbers.push(batch.checkpointBlockNumbers[idx]);
161
156
  }
162
157
  }
163
- ChainState.drainAddressesForWrite(chainState, progressedChain.progressBlockNumber, checkpointBlockNumbers).forEach(dc => {
164
- let entity_id = Config.EnvioAddresses.makeId(chainId, dc.address);
165
- let entity_registration_block = dc.registrationBlock;
166
- let entity_contract_name = dc.contractName;
167
- let entity = {
168
- id: entity_id,
169
- chain_id: chainId,
170
- registration_block: entity_registration_block,
171
- registration_log_index: -1,
172
- contract_name: entity_contract_name
173
- };
174
- InMemoryTable.Entity.set(inMemTable, committedCheckpointId, {
175
- type: "SET",
176
- entityId: entity_id,
177
- entity: entity,
178
- checkpointId: checkpointIds[dc.checkpointIdx]
179
- });
180
- });
158
+ batch.registeredAddresses.push(...ChainState.drainAddressesForWrite(chainState, progressedChain.progressBlockNumber, checkpointBlockNumbers).map(dc => ({
159
+ row: {
160
+ chainId: chainId,
161
+ address: dc.address,
162
+ contractId: dc.contractId,
163
+ registrationBlock: dc.registrationBlock
164
+ },
165
+ checkpointId: checkpointIds[dc.checkpointIdx]
166
+ })));
181
167
  });
182
168
  }
183
169