envio 3.1.1 → 3.2.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 (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 +52 -0
  19. package/src/EventConfigBuilder.res.mjs +32 -0
  20. package/src/EventUtils.res +2 -2
  21. package/src/FetchState.res +126 -71
  22. package/src/FetchState.res.mjs +73 -51
  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 +12 -1
  29. package/src/HandlerLoader.res.mjs +6 -1
  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 +54 -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 +4 -4
  46. package/src/LogSelection.res.mjs +5 -7
  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 +17 -57
  68. package/src/TestIndexer.res.mjs +14 -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 +10 -9
  114. package/src/sources/HyperSyncSource.res.mjs +4 -4
  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
package/src/db/Schema.res CHANGED
@@ -6,11 +6,11 @@ let make = (tables: array<Table.table>) => {
6
6
 
7
7
  exception UndefinedEntity(Table.derivedFromField)
8
8
  exception UndefinedFieldInEntity(Table.derivedFromField)
9
- let getDerivedFromFieldName = (schema: t, derivedFromField: Table.derivedFromField) =>
9
+ let getDerivedFromPgFieldName = (schema: t, derivedFromField: Table.derivedFromField) =>
10
10
  switch schema->Utils.Dict.dangerouslyGetNonOption(derivedFromField.derivedFromEntity) {
11
11
  | Some(entity) =>
12
12
  switch entity->Table.getFieldByName(derivedFromField.derivedFromField) {
13
- | Some(field) => field->Table.getFieldName->Ok
13
+ | Some(field) => field->Table.getPgFieldName->Ok
14
14
  | None => Error(UndefinedFieldInEntity(derivedFromField)) //Unexpected, schema should be parsed on codegen
15
15
  }
16
16
  | None => Error(UndefinedEntity(derivedFromField)) //Unexpected, schema should be parsed on codegen
@@ -14,7 +14,7 @@ let UndefinedEntity = /* @__PURE__ */Primitive_exceptions.create("Schema.Undefin
14
14
 
15
15
  let UndefinedFieldInEntity = /* @__PURE__ */Primitive_exceptions.create("Schema.UndefinedFieldInEntity");
16
16
 
17
- function getDerivedFromFieldName(schema, derivedFromField) {
17
+ function getDerivedFromPgFieldName(schema, derivedFromField) {
18
18
  let entity = schema[derivedFromField.derivedFromEntity];
19
19
  if (entity === undefined) {
20
20
  return {
@@ -29,7 +29,7 @@ function getDerivedFromFieldName(schema, derivedFromField) {
29
29
  if (field !== undefined) {
30
30
  return {
31
31
  TAG: "Ok",
32
- _0: Table.getFieldName(field)
32
+ _0: Table.getPgFieldName(field)
33
33
  };
34
34
  } else {
35
35
  return {
@@ -46,6 +46,6 @@ export {
46
46
  make,
47
47
  UndefinedEntity,
48
48
  UndefinedFieldInEntity,
49
- getDerivedFromFieldName,
49
+ getDerivedFromPgFieldName,
50
50
  }
51
51
  /* Table Not a pure module */
package/src/db/Table.res CHANGED
@@ -44,6 +44,11 @@ type field = {
44
44
  linkedEntity: option<string>,
45
45
  defaultValue: option<string>,
46
46
  description: option<string>,
47
+ // Override the column name per storage backend (eg when `column_name_format:
48
+ // snake_case` is configured), while the API keeps using fieldName. The
49
+ // backends can be configured with different formats, so each gets its own override.
50
+ postgresDbName: option<string>,
51
+ clickhouseDbName: option<string>,
47
52
  }
48
53
 
49
54
  type derivedFromField = {
@@ -66,6 +71,8 @@ let mkField = (
66
71
  ~isIndex=false,
67
72
  ~linkedEntity=?,
68
73
  ~description=?,
74
+ ~postgresDbName=?,
75
+ ~clickhouseDbName=?,
69
76
  ) =>
70
77
  {
71
78
  fieldName,
@@ -78,6 +85,8 @@ let mkField = (
78
85
  linkedEntity,
79
86
  defaultValue: default,
80
87
  description,
88
+ postgresDbName,
89
+ clickhouseDbName,
81
90
  }->Field
82
91
 
83
92
  let mkDerivedFromField = (fieldName, ~derivedFromEntity, ~derivedFromField, ~description=?) =>
@@ -96,12 +105,29 @@ let getUserDefinedFieldName = fieldOrDerived =>
96
105
 
97
106
  let isLinkedEntityField = field => field.linkedEntity->Option.isSome
98
107
 
99
- let getDbFieldName = field =>
108
+ // The field name exposed to the user-facing APIs (entity records, getWhere,
109
+ // Hasura GraphQL). Entity references get an `_id` suffix since the column
110
+ // stores the referenced entity id.
111
+ let getApiFieldName = field =>
100
112
  field->isLinkedEntityField ? field.fieldName ++ "_id" : field.fieldName
101
113
 
102
- let getFieldName = fieldOrDerived =>
114
+ // The actual column name in the storage. Matches the API field name unless
115
+ // the storage is configured with a different column naming.
116
+ let getPgDbFieldName = field =>
117
+ switch field.postgresDbName {
118
+ | Some(dbName) => dbName
119
+ | None => field->getApiFieldName
120
+ }
121
+
122
+ let getClickHouseDbFieldName = field =>
123
+ switch field.clickhouseDbName {
124
+ | Some(dbName) => dbName
125
+ | None => field->getApiFieldName
126
+ }
127
+
128
+ let getPgFieldName = fieldOrDerived =>
103
129
  switch fieldOrDerived {
104
- | Field(field) => field->getDbFieldName
130
+ | Field(field) => field->getPgDbFieldName
105
131
  | DerivedFrom({fieldName}) => fieldName
106
132
  }
107
133
 
@@ -177,10 +203,10 @@ let mkTable = (tableName, ~compositeIndices=[], ~fields, ~description=?) => {
177
203
  description,
178
204
  }
179
205
 
180
- let getPrimaryKeyFieldNames = table =>
206
+ let getPgPrimaryKeyFieldNames = table =>
181
207
  table.fields->Array.filterMap(field =>
182
208
  switch field {
183
- | Field({isPrimaryKey: true, fieldName}) => Some(fieldName)
209
+ | Field({isPrimaryKey: true} as field) => Some(field->getPgDbFieldName)
184
210
  | _ => None
185
211
  }
186
212
  )
@@ -193,10 +219,6 @@ let getFields = table =>
193
219
  }
194
220
  )
195
221
 
196
- let getFieldNames = table => {
197
- table->getFields->Array.map(getDbFieldName)
198
- }
199
-
200
222
  let getNonDefaultFields = table =>
201
223
  table.fields->Array.filterMap(field =>
202
224
  switch field {
@@ -223,23 +245,82 @@ let getDerivedFromFields = table =>
223
245
  }
224
246
  )
225
247
 
226
- let getNonDefaultFieldNames = table => {
227
- table->getNonDefaultFields->Array.map(getDbFieldName)
228
- }
229
-
230
248
  let getFieldByName = (table, fieldName) =>
231
249
  table.fields->Array.find(field => field->getUserDefinedFieldName === fieldName)
232
250
 
233
251
  // TODO: Test whether it should be passed via args and match the column type
234
252
 
235
- let getFieldByDbName = (table, dbFieldName) =>
253
+ let getFieldByApiName = (table, apiFieldName) =>
236
254
  table.fields->Array.find(field =>
237
255
  switch field {
238
- | Field(f) => f->getDbFieldName
256
+ | Field(f) => f->getApiFieldName
239
257
  | DerivedFrom({fieldName}) => fieldName
240
- } === dbFieldName
258
+ } === apiFieldName
241
259
  )
242
260
 
261
+ // Both schema instances are created once per field: rescript-schema compiles
262
+ // and caches operations on the schema instance, so building S.array(fieldSchema)
263
+ // per query would recompile the serializer on every call.
264
+ type queryField = {
265
+ fieldSchema: S.t<unknown>,
266
+ // Serializes the values array of an "in" filter
267
+ arrayFieldSchema: S.t<unknown>,
268
+ // The Postgres column referenced in load SQL, which only differs from the
269
+ // API field name keying this entry when column renaming is configured.
270
+ // Loads are served by Postgres only (ClickHouse is a write-only sink), so
271
+ // no ClickHouse counterpart is needed here.
272
+ pgDbFieldName: string,
273
+ }
274
+ let queryFields: table => dict<queryField> = Utils.WeakMap.memoize(table => {
275
+ let dict = Dict.make()
276
+ table.fields->Array.forEach(field =>
277
+ switch field {
278
+ | Field(field) =>
279
+ dict->Dict.set(
280
+ field->getApiFieldName,
281
+ {
282
+ fieldSchema: field.fieldSchema,
283
+ arrayFieldSchema: S.array(field.fieldSchema)->S.toUnknown,
284
+ pgDbFieldName: field->getPgDbFieldName,
285
+ },
286
+ )
287
+ | DerivedFrom(_) => ()
288
+ }
289
+ )
290
+ dict
291
+ })
292
+
293
+ // Parses rows into entity objects keyed by API field names (the camelCase
294
+ // record field names are type-level only), reading each value from the
295
+ // row key produced by ~rowFieldName.
296
+ let makeRowsSchema = (table, ~rowFieldName) =>
297
+ S.array(
298
+ S.object(s => {
299
+ let dict = Dict.make()
300
+ table.fields->Array.forEach(
301
+ field =>
302
+ switch field {
303
+ | Field(field) =>
304
+ dict->Dict.set(field->getApiFieldName, s.field(field->rowFieldName, field.fieldSchema))
305
+ | DerivedFrom(_) => ()
306
+ },
307
+ )
308
+ dict
309
+ })->(Utils.magic: S.t<dict<unknown>> => S.t<unknown>),
310
+ )
311
+
312
+ let rowsSchema: table => S.t<array<unknown>> = Utils.WeakMap.memoize(table =>
313
+ table->makeRowsSchema(~rowFieldName=getApiFieldName)
314
+ )
315
+
316
+ // Rows loaded from Postgres are keyed by the possibly renamed column names.
317
+ // Lives here rather than in PgStorage because InMemoryStore also parses
318
+ // Postgres rollback rows and can't depend on PgStorage without a module
319
+ // cycle.
320
+ let pgRowsSchema: table => S.t<array<unknown>> = Utils.WeakMap.memoize(table =>
321
+ table->makeRowsSchema(~rowFieldName=getPgDbFieldName)
322
+ )
323
+
243
324
  exception NonExistingTableField(string)
244
325
 
245
326
  /*
@@ -250,7 +331,7 @@ let getUnfilteredCompositeIndicesUnsafe = (table): array<array<compositeIndexFie
250
331
  table.compositeIndices->Array.map(compositeIndex =>
251
332
  compositeIndex->Array.map(indexField => {
252
333
  let dbFieldName = switch table->getFieldByName(indexField.fieldName) {
253
- | Some(field) => field->getFieldName
334
+ | Some(field) => field->getPgFieldName
254
335
  | None => throw(NonExistingTableField(indexField.fieldName)) //Unexpected should be validated in schema parser
255
336
  }
256
337
  {fieldName: dbFieldName, direction: indexField.direction}
@@ -276,7 +357,7 @@ let toSqlParams = (table: table, ~schema, ~pgSchema) => {
276
357
  switch schema->S.classify {
277
358
  | Object({items}) =>
278
359
  let dict = Dict.make()
279
- items->Belt.Array.forEach(({location, inlinedLocation, schema}) => {
360
+ items->Array.forEach(({location, schema}) => {
280
361
  let rec coerceSchema = schema =>
281
362
  switch schema->S.classify {
282
363
  | BigInt => Utils.BigInt.schema->S.toUnknown
@@ -300,18 +381,21 @@ let toSqlParams = (table: table, ~schema, ~pgSchema) => {
300
381
  | _ => schema
301
382
  }
302
383
 
303
- let field = switch table->getFieldByDbName(location) {
384
+ let field = switch table->getFieldByApiName(location) {
304
385
  | Some(field) => field
305
386
  | None => throw(NonExistingTableField(location))
306
387
  }
307
388
 
389
+ // Schema locations use API field names, while the SQL references
390
+ // columns by their possibly renamed db names.
391
+ let quotedDbName = `"${field->getPgFieldName}"`
308
392
  quotedFieldNames
309
- ->Array.push(inlinedLocation)
393
+ ->Array.push(quotedDbName)
310
394
  ->ignore
311
395
  switch field {
312
396
  | Field({isPrimaryKey: false}) =>
313
397
  quotedNonPrimaryFieldNames
314
- ->Array.push(inlinedLocation)
398
+ ->Array.push(quotedDbName)
315
399
  ->ignore
316
400
  | _ => ()
317
401
  }
@@ -360,7 +444,7 @@ And maps the fields defined to their actual db name (some have _id suffix)
360
444
  let getSingleIndices = (table): array<string> => {
361
445
  let indexFields = table.fields->Array.filterMap(field =>
362
446
  switch field {
363
- | Field(field) if field.isIndex => Some(field->getDbFieldName)
447
+ | Field(field) if field.isIndex => Some(field->getPgDbFieldName)
364
448
  | _ => None
365
449
  }
366
450
  )
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Utils from "../Utils.res.mjs";
4
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
5
4
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
5
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
6
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
@@ -17,7 +16,7 @@ function makeEnumConfig(name, variants) {
17
16
  };
18
17
  }
19
18
 
20
- function mkField(fieldName, fieldType, fieldSchema, $$default, isArrayOpt, isNullableOpt, isPrimaryKeyOpt, isIndexOpt, linkedEntity, description) {
19
+ function mkField(fieldName, fieldType, fieldSchema, $$default, isArrayOpt, isNullableOpt, isPrimaryKeyOpt, isIndexOpt, linkedEntity, description, postgresDbName, clickhouseDbName) {
21
20
  let isArray = isArrayOpt !== undefined ? isArrayOpt : false;
22
21
  let isNullable = isNullableOpt !== undefined ? isNullableOpt : false;
23
22
  let isPrimaryKey = isPrimaryKeyOpt !== undefined ? isPrimaryKeyOpt : false;
@@ -34,7 +33,9 @@ function mkField(fieldName, fieldType, fieldSchema, $$default, isArrayOpt, isNul
34
33
  isIndex: isIndex,
35
34
  linkedEntity: linkedEntity,
36
35
  defaultValue: $$default,
37
- description: description
36
+ description: description,
37
+ postgresDbName: postgresDbName,
38
+ clickhouseDbName: clickhouseDbName
38
39
  }
39
40
  };
40
41
  }
@@ -59,7 +60,7 @@ function isLinkedEntityField(field) {
59
60
  return Stdlib_Option.isSome(field.linkedEntity);
60
61
  }
61
62
 
62
- function getDbFieldName(field) {
63
+ function getApiFieldName(field) {
63
64
  if (Stdlib_Option.isSome(field.linkedEntity)) {
64
65
  return field.fieldName + "_id";
65
66
  } else {
@@ -67,9 +68,27 @@ function getDbFieldName(field) {
67
68
  }
68
69
  }
69
70
 
70
- function getFieldName(fieldOrDerived) {
71
+ function getPgDbFieldName(field) {
72
+ let dbName = field.postgresDbName;
73
+ if (dbName !== undefined) {
74
+ return dbName;
75
+ } else {
76
+ return getApiFieldName(field);
77
+ }
78
+ }
79
+
80
+ function getClickHouseDbFieldName(field) {
81
+ let dbName = field.clickhouseDbName;
82
+ if (dbName !== undefined) {
83
+ return dbName;
84
+ } else {
85
+ return getApiFieldName(field);
86
+ }
87
+ }
88
+
89
+ function getPgFieldName(fieldOrDerived) {
71
90
  if (fieldOrDerived.TAG === "Field") {
72
- return getDbFieldName(fieldOrDerived._0);
91
+ return getPgDbFieldName(fieldOrDerived._0);
73
92
  } else {
74
93
  return fieldOrDerived._0.fieldName;
75
94
  }
@@ -145,14 +164,14 @@ function mkTable(tableName, compositeIndicesOpt, fields, description) {
145
164
  };
146
165
  }
147
166
 
148
- function getPrimaryKeyFieldNames(table) {
167
+ function getPgPrimaryKeyFieldNames(table) {
149
168
  return Stdlib_Array.filterMap(table.fields, field => {
150
169
  if (field.TAG !== "Field") {
151
170
  return;
152
171
  }
153
- let match = field._0;
154
- if (match.isPrimaryKey) {
155
- return match.fieldName;
172
+ let field$1 = field._0;
173
+ if (field$1.isPrimaryKey) {
174
+ return getPgDbFieldName(field$1);
156
175
  }
157
176
  });
158
177
  }
@@ -165,10 +184,6 @@ function getFields(table) {
165
184
  });
166
185
  }
167
186
 
168
- function getFieldNames(table) {
169
- return getFields(table).map(getDbFieldName);
170
- }
171
-
172
187
  function getNonDefaultFields(table) {
173
188
  return Stdlib_Array.filterMap(table.fields, field => {
174
189
  if (field.TAG !== "Field") {
@@ -207,22 +222,52 @@ function getDerivedFromFields(table) {
207
222
  });
208
223
  }
209
224
 
210
- function getNonDefaultFieldNames(table) {
211
- return getNonDefaultFields(table).map(getDbFieldName);
212
- }
213
-
214
225
  function getFieldByName(table, fieldName) {
215
226
  return table.fields.find(field => getUserDefinedFieldName(field) === fieldName);
216
227
  }
217
228
 
218
- function getFieldByDbName(table, dbFieldName) {
229
+ function getFieldByApiName(table, apiFieldName) {
219
230
  return table.fields.find(field => {
220
231
  let tmp;
221
- tmp = field.TAG === "Field" ? getDbFieldName(field._0) : field._0.fieldName;
222
- return tmp === dbFieldName;
232
+ tmp = field.TAG === "Field" ? getApiFieldName(field._0) : field._0.fieldName;
233
+ return tmp === apiFieldName;
234
+ });
235
+ }
236
+
237
+ let queryFields = Utils.$$WeakMap.memoize(table => {
238
+ let dict = {};
239
+ table.fields.forEach(field => {
240
+ if (field.TAG !== "Field") {
241
+ return;
242
+ }
243
+ let field$1 = field._0;
244
+ dict[getApiFieldName(field$1)] = {
245
+ fieldSchema: field$1.fieldSchema,
246
+ arrayFieldSchema: S$RescriptSchema.array(field$1.fieldSchema),
247
+ pgDbFieldName: getPgDbFieldName(field$1)
248
+ };
223
249
  });
250
+ return dict;
251
+ });
252
+
253
+ function makeRowsSchema(table, rowFieldName) {
254
+ return S$RescriptSchema.array(S$RescriptSchema.object(s => {
255
+ let dict = {};
256
+ table.fields.forEach(field => {
257
+ if (field.TAG !== "Field") {
258
+ return;
259
+ }
260
+ let field$1 = field._0;
261
+ dict[getApiFieldName(field$1)] = s.f(rowFieldName(field$1), field$1.fieldSchema);
262
+ });
263
+ return dict;
264
+ }));
224
265
  }
225
266
 
267
+ let rowsSchema = Utils.$$WeakMap.memoize(table => makeRowsSchema(table, getApiFieldName));
268
+
269
+ let pgRowsSchema = Utils.$$WeakMap.memoize(table => makeRowsSchema(table, getPgDbFieldName));
270
+
226
271
  let NonExistingTableField = /* @__PURE__ */Primitive_exceptions.create("Table.NonExistingTableField");
227
272
 
228
273
  function getUnfilteredCompositeIndicesUnsafe(table) {
@@ -230,7 +275,7 @@ function getUnfilteredCompositeIndicesUnsafe(table) {
230
275
  let field = getFieldByName(table, indexField.fieldName);
231
276
  let dbFieldName;
232
277
  if (field !== undefined) {
233
- dbFieldName = getFieldName(field);
278
+ dbFieldName = getPgFieldName(field);
234
279
  } else {
235
280
  throw {
236
281
  RE_EXN_ID: NonExistingTableField,
@@ -261,8 +306,7 @@ function toSqlParams(table, schema, pgSchema) {
261
306
  return Stdlib_JsError.throwWithMessage("Failed creating db schema. Expected an object schema for table");
262
307
  }
263
308
  let dict = {};
264
- Belt_Array.forEach(match.items, param => {
265
- let inlinedLocation = param.inlinedLocation;
309
+ match.items.forEach(param => {
266
310
  let location = param.location;
267
311
  let coerceSchema = schema => {
268
312
  let child = schema.t;
@@ -294,7 +338,7 @@ function toSqlParams(table, schema, pgSchema) {
294
338
  }
295
339
  }
296
340
  };
297
- let field = getFieldByDbName(table, location);
341
+ let field = getFieldByApiName(table, location);
298
342
  let field$1;
299
343
  if (field !== undefined) {
300
344
  field$1 = field;
@@ -305,12 +349,13 @@ function toSqlParams(table, schema, pgSchema) {
305
349
  Error: new Error()
306
350
  };
307
351
  }
308
- quotedFieldNames.push(inlinedLocation);
352
+ let quotedDbName = `"` + getPgFieldName(field$1) + `"`;
353
+ quotedFieldNames.push(quotedDbName);
309
354
  if (field$1.TAG === "Field") {
310
355
  if (field$1._0.isPrimaryKey) {
311
356
 
312
357
  } else {
313
- quotedNonPrimaryFieldNames.push(inlinedLocation);
358
+ quotedNonPrimaryFieldNames.push(quotedDbName);
314
359
  }
315
360
  }
316
361
  let tmp;
@@ -347,7 +392,7 @@ function getSingleIndices(table) {
347
392
  }
348
393
  let field$1 = field._0;
349
394
  if (field$1.isIndex) {
350
- return getDbFieldName(field$1);
395
+ return getPgDbFieldName(field$1);
351
396
  }
352
397
  });
353
398
  return Array.from(new Set(Stdlib_Array.filterMap(getUnfilteredCompositeIndicesUnsafe(table), cidx => {
@@ -371,24 +416,28 @@ export {
371
416
  mkDerivedFromField,
372
417
  getUserDefinedFieldName,
373
418
  isLinkedEntityField,
374
- getDbFieldName,
375
- getFieldName,
419
+ getApiFieldName,
420
+ getPgDbFieldName,
421
+ getClickHouseDbFieldName,
422
+ getPgFieldName,
376
423
  idFieldName,
377
424
  getPgFieldType,
378
425
  mkTable,
379
- getPrimaryKeyFieldNames,
426
+ getPgPrimaryKeyFieldNames,
380
427
  getFields,
381
- getFieldNames,
382
428
  getNonDefaultFields,
383
429
  getLinkedEntityFields,
384
430
  getDerivedFromFields,
385
- getNonDefaultFieldNames,
386
431
  getFieldByName,
387
- getFieldByDbName,
432
+ getFieldByApiName,
433
+ queryFields,
434
+ makeRowsSchema,
435
+ rowsSchema,
436
+ pgRowsSchema,
388
437
  NonExistingTableField,
389
438
  getUnfilteredCompositeIndicesUnsafe,
390
439
  toSqlParams,
391
440
  getSingleIndices,
392
441
  getCompositeIndices,
393
442
  }
394
- /* Utils Not a pure module */
443
+ /* queryFields Not a pure module */
@@ -97,14 +97,14 @@ let get = (router: t<'a>, ~tag, ~contractAddress, ~blockNumber, ~indexingAddress
97
97
  }
98
98
 
99
99
  let getEvmEventId = (~sighash, ~topicCount) => {
100
- sighash ++ "_" ++ topicCount->Belt.Int.toString
100
+ sighash ++ "_" ++ topicCount->Int.toString
101
101
  }
102
102
 
103
103
  let fromEvmEventModsOrThrow = (events: array<Internal.evmEventConfig>, ~chain): t<
104
104
  Internal.evmEventConfig,
105
105
  > => {
106
106
  let router = empty()
107
- events->Belt.Array.forEach(config => {
107
+ events->Array.forEach(config => {
108
108
  router->addOrThrow(
109
109
  config.id,
110
110
  config,
@@ -116,3 +116,68 @@ let fromEvmEventModsOrThrow = (events: array<Internal.evmEventConfig>, ~chain):
116
116
  })
117
117
  router
118
118
  }
119
+
120
+ /** Dispatch key for SVM instructions. `None` matches any instruction in the
121
+ program (lowest priority). */
122
+ let getSvmEventId = (~programId: SvmTypes.Pubkey.t, ~discriminator: option<string>) =>
123
+ switch discriminator {
124
+ | None => programId->SvmTypes.Pubkey.toString ++ "_none"
125
+ | Some(d) => programId->SvmTypes.Pubkey.toString ++ "_" ++ d
126
+ }
127
+
128
+ /** Discriminator byte-lengths declared by a program, sorted descending. The
129
+ source uses this to probe `(programId, dN)` keys longest-first when routing
130
+ a returned instruction to a handler — matching the locked Q1 answer. */
131
+ type svmProgramOrdering = {
132
+ programId: SvmTypes.Pubkey.t,
133
+ /** Byte lengths in descending order, deduplicated. Includes `0` only when
134
+ a handler is registered with no discriminator (program-wide match). */
135
+ byteLengthsDesc: array<int>,
136
+ }
137
+
138
+ let fromSvmEventConfigsOrThrow = (events: array<Internal.svmInstructionEventConfig>, ~chain): (
139
+ t<Internal.svmInstructionEventConfig>,
140
+ array<svmProgramOrdering>,
141
+ ) => {
142
+ let router = empty()
143
+ events->Array.forEach(config => {
144
+ // The router tag must include the programId so two programs declaring the
145
+ // same discriminator coexist. The source-side lookup uses the same shape
146
+ // via `getSvmEventId(~programId, ~discriminator)`.
147
+ let routerTag = getSvmEventId(~programId=config.programId, ~discriminator=config.discriminator)
148
+ router->addOrThrow(
149
+ routerTag,
150
+ config,
151
+ ~contractName=config.contractName,
152
+ ~eventName=config.name,
153
+ ~chain,
154
+ ~isWildcard=config.isWildcard,
155
+ )
156
+ })
157
+
158
+ // Per-program list of declared discriminator byte lengths, sorted desc.
159
+ let byProgram: dict<Utils.Set.t<int>> = Dict.make()
160
+ events->Array.forEach(config => {
161
+ let key = config.programId->SvmTypes.Pubkey.toString
162
+ let set = switch byProgram->Utils.Dict.dangerouslyGetNonOption(key) {
163
+ | Some(s) => s
164
+ | None =>
165
+ let s = Utils.Set.make()
166
+ byProgram->Dict.set(key, s)
167
+ s
168
+ }
169
+ let _ = set->Utils.Set.add(config.discriminatorByteLen)
170
+ })
171
+ let ordering =
172
+ byProgram
173
+ ->Dict.toArray
174
+ ->Array.map(((programIdString, lens)) => {
175
+ let sorted = lens->Utils.Set.toArray->Array.toSorted((a, b) => (b - a)->Int.toFloat)
176
+ {
177
+ programId: programIdString->SvmTypes.Pubkey.fromStringUnsafe,
178
+ byteLengthsDesc: sorted,
179
+ }
180
+ })
181
+
182
+ (router, ordering)
183
+ }
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as ChainMap from "../ChainMap.res.mjs";
4
- import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
5
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
5
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
7
6
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
@@ -102,15 +101,56 @@ function get$1(router, tag, contractAddress, blockNumber, indexingAddresses) {
102
101
  }
103
102
 
104
103
  function getEvmEventId(sighash, topicCount) {
105
- return sighash + "_" + String(topicCount);
104
+ return sighash + "_" + topicCount.toString();
106
105
  }
107
106
 
108
107
  function fromEvmEventModsOrThrow(events, chain) {
109
108
  let router = {};
110
- Belt_Array.forEach(events, config => addOrThrow$1(router, config.id, config, config.contractName, config.isWildcard, config.name, chain));
109
+ events.forEach(config => addOrThrow$1(router, config.id, config, config.contractName, config.isWildcard, config.name, chain));
111
110
  return router;
112
111
  }
113
112
 
113
+ function getSvmEventId(programId, discriminator) {
114
+ if (discriminator !== undefined) {
115
+ return programId + "_" + discriminator;
116
+ } else {
117
+ return programId + "_none";
118
+ }
119
+ }
120
+
121
+ function fromSvmEventConfigsOrThrow(events, chain) {
122
+ let router = {};
123
+ events.forEach(config => {
124
+ let routerTag = getSvmEventId(config.programId, config.discriminator);
125
+ addOrThrow$1(router, routerTag, config, config.contractName, config.isWildcard, config.name, chain);
126
+ });
127
+ let byProgram = {};
128
+ events.forEach(config => {
129
+ let key = config.programId;
130
+ let s = byProgram[key];
131
+ let set;
132
+ if (s !== undefined) {
133
+ set = Primitive_option.valFromOption(s);
134
+ } else {
135
+ let s$1 = new Set();
136
+ byProgram[key] = s$1;
137
+ set = s$1;
138
+ }
139
+ set.add(config.discriminatorByteLen);
140
+ });
141
+ let ordering = Object.entries(byProgram).map(param => {
142
+ let sorted = Array.from(param[1]).toSorted((a, b) => b - a | 0);
143
+ return {
144
+ programId: param[0],
145
+ byteLengthsDesc: sorted
146
+ };
147
+ });
148
+ return [
149
+ router,
150
+ ordering
151
+ ];
152
+ }
153
+
114
154
  export {
115
155
  EventDuplicate,
116
156
  WildcardCollision,
@@ -120,5 +160,7 @@ export {
120
160
  get$1 as get,
121
161
  getEvmEventId,
122
162
  fromEvmEventModsOrThrow,
163
+ getSvmEventId,
164
+ fromSvmEventConfigsOrThrow,
123
165
  }
124
166
  /* ChainMap Not a pure module */
@@ -1,7 +1,3 @@
1
- @get external getNumber: Internal.eventBlock => int = "number"
2
- @get external getTimestamp: Internal.eventBlock => int = "timestamp"
3
- @get external getId: Internal.eventBlock => string = "hash"
4
-
5
1
  let cleanUpRawEventFieldsInPlace: JSON.t => unit = %raw(`fields => {
6
2
  delete fields.hash
7
3
  delete fields.number
@@ -77,9 +73,6 @@ let ecosystem: Ecosystem.t = {
77
73
  blockNumberName: "number",
78
74
  blockTimestampName: "timestamp",
79
75
  blockHashName: "hash",
80
- getNumber,
81
- getTimestamp,
82
- getId,
83
76
  cleanUpRawEventFieldsInPlace,
84
77
  onBlockMethodName: "onBlock",
85
78
  // EVM filter shape: `{block: {number: {_gte?, _lte?, _every?}}}`.