Loading Linked Entities
Introduction
TLDR: When you have a schema that has entities that link/reference other entities (linked entities), you can use the
loaders
argument to load those linked entities from your handler.
Sometimes the entities that you want loaded in your handler are nested one or more layers deep on the entity that you have the ID for in the loader.
Another prominant use case for linked entities: You may have a global entity (an entity that has a hardcoded ID) that references other entities. Without linked entity loaders, you wouldn't be able to load and access those referenced entities, so these types of loaders are extremely important for many types of advanced indexers.
Example
The below schema shows 4 user-defined entities that reference/link to each other. What if the event only contains the ID of entity A, but we care about the important information entity ImportantEntityICareAbout
that is linked via A->B->C->ImportantEntityICareAbout
?
schema.graphql
type A {
id: ID!
b: B!
c: [C!]! @derivedFrom(field: "a")
optionalBigInt: BigInt
}
type B {
id: ID!
c: C!
}
type C {
id: ID!
a: A!
importantData: ImportantEntityICareAbout!
}
type ImportantEntityICareAbout {
id: ID!
otherData: String!
}
config.yaml
For illustration there is a TestEvent
:
networks:
- id: 123456
contracts:
- name: Gravatar
events:
- event: "TestEvent"
Event Handler file
- Javascript
- Typescript
- Rescript
GravatarContract.TestEvent.loader(({ event, context }) => {
context.A.load(event.params.id, {
loadB: { loadC: { loadImportantData: true }, loadA: {} },
});
// ... other loaders
});
GravatarContract.TestEvent.handler(({ event, context }) => {
const entityA = context.A.get(event.params.id);
const linkedB = context.A.getB(entityA);
const linkedC = context.B.getC(linkedB);
const importantDataEntity = context.C.getImportantData(linkedC);
// ... rest of the handler that uses or updates these entities.
});
GravatarContract_TestEvent_loader(({ event, context }) => {
context.A.load(event.params.id, {
loadB: { loadC: { loadImportantData: true }, loadA: {} },
});
// ... other loaders
});
GravatarContract_TestEvent_handler(({ event, context }) => {
const entityA = context.A.get(event.params.id);
const linkedB = context.A.getB(entityA);
const linkedC = context.B.getC(linkedB);
const importantDataEntity = context.C.getImportantData(linkedC);
// ... rest of the handler that uses or updates these entities.
});
GravatarContract.TestEvent.loader((event, context) => {
context.a.exampleALoad(
event.params.id,
~loaders: {loadB: {loadC: {loadImportantData: true}, loadA: {}}},
)
// ... other loaders
})
GravatarContract.TestEvent.handler((event, context) => {
let entityA = context.A.get(event.params.id)
let linkedB = context.A.getB(entityA)
let linkedC = context.B.getC(linkedB)
let importantDataEntity = context.C.getImportantData(linkedC)
// ... rest of the handler that uses or updates these entities.
})
If the entity you want to load has linked entities of its own, then you need to put a {}
(empty object next to the name to indicate stopping the recursive loading at that point), otherwise you must put a true
. Thus in the above example, we put true
next to the loadImportantData
, and a {}
next to the inner loadA
.
Note: Currently loading data from derived fields is unsupported.