envio 2.28.0-alpha.3 → 2.28.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.
- package/package.json +6 -6
- package/src/Batch.res +146 -0
- package/src/Batch.res.js +129 -0
- package/src/FetchState.res +15 -0
- package/src/FetchState.res.js +20 -0
- package/src/Hasura.res +3 -19
- package/src/Hasura.res.js +6 -16
- package/src/InternalConfig.res +10 -0
- package/src/Persistence.res +25 -6
- package/src/Persistence.res.js +18 -3
- package/src/PgStorage.res +16 -8
- package/src/PgStorage.res.js +9 -6
- package/src/Throttler.res +4 -1
- package/src/Throttler.res.js +2 -1
- package/src/Utils.res +7 -0
- package/src/Utils.res.js +6 -1
- package/src/bindings/Postgres.res +1 -1
- package/src/db/InternalTable.gen.ts +0 -7
- package/src/db/InternalTable.res +140 -75
- package/src/db/InternalTable.res.js +104 -73
- package/src/sources/EventRouter.res +113 -0
- package/src/sources/EventRouter.res.js +125 -0
- package/src/sources/HyperSync.res +15 -7
- package/src/sources/HyperSync.res.js +48 -15
- package/src/sources/HyperSyncClient.res +4 -3
- package/src/sources/HyperSyncClient.res.js +6 -1
- package/src/sources/RpcSource.res +748 -0
- package/src/sources/RpcSource.res.js +697 -0
package/src/Throttler.res.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var Pino = require("./bindings/Pino.res.js");
|
|
5
|
+
var Utils = require("./Utils.res.js");
|
|
5
6
|
var Caml_js_exceptions = require("rescript/lib/js/caml_js_exceptions.js");
|
|
6
7
|
|
|
7
8
|
function make(intervalMillis, logger) {
|
|
@@ -38,7 +39,7 @@ async function startInternal(throttler) {
|
|
|
38
39
|
}
|
|
39
40
|
catch (raw_exn){
|
|
40
41
|
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
41
|
-
throttler.logger.error(Pino.createPinoMessageWithError("Scheduled action failed in throttler", exn));
|
|
42
|
+
throttler.logger.error(Pino.createPinoMessageWithError("Scheduled action failed in throttler", Utils.prettifyExn(exn)));
|
|
42
43
|
}
|
|
43
44
|
throttler.isRunning = false;
|
|
44
45
|
return await startInternal(throttler);
|
package/src/Utils.res
CHANGED
|
@@ -130,6 +130,13 @@ module Dict = {
|
|
|
130
130
|
let shallowCopy: dict<'a> => dict<'a> = %raw(`(dict) => ({...dict})`)
|
|
131
131
|
|
|
132
132
|
let size = dict => dict->Js.Dict.keys->Js.Array2.length
|
|
133
|
+
|
|
134
|
+
@set_index
|
|
135
|
+
external setByInt: (dict<'a>, int, 'a) => unit = ""
|
|
136
|
+
|
|
137
|
+
let incrementByInt: (dict<int>, int) => unit = %raw(`(dict, key) => {
|
|
138
|
+
dict[key]++
|
|
139
|
+
}`)
|
|
133
140
|
}
|
|
134
141
|
|
|
135
142
|
module Math = {
|
package/src/Utils.res.js
CHANGED
|
@@ -130,6 +130,10 @@ function size(dict) {
|
|
|
130
130
|
return Object.keys(dict).length;
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
+
var incrementByInt = ((dict, key) => {
|
|
134
|
+
dict[key]++
|
|
135
|
+
});
|
|
136
|
+
|
|
133
137
|
var Dict = {
|
|
134
138
|
has: has,
|
|
135
139
|
push: push,
|
|
@@ -141,7 +145,8 @@ var Dict = {
|
|
|
141
145
|
deleteInPlace: deleteInPlace,
|
|
142
146
|
updateImmutable: updateImmutable,
|
|
143
147
|
shallowCopy: shallowCopy,
|
|
144
|
-
size: size
|
|
148
|
+
size: size,
|
|
149
|
+
incrementByInt: incrementByInt
|
|
145
150
|
};
|
|
146
151
|
|
|
147
152
|
function minOptInt(a, b) {
|
|
@@ -78,7 +78,7 @@ type poolConfig = {
|
|
|
78
78
|
// types?: array<'a>, // Array of custom types, see more below (default: [])
|
|
79
79
|
onnotice?: string => unit, // Default console.log, set false to silence NOTICE (default: fn)
|
|
80
80
|
onParameter?: (string, string) => unit, // (key, value) when server param change (default: fn)
|
|
81
|
-
debug?:
|
|
81
|
+
debug?: (~connection: unknown, ~query: unknown, ~params: unknown, ~types: unknown) => unit, // Is called with (connection, query, params, types)
|
|
82
82
|
socket?: unit => unit, // fn returning custom socket to use (default: fn)
|
|
83
83
|
transform?: transformConfig,
|
|
84
84
|
connection?: connectionConfig,
|
|
@@ -7,13 +7,6 @@ import type {Json_t as Js_Json_t} from '../../src/Js.shim';
|
|
|
7
7
|
|
|
8
8
|
import type {t as Address_t} from '../../src/Address.gen';
|
|
9
9
|
|
|
10
|
-
export type EventSyncState_t = {
|
|
11
|
-
readonly chain_id: number;
|
|
12
|
-
readonly block_number: number;
|
|
13
|
-
readonly log_index: number;
|
|
14
|
-
readonly block_timestamp: number
|
|
15
|
-
};
|
|
16
|
-
|
|
17
10
|
export type RawEvents_t = {
|
|
18
11
|
readonly chain_id: number;
|
|
19
12
|
readonly event_id: bigint;
|
package/src/db/InternalTable.res
CHANGED
|
@@ -5,51 +5,15 @@ let isPrimaryKey = true
|
|
|
5
5
|
let isNullable = true
|
|
6
6
|
let isIndex = true
|
|
7
7
|
|
|
8
|
-
module EventSyncState = {
|
|
9
|
-
//Used unsafely in DbFunctions.res so just enforcing the naming here
|
|
10
|
-
let blockTimestampFieldName = "block_timestamp"
|
|
11
|
-
let blockNumberFieldName = "block_number"
|
|
12
|
-
let logIndexFieldName = "log_index"
|
|
13
|
-
let isPreRegisteringDynamicContractsFieldName = "is_pre_registering_dynamic_contracts"
|
|
14
|
-
|
|
15
|
-
// @genType Used for Test DB
|
|
16
|
-
@genType
|
|
17
|
-
type t = {
|
|
18
|
-
@as("chain_id") chainId: int,
|
|
19
|
-
@as("block_number") blockNumber: int,
|
|
20
|
-
@as("log_index") logIndex: int,
|
|
21
|
-
@as("block_timestamp") blockTimestamp: int,
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let table = mkTable(
|
|
25
|
-
"event_sync_state",
|
|
26
|
-
~fields=[
|
|
27
|
-
mkField("chain_id", Integer, ~fieldSchema=S.int, ~isPrimaryKey),
|
|
28
|
-
mkField(blockNumberFieldName, Integer, ~fieldSchema=S.int),
|
|
29
|
-
mkField(logIndexFieldName, Integer, ~fieldSchema=S.int),
|
|
30
|
-
mkField(blockTimestampFieldName, Integer, ~fieldSchema=S.int),
|
|
31
|
-
// Keep it in case Hosted Service relies on it to prevent a breaking changes
|
|
32
|
-
mkField(
|
|
33
|
-
isPreRegisteringDynamicContractsFieldName,
|
|
34
|
-
Boolean,
|
|
35
|
-
~default="false",
|
|
36
|
-
~fieldSchema=S.bool,
|
|
37
|
-
),
|
|
38
|
-
],
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
//We need to update values here not delet the rows, since restarting without a row
|
|
42
|
-
//has a different behaviour to restarting with an initialised row with zero values
|
|
43
|
-
let resetCurrentCurrentSyncStateQuery = (~pgSchema) =>
|
|
44
|
-
`UPDATE "${pgSchema}"."${table.tableName}"
|
|
45
|
-
SET ${blockNumberFieldName} = 0,
|
|
46
|
-
${logIndexFieldName} = 0,
|
|
47
|
-
${blockTimestampFieldName} = 0,
|
|
48
|
-
${isPreRegisteringDynamicContractsFieldName} = false;`
|
|
49
|
-
}
|
|
50
|
-
|
|
51
8
|
module Chains = {
|
|
9
|
+
type progressFields = [
|
|
10
|
+
| #progress_block
|
|
11
|
+
| #_progress_log_index
|
|
12
|
+
| #events_processed
|
|
13
|
+
]
|
|
14
|
+
|
|
52
15
|
type field = [
|
|
16
|
+
| progressFields
|
|
53
17
|
| #id
|
|
54
18
|
| #start_block
|
|
55
19
|
| #end_block
|
|
@@ -57,10 +21,8 @@ module Chains = {
|
|
|
57
21
|
| #first_event_block
|
|
58
22
|
| #buffer_block
|
|
59
23
|
| #ready_at
|
|
60
|
-
| #events_processed
|
|
61
|
-
| #_is_hyper_sync
|
|
62
|
-
| #_latest_processed_block
|
|
63
24
|
| #_num_batches_fetched
|
|
25
|
+
| #_is_hyper_sync
|
|
64
26
|
]
|
|
65
27
|
|
|
66
28
|
let fields: array<field> = [
|
|
@@ -70,28 +32,34 @@ module Chains = {
|
|
|
70
32
|
#source_block,
|
|
71
33
|
#first_event_block,
|
|
72
34
|
#buffer_block,
|
|
35
|
+
#progress_block,
|
|
73
36
|
#ready_at,
|
|
74
37
|
#events_processed,
|
|
38
|
+
#_progress_log_index,
|
|
75
39
|
#_is_hyper_sync,
|
|
76
|
-
#_latest_processed_block,
|
|
77
40
|
#_num_batches_fetched,
|
|
78
41
|
]
|
|
79
42
|
|
|
80
|
-
type
|
|
81
|
-
@as("id") id: int,
|
|
82
|
-
@as("start_block") startBlock: int,
|
|
83
|
-
@as("end_block") endBlock: Js.null<int>,
|
|
84
|
-
@as("source_block") blockHeight: int,
|
|
43
|
+
type metaFields = {
|
|
85
44
|
@as("first_event_block") firstEventBlockNumber: Js.null<int>,
|
|
86
45
|
@as("buffer_block") latestFetchedBlockNumber: int,
|
|
46
|
+
@as("source_block") blockHeight: int,
|
|
87
47
|
@as("ready_at")
|
|
88
48
|
timestampCaughtUpToHeadOrEndblock: Js.null<Js.Date.t>,
|
|
89
|
-
@as("events_processed") numEventsProcessed: int,
|
|
90
|
-
@as("_latest_processed_block") latestProcessedBlock: Js.null<int>,
|
|
91
49
|
@as("_is_hyper_sync") isHyperSync: bool,
|
|
92
50
|
@as("_num_batches_fetched") numBatchesFetched: int,
|
|
93
51
|
}
|
|
94
52
|
|
|
53
|
+
type t = {
|
|
54
|
+
@as("id") id: int,
|
|
55
|
+
@as("start_block") startBlock: int,
|
|
56
|
+
@as("end_block") endBlock: Js.null<int>,
|
|
57
|
+
@as("progress_block") progressBlockNumber: int,
|
|
58
|
+
@as("_progress_log_index") progressNextBlockLogIndex: Js.null<int>,
|
|
59
|
+
@as("events_processed") numEventsProcessed: int,
|
|
60
|
+
...metaFields,
|
|
61
|
+
}
|
|
62
|
+
|
|
95
63
|
let table = mkTable(
|
|
96
64
|
"envio_chains",
|
|
97
65
|
~fields=[
|
|
@@ -118,15 +86,20 @@ module Chains = {
|
|
|
118
86
|
~fieldSchema=S.null(Utils.Schema.dbDate),
|
|
119
87
|
~isNullable,
|
|
120
88
|
),
|
|
121
|
-
mkField((#events_processed: field :> string), Integer, ~fieldSchema=S.int),
|
|
89
|
+
mkField((#events_processed: field :> string), Integer, ~fieldSchema=S.int),
|
|
90
|
+
// TODO: In the future it should reference a table with sources
|
|
122
91
|
mkField((#_is_hyper_sync: field :> string), Boolean, ~fieldSchema=S.bool),
|
|
123
|
-
//
|
|
92
|
+
// Fully processed block number
|
|
93
|
+
mkField((#progress_block: field :> string), Integer, ~fieldSchema=S.int),
|
|
94
|
+
// Optional log index of the next block after progress block
|
|
95
|
+
// To correctly resume indexing when we processed half of the block.
|
|
124
96
|
mkField(
|
|
125
|
-
(#
|
|
97
|
+
(#_progress_log_index: field :> string),
|
|
126
98
|
Integer,
|
|
127
99
|
~fieldSchema=S.null(S.int),
|
|
128
100
|
~isNullable,
|
|
129
101
|
),
|
|
102
|
+
// TODO: Should deprecate after changing the ETA calculation logic
|
|
130
103
|
mkField((#_num_batches_fetched: field :> string), Integer, ~fieldSchema=S.int),
|
|
131
104
|
],
|
|
132
105
|
)
|
|
@@ -140,7 +113,8 @@ module Chains = {
|
|
|
140
113
|
firstEventBlockNumber: Js.Null.empty,
|
|
141
114
|
latestFetchedBlockNumber: -1,
|
|
142
115
|
timestampCaughtUpToHeadOrEndblock: Js.Null.empty,
|
|
143
|
-
|
|
116
|
+
progressBlockNumber: -1,
|
|
117
|
+
progressNextBlockLogIndex: Js.Null.empty,
|
|
144
118
|
isHyperSync: false,
|
|
145
119
|
numEventsProcessed: 0,
|
|
146
120
|
numBatchesFetched: 0,
|
|
@@ -178,21 +152,19 @@ VALUES ${valuesRows->Js.Array2.joinWith(",\n ")};`,
|
|
|
178
152
|
}
|
|
179
153
|
}
|
|
180
154
|
|
|
181
|
-
// Fields that
|
|
182
|
-
let
|
|
155
|
+
// Fields that can be updated outside of the batch transaction
|
|
156
|
+
let metaFields: array<field> = [
|
|
183
157
|
#source_block,
|
|
184
|
-
#first_event_block,
|
|
185
158
|
#buffer_block,
|
|
159
|
+
#first_event_block,
|
|
186
160
|
#ready_at,
|
|
187
|
-
#events_processed,
|
|
188
161
|
#_is_hyper_sync,
|
|
189
|
-
#_latest_processed_block,
|
|
190
162
|
#_num_batches_fetched,
|
|
191
163
|
]
|
|
192
164
|
|
|
193
|
-
let
|
|
165
|
+
let makeMetaFieldsUpdateQuery = (~pgSchema) => {
|
|
194
166
|
// Generate SET clauses with parameter placeholders
|
|
195
|
-
let setClauses = Belt.Array.mapWithIndex(
|
|
167
|
+
let setClauses = Belt.Array.mapWithIndex(metaFields, (index, field) => {
|
|
196
168
|
let fieldName = (field :> string)
|
|
197
169
|
let paramIndex = index + 2 // +2 because $1 is for id in WHERE clause
|
|
198
170
|
`"${fieldName}" = $${Belt.Int.toString(paramIndex)}`
|
|
@@ -203,27 +175,80 @@ SET ${setClauses->Js.Array2.joinWith(",\n ")}
|
|
|
203
175
|
WHERE "id" = $1;`
|
|
204
176
|
}
|
|
205
177
|
|
|
206
|
-
let
|
|
207
|
-
|
|
178
|
+
let progressFields: array<progressFields> = [
|
|
179
|
+
#progress_block,
|
|
180
|
+
#_progress_log_index,
|
|
181
|
+
#events_processed,
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
let makeProgressFieldsUpdateQuery = (~pgSchema) => {
|
|
185
|
+
let setClauses = Belt.Array.mapWithIndex(progressFields, (index, field) => {
|
|
186
|
+
let fieldName = (field :> string)
|
|
187
|
+
let paramIndex = index + 2 // +2 because $1 is for id in WHERE clause
|
|
188
|
+
`"${fieldName}" = $${Belt.Int.toString(paramIndex)}`
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
`UPDATE "${pgSchema}"."${table.tableName}"
|
|
192
|
+
SET ${setClauses->Js.Array2.joinWith(",\n ")}
|
|
193
|
+
WHERE "id" = $1;`
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let setMeta = (sql, ~pgSchema, ~chainsData: dict<metaFields>) => {
|
|
197
|
+
let query = makeMetaFieldsUpdateQuery(~pgSchema)
|
|
198
|
+
|
|
199
|
+
let promises = []
|
|
208
200
|
|
|
209
|
-
|
|
201
|
+
chainsData->Utils.Dict.forEachWithKey((chainId, data) => {
|
|
210
202
|
let params = []
|
|
211
203
|
|
|
212
204
|
// Push id first (for WHERE clause)
|
|
213
|
-
|
|
214
|
-
params->Js.Array2.push(idValue)->ignore
|
|
205
|
+
params->Js.Array2.push(chainId->(Utils.magic: string => unknown))->ignore
|
|
215
206
|
|
|
216
207
|
// Then push all updateable field values (for SET clause)
|
|
217
|
-
|
|
218
|
-
let value =
|
|
208
|
+
metaFields->Js.Array2.forEach(field => {
|
|
209
|
+
let value =
|
|
210
|
+
data->(Utils.magic: metaFields => dict<unknown>)->Js.Dict.unsafeGet((field :> string))
|
|
219
211
|
params->Js.Array2.push(value)->ignore
|
|
220
212
|
})
|
|
221
213
|
|
|
222
|
-
sql->Postgres.preparedUnsafe(query, params->Obj.magic)
|
|
214
|
+
promises->Js.Array2.push(sql->Postgres.preparedUnsafe(query, params->Obj.magic))->ignore
|
|
223
215
|
})
|
|
224
216
|
|
|
225
217
|
Promise.all(promises)
|
|
226
218
|
}
|
|
219
|
+
|
|
220
|
+
let setProgressedChains = (sql, ~pgSchema, ~progressedChains: array<Batch.progressedChain>) => {
|
|
221
|
+
let query = makeProgressFieldsUpdateQuery(~pgSchema)
|
|
222
|
+
|
|
223
|
+
let promises = []
|
|
224
|
+
|
|
225
|
+
progressedChains->Js.Array2.forEach(data => {
|
|
226
|
+
let params = []
|
|
227
|
+
|
|
228
|
+
// Push id first (for WHERE clause)
|
|
229
|
+
params->Js.Array2.push(data.chainId->(Utils.magic: int => unknown))->ignore
|
|
230
|
+
|
|
231
|
+
// Then push all updateable field values (for SET clause)
|
|
232
|
+
progressFields->Js.Array2.forEach(field => {
|
|
233
|
+
params
|
|
234
|
+
->Js.Array2.push(
|
|
235
|
+
switch field {
|
|
236
|
+
| #progress_block => data.progressBlockNumber->(Utils.magic: int => unknown)
|
|
237
|
+
| #_progress_log_index =>
|
|
238
|
+
data.progressNextBlockLogIndex
|
|
239
|
+
->Js.Null.fromOption
|
|
240
|
+
->(Utils.magic: Js.null<int> => unknown)
|
|
241
|
+
| #events_processed => data.totalEventsProcessed->(Utils.magic: int => unknown)
|
|
242
|
+
},
|
|
243
|
+
)
|
|
244
|
+
->ignore
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
promises->Js.Array2.push(sql->Postgres.preparedUnsafe(query, params->Obj.magic))->ignore
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
Promise.all(promises)->Promise.ignoreValue
|
|
251
|
+
}
|
|
227
252
|
}
|
|
228
253
|
|
|
229
254
|
module PersistedState = {
|
|
@@ -336,10 +361,12 @@ module Views = {
|
|
|
336
361
|
"${(#id: Chains.field :> string)}" AS "chainId",
|
|
337
362
|
"${(#start_block: Chains.field :> string)}" AS "startBlock",
|
|
338
363
|
"${(#end_block: Chains.field :> string)}" AS "endBlock",
|
|
364
|
+
"${(#progress_block: Chains.field :> string)}" AS "progressBlock",
|
|
339
365
|
"${(#buffer_block: Chains.field :> string)}" AS "bufferBlock",
|
|
340
|
-
"${(#ready_at: Chains.field :> string)}" AS "readyAt",
|
|
341
366
|
"${(#first_event_block: Chains.field :> string)}" AS "firstEventBlock",
|
|
342
367
|
"${(#events_processed: Chains.field :> string)}" AS "eventsProcessed",
|
|
368
|
+
"${(#source_block: Chains.field :> string)}" AS "sourceBlock",
|
|
369
|
+
"${(#ready_at: Chains.field :> string)}" AS "readyAt",
|
|
343
370
|
("${(#ready_at: Chains.field :> string)}" IS NOT NULL) AS "isReady"
|
|
344
371
|
FROM "${pgSchema}"."${Chains.table.tableName}"
|
|
345
372
|
ORDER BY "${(#id: Chains.field :> string)}";`
|
|
@@ -354,7 +381,7 @@ module Views = {
|
|
|
354
381
|
"${(#first_event_block: Chains.field :> string)}" AS "first_event_block_number",
|
|
355
382
|
"${(#_is_hyper_sync: Chains.field :> string)}" AS "is_hyper_sync",
|
|
356
383
|
"${(#buffer_block: Chains.field :> string)}" AS "latest_fetched_block_number",
|
|
357
|
-
"${(#
|
|
384
|
+
"${(#progress_block: Chains.field :> string)}" AS "latest_processed_block",
|
|
358
385
|
"${(#_num_batches_fetched: Chains.field :> string)}" AS "num_batches_fetched",
|
|
359
386
|
"${(#events_processed: Chains.field :> string)}" AS "num_events_processed",
|
|
360
387
|
"${(#start_block: Chains.field :> string)}" AS "start_block",
|
|
@@ -427,4 +454,42 @@ module DynamicContractRegistry = {
|
|
|
427
454
|
table,
|
|
428
455
|
entityHistory,
|
|
429
456
|
}->Internal.fromGenericEntityConfig
|
|
457
|
+
|
|
458
|
+
let makeCleanUpOnRestartQuery = (~pgSchema, ~chains: array<Chains.t>) => {
|
|
459
|
+
let query = ref(``)
|
|
460
|
+
|
|
461
|
+
chains->Js.Array2.forEach(chain => {
|
|
462
|
+
if query.contents !== "" {
|
|
463
|
+
query := query.contents ++ "\n"
|
|
464
|
+
}
|
|
465
|
+
query :=
|
|
466
|
+
query.contents ++
|
|
467
|
+
`DELETE FROM "${pgSchema}"."${table.tableName}"
|
|
468
|
+
WHERE chain_id = ${chain.id->Belt.Int.toString}${switch chain {
|
|
469
|
+
| {progressBlockNumber, progressNextBlockLogIndex: Value(progressNextBlockLogIndex)} =>
|
|
470
|
+
` AND (
|
|
471
|
+
registering_event_block_number > ${(progressBlockNumber + 1)->Belt.Int.toString}
|
|
472
|
+
OR registering_event_block_number = ${(progressBlockNumber + 1)->Belt.Int.toString}
|
|
473
|
+
AND registering_event_log_index > ${progressNextBlockLogIndex->Belt.Int.toString}
|
|
474
|
+
)`
|
|
475
|
+
| {progressBlockNumber: -1, progressNextBlockLogIndex: Null} => ``
|
|
476
|
+
| {progressBlockNumber, progressNextBlockLogIndex: Null} =>
|
|
477
|
+
` AND registering_event_block_number > ${progressBlockNumber->Belt.Int.toString}`
|
|
478
|
+
}};
|
|
479
|
+
DELETE FROM "${pgSchema}"."${table.tableName}_history"
|
|
480
|
+
WHERE entity_history_chain_id = ${chain.id->Belt.Int.toString}${switch chain {
|
|
481
|
+
| {progressBlockNumber, progressNextBlockLogIndex: Value(progressNextBlockLogIndex)} =>
|
|
482
|
+
` AND (
|
|
483
|
+
entity_history_block_number > ${(progressBlockNumber + 1)->Belt.Int.toString}
|
|
484
|
+
OR entity_history_block_number = ${(progressBlockNumber + 1)->Belt.Int.toString}
|
|
485
|
+
AND entity_history_log_index > ${progressNextBlockLogIndex->Belt.Int.toString}
|
|
486
|
+
)`
|
|
487
|
+
| {progressBlockNumber: -1, progressNextBlockLogIndex: Null} => ``
|
|
488
|
+
| {progressBlockNumber, progressNextBlockLogIndex: Null} =>
|
|
489
|
+
` AND entity_history_block_number > ${progressBlockNumber->Belt.Int.toString}`
|
|
490
|
+
}};`
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
query.contents
|
|
494
|
+
}
|
|
430
495
|
}
|