envio 3.1.2 → 3.2.1

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 (134) hide show
  1. package/evm.schema.json +83 -11
  2. package/fuel.schema.json +83 -11
  3. package/index.d.ts +184 -3
  4. package/package.json +6 -6
  5. package/src/Batch.res +2 -2
  6. package/src/ChainFetcher.res +27 -3
  7. package/src/ChainFetcher.res.mjs +17 -3
  8. package/src/ChainManager.res +163 -0
  9. package/src/ChainManager.res.mjs +136 -0
  10. package/src/Config.res +213 -30
  11. package/src/Config.res.mjs +102 -41
  12. package/src/Core.res +16 -10
  13. package/src/Ecosystem.res +0 -3
  14. package/src/Env.res +2 -2
  15. package/src/Env.res.mjs +2 -2
  16. package/src/Envio.res +101 -2
  17. package/src/Envio.res.mjs +2 -3
  18. package/src/EventConfigBuilder.res +87 -0
  19. package/src/EventConfigBuilder.res.mjs +53 -0
  20. package/src/EventUtils.res +2 -2
  21. package/src/FetchState.res +63 -67
  22. package/src/FetchState.res.mjs +44 -42
  23. package/src/GlobalState.res +219 -363
  24. package/src/GlobalState.res.mjs +314 -491
  25. package/src/GlobalStateManager.res +49 -59
  26. package/src/GlobalStateManager.res.mjs +5 -4
  27. package/src/GlobalStateManager.resi +1 -1
  28. package/src/HandlerLoader.res +18 -2
  29. package/src/HandlerLoader.res.mjs +16 -34
  30. package/src/HandlerRegister.res +9 -9
  31. package/src/HandlerRegister.res.mjs +9 -9
  32. package/src/Hasura.res +102 -32
  33. package/src/Hasura.res.mjs +88 -34
  34. package/src/InMemoryStore.res +10 -1
  35. package/src/InMemoryStore.res.mjs +4 -1
  36. package/src/InMemoryTable.res +83 -136
  37. package/src/InMemoryTable.res.mjs +57 -86
  38. package/src/Internal.res +70 -5
  39. package/src/Internal.res.mjs +2 -8
  40. package/src/LazyLoader.res +2 -2
  41. package/src/LazyLoader.res.mjs +3 -3
  42. package/src/LoadLayer.res +47 -60
  43. package/src/LoadLayer.res.mjs +28 -50
  44. package/src/LoadLayer.resi +2 -5
  45. package/src/LogSelection.res +90 -21
  46. package/src/LogSelection.res.mjs +72 -21
  47. package/src/Logging.res +1 -1
  48. package/src/Main.res +61 -2
  49. package/src/Main.res.mjs +37 -1
  50. package/src/Persistence.res +3 -16
  51. package/src/PgStorage.res +125 -114
  52. package/src/PgStorage.res.mjs +112 -95
  53. package/src/Ports.res +5 -0
  54. package/src/Ports.res.mjs +9 -0
  55. package/src/Prometheus.res +3 -3
  56. package/src/Prometheus.res.mjs +4 -4
  57. package/src/ReorgDetection.res +4 -4
  58. package/src/ReorgDetection.res.mjs +4 -5
  59. package/src/SafeCheckpointTracking.res +16 -16
  60. package/src/SafeCheckpointTracking.res.mjs +2 -2
  61. package/src/SimulateItems.res +10 -14
  62. package/src/SimulateItems.res.mjs +5 -2
  63. package/src/Sink.res +1 -1
  64. package/src/Sink.res.mjs +1 -2
  65. package/src/SvmTypes.res +9 -0
  66. package/src/SvmTypes.res.mjs +14 -0
  67. package/src/TestIndexer.res +35 -68
  68. package/src/TestIndexer.res.mjs +17 -48
  69. package/src/TestIndexerProxyStorage.res +23 -23
  70. package/src/TestIndexerProxyStorage.res.mjs +12 -15
  71. package/src/Throttler.res +2 -2
  72. package/src/Time.res +2 -2
  73. package/src/Time.res.mjs +2 -2
  74. package/src/UserContext.res +19 -118
  75. package/src/UserContext.res.mjs +10 -66
  76. package/src/Utils.res +15 -15
  77. package/src/Utils.res.mjs +7 -8
  78. package/src/adapters/MarkBatchProcessedAdapter.res +5 -0
  79. package/src/adapters/MarkBatchProcessedAdapter.res.mjs +14 -0
  80. package/src/bindings/BigDecimal.res +1 -1
  81. package/src/bindings/BigDecimal.res.mjs +2 -2
  82. package/src/bindings/ClickHouse.res +8 -6
  83. package/src/bindings/ClickHouse.res.mjs +5 -5
  84. package/src/bindings/Hrtime.res +1 -1
  85. package/src/bindings/Pino.res +2 -2
  86. package/src/bindings/Pino.res.mjs +3 -4
  87. package/src/db/EntityFilter.res +410 -0
  88. package/src/db/EntityFilter.res.mjs +424 -0
  89. package/src/db/EntityHistory.res +1 -1
  90. package/src/db/EntityHistory.res.mjs +1 -1
  91. package/src/db/InternalTable.res +10 -10
  92. package/src/db/InternalTable.res.mjs +41 -45
  93. package/src/db/Schema.res +2 -2
  94. package/src/db/Schema.res.mjs +3 -3
  95. package/src/db/Table.res +106 -22
  96. package/src/db/Table.res.mjs +84 -35
  97. package/src/sources/EventRouter.res +67 -2
  98. package/src/sources/EventRouter.res.mjs +45 -3
  99. package/src/sources/Evm.res +0 -7
  100. package/src/sources/Evm.res.mjs +0 -15
  101. package/src/sources/EvmChain.res +1 -1
  102. package/src/sources/EvmChain.res.mjs +1 -2
  103. package/src/sources/EvmRpcClient.res +42 -0
  104. package/src/sources/EvmRpcClient.res.mjs +64 -0
  105. package/src/sources/Fuel.res +0 -7
  106. package/src/sources/Fuel.res.mjs +0 -15
  107. package/src/sources/HyperFuelSource.res +5 -4
  108. package/src/sources/HyperFuelSource.res.mjs +2 -2
  109. package/src/sources/HyperSyncClient.res +9 -5
  110. package/src/sources/HyperSyncClient.res.mjs +2 -2
  111. package/src/sources/HyperSyncHeightStream.res +2 -2
  112. package/src/sources/HyperSyncHeightStream.res.mjs +2 -2
  113. package/src/sources/HyperSyncSource.res +12 -11
  114. package/src/sources/HyperSyncSource.res.mjs +6 -6
  115. package/src/sources/Rpc.res +1 -5
  116. package/src/sources/Rpc.res.mjs +1 -9
  117. package/src/sources/RpcSource.res +57 -21
  118. package/src/sources/RpcSource.res.mjs +47 -20
  119. package/src/sources/RpcWebSocketHeightStream.res +1 -1
  120. package/src/sources/SourceManager.res +3 -2
  121. package/src/sources/SourceManager.res.mjs +1 -1
  122. package/src/sources/Svm.res +3 -10
  123. package/src/sources/Svm.res.mjs +4 -18
  124. package/src/sources/SvmHyperSyncClient.res +265 -0
  125. package/src/sources/SvmHyperSyncClient.res.mjs +28 -0
  126. package/src/sources/SvmHyperSyncSource.res +638 -0
  127. package/src/sources/SvmHyperSyncSource.res.mjs +557 -0
  128. package/src/tui/Tui.res +9 -2
  129. package/src/tui/Tui.res.mjs +18 -3
  130. package/src/tui/components/BufferedProgressBar.res +2 -2
  131. package/src/tui/components/TuiData.res +3 -0
  132. package/svm.schema.json +523 -14
  133. package/src/TableIndices.res +0 -115
  134. package/src/TableIndices.res.mjs +0 -144
@@ -40,8 +40,6 @@ type initialState = {
40
40
  envioInfo: option<JSON.t>,
41
41
  }
42
42
 
43
- type operator = [#">" | #"=" | #"<"]
44
-
45
43
  type updatedEffectCache = {
46
44
  effect: Internal.effect,
47
45
  items: array<Internal.effectCacheItem>,
@@ -78,21 +76,10 @@ type storage = {
78
76
  ~envioInfo: JSON.t,
79
77
  ) => promise<initialState>,
80
78
  resumeInitialState: unit => promise<initialState>,
79
+ // Returns rows matching the filter.
80
+ // Field values are serialized and rows parsed with the table's field schemas.
81
81
  @raises("StorageError")
82
- loadByIdsOrThrow: 'item. (
83
- ~ids: array<string>,
84
- ~table: Table.table,
85
- ~rowsSchema: S.t<array<'item>>,
86
- ) => promise<array<'item>>,
87
- @raises("StorageError")
88
- loadByFieldOrThrow: 'item 'value. (
89
- ~fieldName: string,
90
- ~fieldSchema: S.t<'value>,
91
- ~fieldValue: 'value,
92
- ~operator: operator,
93
- ~table: Table.table,
94
- ~rowsSchema: S.t<array<'item>>,
95
- ) => promise<array<'item>>,
82
+ loadOrThrow: (~filter: EntityFilter.t, ~table: Table.table) => promise<array<unknown>>,
96
83
  // This is to download cache from the database to .envio/cache
97
84
  dumpEffectCache: unit => promise<unit>,
98
85
  reset: unit => promise<unit>,
package/src/PgStorage.res CHANGED
@@ -26,7 +26,7 @@ let makeCreateIndexQuery = (~tableName, ~indexFields, ~pgSchema) => {
26
26
  let indexName = tableName ++ "_" ++ indexFields->Array.joinUnsafe("_")
27
27
 
28
28
  // Case for indexer before envio@2.28
29
- let index = indexFields->Belt.Array.map(idx => `"${idx}"`)->Array.joinUnsafe(", ")
29
+ let index = indexFields->Array.map(idx => `"${idx}"`)->Array.joinUnsafe(", ")
30
30
  `CREATE INDEX IF NOT EXISTS "${indexName}" ON "${pgSchema}"."${tableName}"(${index});`
31
31
  }
32
32
 
@@ -55,7 +55,7 @@ let makeCreateCompositeIndexQuery = (
55
55
  ->Array.joinUnsafe("_")
56
56
  let index =
57
57
  indexFields
58
- ->Belt.Array.map(f => `"${f.fieldName}"${directionToSql(f.direction)}`)
58
+ ->Array.map(f => `"${f.fieldName}"${directionToSql(f.direction)}`)
59
59
  ->Array.joinUnsafe(", ")
60
60
  `CREATE INDEX IF NOT EXISTS "${indexName}" ON "${pgSchema}"."${tableName}"(${index});`
61
61
  }
@@ -81,7 +81,7 @@ let makeCreateTableQuery = (table: Table.table, ~pgSchema, ~isNumericArrayAsText
81
81
  ->Table.getFields
82
82
  ->Array.map(field => {
83
83
  let {fieldType, isNullable, isArray, defaultValue} = field
84
- let fieldName = field->Table.getDbFieldName
84
+ let fieldName = field->Table.getPgDbFieldName
85
85
 
86
86
  {
87
87
  `"${fieldName}" ${Table.getPgFieldType(
@@ -98,7 +98,7 @@ let makeCreateTableQuery = (table: Table.table, ~pgSchema, ~isNumericArrayAsText
98
98
  })
99
99
  ->Array.joinUnsafe(", ")
100
100
 
101
- let primaryKeyFieldNames = table->Table.getPrimaryKeyFieldNames
101
+ let primaryKeyFieldNames = table->Table.getPgPrimaryKeyFieldNames
102
102
  let primaryKey = primaryKeyFieldNames->Array.map(field => `"${field}"`)->Array.joinUnsafe(", ")
103
103
 
104
104
  `CREATE TABLE IF NOT EXISTS "${pgSchema}"."${table.tableName}"(${fieldsMapped}${primaryKeyFieldNames->Array.length > 0
@@ -116,7 +116,7 @@ let getEntityHistory = (~entityConfig: Internal.entityConfig): EntityHistory.pgE
116
116
  let cache = {
117
117
  let id = "id"
118
118
 
119
- let dataFields = entityConfig.table.fields->Belt.Array.keepMap(field =>
119
+ let dataFields = entityConfig.table.fields->Array.filterMap(field =>
120
120
  switch field {
121
121
  | Field(field) =>
122
122
  switch field.fieldName {
@@ -157,7 +157,7 @@ let getEntityHistory = (~entityConfig: Internal.entityConfig): EntityHistory.pgE
157
157
  //ignore composite indices
158
158
  let table = Table.mkTable(
159
159
  historyTableName,
160
- ~fields=dataFields->Belt.Array.concat([checkpointIdField, actionField]),
160
+ ~fields=dataFields->Array.concat([checkpointIdField, actionField]),
161
161
  )
162
162
 
163
163
  let setChangeSchema = EntityHistory.makeSetUpdateSchema(entityConfig.schema)
@@ -245,7 +245,7 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
245
245
  ->Table.getDerivedFromFields
246
246
  ->Array.forEach(derivedFromField => {
247
247
  let indexField =
248
- derivedSchema->Schema.getDerivedFromFieldName(derivedFromField)->Utils.unwrapResultExn
248
+ derivedSchema->Schema.getDerivedFromPgFieldName(derivedFromField)->Utils.unwrapResultExn
249
249
  query :=
250
250
  query.contents ++
251
251
  "\n" ++
@@ -281,16 +281,82 @@ $$ LANGUAGE plpgsql;`,
281
281
  ]
282
282
  }
283
283
 
284
- let makeLoadByIdQuery = (~pgSchema, ~tableName) => {
285
- `SELECT * FROM "${pgSchema}"."${tableName}" WHERE id = $1 LIMIT 1;`
284
+ let makeLoadQuery = (~pgSchema, ~tableName, ~condition) => {
285
+ `SELECT * FROM "${pgSchema}"."${tableName}" WHERE ${condition};`
286
286
  }
287
287
 
288
- let makeLoadByFieldQuery = (~pgSchema, ~tableName, ~fieldName, ~operator) => {
289
- `SELECT * FROM "${pgSchema}"."${tableName}" WHERE "${fieldName}" ${operator} $1;`
290
- }
291
-
292
- let makeLoadByIdsQuery = (~pgSchema, ~tableName) => {
293
- `SELECT * FROM "${pgSchema}"."${tableName}" WHERE id = ANY($1::text[]);`
288
+ // Appends the filter's serialized field values to params (mutated in place)
289
+ // and returns the matching SQL condition referencing them by index.
290
+ // Field names are spliced as quoted identifiers only after the queryFields
291
+ // lookup proves they exist on the table (and they originate from
292
+ // codegen-validated schemas), so the interpolation can't be abused.
293
+ let rec makeFilterCondition = (
294
+ ~filter: EntityFilter.t,
295
+ ~table: Table.table,
296
+ ~params: array<JSON.t>,
297
+ ) => {
298
+ // Filters reference fields by API name, while the SQL references columns
299
+ // by their possibly renamed db names.
300
+ let getQueryFieldOrThrow = fieldName =>
301
+ switch table->Table.queryFields->Dict.get(fieldName) {
302
+ | Some(queryField) => queryField
303
+ | None =>
304
+ throw(
305
+ Persistence.StorageError({
306
+ message: `Failed loading "${table.tableName}" from storage. The table doesn't have the field "${fieldName}".`,
307
+ reason: Table.NonExistingTableField(fieldName),
308
+ }),
309
+ )
310
+ }
311
+ let serializeParamOrThrow = (~queryField: Table.queryField, ~fieldName, ~fieldValue: unknown, ~isArray) => {
312
+ let param = try fieldValue->S.reverseConvertToJsonOrThrow(
313
+ isArray ? queryField.arrayFieldSchema : queryField.fieldSchema,
314
+ ) catch {
315
+ | exn =>
316
+ throw(
317
+ Persistence.StorageError({
318
+ message: `Failed loading "${table.tableName}" from storage by field "${fieldName}". Couldn't serialize provided value.`,
319
+ reason: exn,
320
+ }),
321
+ )
322
+ }
323
+ params->Array.push(param)->ignore
324
+ `$${params->Array.length->Int.toString}`
325
+ }
326
+ let scalarCondition = (~fieldName, ~fieldValue, ~op) => {
327
+ let queryField = getQueryFieldOrThrow(fieldName)
328
+ `"${queryField.pgDbFieldName}" ${op} ${serializeParamOrThrow(
329
+ ~queryField,
330
+ ~fieldName,
331
+ ~fieldValue,
332
+ ~isArray=false,
333
+ )}`
334
+ }
335
+ switch filter {
336
+ | Eq({fieldName, fieldValue}) => scalarCondition(~fieldName, ~fieldValue, ~op="=")
337
+ | Gt({fieldName, fieldValue}) => scalarCondition(~fieldName, ~fieldValue, ~op=">")
338
+ | Lt({fieldName, fieldValue}) => scalarCondition(~fieldName, ~fieldValue, ~op="<")
339
+ | In({fieldName, fieldValue}) => {
340
+ let queryField = getQueryFieldOrThrow(fieldName)
341
+ `"${queryField.pgDbFieldName}" = ANY(${serializeParamOrThrow(
342
+ ~queryField,
343
+ ~fieldName,
344
+ ~fieldValue=fieldValue->(Utils.magic: array<unknown> => unknown),
345
+ ~isArray=true,
346
+ )})`
347
+ }
348
+ | And({filters: []}) =>
349
+ throw(
350
+ Persistence.StorageError({
351
+ message: `Failed loading "${table.tableName}" from storage. The "and" filter must contain at least one nested filter.`,
352
+ reason: Utils.Error.make(`Empty "and" filter`),
353
+ }),
354
+ )
355
+ | And({filters}) =>
356
+ `(${filters
357
+ ->Array.map(filter => makeFilterCondition(~filter, ~table, ~params))
358
+ ->Array.join(" AND ")})`
359
+ }
294
360
  }
295
361
 
296
362
  let makeDeleteByIdQuery = (~pgSchema, ~tableName) => {
@@ -309,7 +375,7 @@ let makeInsertUnnestSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema, ~is
309
375
  let {quotedFieldNames, quotedNonPrimaryFieldNames, arrayFieldTypes} =
310
376
  table->Table.toSqlParams(~schema=itemSchema, ~pgSchema)
311
377
 
312
- let primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table)
378
+ let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table)
313
379
 
314
380
  `INSERT INTO "${pgSchema}"."${table.tableName}" (${quotedFieldNames->Array.joinUnsafe(", ")})
315
381
  SELECT * FROM unnest(${arrayFieldTypes
@@ -339,7 +405,7 @@ let makeInsertValuesSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema, ~it
339
405
  let {quotedFieldNames, quotedNonPrimaryFieldNames} =
340
406
  table->Table.toSqlParams(~schema=itemSchema, ~pgSchema)
341
407
 
342
- let primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table)
408
+ let primaryKeyFieldNames = Table.getPgPrimaryKeyFieldNames(table)
343
409
  let fieldsCount = quotedFieldNames->Array.length
344
410
 
345
411
  // Create placeholder variables for the VALUES clause - using $1, $2, etc.
@@ -698,9 +764,9 @@ let makeInsertDeleteUpdatesQuery = (~entityConfig: Internal.entityConfig, ~pgSch
698
764
  )
699
765
 
700
766
  // Get all field names for the INSERT statement
701
- let allHistoryFieldNames = entityConfig.table.fields->Belt.Array.keepMap(fieldOrDerived =>
767
+ let allHistoryFieldNames = entityConfig.table.fields->Array.filterMap(fieldOrDerived =>
702
768
  switch fieldOrDerived {
703
- | Field(field) => field->Table.getDbFieldName->Some
769
+ | Field(field) => field->Table.getPgDbFieldName->Some
704
770
  | DerivedFrom(_) => None
705
771
  }
706
772
  )
@@ -708,10 +774,10 @@ let makeInsertDeleteUpdatesQuery = (~entityConfig: Internal.entityConfig, ~pgSch
708
774
  allHistoryFieldNames->Array.push(EntityHistory.changeFieldName)->ignore
709
775
 
710
776
  let allHistoryFieldNamesStr =
711
- allHistoryFieldNames->Belt.Array.map(name => `"${name}"`)->Array.joinUnsafe(", ")
777
+ allHistoryFieldNames->Array.map(name => `"${name}"`)->Array.joinUnsafe(", ")
712
778
 
713
779
  // Build the SELECT part: id from unnest, envio_checkpoint_id from unnest, 'DELETE' for action, NULL for all other fields
714
- let selectParts = allHistoryFieldNames->Belt.Array.map(fieldName => {
780
+ let selectParts = allHistoryFieldNames->Array.map(fieldName => {
715
781
  switch fieldName {
716
782
  | field if field == Table.idFieldName => `u.${Table.idFieldName}`
717
783
  | field if field == EntityHistory.checkpointIdFieldName =>
@@ -772,8 +838,8 @@ let makeRawEvent = (
772
838
  eventItem: Internal.eventItem,
773
839
  ~config: Config.t,
774
840
  ): InternalTable.RawEvents.t => {
775
- let {event, eventConfig, chain, blockNumber, timestamp: blockTimestamp} = eventItem
776
- let {block, transaction, params, logIndex, srcAddress} = event
841
+ let {event, eventConfig, chain, blockNumber, blockHash, timestamp: blockTimestamp} = eventItem
842
+ let {block, transaction, params, logIndex, srcAddress} = event->Internal.toGenericEvent
777
843
  let chainId = chain->ChainMap.Chain.toChainId
778
844
  let eventId = EventUtils.packEventIndex(~logIndex, ~blockNumber)
779
845
  let blockFields =
@@ -809,7 +875,7 @@ let makeRawEvent = (
809
875
  blockNumber,
810
876
  logIndex,
811
877
  srcAddress,
812
- blockHash: block->config.ecosystem.getId,
878
+ blockHash,
813
879
  blockTimestamp,
814
880
  blockFields,
815
881
  transactionFields,
@@ -838,7 +904,7 @@ let rec writeBatch = async (
838
904
  let specificError = ref(None)
839
905
 
840
906
  let rawEvents = if config.enableRawEvents {
841
- let rows = batch.items->Belt.Array.keepMap(item =>
907
+ let rows = batch.items->Array.filterMap(item =>
842
908
  switch item {
843
909
  | Internal.Event(_) => Some(item->Internal.castUnsafeEventItem->makeRawEvent(~config))
844
910
  | Internal.Block(_) => None
@@ -869,7 +935,7 @@ let rec writeBatch = async (
869
935
  }
870
936
  }
871
937
 
872
- let setEntities = updatedEntities->Belt.Array.map(({entityConfig, changes}) => {
938
+ let setEntities = updatedEntities->Array.map(({entityConfig, changes}) => {
873
939
  let entitiesToSet = []
874
940
  let idsToDelete = []
875
941
 
@@ -888,10 +954,10 @@ let rec writeBatch = async (
888
954
  // history-table batches.
889
955
  let latestChangeById = Dict.make()
890
956
  let orderedIds = []
891
- changes->Belt.Array.forEach(change => {
957
+ changes->Array.forEach(change => {
892
958
  let entityId = change->Change.getEntityId
893
959
  if latestChangeById->Utils.Dict.dangerouslyGetNonOption(entityId)->Option.isNone {
894
- orderedIds->Belt.Array.push(entityId)
960
+ orderedIds->Array.push(entityId)
895
961
  }
896
962
  latestChangeById->Dict.set(entityId, change)
897
963
  if shouldSaveHistory {
@@ -900,19 +966,19 @@ let rec writeBatch = async (
900
966
  } else {
901
967
  switch change {
902
968
  | Delete({entityId, checkpointId}) =>
903
- batchDeleteEntityIds->Belt.Array.push(entityId)->ignore
904
- batchDeleteCheckpointIds->Belt.Array.push(checkpointId)->ignore
905
- | Set(_) => batchSetUpdates->Belt.Array.push(change)->ignore
969
+ batchDeleteEntityIds->Array.push(entityId)->ignore
970
+ batchDeleteCheckpointIds->Array.push(checkpointId)->ignore
971
+ | Set(_) => batchSetUpdates->Array.push(change)->ignore
906
972
  }
907
973
  }
908
974
  }
909
975
  })
910
976
 
911
977
  let backfillHistoryIds = Utils.Set.make()
912
- orderedIds->Belt.Array.forEach(entityId => {
978
+ orderedIds->Array.forEach(entityId => {
913
979
  switch latestChangeById->Dict.getUnsafe(entityId) {
914
- | Set({entity}) => entitiesToSet->Belt.Array.push(entity)
915
- | Delete({entityId}) => idsToDelete->Belt.Array.push(entityId)
980
+ | Set({entity}) => entitiesToSet->Array.push(entity)
981
+ | Delete({entityId}) => idsToDelete->Array.push(entityId)
916
982
  }
917
983
 
918
984
  // An id needs a history backfill iff none of its changes is the diff.
@@ -943,7 +1009,7 @@ let rec writeBatch = async (
943
1009
  }
944
1010
 
945
1011
  if batchDeleteCheckpointIds->Utils.Array.notEmpty {
946
- promises->Belt.Array.push(
1012
+ promises->Array.push(
947
1013
  sql
948
1014
  ->Postgres.preparedUnsafe(
949
1015
  makeInsertDeleteUpdatesQuery(~entityConfig, ~pgSchema),
@@ -986,7 +1052,7 @@ let rec writeBatch = async (
986
1052
  if shouldRemoveInvalidUtf8 {
987
1053
  entitiesToSet->removeInvalidUtf8InPlace
988
1054
  }
989
- promises->Belt.Array.push(
1055
+ promises->Array.push(
990
1056
  sql->setOrThrow(
991
1057
  ~items=entitiesToSet,
992
1058
  ~table=entityConfig.table,
@@ -996,7 +1062,7 @@ let rec writeBatch = async (
996
1062
  )
997
1063
  }
998
1064
  if idsToDelete->Utils.Array.notEmpty {
999
- promises->Belt.Array.push(
1065
+ promises->Array.push(
1000
1066
  sql->deleteByIdsOrThrow(~pgSchema, ~ids=idsToDelete, ~table=entityConfig.table),
1001
1067
  )
1002
1068
  }
@@ -1066,7 +1132,7 @@ let rec writeBatch = async (
1066
1132
  }),
1067
1133
  ),
1068
1134
  setRawEvents,
1069
- ]->Belt.Array.concat(setEntities)
1135
+ ]->Array.concat(setEntities)
1070
1136
 
1071
1137
  switch chainMetaData {
1072
1138
  | Some(chainsData) =>
@@ -1079,7 +1145,7 @@ let rec writeBatch = async (
1079
1145
  }
1080
1146
 
1081
1147
  if shouldSaveHistory {
1082
- setOperations->Belt.Array.push(sql =>
1148
+ setOperations->Array.push(sql =>
1083
1149
  sql->InternalTable.Checkpoints.insert(
1084
1150
  ~pgSchema,
1085
1151
  ~checkpointIds=batch.checkpointIds,
@@ -1092,7 +1158,7 @@ let rec writeBatch = async (
1092
1158
  }
1093
1159
 
1094
1160
  await setOperations
1095
- ->Belt.Array.map(dbFunc => sql->dbFunc)
1161
+ ->Array.map(dbFunc => sql->dbFunc)
1096
1162
  ->Promise.all
1097
1163
  ->Utils.Promise.ignoreValue
1098
1164
 
@@ -1108,7 +1174,7 @@ let rec writeBatch = async (
1108
1174
  // Since effect cache currently doesn't support rollback,
1109
1175
  // we can run it outside of the transaction for simplicity.
1110
1176
  updatedEffectsCache
1111
- ->Belt.Array.map(({effect, items, shouldInitialize}: Persistence.updatedEffectCache) => {
1177
+ ->Array.map(({effect, items, shouldInitialize}: Persistence.updatedEffectCache) => {
1112
1178
  setEffectCacheOrThrow(~effect, ~items, ~initialize=shouldInitialize)
1113
1179
  })
1114
1180
  ->Promise.all,
@@ -1157,15 +1223,15 @@ let rec writeBatch = async (
1157
1223
  // Returns the most recent entity state for IDs that need to be restored during rollback.
1158
1224
  // For each ID modified after the rollback target, retrieves its latest state at or before the target.
1159
1225
  let makeGetRollbackRestoredEntitiesQuery = (~entityConfig: Internal.entityConfig, ~pgSchema) => {
1160
- let dataFieldNames = entityConfig.table.fields->Belt.Array.keepMap(fieldOrDerived =>
1226
+ let dataFieldNames = entityConfig.table.fields->Array.filterMap(fieldOrDerived =>
1161
1227
  switch fieldOrDerived {
1162
- | Field(field) => field->Table.getDbFieldName->Some
1228
+ | Field(field) => field->Table.getPgDbFieldName->Some
1163
1229
  | DerivedFrom(_) => None
1164
1230
  }
1165
1231
  )
1166
1232
 
1167
1233
  let dataFieldsCommaSeparated =
1168
- dataFieldNames->Belt.Array.map(name => `"${name}"`)->Array.joinUnsafe(", ")
1234
+ dataFieldNames->Array.map(name => `"${name}"`)->Array.joinUnsafe(", ")
1169
1235
 
1170
1236
  let historyTableName = EntityHistory.historyTableName(
1171
1237
  ~entityName=entityConfig.name,
@@ -1434,80 +1500,26 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1434
1500
  }
1435
1501
  }
1436
1502
 
1437
- let loadByIdsOrThrow = async (~ids, ~table: Table.table, ~rowsSchema) => {
1438
- switch await (
1439
- switch ids {
1440
- | [_] =>
1441
- sql->Postgres.preparedUnsafe(
1442
- makeLoadByIdQuery(~pgSchema, ~tableName=table.tableName),
1443
- ids->Obj.magic,
1444
- )
1445
- | _ =>
1446
- sql->Postgres.preparedUnsafe(
1447
- makeLoadByIdsQuery(~pgSchema, ~tableName=table.tableName),
1448
- [ids]->Obj.magic,
1449
- )
1450
- }
1451
- ) {
1452
- | exception exn =>
1453
- throw(
1454
- Persistence.StorageError({
1455
- message: `Failed loading "${table.tableName}" from storage by ids`,
1456
- reason: exn,
1457
- }),
1458
- )
1459
- | rows =>
1460
- try rows->S.parseOrThrow(rowsSchema) catch {
1461
- | exn =>
1462
- throw(
1463
- Persistence.StorageError({
1464
- message: `Failed to parse "${table.tableName}" loaded from storage by ids`,
1465
- reason: exn,
1466
- }),
1467
- )
1468
- }
1469
- }
1470
- }
1471
-
1472
- let loadByFieldOrThrow = async (
1473
- ~fieldName: string,
1474
- ~fieldSchema,
1475
- ~fieldValue,
1476
- ~operator: Persistence.operator,
1477
- ~table: Table.table,
1478
- ~rowsSchema,
1479
- ) => {
1480
- let params = try [fieldValue->S.reverseConvertToJsonOrThrow(fieldSchema)]->Obj.magic catch {
1481
- | exn =>
1482
- throw(
1483
- Persistence.StorageError({
1484
- message: `Failed loading "${table.tableName}" from storage by field "${fieldName}". Couldn't serialize provided value.`,
1485
- reason: exn,
1486
- }),
1487
- )
1488
- }
1503
+ let loadOrThrow = async (~filter: EntityFilter.t, ~table: Table.table) => {
1504
+ let params = []
1505
+ let condition = makeFilterCondition(~filter, ~table, ~params)
1489
1506
  switch await sql->Postgres.preparedUnsafe(
1490
- makeLoadByFieldQuery(
1491
- ~pgSchema,
1492
- ~tableName=table.tableName,
1493
- ~fieldName,
1494
- ~operator=(operator :> string),
1495
- ),
1496
- params,
1507
+ makeLoadQuery(~pgSchema, ~tableName=table.tableName, ~condition),
1508
+ params->Obj.magic,
1497
1509
  ) {
1498
1510
  | exception exn =>
1499
1511
  throw(
1500
1512
  Persistence.StorageError({
1501
- message: `Failed loading "${table.tableName}" from storage by field "${fieldName}"`,
1513
+ message: `Failed loading "${table.tableName}" from storage by condition: ${condition}`,
1502
1514
  reason: exn,
1503
1515
  }),
1504
1516
  )
1505
1517
  | rows =>
1506
- try rows->S.parseOrThrow(rowsSchema) catch {
1518
+ try rows->S.parseOrThrow(table->Table.pgRowsSchema) catch {
1507
1519
  | exn =>
1508
1520
  throw(
1509
1521
  Persistence.StorageError({
1510
- message: `Failed to parse "${table.tableName}" loaded from storage by ids`,
1522
+ message: `Failed to parse "${table.tableName}" loaded from storage by condition: ${condition}`,
1511
1523
  reason: exn,
1512
1524
  }),
1513
1525
  )
@@ -1576,7 +1588,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1576
1588
  Logging.info(
1577
1589
  `Dumping cache: ${cacheTableInfo
1578
1590
  ->Array.map(({tableName, count}) =>
1579
- tableName ++ " (" ++ count->Belt.Int.toString ++ " rows)"
1591
+ tableName ++ " (" ++ count->Int.toString ++ " rows)"
1580
1592
  )
1581
1593
  ->Array.joinUnsafe(", ")}`,
1582
1594
  )
@@ -1620,7 +1632,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1620
1632
  sql,
1621
1633
  ~pgSchema,
1622
1634
  )->Promise.thenResolve(rawInitialStates => {
1623
- rawInitialStates->Belt.Array.map((rawInitialState): Persistence.initialChainState => {
1635
+ rawInitialStates->Array.map((rawInitialState): Persistence.initialChainState => {
1624
1636
  id: rawInitialState.id,
1625
1637
  startBlock: rawInitialState.startBlock,
1626
1638
  endBlock: rawInitialState.endBlock->Null.toOption,
@@ -1651,10 +1663,10 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1651
1663
  InternalTable.EnvioInfo.read(sql, ~pgSchema),
1652
1664
  ))
1653
1665
 
1654
- let checkpointId = (checkpointIdResult->Belt.Array.getUnsafe(0))["id"]->BigInt.fromStringOrThrow
1666
+ let checkpointId = (checkpointIdResult->Array.getUnsafe(0))["id"]->BigInt.fromStringOrThrow
1655
1667
 
1656
1668
  // Convert string checkpoint IDs from DB to bigint
1657
- let reorgCheckpoints = Belt.Array.map(reorgCheckpoints, (raw): Internal.reorgCheckpoint => {
1669
+ let reorgCheckpoints = Array.map(reorgCheckpoints, (raw): Internal.reorgCheckpoint => {
1658
1670
  checkpointId: raw["id"]->BigInt.fromStringOrThrow,
1659
1671
  chainId: raw["chain_id"],
1660
1672
  blockNumber: raw["block_number"],
@@ -1803,8 +1815,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1803
1815
  isInitialized,
1804
1816
  initialize,
1805
1817
  resumeInitialState,
1806
- loadByFieldOrThrow,
1807
- loadByIdsOrThrow,
1818
+ loadOrThrow,
1808
1819
  dumpEffectCache,
1809
1820
  reset,
1810
1821
  setChainMeta,
@@ -1883,7 +1894,7 @@ let makeStorageFromEnv = (
1883
1894
  ~pgSchema,
1884
1895
  ~userEntities=config->Config.getPgUserEntities,
1885
1896
  ~responseLimit=Env.Hasura.responseLimit,
1886
- ~schema=Schema.make(config.allEntities->Belt.Array.map(e => e.table)),
1897
+ ~schema=Schema.make(config.allEntities->Array.map(e => e.table)),
1887
1898
  ~aggregateEntities=Env.Hasura.aggregateEntities,
1888
1899
  )->Promise.catch(err => {
1889
1900
  Logging.errorWithExn(err->Utils.prettifyExn, `Error tracking tables`)->Promise.resolve
@@ -1908,7 +1919,7 @@ let makeStorageFromEnv = (
1908
1919
  ~tableConfigs=tableNames->Array.map(tableName => {
1909
1920
  Hasura.tableName,
1910
1921
  description: None,
1911
- columnDescriptions: dict{},
1922
+ columnConfigs: dict{},
1912
1923
  }),
1913
1924
  )->Promise.catch(err => {
1914
1925
  Logging.errorWithExn(