envio 2.26.0-rc.0 → 2.26.0-rc.2
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 +7 -0
- package/fuel.schema.json +7 -0
- package/index.d.ts +6 -22
- package/index.js +2 -1
- package/package.json +5 -5
- package/src/Envio.gen.ts +3 -1
- package/src/Envio.res +27 -0
- package/src/Envio.res.js +28 -1
- package/src/FetchState.res +1 -4
- package/src/Internal.res +20 -0
- package/src/Internal.res.js +12 -0
- package/src/Logging.res +8 -0
- package/src/Logging.res.js +29 -0
- package/src/Persistence.res +109 -47
- package/src/Persistence.res.js +62 -17
- package/src/PgStorage.res +488 -86
- package/src/PgStorage.res.js +365 -57
- package/src/Prometheus.res +12 -0
- package/src/Prometheus.res.js +12 -0
- package/src/Utils.res +39 -9
- package/src/Utils.res.js +17 -6
- package/src/bindings/BigInt.gen.ts +10 -0
- package/src/bindings/BigInt.res +1 -0
- package/src/bindings/NodeJs.res +27 -26
- package/src/bindings/NodeJs.res.js +5 -13
- package/src/db/EntityHistory.res +5 -28
- package/src/db/EntityHistory.res.js +4 -23
- package/src/db/Table.res +3 -61
- package/src/db/Table.res.js +3 -42
package/evm.schema.json
CHANGED
|
@@ -33,6 +33,13 @@
|
|
|
33
33
|
"null"
|
|
34
34
|
]
|
|
35
35
|
},
|
|
36
|
+
"output": {
|
|
37
|
+
"description": "Path where the generated directory will be placed. By default it's 'generated' relative to the current working directory. If set, it'll be a path relative to the config file location.",
|
|
38
|
+
"type": [
|
|
39
|
+
"string",
|
|
40
|
+
"null"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
36
43
|
"contracts": {
|
|
37
44
|
"description": "Global contract definitions that must contain all definitions except addresses. You can share a single handler/abi/event definitions for contracts across multiple chains.",
|
|
38
45
|
"type": [
|
package/fuel.schema.json
CHANGED
|
@@ -26,6 +26,13 @@
|
|
|
26
26
|
"null"
|
|
27
27
|
]
|
|
28
28
|
},
|
|
29
|
+
"output": {
|
|
30
|
+
"description": "Path where the generated directory will be placed. By default it's 'generated' relative to the current working directory. If set, it'll be a path relative to the config file location.",
|
|
31
|
+
"type": [
|
|
32
|
+
"string",
|
|
33
|
+
"null"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
29
36
|
"contracts": {
|
|
30
37
|
"description": "Global contract definitions that must contain all definitions except addresses. You can share a single handler/abi/event definitions for contracts across multiple chains.",
|
|
31
38
|
"type": [
|
package/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
} from "./src/Envio.gen.ts";
|
|
14
14
|
|
|
15
15
|
import { schema as bigDecimalSchema } from "./src/bindings/BigDecimal.gen.ts";
|
|
16
|
+
import { schema as bigintSchema } from "./src/bindings/BigInt.gen.ts";
|
|
16
17
|
import * as Sury from "rescript-schema";
|
|
17
18
|
|
|
18
19
|
type UnknownToOutput<T> = T extends Sury.Schema<unknown>
|
|
@@ -35,26 +36,6 @@ type UnknownToOutput<T> = T extends Sury.Schema<unknown>
|
|
|
35
36
|
>
|
|
36
37
|
: T;
|
|
37
38
|
|
|
38
|
-
type UnknownToInput<T> = T extends Sury.Schema<unknown>
|
|
39
|
-
? Sury.Input<T>
|
|
40
|
-
: T extends (...args: any[]) => any
|
|
41
|
-
? T
|
|
42
|
-
: T extends unknown[]
|
|
43
|
-
? { [K in keyof T]: UnknownToInput<T[K]> }
|
|
44
|
-
: T extends { [k in keyof T]: unknown }
|
|
45
|
-
? Flatten<
|
|
46
|
-
{
|
|
47
|
-
[k in keyof T as HasUndefined<UnknownToInput<T[k]>> extends true
|
|
48
|
-
? k
|
|
49
|
-
: never]?: UnknownToInput<T[k]>;
|
|
50
|
-
} & {
|
|
51
|
-
[k in keyof T as HasUndefined<UnknownToInput<T[k]>> extends true
|
|
52
|
-
? never
|
|
53
|
-
: k]: UnknownToInput<T[k]>;
|
|
54
|
-
}
|
|
55
|
-
>
|
|
56
|
-
: T;
|
|
57
|
-
|
|
58
39
|
type HasUndefined<T> = [T] extends [undefined]
|
|
59
40
|
? true
|
|
60
41
|
: undefined extends T
|
|
@@ -92,7 +73,7 @@ type Flatten<T> = T extends object
|
|
|
92
73
|
export function experimental_createEffect<
|
|
93
74
|
IS,
|
|
94
75
|
OS,
|
|
95
|
-
I =
|
|
76
|
+
I = UnknownToOutput<IS>,
|
|
96
77
|
O = UnknownToOutput<OS>,
|
|
97
78
|
// A hack to enforce that the inferred return type
|
|
98
79
|
// matches the output schema type
|
|
@@ -105,6 +86,8 @@ export function experimental_createEffect<
|
|
|
105
86
|
readonly input: IS;
|
|
106
87
|
/** The output schema of the effect. */
|
|
107
88
|
readonly output: OS;
|
|
89
|
+
/** Whether the effect should be cached. */
|
|
90
|
+
readonly cache?: boolean;
|
|
108
91
|
},
|
|
109
92
|
handler: (args: EffectArgs<I>) => Promise<R>
|
|
110
93
|
): Effect<I, O>;
|
|
@@ -119,7 +102,7 @@ export declare namespace S {
|
|
|
119
102
|
export const boolean: typeof Sury.boolean;
|
|
120
103
|
export const int32: typeof Sury.int32;
|
|
121
104
|
export const number: typeof Sury.number;
|
|
122
|
-
export const bigint: typeof
|
|
105
|
+
export const bigint: typeof bigintSchema;
|
|
123
106
|
export const never: typeof Sury.never;
|
|
124
107
|
export const union: typeof Sury.union;
|
|
125
108
|
export const object: typeof Sury.object;
|
|
@@ -128,6 +111,7 @@ export declare namespace S {
|
|
|
128
111
|
// Don't expose recursive for now, since it's too advanced
|
|
129
112
|
// export const recursive: typeof Sury.recursive;
|
|
130
113
|
export const transform: typeof Sury.transform;
|
|
114
|
+
export const shape: typeof Sury.shape;
|
|
131
115
|
export const refine: typeof Sury.refine;
|
|
132
116
|
export const schema: typeof Sury.schema;
|
|
133
117
|
export const record: typeof Sury.record;
|
package/index.js
CHANGED
|
@@ -13,7 +13,7 @@ exports.S = {
|
|
|
13
13
|
boolean: Sury.boolean,
|
|
14
14
|
int32: Sury.int32,
|
|
15
15
|
number: Sury.number,
|
|
16
|
-
bigint:
|
|
16
|
+
bigint: require("./src/bindings/BigInt.res.js").schema,
|
|
17
17
|
never: Sury.never,
|
|
18
18
|
union: Sury.union,
|
|
19
19
|
object: Sury.object,
|
|
@@ -22,6 +22,7 @@ exports.S = {
|
|
|
22
22
|
// Don't expose recursive for now, since it's too advanced
|
|
23
23
|
// recursive: Sury.recursive,
|
|
24
24
|
transform: Sury.transform,
|
|
25
|
+
shape: Sury.shape,
|
|
25
26
|
refine: Sury.refine,
|
|
26
27
|
schema: Sury.schema,
|
|
27
28
|
record: Sury.record,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envio",
|
|
3
|
-
"version": "v2.26.0-rc.
|
|
3
|
+
"version": "v2.26.0-rc.2",
|
|
4
4
|
"description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
|
|
5
5
|
"bin": "./bin.js",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://envio.dev",
|
|
27
27
|
"optionalDependencies": {
|
|
28
|
-
"envio-linux-x64": "v2.26.0-rc.
|
|
29
|
-
"envio-linux-arm64": "v2.26.0-rc.
|
|
30
|
-
"envio-darwin-x64": "v2.26.0-rc.
|
|
31
|
-
"envio-darwin-arm64": "v2.26.0-rc.
|
|
28
|
+
"envio-linux-x64": "v2.26.0-rc.2",
|
|
29
|
+
"envio-linux-arm64": "v2.26.0-rc.2",
|
|
30
|
+
"envio-darwin-x64": "v2.26.0-rc.2",
|
|
31
|
+
"envio-darwin-arm64": "v2.26.0-rc.2"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@envio-dev/hypersync-client": "0.6.5",
|
package/src/Envio.gen.ts
CHANGED
|
@@ -21,7 +21,9 @@ export type effectOptions<input,output> = {
|
|
|
21
21
|
/** The input schema of the effect. */
|
|
22
22
|
readonly input: RescriptSchema_S_t<input>;
|
|
23
23
|
/** The output schema of the effect. */
|
|
24
|
-
readonly output: RescriptSchema_S_t<output
|
|
24
|
+
readonly output: RescriptSchema_S_t<output>;
|
|
25
|
+
/** Whether the effect should be cached. */
|
|
26
|
+
readonly cache?: boolean
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export type effectContext = $$effectContext;
|
package/src/Envio.res
CHANGED
|
@@ -22,6 +22,8 @@ and effectOptions<'input, 'output> = {
|
|
|
22
22
|
input: S.t<'input>,
|
|
23
23
|
/** The output schema of the effect. */
|
|
24
24
|
output: S.t<'output>,
|
|
25
|
+
/** Whether the effect should be cached. */
|
|
26
|
+
cache?: bool,
|
|
25
27
|
}
|
|
26
28
|
@genType.import(("./Types.ts", "EffectContext"))
|
|
27
29
|
and effectContext = {
|
|
@@ -40,6 +42,8 @@ let experimental_createEffect = (
|
|
|
40
42
|
handler: effectArgs<'input> => promise<'output>,
|
|
41
43
|
) => {
|
|
42
44
|
Prometheus.EffectCallsCount.set(~callsCount=0, ~effectName=options.name)
|
|
45
|
+
let outputSchema =
|
|
46
|
+
S.schema(_ => options.output)->(Utils.magic: S.t<S.t<'output>> => S.t<Internal.effectOutput>)
|
|
43
47
|
{
|
|
44
48
|
name: options.name,
|
|
45
49
|
handler: handler->(
|
|
@@ -48,5 +52,28 @@ let experimental_createEffect = (
|
|
|
48
52
|
>
|
|
49
53
|
),
|
|
50
54
|
callsCount: 0,
|
|
55
|
+
// This is the way to make the createEffect API
|
|
56
|
+
// work without the need for users to call S.schema themselves,
|
|
57
|
+
// but simply pass the desired object/tuple/etc.
|
|
58
|
+
// If they pass a schem, it'll also work.
|
|
59
|
+
input: S.schema(_ => options.input)->(
|
|
60
|
+
Utils.magic: S.t<S.t<'input>> => S.t<Internal.effectInput>
|
|
61
|
+
),
|
|
62
|
+
output: outputSchema,
|
|
63
|
+
cache: switch options.cache {
|
|
64
|
+
| Some(true) =>
|
|
65
|
+
let itemSchema = S.schema((s): Internal.effectCacheItem => {
|
|
66
|
+
id: s.matches(S.string),
|
|
67
|
+
output: s.matches(outputSchema),
|
|
68
|
+
})
|
|
69
|
+
Some({
|
|
70
|
+
table: Internal.makeCacheTable(~effectName=options.name),
|
|
71
|
+
rowsSchema: S.array(itemSchema),
|
|
72
|
+
itemSchema,
|
|
73
|
+
})
|
|
74
|
+
| None
|
|
75
|
+
| Some(false) =>
|
|
76
|
+
None
|
|
77
|
+
},
|
|
51
78
|
}->(Utils.magic: Internal.effect => effect<'input, 'output>)
|
|
52
79
|
}
|
package/src/Envio.res.js
CHANGED
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var Internal = require("./Internal.res.js");
|
|
4
5
|
var Prometheus = require("./Prometheus.res.js");
|
|
6
|
+
var S$RescriptSchema = require("rescript-schema/src/S.res.js");
|
|
5
7
|
|
|
6
8
|
function experimental_createEffect(options, handler) {
|
|
7
9
|
Prometheus.EffectCallsCount.set(0, options.name);
|
|
10
|
+
var outputSchema = S$RescriptSchema.schema(function (param) {
|
|
11
|
+
return options.output;
|
|
12
|
+
});
|
|
13
|
+
var match = options.cache;
|
|
14
|
+
var tmp;
|
|
15
|
+
if (match !== undefined && match) {
|
|
16
|
+
var itemSchema = S$RescriptSchema.schema(function (s) {
|
|
17
|
+
return {
|
|
18
|
+
id: s.m(S$RescriptSchema.string),
|
|
19
|
+
output: s.m(outputSchema)
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
tmp = {
|
|
23
|
+
itemSchema: itemSchema,
|
|
24
|
+
rowsSchema: S$RescriptSchema.array(itemSchema),
|
|
25
|
+
table: Internal.makeCacheTable(options.name)
|
|
26
|
+
};
|
|
27
|
+
} else {
|
|
28
|
+
tmp = undefined;
|
|
29
|
+
}
|
|
8
30
|
return {
|
|
9
31
|
name: options.name,
|
|
10
32
|
handler: handler,
|
|
33
|
+
cache: tmp,
|
|
34
|
+
output: outputSchema,
|
|
35
|
+
input: S$RescriptSchema.schema(function (param) {
|
|
36
|
+
return options.input;
|
|
37
|
+
}),
|
|
11
38
|
callsCount: 0
|
|
12
39
|
};
|
|
13
40
|
}
|
|
14
41
|
|
|
15
42
|
exports.experimental_createEffect = experimental_createEffect;
|
|
16
|
-
/*
|
|
43
|
+
/* Internal Not a pure module */
|
package/src/FetchState.res
CHANGED
|
@@ -901,10 +901,7 @@ let queueItemIsInReorgThreshold = (
|
|
|
901
901
|
if currentBlockHeight === 0 {
|
|
902
902
|
false
|
|
903
903
|
} else {
|
|
904
|
-
|
|
905
|
-
| Item(_) => queueItem->queueItemBlockNumber > highestBlockBelowThreshold
|
|
906
|
-
| NoItem(_) => queueItem->queueItemBlockNumber > highestBlockBelowThreshold
|
|
907
|
-
}
|
|
904
|
+
queueItem->queueItemBlockNumber > highestBlockBelowThreshold
|
|
908
905
|
}
|
|
909
906
|
}
|
|
910
907
|
|
package/src/Internal.res
CHANGED
|
@@ -194,11 +194,31 @@ type effectArgs = {
|
|
|
194
194
|
context: effectContext,
|
|
195
195
|
cacheKey: string,
|
|
196
196
|
}
|
|
197
|
+
type effectCacheItem = {id: string, output: effectOutput}
|
|
198
|
+
type effectCacheMeta = {
|
|
199
|
+
itemSchema: S.t<effectCacheItem>,
|
|
200
|
+
rowsSchema: S.t<array<effectCacheItem>>,
|
|
201
|
+
table: Table.table,
|
|
202
|
+
}
|
|
197
203
|
type effect = {
|
|
198
204
|
name: string,
|
|
199
205
|
handler: effectArgs => promise<effectOutput>,
|
|
206
|
+
cache: option<effectCacheMeta>,
|
|
207
|
+
output: S.t<effectOutput>,
|
|
208
|
+
input: S.t<effectInput>,
|
|
200
209
|
mutable callsCount: int,
|
|
201
210
|
}
|
|
211
|
+
let cacheTablePrefix = "envio_effect_"
|
|
212
|
+
let makeCacheTable = (~effectName) => {
|
|
213
|
+
Table.mkTable(
|
|
214
|
+
cacheTablePrefix ++ effectName,
|
|
215
|
+
~fields=[
|
|
216
|
+
Table.mkField("id", Text, ~fieldSchema=S.string, ~isPrimaryKey=true),
|
|
217
|
+
Table.mkField("output", JsonB, ~fieldSchema=S.json(~validate=false)),
|
|
218
|
+
],
|
|
219
|
+
~compositeIndices=[],
|
|
220
|
+
)
|
|
221
|
+
}
|
|
202
222
|
|
|
203
223
|
@genType.import(("./Types.ts", "Invalid"))
|
|
204
224
|
type noEventFilters
|
package/src/Internal.res.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var Table = require("./db/Table.res.js");
|
|
4
5
|
var $$BigInt = require("./bindings/BigInt.res.js");
|
|
5
6
|
var Js_exn = require("rescript/lib/js/js_exn.js");
|
|
6
7
|
var Address = require("./Address.res.js");
|
|
@@ -34,6 +35,15 @@ function makeEnumConfig(name, variants) {
|
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
var cacheTablePrefix = "envio_effect_";
|
|
39
|
+
|
|
40
|
+
function makeCacheTable(effectName) {
|
|
41
|
+
return Table.mkTable(cacheTablePrefix + effectName, [], [
|
|
42
|
+
Table.mkField("id", "TEXT", S$RescriptSchema.string, undefined, undefined, undefined, true, undefined, undefined),
|
|
43
|
+
Table.mkField("output", "JSONB", S$RescriptSchema.json(false), undefined, undefined, undefined, undefined, undefined, undefined)
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
function prettifyExn(exn) {
|
|
38
48
|
var e = Caml_js_exceptions.internalToOCamlException(exn);
|
|
39
49
|
if (e.RE_EXN_ID === Js_exn.$$Error) {
|
|
@@ -46,5 +56,7 @@ function prettifyExn(exn) {
|
|
|
46
56
|
exports.fuelSupplyParamsSchema = fuelSupplyParamsSchema;
|
|
47
57
|
exports.fuelTransferParamsSchema = fuelTransferParamsSchema;
|
|
48
58
|
exports.makeEnumConfig = makeEnumConfig;
|
|
59
|
+
exports.cacheTablePrefix = cacheTablePrefix;
|
|
60
|
+
exports.makeCacheTable = makeCacheTable;
|
|
49
61
|
exports.prettifyExn = prettifyExn;
|
|
50
62
|
/* fuelSupplyParamsSchema Not a pure module */
|
package/src/Logging.res
CHANGED
|
@@ -168,6 +168,14 @@ let logForItem = (eventItem, level: Pino.logLevel, message: string, ~params=?) =
|
|
|
168
168
|
(eventItem->getEventLogger->Utils.magic->Js.Dict.unsafeGet((level :> string)))(params, message)
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
let noopLogger: Envio.logger = {
|
|
172
|
+
info: (_message: string, ~params as _=?) => (),
|
|
173
|
+
debug: (_message: string, ~params as _=?) => (),
|
|
174
|
+
warn: (_message: string, ~params as _=?) => (),
|
|
175
|
+
error: (_message: string, ~params as _=?) => (),
|
|
176
|
+
errorWithExn: (_message: string, _exn) => (),
|
|
177
|
+
}
|
|
178
|
+
|
|
171
179
|
let getUserLogger = (eventItem): Envio.logger => {
|
|
172
180
|
info: (message: string, ~params=?) => eventItem->logForItem(#uinfo, message, ~params?),
|
|
173
181
|
debug: (message: string, ~params=?) => eventItem->logForItem(#udebug, message, ~params?),
|
package/src/Logging.res.js
CHANGED
|
@@ -197,6 +197,34 @@ function logForItem(eventItem, level, message, params) {
|
|
|
197
197
|
return getEventLogger(eventItem)[level](params, message);
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
function noopLogger_debug(_message, param) {
|
|
201
|
+
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function noopLogger_info(_message, param) {
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function noopLogger_warn(_message, param) {
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function noopLogger_error(_message, param) {
|
|
213
|
+
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function noopLogger_errorWithExn(_message, _exn) {
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var noopLogger = {
|
|
221
|
+
debug: noopLogger_debug,
|
|
222
|
+
info: noopLogger_info,
|
|
223
|
+
warn: noopLogger_warn,
|
|
224
|
+
error: noopLogger_error,
|
|
225
|
+
errorWithExn: noopLogger_errorWithExn
|
|
226
|
+
};
|
|
227
|
+
|
|
200
228
|
function getUserLogger(eventItem) {
|
|
201
229
|
return {
|
|
202
230
|
debug: (function (message, params) {
|
|
@@ -243,5 +271,6 @@ exports.createChild = createChild;
|
|
|
243
271
|
exports.createChildFrom = createChildFrom;
|
|
244
272
|
exports.getEventLogger = getEventLogger;
|
|
245
273
|
exports.logForItem = logForItem;
|
|
274
|
+
exports.noopLogger = noopLogger;
|
|
246
275
|
exports.getUserLogger = getUserLogger;
|
|
247
276
|
/* logLevels Not a pure module */
|
package/src/Persistence.res
CHANGED
|
@@ -5,6 +5,16 @@
|
|
|
5
5
|
// Currently there are quite many code spread across
|
|
6
6
|
// DbFunctions, Db, Migrations, InMemoryStore modules which use codegen code directly.
|
|
7
7
|
|
|
8
|
+
// The type reflects an cache table in the db
|
|
9
|
+
// It might be present even if the effect is not used in the application
|
|
10
|
+
type effectCacheRecord = {
|
|
11
|
+
effectName: string,
|
|
12
|
+
// Number of rows in the table
|
|
13
|
+
mutable count: int,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type operator = [#">" | #"="]
|
|
17
|
+
|
|
8
18
|
type storage = {
|
|
9
19
|
// Should return true if we already have persisted data
|
|
10
20
|
// and we can skip initialization
|
|
@@ -15,8 +25,6 @@ type storage = {
|
|
|
15
25
|
~entities: array<Internal.entityConfig>=?,
|
|
16
26
|
~generalTables: array<Table.table>=?,
|
|
17
27
|
~enums: array<Internal.enumConfig<Internal.enum>>=?,
|
|
18
|
-
// If true, the storage should clear existing data
|
|
19
|
-
~cleanRun: bool=?,
|
|
20
28
|
) => promise<unit>,
|
|
21
29
|
@raises("StorageError")
|
|
22
30
|
loadByIdsOrThrow: 'item. (
|
|
@@ -25,11 +33,28 @@ type storage = {
|
|
|
25
33
|
~rowsSchema: S.t<array<'item>>,
|
|
26
34
|
) => promise<array<'item>>,
|
|
27
35
|
@raises("StorageError")
|
|
36
|
+
loadByFieldOrThrow: 'item 'value. (
|
|
37
|
+
~fieldName: string,
|
|
38
|
+
~fieldSchema: S.t<'value>,
|
|
39
|
+
~fieldValue: 'value,
|
|
40
|
+
~operator: operator,
|
|
41
|
+
~table: Table.table,
|
|
42
|
+
~rowsSchema: S.t<array<'item>>,
|
|
43
|
+
) => promise<array<'item>>,
|
|
44
|
+
@raises("StorageError")
|
|
28
45
|
setOrThrow: 'item. (
|
|
29
46
|
~items: array<'item>,
|
|
30
47
|
~table: Table.table,
|
|
31
48
|
~itemSchema: S.t<'item>,
|
|
32
49
|
) => promise<unit>,
|
|
50
|
+
@raises("StorageError")
|
|
51
|
+
setEffectCacheOrThrow: (
|
|
52
|
+
~effect: Internal.effect,
|
|
53
|
+
~items: array<Internal.effectCacheItem>,
|
|
54
|
+
~initialize: bool,
|
|
55
|
+
) => promise<unit>,
|
|
56
|
+
dumpEffectCache: unit => promise<unit>,
|
|
57
|
+
restoreEffectCache: (~withUpload: bool) => promise<array<effectCacheRecord>>,
|
|
33
58
|
}
|
|
34
59
|
|
|
35
60
|
exception StorageError({message: string, reason: exn})
|
|
@@ -37,7 +62,7 @@ exception StorageError({message: string, reason: exn})
|
|
|
37
62
|
type storageStatus =
|
|
38
63
|
| Unknown
|
|
39
64
|
| Initializing(promise<unit>)
|
|
40
|
-
| Ready({cleanRun: bool})
|
|
65
|
+
| Ready({cleanRun: bool, cache: dict<effectCacheRecord>})
|
|
41
66
|
|
|
42
67
|
type t = {
|
|
43
68
|
userEntities: array<Internal.entityConfig>,
|
|
@@ -46,8 +71,6 @@ type t = {
|
|
|
46
71
|
allEnums: array<Internal.enumConfig<Internal.enum>>,
|
|
47
72
|
mutable storageStatus: storageStatus,
|
|
48
73
|
storage: storage,
|
|
49
|
-
onStorageInitialize: option<unit => promise<unit>>,
|
|
50
|
-
cacheStorage: storage,
|
|
51
74
|
}
|
|
52
75
|
|
|
53
76
|
let entityHistoryActionEnumConfig: Internal.enumConfig<EntityHistory.RowAction.t> = {
|
|
@@ -64,8 +87,6 @@ let make = (
|
|
|
64
87
|
~allEnums,
|
|
65
88
|
~staticTables,
|
|
66
89
|
~storage,
|
|
67
|
-
~cacheStorage,
|
|
68
|
-
~onStorageInitialize=?,
|
|
69
90
|
) => {
|
|
70
91
|
let allEntities = userEntities->Js.Array2.concat([dcRegistryEntityConfig])
|
|
71
92
|
let allEnums =
|
|
@@ -77,53 +98,70 @@ let make = (
|
|
|
77
98
|
allEnums,
|
|
78
99
|
storageStatus: Unknown,
|
|
79
100
|
storage,
|
|
80
|
-
onStorageInitialize,
|
|
81
|
-
cacheStorage,
|
|
82
101
|
}
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
let init =
|
|
86
|
-
persistence,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
let init = {
|
|
105
|
+
let loadInitialCache = async (persistence, ~withUpload) => {
|
|
106
|
+
let effectCacheRecords = await persistence.storage.restoreEffectCache(~withUpload)
|
|
107
|
+
let cache = Js.Dict.empty()
|
|
108
|
+
effectCacheRecords->Js.Array2.forEach(record => {
|
|
109
|
+
Prometheus.EffectCacheCount.set(~count=record.count, ~effectName=record.effectName)
|
|
110
|
+
cache->Js.Dict.set(record.effectName, record)
|
|
111
|
+
})
|
|
112
|
+
cache
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async (persistence, ~reset=false) => {
|
|
116
|
+
try {
|
|
117
|
+
let shouldRun = switch persistence.storageStatus {
|
|
118
|
+
| Unknown => true
|
|
119
|
+
| Initializing(promise) => {
|
|
120
|
+
await promise
|
|
121
|
+
reset
|
|
122
|
+
}
|
|
123
|
+
| Ready(_) => reset
|
|
99
124
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
if shouldRun {
|
|
126
|
+
let resolveRef = ref(%raw(`null`))
|
|
127
|
+
let promise = Promise.make((resolve, _) => {
|
|
128
|
+
resolveRef := resolve
|
|
129
|
+
})
|
|
130
|
+
persistence.storageStatus = Initializing(promise)
|
|
131
|
+
if reset || !(await persistence.storage.isInitialized()) {
|
|
132
|
+
Logging.info(`Initializing the indexer storage...`)
|
|
133
|
+
|
|
134
|
+
await persistence.storage.initialize(
|
|
135
|
+
~entities=persistence.allEntities,
|
|
136
|
+
~generalTables=persistence.staticTables,
|
|
137
|
+
~enums=persistence.allEnums,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
Logging.info(`The indexer storage is ready. Uploading cache...`)
|
|
141
|
+
persistence.storageStatus = Ready({
|
|
142
|
+
cleanRun: true,
|
|
143
|
+
cache: await loadInitialCache(persistence, ~withUpload=true),
|
|
144
|
+
})
|
|
145
|
+
} else if (
|
|
146
|
+
// In case of a race condition,
|
|
147
|
+
// we want to set the initial status to Ready only once.
|
|
148
|
+
switch persistence.storageStatus {
|
|
149
|
+
| Initializing(_) => true
|
|
150
|
+
| _ => false
|
|
151
|
+
}
|
|
152
|
+
) {
|
|
153
|
+
Logging.info(`The indexer storage is ready.`)
|
|
154
|
+
persistence.storageStatus = Ready({
|
|
155
|
+
cleanRun: false,
|
|
156
|
+
cache: await loadInitialCache(persistence, ~withUpload=false),
|
|
157
|
+
})
|
|
121
158
|
}
|
|
159
|
+
resolveRef.contents()
|
|
122
160
|
}
|
|
123
|
-
|
|
161
|
+
} catch {
|
|
162
|
+
| exn =>
|
|
163
|
+
exn->ErrorHandling.mkLogAndRaise(~msg=`EE800: Failed to initialize the indexer storage.`)
|
|
124
164
|
}
|
|
125
|
-
} catch {
|
|
126
|
-
| exn => exn->ErrorHandling.mkLogAndRaise(~msg=`EE800: Failed to initialize the indexer storage.`)
|
|
127
165
|
}
|
|
128
166
|
}
|
|
129
167
|
|
|
@@ -135,3 +173,27 @@ let getInitializedStorageOrThrow = persistence => {
|
|
|
135
173
|
| Ready(_) => persistence.storage
|
|
136
174
|
}
|
|
137
175
|
}
|
|
176
|
+
|
|
177
|
+
let setEffectCacheOrThrow = async (persistence, ~effect: Internal.effect, ~items) => {
|
|
178
|
+
switch persistence.storageStatus {
|
|
179
|
+
| Unknown
|
|
180
|
+
| Initializing(_) =>
|
|
181
|
+
Js.Exn.raiseError(`Failed to access the indexer storage. The Persistence layer is not initialized.`)
|
|
182
|
+
| Ready({cache}) => {
|
|
183
|
+
let storage = persistence.storage
|
|
184
|
+
let effectName = effect.name
|
|
185
|
+
let effectCacheRecord = switch cache->Utils.Dict.dangerouslyGetNonOption(effectName) {
|
|
186
|
+
| Some(c) => c
|
|
187
|
+
| None => {
|
|
188
|
+
let c = {effectName, count: 0}
|
|
189
|
+
cache->Js.Dict.set(effectName, c)
|
|
190
|
+
c
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
let initialize = effectCacheRecord.count === 0
|
|
194
|
+
await storage.setEffectCacheOrThrow(~effect, ~items, ~initialize)
|
|
195
|
+
effectCacheRecord.count = effectCacheRecord.count + items->Js.Array2.length
|
|
196
|
+
Prometheus.EffectCacheCount.set(~count=effectCacheRecord.count, ~effectName)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|