envio 3.11.0 → 3.12.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.
- package/index.d.ts +3 -0
- package/package.json +6 -6
- package/src/Batch.res +111 -78
- package/src/Batch.res.mjs +53 -46
- package/src/BatchProcessing.res +1 -11
- package/src/BatchProcessing.res.mjs +1 -4
- package/src/ChainFetching.res +7 -3
- package/src/ChainFetching.res.mjs +1 -1
- package/src/ChainState.res +82 -20
- package/src/ChainState.res.mjs +51 -13
- package/src/ChainState.resi +6 -1
- package/src/Config.res +58 -37
- package/src/Config.res.mjs +63 -53
- package/src/CrossChainState.res +50 -53
- package/src/CrossChainState.res.mjs +25 -23
- package/src/CrossChainState.resi +6 -13
- package/src/EffectState.res +13 -4
- package/src/EffectState.resi +7 -1
- package/src/EventProcessing.res +6 -6
- package/src/EventProcessing.res.mjs +6 -6
- package/src/FetchState.res +65 -46
- package/src/FetchState.res.mjs +68 -36
- package/src/FinalizeBackfill.res +16 -12
- package/src/FinalizeBackfill.res.mjs +3 -3
- package/src/HistoryPolicy.res +46 -0
- package/src/HistoryPolicy.res.mjs +50 -0
- package/src/InMemoryStore.res +30 -32
- package/src/InMemoryStore.res.mjs +33 -28
- package/src/InMemoryTable.res +155 -67
- package/src/InMemoryTable.res.mjs +151 -60
- package/src/IndexerState.res +66 -45
- package/src/IndexerState.res.mjs +57 -29
- package/src/IndexerState.resi +8 -13
- package/src/Internal.res +4 -2
- package/src/LoadLayer.res +68 -38
- package/src/LoadLayer.res.mjs +50 -64
- package/src/LoadLayer.resi +1 -1
- package/src/Main.res +25 -24
- package/src/Main.res.mjs +24 -25
- package/src/Metrics.res +49 -1
- package/src/Metrics.res.mjs +26 -3
- package/src/Persistence.res +55 -16
- package/src/Persistence.res.mjs +18 -3
- package/src/PgStorage.res +286 -180
- package/src/PgStorage.res.mjs +209 -122
- package/src/PruneStaleHistory.res +9 -15
- package/src/PruneStaleHistory.res.mjs +11 -20
- package/src/Rollback.res +9 -14
- package/src/Rollback.res.mjs +5 -3
- package/src/Sink.res +7 -5
- package/src/Sink.res.mjs +4 -4
- package/src/Staging.res +298 -0
- package/src/Staging.res.mjs +257 -0
- package/src/TestIndexer.res +14 -30
- package/src/TestIndexer.res.mjs +11 -9
- package/src/UserContext.res +20 -36
- package/src/UserContext.res.mjs +6 -9
- package/src/Utils.res +10 -4
- package/src/Utils.res.mjs +16 -16
- package/src/Writing.res +34 -20
- package/src/Writing.res.mjs +15 -20
- package/src/bindings/ClickHouse.res +41 -34
- package/src/bindings/ClickHouse.res.mjs +36 -30
- package/src/bindings/ClickHouseSink.res +45 -186
- package/src/bindings/ClickHouseSink.res.mjs +21 -174
- package/src/db/CheckpointSequence.res +109 -0
- package/src/db/CheckpointSequence.res.mjs +99 -0
- package/src/db/EntityFilter.res +487 -275
- package/src/db/EntityFilter.res.mjs +557 -309
- package/src/db/EntityHistory.res +6 -5
- package/src/db/EntityHistory.res.mjs +5 -5
- package/src/db/Frontier.res +86 -0
- package/src/db/Frontier.res.mjs +126 -0
- package/src/db/InternalTable.res +145 -27
- package/src/db/InternalTable.res.mjs +115 -29
- package/src/db/RollbackFloors.res +34 -41
- package/src/db/RollbackFloors.res.mjs +27 -71
- package/src/db/Table.res +21 -6
- package/src/db/Table.res.mjs +13 -4
- package/src/sources/BlockStore.res +8 -0
- package/src/sources/EvmHyperSyncSource.res +5 -1
- package/src/sources/EvmHyperSyncSource.res.mjs +4 -3
- package/src/sources/FuelHyperSyncSource.res +1 -0
- package/src/sources/FuelHyperSyncSource.res.mjs +1 -1
- package/src/sources/HyperSync.res +6 -0
- package/src/sources/HyperSync.res.mjs +5 -2
- package/src/sources/HyperSync.resi +2 -0
- package/src/sources/HyperSyncClient.res +6 -0
- package/src/sources/HyperSyncSSE.res +1 -1
- package/src/sources/HyperSyncSSE.res.mjs +4 -10
- package/src/sources/RequestStat.res +8 -1
- package/src/sources/RpcSource.res +1 -0
- package/src/sources/RpcSource.res.mjs +1 -1
- package/src/sources/SimulateSource.res +1 -0
- package/src/sources/SimulateSource.res.mjs +1 -1
- package/src/sources/Source.res +11 -3
- package/src/sources/SourceManager.res +34 -13
- package/src/sources/SourceManager.res.mjs +26 -9
- package/src/sources/SourceManager.resi +2 -0
- package/src/sources/SvmHyperSyncClient.res +5 -0
- package/src/sources/SvmHyperSyncSource.res +3 -0
- package/src/sources/SvmHyperSyncSource.res.mjs +4 -2
- package/src/tui/Tui.res +56 -143
- package/src/tui/Tui.res.mjs +70 -166
- package/src/tui/components/TuiData.res +61 -16
- package/src/tui/components/TuiData.res.mjs +53 -15
- package/svm.schema.json +0 -7
- package/src/db/CheckpointBounds.res +0 -53
- package/src/db/CheckpointBounds.res.mjs +0 -44
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
4
|
+
|
|
5
|
+
function kindOfOrdinal(ordinal) {
|
|
6
|
+
switch (ordinal) {
|
|
7
|
+
case 0 :
|
|
8
|
+
return 0;
|
|
9
|
+
case 1 :
|
|
10
|
+
return 1;
|
|
11
|
+
case 2 :
|
|
12
|
+
return 2;
|
|
13
|
+
case 3 :
|
|
14
|
+
return 3;
|
|
15
|
+
case 4 :
|
|
16
|
+
return 4;
|
|
17
|
+
default:
|
|
18
|
+
return Stdlib_JsError.throwWithMessage(`Unknown staged column kind ` + ordinal.toString());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let encoder = new TextEncoder();
|
|
23
|
+
|
|
24
|
+
function begin(arena, table, rows, columns) {
|
|
25
|
+
let match = arena.beginStage(table, rows);
|
|
26
|
+
let buffers = match.buffers;
|
|
27
|
+
let slot = {
|
|
28
|
+
contents: 0
|
|
29
|
+
};
|
|
30
|
+
let take = () => {
|
|
31
|
+
let buffer = buffers[slot.contents];
|
|
32
|
+
slot.contents = slot.contents + 1 | 0;
|
|
33
|
+
return buffer;
|
|
34
|
+
};
|
|
35
|
+
let takeVariable = () => {
|
|
36
|
+
let slot$1 = slot.contents;
|
|
37
|
+
let data = new Uint8Array(take());
|
|
38
|
+
let ends = new Uint32Array(take());
|
|
39
|
+
return {
|
|
40
|
+
data: data,
|
|
41
|
+
ends: ends,
|
|
42
|
+
slot: slot$1,
|
|
43
|
+
cursor: 0
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
let builders = columns.map((param, index) => {
|
|
47
|
+
let storage;
|
|
48
|
+
switch (param.kind) {
|
|
49
|
+
case 0 :
|
|
50
|
+
storage = {
|
|
51
|
+
TAG: "Floats",
|
|
52
|
+
_0: new Float64Array(take())
|
|
53
|
+
};
|
|
54
|
+
break;
|
|
55
|
+
case 1 :
|
|
56
|
+
storage = {
|
|
57
|
+
TAG: "Unsigned",
|
|
58
|
+
_0: new BigUint64Array(take())
|
|
59
|
+
};
|
|
60
|
+
break;
|
|
61
|
+
case 2 :
|
|
62
|
+
storage = {
|
|
63
|
+
TAG: "Signed",
|
|
64
|
+
_0: new BigInt64Array(take())
|
|
65
|
+
};
|
|
66
|
+
break;
|
|
67
|
+
case 3 :
|
|
68
|
+
storage = {
|
|
69
|
+
TAG: "Text",
|
|
70
|
+
_0: takeVariable()
|
|
71
|
+
};
|
|
72
|
+
break;
|
|
73
|
+
case 4 :
|
|
74
|
+
storage = {
|
|
75
|
+
TAG: "Bytes",
|
|
76
|
+
_0: takeVariable()
|
|
77
|
+
};
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
name: param.name,
|
|
82
|
+
isNullable: param.isNullable,
|
|
83
|
+
replacer: param.replacer,
|
|
84
|
+
index: index,
|
|
85
|
+
storage: storage,
|
|
86
|
+
nulls: new Uint8Array(take())
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
arena: arena,
|
|
91
|
+
handle: match.handle,
|
|
92
|
+
buffers: buffers,
|
|
93
|
+
builders: builders
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function ensure(stage, builder, variable, needed) {
|
|
98
|
+
if (needed <= variable.data.length) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
let fresh = stage.arena.growStage(stage.handle, builder.index, needed, variable.data.buffer);
|
|
102
|
+
stage.buffers[variable.slot] = fresh;
|
|
103
|
+
variable.data = new Uint8Array(fresh);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function finiteOrThrow(number, column) {
|
|
107
|
+
if (isFinite(number)) {
|
|
108
|
+
return number;
|
|
109
|
+
} else {
|
|
110
|
+
return Stdlib_JsError.throwWithMessage(number.toString() + ` is not a finite number, so it cannot be stored in the \`` + column + `\` column. Store a finite number, or keep it out of the entity.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function toText(value, replacer) {
|
|
115
|
+
let match = typeof value;
|
|
116
|
+
if (match === "bigint") {
|
|
117
|
+
return String(value);
|
|
118
|
+
} else if (match === "string") {
|
|
119
|
+
return value;
|
|
120
|
+
} else {
|
|
121
|
+
return JSON.stringify(value, replacer);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let writeAscii = ((data, text, offset) => {
|
|
126
|
+
const length = text.length;
|
|
127
|
+
for (let index = 0; index < length; index++) {
|
|
128
|
+
const code = text.charCodeAt(index);
|
|
129
|
+
if (code > 0x7f) {
|
|
130
|
+
return -1;
|
|
131
|
+
}
|
|
132
|
+
data[offset + index] = code;
|
|
133
|
+
}
|
|
134
|
+
return length;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
function markNull(builder, row) {
|
|
138
|
+
builder.nulls[row] = 1;
|
|
139
|
+
let match = builder.storage;
|
|
140
|
+
switch (match.TAG) {
|
|
141
|
+
case "Text" :
|
|
142
|
+
case "Bytes" :
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
let variable = match._0;
|
|
148
|
+
variable.ends[row] = variable.cursor;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function checkedBigInt(value, builder, min, max) {
|
|
152
|
+
let value$1 = BigInt(value);
|
|
153
|
+
if (value$1 < min || value$1 > max) {
|
|
154
|
+
Stdlib_JsError.throwWithMessage(value$1.toString() + ` is out of range for the \`` + builder.name + `\` column`);
|
|
155
|
+
}
|
|
156
|
+
return value$1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function writePresent(stage, builder, row, value) {
|
|
160
|
+
let floats = builder.storage;
|
|
161
|
+
switch (floats.TAG) {
|
|
162
|
+
case "Floats" :
|
|
163
|
+
floats._0[row] = finiteOrThrow(Number(value), builder.name);
|
|
164
|
+
return;
|
|
165
|
+
case "Unsigned" :
|
|
166
|
+
floats._0[row] = checkedBigInt(value, builder, 0n, 18446744073709551615n);
|
|
167
|
+
return;
|
|
168
|
+
case "Signed" :
|
|
169
|
+
floats._0[row] = checkedBigInt(value, builder, -9223372036854775808n, 9223372036854775807n);
|
|
170
|
+
return;
|
|
171
|
+
case "Text" :
|
|
172
|
+
let variable = floats._0;
|
|
173
|
+
let text = toText(value, builder.replacer);
|
|
174
|
+
let units = text.length;
|
|
175
|
+
ensure(stage, builder, variable, variable.cursor + units | 0);
|
|
176
|
+
let ascii = writeAscii(variable.data, text, variable.cursor);
|
|
177
|
+
let written;
|
|
178
|
+
if (ascii !== -1) {
|
|
179
|
+
written = ascii;
|
|
180
|
+
} else {
|
|
181
|
+
let match = encoder.encodeInto(text, variable.data.subarray(variable.cursor));
|
|
182
|
+
if (match.read < units) {
|
|
183
|
+
ensure(stage, builder, variable, variable.cursor + (units * 3 | 0) | 0);
|
|
184
|
+
written = encoder.encodeInto(text, variable.data.subarray(variable.cursor)).written;
|
|
185
|
+
} else {
|
|
186
|
+
written = match.written;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
variable.cursor = variable.cursor + written | 0;
|
|
190
|
+
variable.ends[row] = variable.cursor;
|
|
191
|
+
return;
|
|
192
|
+
case "Bytes" :
|
|
193
|
+
let variable$1 = floats._0;
|
|
194
|
+
let length = value.length;
|
|
195
|
+
ensure(stage, builder, variable$1, variable$1.cursor + length | 0);
|
|
196
|
+
variable$1.data.set(value, variable$1.cursor);
|
|
197
|
+
variable$1.cursor = variable$1.cursor + length | 0;
|
|
198
|
+
variable$1.ends[row] = variable$1.cursor;
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isAbsent(value) {
|
|
204
|
+
if (value === undefined) {
|
|
205
|
+
return true;
|
|
206
|
+
} else {
|
|
207
|
+
return value === null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function writeValue(stage, column, row, value) {
|
|
212
|
+
let builder = stage.builders[column];
|
|
213
|
+
if (isAbsent(value)) {
|
|
214
|
+
if (builder.isNullable) {
|
|
215
|
+
return markNull(builder, row);
|
|
216
|
+
} else {
|
|
217
|
+
return Stdlib_JsError.throwWithMessage(`No value for the \`` + builder.name + `\` column, which is not nullable. Set the field before saving the entity, or make it optional in the schema.`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
return writePresent(stage, builder, row, value);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function writeDeletedValue(stage, column, row, value) {
|
|
225
|
+
let builder = stage.builders[column];
|
|
226
|
+
if (isAbsent(value)) {
|
|
227
|
+
return markNull(builder, row);
|
|
228
|
+
} else {
|
|
229
|
+
return writePresent(stage, builder, row, value);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function columnCount(stage) {
|
|
234
|
+
return stage.builders.length;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function commit(stage) {
|
|
238
|
+
stage.arena.commitStage(stage.handle, stage.buffers);
|
|
239
|
+
return stage.handle;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function abort(stage) {
|
|
243
|
+
stage.arena.abortStage(stage.handle, stage.buffers);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export {
|
|
247
|
+
kindOfOrdinal,
|
|
248
|
+
begin,
|
|
249
|
+
finiteOrThrow,
|
|
250
|
+
toText,
|
|
251
|
+
writeValue,
|
|
252
|
+
writeDeletedValue,
|
|
253
|
+
columnCount,
|
|
254
|
+
commit,
|
|
255
|
+
abort,
|
|
256
|
+
}
|
|
257
|
+
/* encoder Not a pure module */
|
package/src/TestIndexer.res
CHANGED
|
@@ -75,15 +75,10 @@ let handleLoad = (state: testIndexerState, ~tableName: string, ~filter: EntityFi
|
|
|
75
75
|
| None => []
|
|
76
76
|
| Some(entityConfig) =>
|
|
77
77
|
let entityDict = state.entities->Dict.get(tableName)->Option.getOr(Dict.make())
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// The store holds decoded entities and the filter carries decoded values,
|
|
83
|
-
// so compare directly (same approach as InMemoryTable) — no JSON round-trip.
|
|
84
|
-
let entityAsDict = entity->(Utils.magic: Internal.entity => dict<EntityFilter.FieldValue.t>)
|
|
85
|
-
filter->EntityFilter.matches(~entity=entityAsDict)
|
|
86
|
-
})
|
|
78
|
+
// The store holds decoded entities and the filter carries decoded values,
|
|
79
|
+
// so compare directly (same approach as InMemoryTable) — no JSON round-trip.
|
|
80
|
+
let matcher = filter->EntityFilter.makeMatcher(~table=entityConfig.table)
|
|
81
|
+
let matched = entityDict->Dict.valuesToArray->Array.filter(matcher)
|
|
87
82
|
// The chain is already fixed by the scope the load ran for, so the loaded
|
|
88
83
|
// entity is handed back in the shape the handlers see.
|
|
89
84
|
switch entityConfig.table->Table.getChainIdField {
|
|
@@ -266,6 +261,7 @@ let makeInitialState = (
|
|
|
266
261
|
sourceBlockNumber: processChainConfig.endBlock->Option.getOr(0),
|
|
267
262
|
maxReorgDepth: 0, // No reorg support in test indexer
|
|
268
263
|
progressBlockNumber: -1,
|
|
264
|
+
progressBlockTime: None,
|
|
269
265
|
numEventsProcessed: 0.,
|
|
270
266
|
firstEventBlockNumber: None,
|
|
271
267
|
timestampCaughtUpToHeadOrEndblock: None,
|
|
@@ -279,7 +275,7 @@ let makeInitialState = (
|
|
|
279
275
|
envioInfo: Some(JSON.Encode.object(Dict.make())),
|
|
280
276
|
cache: Dict.make(),
|
|
281
277
|
chains,
|
|
282
|
-
|
|
278
|
+
checkpointFrontier: Frontier.empty(),
|
|
283
279
|
reorgCheckpoints: [],
|
|
284
280
|
}
|
|
285
281
|
}
|
|
@@ -543,23 +539,12 @@ let makeEntityGetWhere = (~state: testIndexerState, ~entityConfig: Internal.enti
|
|
|
543
539
|
`Cannot call ${entityConfig.name}.getWhere() while indexer.process() is running. ` ++ "Wait for process() to complete before accessing entities directly.",
|
|
544
540
|
)
|
|
545
541
|
}
|
|
546
|
-
let
|
|
547
|
-
filter
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
)
|
|
542
|
+
let matcher =
|
|
543
|
+
filter
|
|
544
|
+
->EntityFilter.parseOrThrow(~entityName=entityConfig.name, ~table=entityConfig.table)
|
|
545
|
+
->EntityFilter.makeMatcher(~table=entityConfig.table)
|
|
551
546
|
let entityDict = state.entities->Dict.get(entityConfig.name)->Option.getOr(Dict.make())
|
|
552
|
-
|
|
553
|
-
// matches are disjoint, so the union needs no dedup.
|
|
554
|
-
Promise.resolve(
|
|
555
|
-
entityDict
|
|
556
|
-
->Dict.valuesToArray
|
|
557
|
-
->Array.filter(entity => {
|
|
558
|
-
let entityAsDict = entity->(Utils.magic: Internal.entity => dict<EntityFilter.FieldValue.t>)
|
|
559
|
-
filters->Array.some(filter => filter->EntityFilter.matches(~entity=entityAsDict))
|
|
560
|
-
})
|
|
561
|
-
->Array.map(copyEntity),
|
|
562
|
-
)
|
|
547
|
+
Promise.resolve(entityDict->Dict.valuesToArray->Array.filter(matcher)->Array.map(copyEntity))
|
|
563
548
|
}
|
|
564
549
|
}
|
|
565
550
|
|
|
@@ -590,7 +575,7 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
|
|
|
590
575
|
JsError.throwWithMessage(
|
|
591
576
|
"TestIndexer: initialize should not be called; the initial state is derived from config.",
|
|
592
577
|
),
|
|
593
|
-
resumeInitialState: async (~entities as _, ~throwIfIncompatible as _) =>
|
|
578
|
+
resumeInitialState: async (~entities as _, ~chainIds as _, ~throwIfIncompatible as _) =>
|
|
594
579
|
JsError.throwWithMessage(
|
|
595
580
|
"TestIndexer: resumeInitialState should not be called; the initial state is derived from config.",
|
|
596
581
|
),
|
|
@@ -599,13 +584,12 @@ let makeInMemoryStorage = (~state: testIndexerState): Persistence.storage => {
|
|
|
599
584
|
->handleLoad(~tableName=table.tableName, ~filter)
|
|
600
585
|
->(Utils.magic: array<Internal.entity> => array<unknown>),
|
|
601
586
|
// The in-memory storage has no indexes to build, and it's always ready.
|
|
602
|
-
ensureQueryIndexes: async (~
|
|
603
|
-
ensureSchemaIndexes: async (~entities as _) => (),
|
|
587
|
+
ensureQueryIndexes: async (~entityConfig as _, ~scope as _, ~filters as _) => (),
|
|
588
|
+
ensureSchemaIndexes: async (~entities as _, ~chainIds as _) => (),
|
|
604
589
|
finalizeBackfill: async (~entities as _, ~chainIds as _, ~readyAt as _) => (),
|
|
605
590
|
writeBatch: async (
|
|
606
591
|
~batch,
|
|
607
592
|
~rollback as _,
|
|
608
|
-
~isInReorgThreshold as _,
|
|
609
593
|
~config,
|
|
610
594
|
~allEntities as _,
|
|
611
595
|
~updatedEffectsCache as _,
|
package/src/TestIndexer.res.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import * as ChainId from "./ChainId.res.mjs";
|
|
|
8
8
|
import * as Logging from "./Logging.res.mjs";
|
|
9
9
|
import * as ChainMap from "./ChainMap.res.mjs";
|
|
10
10
|
import * as EntityId from "./EntityId.res.mjs";
|
|
11
|
+
import * as Frontier from "./db/Frontier.res.mjs";
|
|
11
12
|
import * as Internal from "./Internal.res.mjs";
|
|
12
13
|
import * as ChainState from "./ChainState.res.mjs";
|
|
13
14
|
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
@@ -19,7 +20,6 @@ import * as EntityFilter from "./db/EntityFilter.res.mjs";
|
|
|
19
20
|
import * as IndexerState from "./IndexerState.res.mjs";
|
|
20
21
|
import * as ErrorHandling from "./ErrorHandling.res.mjs";
|
|
21
22
|
import * as HandlerLoader from "./HandlerLoader.res.mjs";
|
|
22
|
-
import * as InternalTable from "./db/InternalTable.res.mjs";
|
|
23
23
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
24
24
|
import * as SimulateItems from "./SimulateItems.res.mjs";
|
|
25
25
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -56,7 +56,8 @@ function handleLoad(state, tableName, filter) {
|
|
|
56
56
|
return [];
|
|
57
57
|
}
|
|
58
58
|
let entityDict = Stdlib_Option.getOr(state.entities[tableName], {});
|
|
59
|
-
let
|
|
59
|
+
let matcher = EntityFilter.makeMatcher(filter, entityConfig.table);
|
|
60
|
+
let matched = Object.values(entityDict).filter(matcher);
|
|
60
61
|
let field = Table.getChainIdField(entityConfig.table);
|
|
61
62
|
if (field !== undefined) {
|
|
62
63
|
return matched.map(entity => {
|
|
@@ -183,6 +184,7 @@ function makeInitialState(config, processConfigChains, addressRowsByChain, contr
|
|
|
183
184
|
endBlock: processChainConfig.endBlock,
|
|
184
185
|
maxReorgDepth: 0,
|
|
185
186
|
progressBlockNumber: -1,
|
|
187
|
+
progressBlockTime: undefined,
|
|
186
188
|
numEventsProcessed: 0,
|
|
187
189
|
firstEventBlockNumber: undefined,
|
|
188
190
|
timestampCaughtUpToHeadOrEndblock: undefined,
|
|
@@ -196,7 +198,7 @@ function makeInitialState(config, processConfigChains, addressRowsByChain, contr
|
|
|
196
198
|
envioInfo: {},
|
|
197
199
|
cache: {},
|
|
198
200
|
chains: chains,
|
|
199
|
-
|
|
201
|
+
checkpointFrontier: Frontier.empty(),
|
|
200
202
|
reorgCheckpoints: []
|
|
201
203
|
};
|
|
202
204
|
}
|
|
@@ -375,9 +377,9 @@ function makeEntityGetWhere(state, entityConfig) {
|
|
|
375
377
|
if (state.processInProgress) {
|
|
376
378
|
Stdlib_JsError.throwWithMessage(`Cannot call ` + entityConfig.name + `.getWhere() while indexer.process() is running. ` + "Wait for process() to complete before accessing entities directly.");
|
|
377
379
|
}
|
|
378
|
-
let
|
|
380
|
+
let matcher = EntityFilter.makeMatcher(EntityFilter.parseOrThrow(filter, entityConfig.name, entityConfig.table), entityConfig.table);
|
|
379
381
|
let entityDict = Stdlib_Option.getOr(state.entities[entityConfig.name], {});
|
|
380
|
-
return Promise.resolve(Object.values(entityDict).filter(
|
|
382
|
+
return Promise.resolve(Object.values(entityDict).filter(matcher).map(copyEntity));
|
|
381
383
|
};
|
|
382
384
|
}
|
|
383
385
|
|
|
@@ -386,10 +388,10 @@ function makeInMemoryStorage(state) {
|
|
|
386
388
|
name: "test-inmemory",
|
|
387
389
|
isInitialized: async () => true,
|
|
388
390
|
initialize: async (param, param$1, param$2, param$3, param$4) => Stdlib_JsError.throwWithMessage("TestIndexer: initialize should not be called; the initial state is derived from config."),
|
|
389
|
-
resumeInitialState: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: resumeInitialState should not be called; the initial state is derived from config."),
|
|
391
|
+
resumeInitialState: async (param, param$1, param$2) => Stdlib_JsError.throwWithMessage("TestIndexer: resumeInitialState should not be called; the initial state is derived from config."),
|
|
390
392
|
loadOrThrow: async (filter, table) => handleLoad(state, table.tableName, filter),
|
|
391
|
-
ensureQueryIndexes: async (param, param$1) => {},
|
|
392
|
-
ensureSchemaIndexes: async param => {},
|
|
393
|
+
ensureQueryIndexes: async (param, param$1, param$2) => {},
|
|
394
|
+
ensureSchemaIndexes: async (param, param$1) => {},
|
|
393
395
|
finalizeBackfill: async (param, param$1, param$2) => {},
|
|
394
396
|
dumpEffectCache: async () => {},
|
|
395
397
|
reset: async () => {},
|
|
@@ -399,7 +401,7 @@ function makeInMemoryStorage(state) {
|
|
|
399
401
|
getRollbackTargetCheckpoint: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
|
|
400
402
|
getRollbackProgressDiff: async param => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
|
|
401
403
|
getRollbackData: async (param, param$1) => Stdlib_JsError.throwWithMessage("TestIndexer: Rollback is not supported. The runner forces rollbackOnReorg off, so this should be unreachable."),
|
|
402
|
-
writeBatch: async (batch, param,
|
|
404
|
+
writeBatch: async (batch, param, config, param$1, param$2, updatedEntities, registeredAddresses, param$3, param$4) => handleWriteBatch(state, config, updatedEntities, registeredAddresses, batch.checkpointIds, batch.checkpointChainIds, batch.checkpointBlockNumbers, batch.checkpointEventsProcessed),
|
|
403
405
|
close: async () => {}
|
|
404
406
|
};
|
|
405
407
|
}
|
package/src/UserContext.res
CHANGED
|
@@ -95,6 +95,7 @@ let initEffect = (params: contextParams) => {
|
|
|
95
95
|
input,
|
|
96
96
|
context: effectContext,
|
|
97
97
|
cacheKey: input->S.reverseConvertOrThrow(effect.input)->Utils.Hash.makeOrThrow,
|
|
98
|
+
chainId: handlerChainId,
|
|
98
99
|
checkpointId: params.checkpointId,
|
|
99
100
|
}
|
|
100
101
|
LoadLayer.loadEffect(
|
|
@@ -121,39 +122,20 @@ type entityContextParams = {
|
|
|
121
122
|
// The handler context is always chain-scoped, so a per-chain entity resolves to
|
|
122
123
|
// the chain the handler runs on and a cross-chain one to the shared partition.
|
|
123
124
|
let entityScope = (params: entityContextParams) =>
|
|
124
|
-
params.entityConfig->InMemoryStore.entityScope(
|
|
125
|
-
~chainId=params.item->Internal.getItemChainId,
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
let getWhereHandler = (params: entityContextParams, filter: dict<dict<unknown>>) => {
|
|
129
|
-
let entityConfig = params.entityConfig
|
|
130
|
-
|
|
131
|
-
@inline
|
|
132
|
-
let loadWithFilter = filter =>
|
|
133
|
-
LoadLayer.loadByFilter(
|
|
134
|
-
~loadManager=params.loadManager,
|
|
135
|
-
~persistence=params.persistence,
|
|
136
|
-
~entityConfig,
|
|
137
|
-
~scope=params->entityScope,
|
|
138
|
-
~indexerState=params.indexerState,
|
|
139
|
-
~shouldGroup=params.isPreload,
|
|
140
|
-
~item=params.item,
|
|
141
|
-
~ecosystem=params.config.ecosystem,
|
|
142
|
-
~filter,
|
|
143
|
-
)
|
|
125
|
+
params.entityConfig->InMemoryStore.entityScope(~chainId=params.item->Internal.getItemChainId)
|
|
144
126
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
~
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
127
|
+
let getWhereHandler = (params: entityContextParams, filter: dict<dict<unknown>>) =>
|
|
128
|
+
LoadLayer.loadByFilter(
|
|
129
|
+
~loadManager=params.loadManager,
|
|
130
|
+
~persistence=params.persistence,
|
|
131
|
+
~entityConfig=params.entityConfig,
|
|
132
|
+
~scope=params->entityScope,
|
|
133
|
+
~indexerState=params.indexerState,
|
|
134
|
+
~shouldGroup=params.isPreload,
|
|
135
|
+
~item=params.item,
|
|
136
|
+
~ecosystem=params.config.ecosystem,
|
|
137
|
+
~filter,
|
|
138
|
+
)
|
|
157
139
|
|
|
158
140
|
let noopSet = (_entity: Internal.entity) => ()
|
|
159
141
|
let noopDeleteUnsafe = (_entityId: EntityId.t) => ()
|
|
@@ -171,14 +153,16 @@ let entityTraps: Utils.Proxy.traps<entityContextParams> = {
|
|
|
171
153
|
let prop = prop->(Utils.magic: unknown => string)
|
|
172
154
|
|
|
173
155
|
let isClickHouseOnly = !params.entityConfig.storage.postgres
|
|
156
|
+
let scope = params->entityScope
|
|
157
|
+
let committedCheckpointId = params.indexerState->IndexerState.committedCheckpointIdFor(~scope)
|
|
174
158
|
|
|
175
159
|
let set = params.isPreload
|
|
176
160
|
? noopSet
|
|
177
161
|
: (entity: Internal.entity) => {
|
|
178
162
|
params.indexerState
|
|
179
|
-
->InMemoryStore.getInMemTable(~entityConfig=params.entityConfig, ~scope
|
|
163
|
+
->InMemoryStore.getInMemTable(~entityConfig=params.entityConfig, ~scope)
|
|
180
164
|
->InMemoryTable.Entity.set(
|
|
181
|
-
~committedCheckpointId
|
|
165
|
+
~committedCheckpointId,
|
|
182
166
|
Set({
|
|
183
167
|
entityId: entity.id->EntityId.unsafeOfString,
|
|
184
168
|
checkpointId: params.checkpointId,
|
|
@@ -288,9 +272,9 @@ let entityTraps: Utils.Proxy.traps<entityContextParams> = {
|
|
|
288
272
|
} else {
|
|
289
273
|
entityId => {
|
|
290
274
|
params.indexerState
|
|
291
|
-
->InMemoryStore.getInMemTable(~entityConfig=params.entityConfig, ~scope
|
|
275
|
+
->InMemoryStore.getInMemTable(~entityConfig=params.entityConfig, ~scope)
|
|
292
276
|
->InMemoryTable.Entity.set(
|
|
293
|
-
~committedCheckpointId
|
|
277
|
+
~committedCheckpointId,
|
|
294
278
|
Delete({
|
|
295
279
|
entityId,
|
|
296
280
|
checkpointId: params.checkpointId,
|
package/src/UserContext.res.mjs
CHANGED
|
@@ -64,6 +64,7 @@ function initEffect(params) {
|
|
|
64
64
|
input: input,
|
|
65
65
|
context: effectContext,
|
|
66
66
|
cacheKey: effectArgs_cacheKey,
|
|
67
|
+
chainId: handlerChainId,
|
|
67
68
|
checkpointId: effectArgs_checkpointId
|
|
68
69
|
};
|
|
69
70
|
return LoadLayer.loadEffect(params.loadManager, params.persistence, effect, effectArgs, scope, params.indexerState, params.isPreload, params.item, params.config.ecosystem);
|
|
@@ -76,13 +77,7 @@ function entityScope(params) {
|
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
function getWhereHandler(params, filter) {
|
|
79
|
-
|
|
80
|
-
let filters = EntityFilter.parseGetWhereOrThrow(filter, entityConfig.name, entityConfig.table);
|
|
81
|
-
if (filters.length !== 1) {
|
|
82
|
-
return Promise.all(filters.map(filter => LoadLayer.loadByFilter(params.loadManager, params.persistence, entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, filter))).then(results => results.flat());
|
|
83
|
-
} else {
|
|
84
|
-
return LoadLayer.loadByFilter(params.loadManager, params.persistence, entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, filters[0]);
|
|
85
|
-
}
|
|
80
|
+
return LoadLayer.loadByFilter(params.loadManager, params.persistence, params.entityConfig, entityScope(params), params.indexerState, params.isPreload, params.item, params.config.ecosystem, filter);
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
function noopSet(_entity) {
|
|
@@ -99,7 +94,9 @@ function throwClickHouseReadOnly(entityConfig, op) {
|
|
|
99
94
|
|
|
100
95
|
let entityTraps_get = (params, prop) => {
|
|
101
96
|
let isClickHouseOnly = !params.entityConfig.storage.postgres;
|
|
102
|
-
let
|
|
97
|
+
let scope = entityScope(params);
|
|
98
|
+
let committedCheckpointId = IndexerState.committedCheckpointIdFor(params.indexerState, scope);
|
|
99
|
+
let set = params.isPreload ? noopSet : entity => InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, scope), committedCheckpointId, {
|
|
103
100
|
type: "SET",
|
|
104
101
|
entityId: entity.id,
|
|
105
102
|
entity: entity,
|
|
@@ -110,7 +107,7 @@ let entityTraps_get = (params, prop) => {
|
|
|
110
107
|
if (params.isPreload) {
|
|
111
108
|
return noopDeleteUnsafe;
|
|
112
109
|
} else {
|
|
113
|
-
return entityId => InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig,
|
|
110
|
+
return entityId => InMemoryTable.Entity.set(InMemoryStore.getInMemTable(params.indexerState, params.entityConfig, scope), committedCheckpointId, {
|
|
114
111
|
type: "DELETE",
|
|
115
112
|
entityId: entityId,
|
|
116
113
|
checkpointId: params.checkpointId
|
package/src/Utils.res
CHANGED
|
@@ -166,6 +166,15 @@ module Dict = {
|
|
|
166
166
|
|
|
167
167
|
let merge: (dict<'a>, dict<'a>) => dict<'a> = %raw(`(dictA, dictB) => ({...dictA, ...dictB})`)
|
|
168
168
|
|
|
169
|
+
// Keeps every key either dict has; `pick` decides a key both have.
|
|
170
|
+
let mergeWith: (dict<'a>, dict<'a>, ('a, 'a) => 'a) => dict<'a> = %raw(`(a, b, pick) => {
|
|
171
|
+
var merged = {...a}, i;
|
|
172
|
+
for (i in b) {
|
|
173
|
+
merged[i] = i in merged ? pick(merged[i], b[i]) : b[i];
|
|
174
|
+
}
|
|
175
|
+
return merged;
|
|
176
|
+
}`)
|
|
177
|
+
|
|
169
178
|
@val
|
|
170
179
|
external mergeInPlace: (dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
|
|
171
180
|
|
|
@@ -264,7 +273,7 @@ module Dict = {
|
|
|
264
273
|
}
|
|
265
274
|
|
|
266
275
|
module Math = {
|
|
267
|
-
let minOptInt = (a
|
|
276
|
+
let minOptInt = (a: option<int>, b: option<int>) =>
|
|
268
277
|
switch (a, b) {
|
|
269
278
|
| (Some(a), Some(b)) => Some(a < b ? a : b)
|
|
270
279
|
| (Some(a), None) => Some(a)
|
|
@@ -365,9 +374,6 @@ module Array = {
|
|
|
365
374
|
/**
|
|
366
375
|
Helper to check if a value exists in an array
|
|
367
376
|
*/
|
|
368
|
-
let includes = (arr: array<'a>, val: 'a) =>
|
|
369
|
-
arr->Array.find(item => item == val)->Stdlib.Option.isSome
|
|
370
|
-
|
|
371
377
|
let isEmpty = (arr: array<_>) =>
|
|
372
378
|
switch arr {
|
|
373
379
|
| [] => true
|
package/src/Utils.res.mjs
CHANGED
|
@@ -6,11 +6,9 @@ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
|
6
6
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
7
7
|
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
8
8
|
import * as Stdlib_BigInt from "@rescript/runtime/lib/es6/Stdlib_BigInt.js";
|
|
9
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
9
|
import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
|
|
11
10
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
12
11
|
import * as Stdlib_Promise from "@rescript/runtime/lib/es6/Stdlib_Promise.js";
|
|
13
|
-
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
14
12
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
15
13
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
16
14
|
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
@@ -114,6 +112,14 @@ function pushMany(dict, key, values) {
|
|
|
114
112
|
|
|
115
113
|
let merge = ((dictA, dictB) => ({...dictA, ...dictB}));
|
|
116
114
|
|
|
115
|
+
let mergeWith = ((a, b, pick) => {
|
|
116
|
+
var merged = {...a}, i;
|
|
117
|
+
for (i in b) {
|
|
118
|
+
merged[i] = i in merged ? pick(merged[i], b[i]) : b[i];
|
|
119
|
+
}
|
|
120
|
+
return merged;
|
|
121
|
+
});
|
|
122
|
+
|
|
117
123
|
let mapValues = ((dict, f) => {
|
|
118
124
|
var target = {}, i;
|
|
119
125
|
for (i in dict) {
|
|
@@ -197,6 +203,7 @@ let Dict = {
|
|
|
197
203
|
push: push,
|
|
198
204
|
pushMany: pushMany,
|
|
199
205
|
merge: merge,
|
|
206
|
+
mergeWith: mergeWith,
|
|
200
207
|
mapValues: mapValues,
|
|
201
208
|
filterMapValues: filterMapValues,
|
|
202
209
|
mapValuesToArray: mapValuesToArray,
|
|
@@ -212,19 +219,17 @@ let Dict = {
|
|
|
212
219
|
};
|
|
213
220
|
|
|
214
221
|
function minOptInt(a, b) {
|
|
215
|
-
if (a
|
|
222
|
+
if (a !== undefined) {
|
|
216
223
|
if (b !== undefined) {
|
|
217
|
-
return
|
|
224
|
+
return a < b ? a : b;
|
|
218
225
|
} else {
|
|
219
|
-
return;
|
|
226
|
+
return a;
|
|
220
227
|
}
|
|
228
|
+
} else if (b !== undefined) {
|
|
229
|
+
return b;
|
|
230
|
+
} else {
|
|
231
|
+
return;
|
|
221
232
|
}
|
|
222
|
-
let a$1 = Primitive_option.valFromOption(a);
|
|
223
|
-
if (b === undefined) {
|
|
224
|
-
return Primitive_option.some(a$1);
|
|
225
|
-
}
|
|
226
|
-
let b$1 = Primitive_option.valFromOption(b);
|
|
227
|
-
return Primitive_option.some(Primitive_object.lessthan(a$1, b$1) ? a$1 : b$1);
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
let $$Math = {
|
|
@@ -315,10 +320,6 @@ function transposeResults(results) {
|
|
|
315
320
|
};
|
|
316
321
|
}
|
|
317
322
|
|
|
318
|
-
function includes(arr, val) {
|
|
319
|
-
return Stdlib_Option.isSome(arr.find(item => Primitive_object.equal(item, val)));
|
|
320
|
-
}
|
|
321
|
-
|
|
322
323
|
function isEmpty$1(arr) {
|
|
323
324
|
return arr.length === 0;
|
|
324
325
|
}
|
|
@@ -426,7 +427,6 @@ let $$Array$1 = {
|
|
|
426
427
|
clearInPlace: clearInPlace$1,
|
|
427
428
|
setIndexImmutable: setIndexImmutable,
|
|
428
429
|
transposeResults: transposeResults,
|
|
429
|
-
includes: includes,
|
|
430
430
|
isEmpty: isEmpty$1,
|
|
431
431
|
notEmpty: notEmpty,
|
|
432
432
|
awaitEach: awaitEach,
|