envio 3.0.0-alpha.2 → 3.0.0-alpha.3
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/evm.schema.json +44 -33
- package/fuel.schema.json +32 -21
- package/index.d.ts +1 -0
- package/package.json +7 -6
- package/src/Batch.res.mjs +1 -1
- package/src/Benchmark.res +394 -0
- package/src/Benchmark.res.mjs +398 -0
- package/src/ChainFetcher.res +459 -0
- package/src/ChainFetcher.res.mjs +281 -0
- package/src/ChainManager.res +179 -0
- package/src/ChainManager.res.mjs +139 -0
- package/src/Config.res +15 -1
- package/src/Config.res.mjs +27 -4
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +0 -1
- package/src/Env.res.mjs +0 -3
- package/src/Envio.gen.ts +9 -1
- package/src/Envio.res +12 -9
- package/src/EventProcessing.res +476 -0
- package/src/EventProcessing.res.mjs +341 -0
- package/src/FetchState.res +54 -29
- package/src/FetchState.res.mjs +62 -35
- package/src/GlobalState.res +1169 -0
- package/src/GlobalState.res.mjs +1196 -0
- package/src/Internal.res +2 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/Prometheus.res +8 -8
- package/src/Prometheus.res.mjs +10 -10
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/UserContext.res +356 -0
- package/src/UserContext.res.mjs +238 -0
- package/src/bindings/DateFns.res +71 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/sources/Evm.res +87 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +95 -0
- package/src/sources/EvmChain.res.mjs +61 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +37 -0
- package/src/sources/FuelSDK.res.mjs +29 -0
- package/src/sources/HyperFuel.res +2 -2
- package/src/sources/HyperFuel.resi +1 -1
- package/src/sources/HyperFuelClient.res +2 -2
- package/src/sources/HyperFuelSource.res +8 -8
- package/src/sources/HyperFuelSource.res.mjs +5 -5
- package/src/sources/HyperSyncSource.res +5 -5
- package/src/sources/HyperSyncSource.res.mjs +5 -5
- package/src/sources/RpcSource.res +4 -4
- package/src/sources/RpcSource.res.mjs +3 -3
- package/src/sources/Solana.res +59 -0
- package/src/sources/Solana.res.mjs +79 -0
- package/src/sources/Source.res +2 -2
- package/src/sources/SourceManager.res +24 -32
- package/src/sources/SourceManager.res.mjs +20 -20
- package/src/sources/SourceManager.resi +4 -5
package/src/Internal.res
CHANGED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
open Belt
|
|
2
|
+
|
|
3
|
+
let loadById = (
|
|
4
|
+
~loadManager,
|
|
5
|
+
~persistence: Persistence.t,
|
|
6
|
+
~entityConfig: Internal.entityConfig,
|
|
7
|
+
~inMemoryStore,
|
|
8
|
+
~shouldGroup,
|
|
9
|
+
~item,
|
|
10
|
+
~entityId,
|
|
11
|
+
) => {
|
|
12
|
+
let key = `${entityConfig.name}.get`
|
|
13
|
+
let inMemTable = inMemoryStore->InMemoryStore.getInMemTable(~entityConfig)
|
|
14
|
+
|
|
15
|
+
let load = async (idsToLoad, ~onError as _) => {
|
|
16
|
+
let timerRef = Prometheus.StorageLoad.startOperation(~operation=key)
|
|
17
|
+
|
|
18
|
+
// Since LoadManager.call prevents registerign entities already existing in the inMemoryStore,
|
|
19
|
+
// we can be sure that we load only the new ones.
|
|
20
|
+
let dbEntities = try {
|
|
21
|
+
await (persistence->Persistence.getInitializedStorageOrThrow).loadByIdsOrThrow(
|
|
22
|
+
~table=entityConfig.table,
|
|
23
|
+
~rowsSchema=entityConfig.rowsSchema,
|
|
24
|
+
~ids=idsToLoad,
|
|
25
|
+
)
|
|
26
|
+
} catch {
|
|
27
|
+
| Persistence.StorageError({message, reason}) =>
|
|
28
|
+
reason->ErrorHandling.mkLogAndRaise(~logger=item->Logging.getItemLogger, ~msg=message)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let entitiesMap = Js.Dict.empty()
|
|
32
|
+
for idx in 0 to dbEntities->Array.length - 1 {
|
|
33
|
+
let entity = dbEntities->Js.Array2.unsafe_get(idx)
|
|
34
|
+
entitiesMap->Js.Dict.set(entity.id, entity)
|
|
35
|
+
}
|
|
36
|
+
idsToLoad->Js.Array2.forEach(entityId => {
|
|
37
|
+
// Set the entity in the in memory store
|
|
38
|
+
// without overwriting existing values
|
|
39
|
+
// which might be newer than what we got from db
|
|
40
|
+
inMemTable->InMemoryTable.Entity.initValue(
|
|
41
|
+
~allowOverWriteEntity=false,
|
|
42
|
+
~key=entityId,
|
|
43
|
+
~entity=entitiesMap->Utils.Dict.dangerouslyGetNonOption(entityId),
|
|
44
|
+
)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
timerRef->Prometheus.StorageLoad.endOperation(
|
|
48
|
+
~operation=key,
|
|
49
|
+
~whereSize=idsToLoad->Array.length,
|
|
50
|
+
~size=dbEntities->Array.length,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
loadManager->LoadManager.call(
|
|
55
|
+
~key,
|
|
56
|
+
~load,
|
|
57
|
+
~shouldGroup,
|
|
58
|
+
~hasher=LoadManager.noopHasher,
|
|
59
|
+
~getUnsafeInMemory=inMemTable->InMemoryTable.Entity.getUnsafe,
|
|
60
|
+
~hasInMemory=hash => inMemTable.table->InMemoryTable.hasByHash(hash),
|
|
61
|
+
~input=entityId,
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let callEffect = (
|
|
66
|
+
~effect: Internal.effect,
|
|
67
|
+
~arg: Internal.effectArgs,
|
|
68
|
+
~inMemTable: InMemoryStore.effectCacheInMemTable,
|
|
69
|
+
~timerRef,
|
|
70
|
+
~onError,
|
|
71
|
+
) => {
|
|
72
|
+
let effectName = effect.name
|
|
73
|
+
let hadActiveCalls = effect.activeCallsCount > 0
|
|
74
|
+
effect.activeCallsCount = effect.activeCallsCount + 1
|
|
75
|
+
Prometheus.EffectCalls.activeCallsCount->Prometheus.SafeGauge.handleInt(
|
|
76
|
+
~labels=effectName,
|
|
77
|
+
~value=effect.activeCallsCount,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if hadActiveCalls {
|
|
81
|
+
let elapsed = Hrtime.millisBetween(~from=effect.prevCallStartTimerRef, ~to=timerRef)
|
|
82
|
+
if elapsed > 0 {
|
|
83
|
+
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.incrementMany(
|
|
84
|
+
~labels=effectName,
|
|
85
|
+
~value=Hrtime.millisBetween(~from=effect.prevCallStartTimerRef, ~to=timerRef),
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
effect.prevCallStartTimerRef = timerRef
|
|
90
|
+
|
|
91
|
+
effect.handler(arg)
|
|
92
|
+
->Promise.thenResolve(output => {
|
|
93
|
+
inMemTable.dict->Js.Dict.set(arg.cacheKey, output)
|
|
94
|
+
if arg.context.cache {
|
|
95
|
+
inMemTable.idsToStore->Array.push(arg.cacheKey)->ignore
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
->Promise.catchResolve(exn => {
|
|
99
|
+
onError(~inputKey=arg.cacheKey, ~exn)
|
|
100
|
+
})
|
|
101
|
+
->Promise.finally(() => {
|
|
102
|
+
effect.activeCallsCount = effect.activeCallsCount - 1
|
|
103
|
+
Prometheus.EffectCalls.activeCallsCount->Prometheus.SafeGauge.handleInt(
|
|
104
|
+
~labels=effectName,
|
|
105
|
+
~value=effect.activeCallsCount,
|
|
106
|
+
)
|
|
107
|
+
let newTimer = Hrtime.makeTimer()
|
|
108
|
+
Prometheus.EffectCalls.timeCounter->Prometheus.SafeCounter.incrementMany(
|
|
109
|
+
~labels=effectName,
|
|
110
|
+
~value=Hrtime.millisBetween(~from=effect.prevCallStartTimerRef, ~to=newTimer),
|
|
111
|
+
)
|
|
112
|
+
effect.prevCallStartTimerRef = newTimer
|
|
113
|
+
|
|
114
|
+
Prometheus.EffectCalls.totalCallsCount->Prometheus.SafeCounter.increment(~labels=effectName)
|
|
115
|
+
Prometheus.EffectCalls.sumTimeCounter->Prometheus.SafeCounter.incrementMany(
|
|
116
|
+
~labels=effectName,
|
|
117
|
+
~value=timerRef->Hrtime.timeSince->Hrtime.toMillis->Hrtime.intFromMillis,
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let rec executeWithRateLimit = (
|
|
123
|
+
~effect: Internal.effect,
|
|
124
|
+
~effectArgs: array<Internal.effectArgs>,
|
|
125
|
+
~inMemTable,
|
|
126
|
+
~onError,
|
|
127
|
+
~isFromQueue: bool,
|
|
128
|
+
) => {
|
|
129
|
+
let effectName = effect.name
|
|
130
|
+
|
|
131
|
+
let timerRef = Hrtime.makeTimer()
|
|
132
|
+
let promises = []
|
|
133
|
+
|
|
134
|
+
switch effect.rateLimit {
|
|
135
|
+
| None =>
|
|
136
|
+
// No rate limiting - execute all immediately
|
|
137
|
+
for idx in 0 to effectArgs->Array.length - 1 {
|
|
138
|
+
promises
|
|
139
|
+
->Array.push(
|
|
140
|
+
callEffect(
|
|
141
|
+
~effect,
|
|
142
|
+
~arg=effectArgs->Array.getUnsafe(idx),
|
|
143
|
+
~inMemTable,
|
|
144
|
+
~timerRef,
|
|
145
|
+
~onError,
|
|
146
|
+
)->Promise.ignoreValue,
|
|
147
|
+
)
|
|
148
|
+
->ignore
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
| Some(state) =>
|
|
152
|
+
let now = Js.Date.now()
|
|
153
|
+
|
|
154
|
+
// Check if we need to reset the window
|
|
155
|
+
if now >= state.windowStartTime +. state.durationMs->Int.toFloat {
|
|
156
|
+
state.availableCalls = state.callsPerDuration
|
|
157
|
+
state.windowStartTime = now
|
|
158
|
+
state.nextWindowPromise = None
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Split into immediate and queued
|
|
162
|
+
let immediateCount = Js.Math.min_int(state.availableCalls, effectArgs->Array.length)
|
|
163
|
+
let immediateArgs = effectArgs->Array.slice(~offset=0, ~len=immediateCount)
|
|
164
|
+
let queuedArgs = effectArgs->Array.sliceToEnd(immediateCount)
|
|
165
|
+
|
|
166
|
+
// Update available calls
|
|
167
|
+
state.availableCalls = state.availableCalls - immediateCount
|
|
168
|
+
|
|
169
|
+
// Call immediate effects
|
|
170
|
+
for idx in 0 to immediateArgs->Array.length - 1 {
|
|
171
|
+
promises
|
|
172
|
+
->Array.push(
|
|
173
|
+
callEffect(
|
|
174
|
+
~effect,
|
|
175
|
+
~arg=immediateArgs->Array.getUnsafe(idx),
|
|
176
|
+
~inMemTable,
|
|
177
|
+
~timerRef,
|
|
178
|
+
~onError,
|
|
179
|
+
)->Promise.ignoreValue,
|
|
180
|
+
)
|
|
181
|
+
->ignore
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if immediateCount > 0 && isFromQueue {
|
|
185
|
+
// Update queue count metric
|
|
186
|
+
state.queueCount = state.queueCount - immediateCount
|
|
187
|
+
Prometheus.EffectQueueCount.set(~count=state.queueCount, ~effectName)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Handle queued items
|
|
191
|
+
if queuedArgs->Utils.Array.notEmpty {
|
|
192
|
+
if !isFromQueue {
|
|
193
|
+
// Update queue count metric
|
|
194
|
+
state.queueCount = state.queueCount + queuedArgs->Array.length
|
|
195
|
+
Prometheus.EffectQueueCount.set(~count=state.queueCount, ~effectName)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let millisUntilReset = ref(0)
|
|
199
|
+
let nextWindowPromise = switch state.nextWindowPromise {
|
|
200
|
+
| Some(p) => p
|
|
201
|
+
| None =>
|
|
202
|
+
millisUntilReset :=
|
|
203
|
+
(state.windowStartTime +. state.durationMs->Int.toFloat -. now)->Float.toInt
|
|
204
|
+
let p = Utils.delay(millisUntilReset.contents)
|
|
205
|
+
state.nextWindowPromise = Some(p)
|
|
206
|
+
p
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Wait for next window and recursively process queue
|
|
210
|
+
promises
|
|
211
|
+
->Array.push(
|
|
212
|
+
nextWindowPromise
|
|
213
|
+
->Promise.then(() => {
|
|
214
|
+
if millisUntilReset.contents > 0 {
|
|
215
|
+
Prometheus.EffectQueueCount.timeCounter->Prometheus.SafeCounter.incrementMany(
|
|
216
|
+
~labels=effectName,
|
|
217
|
+
~value=millisUntilReset.contents,
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
executeWithRateLimit(
|
|
221
|
+
~effect,
|
|
222
|
+
~effectArgs=queuedArgs,
|
|
223
|
+
~inMemTable,
|
|
224
|
+
~onError,
|
|
225
|
+
~isFromQueue=true,
|
|
226
|
+
)
|
|
227
|
+
})
|
|
228
|
+
->Promise.ignoreValue,
|
|
229
|
+
)
|
|
230
|
+
->ignore
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Wait for all to complete
|
|
235
|
+
promises->Promise.all
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let loadEffect = (
|
|
239
|
+
~loadManager,
|
|
240
|
+
~persistence: Persistence.t,
|
|
241
|
+
~effect: Internal.effect,
|
|
242
|
+
~effectArgs,
|
|
243
|
+
~inMemoryStore,
|
|
244
|
+
~shouldGroup,
|
|
245
|
+
~item,
|
|
246
|
+
) => {
|
|
247
|
+
let effectName = effect.name
|
|
248
|
+
let key = `${effectName}.effect`
|
|
249
|
+
let inMemTable = inMemoryStore->InMemoryStore.getEffectInMemTable(~effect)
|
|
250
|
+
|
|
251
|
+
let load = async (args, ~onError) => {
|
|
252
|
+
let idsToLoad = args->Js.Array2.map((arg: Internal.effectArgs) => arg.cacheKey)
|
|
253
|
+
let idsFromCache = Utils.Set.make()
|
|
254
|
+
|
|
255
|
+
if (
|
|
256
|
+
switch persistence.storageStatus {
|
|
257
|
+
| Ready({cache}) => cache->Utils.Dict.has(effectName)
|
|
258
|
+
| _ => false
|
|
259
|
+
}
|
|
260
|
+
) {
|
|
261
|
+
let timerRef = Prometheus.StorageLoad.startOperation(~operation=key)
|
|
262
|
+
let {table, outputSchema} = effect.storageMeta
|
|
263
|
+
|
|
264
|
+
let dbEntities = try {
|
|
265
|
+
await (persistence->Persistence.getInitializedStorageOrThrow).loadByIdsOrThrow(
|
|
266
|
+
~table,
|
|
267
|
+
~rowsSchema=Internal.effectCacheItemRowsSchema,
|
|
268
|
+
~ids=idsToLoad,
|
|
269
|
+
)
|
|
270
|
+
} catch {
|
|
271
|
+
| exn =>
|
|
272
|
+
item
|
|
273
|
+
->Logging.getItemLogger
|
|
274
|
+
->Logging.childWarn({
|
|
275
|
+
"msg": `Failed to load cache effect cache. The indexer will continue working, but the effect will not be able to use the cache.`,
|
|
276
|
+
"err": exn->Utils.prettifyExn,
|
|
277
|
+
"effect": effectName,
|
|
278
|
+
})
|
|
279
|
+
[]
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
dbEntities->Js.Array2.forEach(dbEntity => {
|
|
283
|
+
try {
|
|
284
|
+
let output = dbEntity.output->S.parseOrThrow(outputSchema)
|
|
285
|
+
idsFromCache->Utils.Set.add(dbEntity.id)->ignore
|
|
286
|
+
inMemTable.dict->Js.Dict.set(dbEntity.id, output)
|
|
287
|
+
} catch {
|
|
288
|
+
| S.Raised(error) =>
|
|
289
|
+
inMemTable.invalidationsCount = inMemTable.invalidationsCount + 1
|
|
290
|
+
Prometheus.EffectCacheInvalidationsCount.increment(~effectName)
|
|
291
|
+
item
|
|
292
|
+
->Logging.getItemLogger
|
|
293
|
+
->Logging.childTrace({
|
|
294
|
+
"msg": "Invalidated effect cache",
|
|
295
|
+
"input": dbEntity.id,
|
|
296
|
+
"effect": effectName,
|
|
297
|
+
"err": error->S.Error.message,
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
timerRef->Prometheus.StorageLoad.endOperation(
|
|
303
|
+
~operation=key,
|
|
304
|
+
~whereSize=idsToLoad->Array.length,
|
|
305
|
+
~size=dbEntities->Array.length,
|
|
306
|
+
)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
let remainingCallsCount = idsToLoad->Array.length - idsFromCache->Utils.Set.size
|
|
310
|
+
if remainingCallsCount > 0 {
|
|
311
|
+
let argsToCall = []
|
|
312
|
+
for idx in 0 to args->Array.length - 1 {
|
|
313
|
+
let arg = args->Array.getUnsafe(idx)
|
|
314
|
+
if !(idsFromCache->Utils.Set.has(arg.cacheKey)) {
|
|
315
|
+
argsToCall->Array.push(arg)->ignore
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if argsToCall->Utils.Array.notEmpty {
|
|
320
|
+
await executeWithRateLimit(
|
|
321
|
+
~effect,
|
|
322
|
+
~effectArgs=argsToCall,
|
|
323
|
+
~inMemTable,
|
|
324
|
+
~onError,
|
|
325
|
+
~isFromQueue=false,
|
|
326
|
+
)->Promise.ignoreValue
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
loadManager->LoadManager.call(
|
|
332
|
+
~key,
|
|
333
|
+
~load,
|
|
334
|
+
~shouldGroup,
|
|
335
|
+
~hasher=args => args.cacheKey,
|
|
336
|
+
~getUnsafeInMemory=hash => inMemTable.dict->Js.Dict.unsafeGet(hash),
|
|
337
|
+
~hasInMemory=hash => inMemTable.dict->Utils.Dict.has(hash),
|
|
338
|
+
~input=effectArgs,
|
|
339
|
+
)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
let loadByField = (
|
|
343
|
+
~loadManager,
|
|
344
|
+
~persistence: Persistence.t,
|
|
345
|
+
~operator: TableIndices.Operator.t,
|
|
346
|
+
~entityConfig: Internal.entityConfig,
|
|
347
|
+
~inMemoryStore,
|
|
348
|
+
~fieldName,
|
|
349
|
+
~fieldValueSchema,
|
|
350
|
+
~shouldGroup,
|
|
351
|
+
~item,
|
|
352
|
+
~fieldValue,
|
|
353
|
+
) => {
|
|
354
|
+
let operatorCallName = switch operator {
|
|
355
|
+
| Eq => "eq"
|
|
356
|
+
| Gt => "gt"
|
|
357
|
+
| Lt => "lt"
|
|
358
|
+
}
|
|
359
|
+
let key = `${entityConfig.name}.getWhere.${fieldName}.${operatorCallName}`
|
|
360
|
+
let inMemTable = inMemoryStore->InMemoryStore.getInMemTable(~entityConfig)
|
|
361
|
+
|
|
362
|
+
let load = async (fieldValues: array<'fieldValue>, ~onError as _) => {
|
|
363
|
+
let timerRef = Prometheus.StorageLoad.startOperation(~operation=key)
|
|
364
|
+
|
|
365
|
+
let size = ref(0)
|
|
366
|
+
|
|
367
|
+
let indiciesToLoad = fieldValues->Js.Array2.map((fieldValue): TableIndices.Index.t => {
|
|
368
|
+
Single({
|
|
369
|
+
fieldName,
|
|
370
|
+
fieldValue: TableIndices.FieldValue.castFrom(fieldValue),
|
|
371
|
+
operator,
|
|
372
|
+
})
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
let _ =
|
|
376
|
+
await indiciesToLoad
|
|
377
|
+
->Js.Array2.map(async index => {
|
|
378
|
+
inMemTable->InMemoryTable.Entity.addEmptyIndex(~index)
|
|
379
|
+
try {
|
|
380
|
+
let entities = await (
|
|
381
|
+
persistence->Persistence.getInitializedStorageOrThrow
|
|
382
|
+
).loadByFieldOrThrow(
|
|
383
|
+
~operator=switch index {
|
|
384
|
+
| Single({operator: Gt}) => #">"
|
|
385
|
+
| Single({operator: Eq}) => #"="
|
|
386
|
+
| Single({operator: Lt}) => #"<"
|
|
387
|
+
},
|
|
388
|
+
~table=entityConfig.table,
|
|
389
|
+
~rowsSchema=entityConfig.rowsSchema,
|
|
390
|
+
~fieldName=index->TableIndices.Index.getFieldName,
|
|
391
|
+
~fieldValue=switch index {
|
|
392
|
+
| Single({fieldValue}) => fieldValue
|
|
393
|
+
},
|
|
394
|
+
~fieldSchema=fieldValueSchema->(
|
|
395
|
+
Utils.magic: S.t<'fieldValue> => S.t<TableIndices.FieldValue.t>
|
|
396
|
+
),
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
entities->Array.forEach(entity => {
|
|
400
|
+
//Set the entity in the in memory store
|
|
401
|
+
inMemTable->InMemoryTable.Entity.initValue(
|
|
402
|
+
~allowOverWriteEntity=false,
|
|
403
|
+
~key=entity.id,
|
|
404
|
+
~entity=Some(entity),
|
|
405
|
+
)
|
|
406
|
+
})
|
|
407
|
+
|
|
408
|
+
size := size.contents + entities->Array.length
|
|
409
|
+
} catch {
|
|
410
|
+
| Persistence.StorageError({message, reason}) =>
|
|
411
|
+
reason->ErrorHandling.mkLogAndRaise(
|
|
412
|
+
~logger=Logging.createChildFrom(
|
|
413
|
+
~logger=item->Logging.getItemLogger,
|
|
414
|
+
~params={
|
|
415
|
+
"operator": operatorCallName,
|
|
416
|
+
"tableName": entityConfig.table.tableName,
|
|
417
|
+
"fieldName": fieldName,
|
|
418
|
+
"fieldValue": fieldValue,
|
|
419
|
+
},
|
|
420
|
+
),
|
|
421
|
+
~msg=message,
|
|
422
|
+
)
|
|
423
|
+
}
|
|
424
|
+
})
|
|
425
|
+
->Promise.all
|
|
426
|
+
|
|
427
|
+
timerRef->Prometheus.StorageLoad.endOperation(
|
|
428
|
+
~operation=key,
|
|
429
|
+
~whereSize=fieldValues->Array.length,
|
|
430
|
+
~size=size.contents,
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
loadManager->LoadManager.call(
|
|
435
|
+
~key,
|
|
436
|
+
~load,
|
|
437
|
+
~input=fieldValue,
|
|
438
|
+
~shouldGroup,
|
|
439
|
+
~hasher=fieldValue =>
|
|
440
|
+
fieldValue->TableIndices.FieldValue.castFrom->TableIndices.FieldValue.toString,
|
|
441
|
+
~getUnsafeInMemory=inMemTable->InMemoryTable.Entity.getUnsafeOnIndex(~fieldName, ~operator),
|
|
442
|
+
~hasInMemory=inMemTable->InMemoryTable.Entity.hasIndex(~fieldName, ~operator),
|
|
443
|
+
)
|
|
444
|
+
}
|