Skip to content

Commit 2245985

Browse files
authored
Preload handlers (#667)
* Implement preload handlers config option * Add S.Infer * Enable preload_handlers for init templates * Mention preload in cursor rules * Fix deleteUnsafe and update tests * Fix fuel tests
1 parent 611ee0d commit 2245985

File tree

35 files changed

+780
-587
lines changed

35 files changed

+780
-587
lines changed

codegenerator/cli/npm/envio/evm.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@
106106
"boolean",
107107
"null"
108108
]
109+
},
110+
"preload_handlers": {
111+
"description": "Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false)",
112+
"type": [
113+
"boolean",
114+
"null"
115+
]
109116
}
110117
},
111118
"additionalProperties": false,

codegenerator/cli/npm/envio/fuel.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@
5656
"boolean",
5757
"null"
5858
]
59+
},
60+
"preload_handlers": {
61+
"description": "Makes handlers run twice to enable preload optimisations. Removes handlerWithLoader API, since it's not needed. (recommended, default: false)",
62+
"type": [
63+
"boolean",
64+
"null"
65+
]
5966
}
6067
},
6168
"additionalProperties": false,

codegenerator/cli/npm/envio/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export function experimental_createEffect<
9595
// Important! Should match the index.js file
9696
export declare namespace S {
9797
export type Output<T> = Sury.Output<T>;
98+
export type Infer<T> = Sury.Output<T>;
9899
export type Input<T> = Sury.Input<T>;
99100
export type Schema<Output, Input = unknown> = Sury.Schema<Output, Input>;
100101
export const string: typeof Sury.string;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
type t = {
2+
contractName: string,
3+
eventName: string,
4+
mutable handler: option<Internal.handler>,
5+
mutable contractRegister: option<Internal.contractRegister>,
6+
mutable eventOptions: option<Internal.eventOptions<Js.Json.t>>,
7+
}
8+
9+
let getHandler = (t: t) => t.handler
10+
11+
let getContractRegister = (t: t) => t.contractRegister
12+
13+
let getEventFilters = (t: t) => t.eventOptions->Belt.Option.flatMap(value => value.eventFilters)
14+
15+
let isWildcard = (t: t) =>
16+
t.eventOptions->Belt.Option.flatMap(value => value.wildcard)->Belt.Option.getWithDefault(false)
17+
18+
let hasRegistration = ({handler, contractRegister}) =>
19+
handler->Belt.Option.isSome || contractRegister->Belt.Option.isSome
20+
21+
let make = (~contractName, ~eventName) => {
22+
contractName,
23+
eventName,
24+
handler: None,
25+
contractRegister: None,
26+
eventOptions: None,
27+
}
28+
29+
type eventNamespace = {contractName: string, eventName: string}
30+
exception DuplicateEventRegistration(eventNamespace)
31+
32+
let setEventOptions = (t: t, ~eventOptions, ~logger=Logging.getLogger()) => {
33+
switch eventOptions {
34+
| Some(value) =>
35+
let value =
36+
value->(Utils.magic: Internal.eventOptions<'eventFilters> => Internal.eventOptions<Js.Json.t>)
37+
switch t.eventOptions {
38+
| None => t.eventOptions = Some(value)
39+
| Some(existingValue) =>
40+
if (
41+
existingValue.wildcard !== value.wildcard ||
42+
// TODO: Can improve the check by using deepEqual
43+
existingValue.eventFilters !== value.eventFilters
44+
) {
45+
let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
46+
DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
47+
~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
48+
~msg="Duplicate eventOptions in handlers not allowed",
49+
)
50+
}
51+
}
52+
| None => ()
53+
}
54+
}
55+
56+
let setHandler = (t: t, handler, ~eventOptions, ~logger=Logging.getLogger()) => {
57+
switch t.handler {
58+
| None =>
59+
t.handler =
60+
handler
61+
->(Utils.magic: Internal.genericHandler<'args> => Internal.handler)
62+
->Some
63+
| Some(_) =>
64+
let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
65+
DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
66+
~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
67+
~msg="Duplicate registration of event handlers not allowed",
68+
)
69+
}
70+
71+
t->setEventOptions(~eventOptions, ~logger)
72+
}
73+
74+
let setContractRegister = (t: t, contractRegister, ~eventOptions, ~logger=Logging.getLogger()) => {
75+
switch t.contractRegister {
76+
| None =>
77+
t.contractRegister = Some(
78+
contractRegister->(
79+
Utils.magic: Internal.genericContractRegister<
80+
Internal.genericContractRegisterArgs<'event, 'context>,
81+
> => Internal.contractRegister
82+
),
83+
)
84+
| Some(_) =>
85+
let eventNamespace = {contractName: t.contractName, eventName: t.eventName}
86+
DuplicateEventRegistration(eventNamespace)->ErrorHandling.mkLogAndRaise(
87+
~logger=Logging.createChildFrom(~logger, ~params=eventNamespace),
88+
~msg="Duplicate contractRegister handlers not allowed",
89+
)
90+
}
91+
t->setEventOptions(~eventOptions, ~logger)
92+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
type t
2+
let make: (~contractName: string, ~eventName: string) => t
3+
let setHandler: (
4+
t,
5+
Internal.genericHandler<
6+
Internal.genericHandlerArgs<'event, Internal.handlerContext, 'loaderReturn>,
7+
>,
8+
~eventOptions: option<Internal.eventOptions<'eventFilters>>,
9+
~logger: Pino.t=?,
10+
) => unit
11+
let setContractRegister: (
12+
t,
13+
Internal.genericContractRegister<Internal.genericContractRegisterArgs<'event, 'context>>,
14+
~eventOptions: option<Internal.eventOptions<'eventFilters>>,
15+
~logger: Pino.t=?,
16+
) => unit
17+
let getHandler: t => option<Internal.handler>
18+
let getContractRegister: t => option<Internal.contractRegister>
19+
let getEventFilters: t => option<Js.Json.t>
20+
let isWildcard: t => bool
21+
let hasRegistration: t => bool

codegenerator/cli/npm/envio/src/Internal.gen.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ export type genericHandlerArgs<event,context,loaderReturn> = {
3434

3535
export type genericHandler<args> = (_1:args) => Promise<void>;
3636

37+
export type entityHandlerContext<entity> = {
38+
readonly get: (_1:string) => Promise<(undefined | entity)>;
39+
readonly getOrThrow: (_1:string, message:(undefined | string)) => Promise<entity>;
40+
readonly getOrCreate: (_1:entity) => Promise<entity>;
41+
readonly set: (_1:entity) => void;
42+
readonly deleteUnsafe: (_1:string) => void
43+
};
44+
3745
export type genericHandlerWithLoader<loader,handler,eventFilters> = {
3846
readonly loader: loader;
3947
readonly handler: handler;
@@ -43,6 +51,13 @@ export type genericHandlerWithLoader<loader,handler,eventFilters> = {
4351
readonly preRegisterDynamicContracts?: boolean
4452
};
4553

54+
export type eventOptions<eventFilters> = {
55+
readonly wildcard?: boolean;
56+
readonly eventFilters?: eventFilters;
57+
/** @deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration. */
58+
readonly preRegisterDynamicContracts?: boolean
59+
};
60+
4661
export type fuelSupplyParams = { readonly subId: string; readonly amount: bigint };
4762

4863
export type fuelTransferParams = {

codegenerator/cli/npm/envio/src/Internal.res

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ type event = genericEvent<eventParams, eventBlock, eventTransaction>
1616

1717
external fromGenericEvent: genericEvent<'a, 'b, 'c> => event = "%identity"
1818

19-
type loaderReturn
20-
2119
@genType
2220
type genericLoaderArgs<'event, 'context> = {
2321
event: 'event,
@@ -26,10 +24,6 @@ type genericLoaderArgs<'event, 'context> = {
2624
@genType
2725
type genericLoader<'args, 'loaderReturn> = 'args => promise<'loaderReturn>
2826

29-
type loaderContext
30-
type loaderArgs = genericLoaderArgs<event, loaderContext>
31-
type loader = genericLoader<loaderArgs, loaderReturn>
32-
3327
@genType
3428
type genericContractRegisterArgs<'event, 'context> = {
3529
event: 'event,
@@ -51,8 +45,21 @@ type genericHandlerArgs<'event, 'context, 'loaderReturn> = {
5145
@genType
5246
type genericHandler<'args> = 'args => promise<unit>
5347

54-
type handlerContext
55-
type handlerArgs = genericHandlerArgs<event, handlerContext, loaderReturn>
48+
@genType
49+
type entityHandlerContext<'entity> = {
50+
get: string => promise<option<'entity>>,
51+
getOrThrow: (string, ~message: string=?) => promise<'entity>,
52+
getOrCreate: 'entity => promise<'entity>,
53+
set: 'entity => unit,
54+
deleteUnsafe: string => unit,
55+
}
56+
57+
type loaderReturn
58+
type handlerContext = private {isPreload: bool}
59+
type handlerArgs = {
60+
event: event,
61+
context: handlerContext,
62+
}
5663
type handler = genericHandler<handlerArgs>
5764

5865
@genType
@@ -81,7 +88,6 @@ type eventConfig = private {
8188
// Usually always false for wildcard events
8289
// But might be true for wildcard event with dynamic event filter by addresses
8390
dependsOnAddresses: bool,
84-
loader: option<loader>,
8591
handler: option<handler>,
8692
contractRegister: option<contractRegister>,
8793
paramsRawEventSchema: S.schema<eventParams>,
@@ -138,6 +144,16 @@ type eventItem = {
138144
mutable loggerCache?: Pino.t,
139145
}
140146

147+
@genType
148+
type eventOptions<'eventFilters> = {
149+
wildcard?: bool,
150+
eventFilters?: 'eventFilters,
151+
/**
152+
@deprecated The option is removed starting from v2.19 since we made the default mode even faster than pre-registration.
153+
*/
154+
preRegisterDynamicContracts?: bool,
155+
}
156+
141157
@genType
142158
type fuelSupplyParams = {
143159
subId: string,

codegenerator/cli/npm/envio/src/bindings/Promise.res

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ external race: array<t<'a>> => t<'a> = "race"
5353

5454
external done: promise<'a> => unit = "%ignore"
5555

56+
external ignoreValue: promise<'a> => promise<unit> = "%identity"
57+
5658
external unsafe_async: 'a => promise<'a> = "%identity"
5759
external unsafe_await: promise<'a> => 'a = "?await"
5860

codegenerator/cli/src/cli_args/init_config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ pub mod evm {
170170
save_full_history: None,
171171
field_selection: None,
172172
raw_events: None,
173+
preload_handlers: Some(true),
173174
})
174175
}
175176

@@ -300,6 +301,7 @@ pub mod fuel {
300301
output: None,
301302
contracts: None,
302303
raw_events: None,
304+
preload_handlers: Some(true),
303305
networks: network_configs,
304306
}
305307
}

codegenerator/cli/src/config_parsing/graph_migration/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ pub async fn generate_config_from_subgraph_id(
284284
save_full_history: None,
285285
field_selection: None,
286286
raw_events: None,
287+
preload_handlers: Some(true),
287288
};
288289
let mut networks: Vec<Network> = vec![];
289290

0 commit comments

Comments
 (0)