Skip to content

Commit

Permalink
Update api to contractRegister with separate function
Browse files Browse the repository at this point in the history
  • Loading branch information
JonoPrest committed Jun 13, 2024
1 parent db33fd4 commit 306dbf9
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ let runEventContractRegister = (

let runEventLoader = async (
~contextEnv,
~handler: RegisteredEvents.registerArgsWithLoader<_>,
~handler: RegisteredEvents.registeredLoaderHandler<_>,
~loadLayer,
) => {
let {loader} = handler
Expand Down Expand Up @@ -288,7 +288,9 @@ let getHandlerRunner = (
~registeredEvents,
) => {
let module(Event) = eventMod
switch registeredEvents->RegisteredEvents.get(Event.eventName) {
switch registeredEvents
->RegisteredEvents.get(Event.eventName)
->Option.flatMap(registeredEvent => registeredEvent.loaderHandler) {
| Some(handler) =>
event->runEventHandler(
~handler,
Expand Down Expand Up @@ -398,6 +400,7 @@ let runLoaders = (
let load = (event, eventName) =>
registeredEvents
->RegisteredEvents.get(eventName)
->Option.flatMap(registeredEvent => registeredEvent.loaderHandler)
->Option.map(
handler => {
let contextEnv = ContextEnv.make(~chain, ~eventName, ~event, ~logger)
Expand Down
36 changes: 22 additions & 14 deletions codegenerator/cli/templates/dynamic/codegen/src/TestHelpers.res.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,29 @@ module EventFunctions = {

let latestProcessedBlocks = EventProcessing.EventsProcessed.makeEmpty()

switch await event->EventProcessing.runEventHandler(
~executeLoadLayer=TestHelpers_MockDb.executeMockDbLoadLayer(mockDbClone),
~inMemoryStore,
~handler=registeredEvent,
~eventMod,
~chain,
~logger,
~latestProcessedBlocks,
~asyncGetters,
) {
| Ok(_) =>
mockDbClone->TestHelpers_MockDb.writeFromMemoryStore(~inMemoryStore)
mockDbClone
| Error(e) => e->ErrorHandling.logAndRaise
switch registeredEvent.loaderHandler {
| Some(handler) =>
switch await event->EventProcessing.runEventHandler(
~executeLoadLayer=TestHelpers_MockDb.executeMockDbLoadLayer(mockDbClone),
~inMemoryStore,
~handler,
~eventMod,
~chain,
~logger,
~latestProcessedBlocks,
~asyncGetters,
) {
| Ok(_) => ()
| Error(e) => e->ErrorHandling.logAndRaise
}
| None => ()//No need to run loaders or handlers
}

//In mem store can still contatin raw events and dynamic contracts for the
//testing framework in cases where either contract register or loaderHandler
//is None
mockDbClone->TestHelpers_MockDb.writeFromMemoryStore(~inMemoryStore)
mockDbClone
}
}

Expand Down
101 changes: 63 additions & 38 deletions codegenerator/cli/templates/static/codegen/src/RegisteredEvents.res
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,40 @@ type handlerArgs<'eventArgs, 'loaderReturn> = {

type handler<'eventArgs, 'loaderReturn> = handlerArgs<'eventArgs, 'loaderReturn> => promise<unit>

type registerArgsWithLoader<'eventArgs, 'loaderReturn> = {
handler: handler<'eventArgs, 'loaderReturn>,
type registeredLoaderHandler<'eventArgs, 'loaderReturn> = {
loader: loader<'eventArgs, 'loaderReturn>,
contractRegister?: contractRegister<'eventArgs>,
handler: handler<'eventArgs, 'loaderReturn>,
}

type registerArgs<'eventArgs> = {
handler: handler<'eventArgs, unit>,
type registeredEvent<'eventArgs, 'loaderReturn> = {
loaderHandler?: registeredLoaderHandler<'eventArgs, 'loaderReturn>,
contractRegister?: contractRegister<'eventArgs>,
}

type t = Js.Dict.t<registerArgsWithLoader<unknown, unknown>>
type t = {
loaderHandlers: Js.Dict.t<registeredLoaderHandler<unknown, unknown>>,
contractRegisters: Js.Dict.t<contractRegister<unknown>>,
}

let add = (registeredEvents, eventName: Types.eventName, args) => {
let make = () => {
loaderHandlers: Js.Dict.empty(),
contractRegisters: Js.Dict.empty(),
}

let addLoaderHandler = (
registeredEvents: t,
eventName: Types.eventName,
args: registeredLoaderHandler<'eventArgs, 'loadReturn>,
) => {
let key = (eventName :> string)
if registeredEvents->Js.Dict.get(key)->Belt.Option.isSome {

if registeredEvents.loaderHandlers->Js.Dict.get(key)->Belt.Option.isSome {
Js.Exn.raiseError(`[envio] The event ${key} is alredy registered.`)
} else {
registeredEvents->Js.Dict.set(
registeredEvents.loaderHandlers->Js.Dict.set(
key,
args->(
Obj.magic: registerArgsWithLoader<'eventArgs, 'loadReturn> => registerArgsWithLoader<
Obj.magic: registeredLoaderHandler<'eventArgs, 'loadReturn> => registeredLoaderHandler<
unknown,
unknown,
>
Expand All @@ -47,41 +59,66 @@ let add = (registeredEvents, eventName: Types.eventName, args) => {
}
}

let addContractRegister = (
registeredEvents: t,
eventName: Types.eventName,
args: contractRegister<'eventArgs>,
) => {
let key = (eventName :> string)

if registeredEvents.contractRegisters->Js.Dict.get(key)->Belt.Option.isSome {
Js.Exn.raiseError(`[envio] The event ${key} is alredy registered.`)
} else {
registeredEvents.contractRegisters->Js.Dict.set(
key,
args->(Obj.magic: contractRegister<'eventArgs> => contractRegister<unknown>),
)
}
}

// This set makes sure that the warning doesn't print for every event of a type, but rather only prints the first time.
let hasPrintedWarning = Set.make()

let get = (registeredEvents, eventName: Types.eventName) => {
let registeredEvent =
registeredEvents
let get = (registeredEvents: t, eventName: Types.eventName) => {
let registeredLoaderHandler =
registeredEvents.loaderHandlers
->Js.Dict.unsafeGet((eventName :> string))
->(
Obj.magic: registerArgsWithLoader<unknown, unknown> => option<
registerArgsWithLoader<'eventArgs, 'loadReturn>,
Obj.magic: registeredLoaderHandler<unknown, unknown> => option<
registeredLoaderHandler<'eventArgs, 'loadReturn>,
>
)
if registeredEvent->Belt.Option.isNone {

let contractRegister =
registeredEvents.contractRegisters
->Js.Dict.unsafeGet((eventName :> string))
->(Obj.magic: contractRegister<unknown> => option<contractRegister<'eventArgs>>)

switch (registeredLoaderHandler, contractRegister) {
| (None, None) =>
if !(hasPrintedWarning->Set.has((eventName :> string))) {
// Here are docs on the 'terminal hyperlink' formatting that I use to link to the docs: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
Logging.warn(
`Skipped ${(eventName :> string)}, as there is no handler registered. You need to implement a ${(eventName :> string)} register method in your handler file or ignore this warning if you don't intend to implement it. Here are our docs on this topic: \n\n https://docs.envio.dev/docs/event-handlers`,
)
let _ = hasPrintedWarning->Set.add((eventName :> string))
}
None
| (loaderHandler, contractRegister) =>
Some({
?loaderHandler,
?contractRegister,
})
}
registeredEvent
}

let global = Js.Dict.empty()
let global = make()

let defaultAsyncFn = _ => Promise.resolve()
let defaultRegister = {
handler: defaultAsyncFn,
loader: defaultAsyncFn,
}

module MakeRegister = (Event: Types.Event) => {
let handler = handler =>
global->add(
global->addLoaderHandler(
Event.eventName,
{
loader: defaultAsyncFn,
Expand All @@ -90,20 +127,8 @@ module MakeRegister = (Event: Types.Event) => {
)

let contractRegister: contractRegister<Event.eventArgs> => unit = contractRegister =>
global->add(
Event.eventName,
{
...defaultRegister,
contractRegister,
},
)

let register: registerArgs<Event.eventArgs> => unit = args =>
global->add(
Event.eventName,
{...defaultRegister, handler: args.handler, contractRegister: ?args.contractRegister},
)
global->addContractRegister(Event.eventName, contractRegister)

let registerWithLoader: registerArgsWithLoader<'a, 'b> => unit = args =>
global->add(Event.eventName, args)
let handlerWithLoader: registeredLoaderHandler<Event.eventArgs, 'loaderReturn> => unit = args =>
global->addLoaderHandler(Event.eventName, args)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,28 @@ type handlerArgs<'eventArgs, 'loaderReturn> = {
type handler<'eventArgs, 'loaderReturn> = handlerArgs<'eventArgs, 'loaderReturn> => promise<unit>

@genType
type registerArgsWithLoader<'eventArgs, 'loaderReturn> = {
handler: handler<'eventArgs, 'loaderReturn>,
type registeredLoaderHandler<'eventArgs, 'loaderReturn> = {
loader: loader<'eventArgs, 'loaderReturn>,
contractRegister?: contractRegister<'eventArgs>,
handler: handler<'eventArgs, 'loaderReturn>,
}

@genType
type registerArgs<'eventArgs> = {
handler: handler<'eventArgs, unit>,
type registeredEvent<'eventArgs, 'loaderReturn> = {
loaderHandler?: registeredLoaderHandler<'eventArgs, 'loaderReturn>,
contractRegister?: contractRegister<'eventArgs>,
}

type t

let get: (t, Types.eventName) => option<registerArgsWithLoader<'eventArgs, 'loadReturn>>
let make: unit => t

let get: (t, Types.eventName) => option<registeredEvent<'eventArgs, 'loadReturn>>

let global: t

module MakeRegister: (E: Types.Event) =>
{
let handler: handler<E.eventArgs, unit> => unit
let contractRegister: contractRegister<E.eventArgs> => unit
let register: registerArgs<E.eventArgs> => unit
let registerWithLoader: registerArgsWithLoader<E.eventArgs, 'b> => unit
let handlerWithLoader: registeredLoaderHandler<E.eventArgs, 'loaderReturn> => unit
}
4 changes: 2 additions & 2 deletions scenarios/erc20_multichain_factory/src/EventHandlers.res
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ let createNewAccountWithZeroBalance = (
accountToken
}

Handlers.ERC20.Approval.registerWithLoader({
Handlers.ERC20.Approval.handlerWithLoader({
loader: ({event, context}) => {
context.account.get(event.params.owner->Ethers.ethAddressToString)
},
Expand Down Expand Up @@ -104,7 +104,7 @@ let manipulateAccountBalance = (
->fn(value)
->setAccountToken

Handlers.ERC20.Transfer.registerWithLoader({
Handlers.ERC20.Transfer.handlerWithLoader({
loader: ({event, context}) => {
let fromAccount_id = event.params.from->Ethers.ethAddressToString
let toAccount_id = event.params.to->Ethers.ethAddressToString
Expand Down
2 changes: 1 addition & 1 deletion scenarios/test_codegen/src/EventHandlers.res
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Handlers.Gravatar.NewGravatar.handler(async ({event, context}) => {
context.gravatar.set(gravatarObject)
})

Handlers.Gravatar.UpdatedGravatar.registerWithLoader({
Handlers.Gravatar.UpdatedGravatar.handlerWithLoader({
loader: ({event, context}) => {
context.gravatar.get(event.params.id->Ethers.BigInt.toString)
},
Expand Down
11 changes: 6 additions & 5 deletions scenarios/test_codegen/src/EventHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import {

const zeroAddress = "0x0000000000000000000000000000000000000000";

NftFactory.SimpleNftCreated.registerWithLoader({
contractRegister: ({ event, context }) => {
context.addSimpleNft(event.params.contractAddress);
},
NftFactory.SimpleNftCreated.contractRegister(({ event, context }) => {
context.addSimpleNft(event.params.contractAddress);
});

NftFactory.SimpleNftCreated.handlerWithLoader({
loader: async (_) => undefined,
handler: async ({ event, context }) => {
let nftCollection: NftCollection = {
Expand All @@ -30,7 +31,7 @@ NftFactory.SimpleNftCreated.registerWithLoader({
},
});

SimpleNft.Transfer.registerWithLoader({
SimpleNft.Transfer.handlerWithLoader({
loader: async ({ event, context }) => {
const [loadedUserFrom, loadedUserTo, nftCollectionUpdated, existingToken] =
await Promise.all([
Expand Down
4 changes: 3 additions & 1 deletion scenarios/test_codegen/test/Mock_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ describe("E2E Mock Event Batch", () => {
eventMod: module(Types.Event with type eventArgs = eventArgs),
) => {
let module(Event) = eventMod
switch RegisteredEvents.global->RegisteredEvents.get(Event.eventName) {
switch RegisteredEvents.global
->RegisteredEvents.get(Event.eventName)
->Option.flatMap(registeredEvent => registeredEvent.loaderHandler) {
| Some(handler) =>
await event->EventProcessing.runEventHandler(
~handler,
Expand Down

0 comments on commit 306dbf9

Please sign in to comment.