Create & update entities
Ponder's entity store API is inspired by the Prisma Client API (opens in a new tab). The entity store API currently supports the following methods:
create
Insert a new entity into the store.
Options
name | type | |
---|---|---|
id | string | number | bigint | ID of the new entity |
data | TEntity | Data required for a new entity |
Returns
Promise<TEntity>
Examples
type Token @entity {
id: Int!
mintedBy: String!
mintedAt: Int!
}
ponder.on("Blitmap:Mint", async ({ event, context }) => {
const { Token } = context.entities;
const token = await Token.create({
id: event.params.tokenId,
data: {
mintedBy: event.params.to,
mintedAt: event.block.timestamp,
},
});
// { id: 7777, mintedBy: "0x7Df1...", mintedAt: 1679507353 }
});
update
Update an entity that already exists.
Options
name | type | |
---|---|---|
id | string | number | bigint | ID of the updated entity |
data | Partial<TEntity> | Data to update |
data (function) | (args: { current: TEntity }) => Partial<TEntity> | Function returning data to update |
Returns
Promise<TEntity>
Examples
type Token @entity {
id: Int!
ownedBy: String!
metadataUpdatedAt: Int!
}
ponder.on("Blitmap:MetadataUpdate", async ({ event, context }) => {
const { Token } = context.entities;
const token = await Token.update({
id: event.params.tokenId,
data: {
metadataUpdatedAt: event.block.timestamp,
},
});
// { id: 7777, mintedBy: "0x1bA3...", updatedAt: 1679507354 }
});
Update function
You can optionally pass a function to the data
field that receives the current entity as an argument and returns the update object. This is useful for updates that depend on the current entity, like an incrementing count or balance.
type Account @entity {
id: Int!
balance: BigInt!
}
ponder.on("ERC20:Transfer", async ({ event, context }) => {
const { Account } = context.entities;
const recipient = await Account.update({
id: event.params.to,
data: ({ current }) => ({
balance: current.balance + event.params.value,
}),
});
// { id: "0x5D92..", balance: 11800000005n }
});
upsert
Update an entity if one already exists with the specified id
, or create a new entity.
Options
name | type | |
---|---|---|
id | string | number | bigint | ID of the entity to create or update |
create | TEntity | Data required for a new entity |
update | Partial<TEntity> | Data to update |
update (function) | (args: { current: TEntity }) => Partial<TEntity> | Function returning data to update |
Returns
Promise<TEntity>
Examples
Upsert can be useful for events like the ERC721 Transfer
event, which is emitted when a token is minted and whenever a token is transferred.
type Token @entity {
id: Int!
mintedBy: String!
ownedBy: String!
}
ponder.on("Blitmap:Transfer", async ({ event, context }) => {
const { Token } = context.entities;
const token = await Token.upsert({
id: event.params.tokenId,
create: {
mintedBy: event.params.to,
ownedBy: event.params.to,
transferCount: 0,
},
update: {
ownedBy: event.params.to,
},
});
// { id: 7777, mintedBy: "0x1bA3...", ownedBy: "0x7F4d..." }
});
Update function
You can optionally pass a function to the update
field that receives the current entity as an argument and returns the update object. This is useful for updates that depend on the current entity, like an incrementing count or balance.
type Token @entity {
id: Int!
ownedBy: String!
transferCount: Int!
}
ponder.on("Blitmap:Transfer", async ({ event, context }) => {
const { Token } = context.entities;
const token = await Token.upsert({
id: event.params.tokenId,
create: {
ownedBy: event.params.to,
transferCount: 0,
},
update: ({ current }) => ({
ownedBy: event.params.to,
transferCount: current.transferCount + 1,
}),
});
// { id: 7777, ownedBy: "0x7F4d...", transferCount: 1 }
});
delete
delete
deletes an entity by id
.
Options
name | type | |
---|---|---|
id | string | number | bigint | ID of the entity to delete |
Returns
Promise<boolean>
(true
if the entity was deleted, false
if it was not found)
Examples
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
const isDeleted = await Player.delete({ id: "Jim" });
// true
const jim = await Player.findUnique({ id: "Jim" });
// null
findUnique
findUnique
finds and returns an entity by id
.
Options
name | type | |
---|---|---|
id | string | number | bigint | ID of the entity to find and return |
Returns
Promise<TEntity | null>
Examples
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
const jim = await Player.findUnique({ id: "Jim" });
// { id: "Jim", age: 34 }
const sara = await Player.findUnique({ id: "Sara" });
// null
findMany
findMany
returns a list of entities according to the filter, sort, and pagination options you provide. Note that findMany
offers programmatic access to the functionality exposed by the autogenerated GraphQL API.
Options
name | type | |
---|---|---|
where | WhereInput<TEntity> | undefined | Filter matching entities to return |
orderBy | OrderByInput<TEntity> | undefined | Sort applied to the list |
skip | number | undefined | Number of records to skip (SQL OFFSET ) |
take | number | undefined | Number of records to take (SQL LIMIT ) |
Returns
Promise<TEntity[]>
Examples
Filtering
Filter the result list by passing a where
option containing a field name, filter condition, and value. The where
option is typed according to the filter conditions available for each field.
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
await Player.create({ id: "Andrew", age: 19 });
await Player.create({ id: "Janet", age: 56 });
const players = await Player.findMany();
// [
// { id: "Jim", age: 34 },
// { id: "Andrew", age: 19 },
// { id: "Janet", age: 56 }
// ]
const players = await Player.findMany({
where: {
id: {
startsWith: "J",
},
},
});
// [
// { id: "Jim", age: 34 },
// { id: "Janet", age: 56 }
// ]
If you provide multiple filters, they will be combined with a logical AND
.
If you need more complex filters that use logical OR
, NOT
, or nested
conditions, please open a
discussion (opens in a new tab).
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
await Player.create({ id: "Andrew", age: 19 });
await Player.create({ id: "Janet", age: 56 });
const players = await Player.findMany({
where: {
id: { contains: "e" }
age: { gt: 30 }
}
});
// [
// { id: "Janet", age: 56 }
// ]
Sorting
Sort the result list by passing an orderBy
option containing a field name and sort direction ("asc"
or "desc"
).
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
await Player.create({ id: "Andrew", age: 19 });
await Player.create({ id: "Janet", age: 56 });
const players = await Player.findMany({
orderBy: {
age: "asc",
},
});
// [
// { id: "Andrew", age: 19 },
// { id: "Jim", age: 34 },
// { id: "Janet", age: 56 }
// ]
Pagination
Paginate through the result list using the skip
and take
options.
Avoid using findMany
to return result lists that require pagination. (If you
need this, you're probably doing something wrong. Ask for help.)
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
await Player.create({ id: "Andrew", age: 19 });
await Player.create({ id: "Janet", age: 56 });
await Player.create({ id: "Polly", age: 29 });
const players = await Player.findMany({
orderBy: { age: "desc" },
skip: 1,
take: 2,
});
// [
// { id: "Jim", age: 34 },
// { id: "Polly", age: 29 }
// ]
createMany
createMany
inserts multiple entities into the store in a single operation. It returns a list of the created entities.
Options
name | type | |
---|---|---|
data | TEntity[] | List of entities to create |
Returns
Promise<TEntity[]>
Examples
type Player @entity {
id: String!
age: Int!
}
await Player.createMany({
data: [
{ id: "Jim", age: 34 },
{ id: "Andrew", age: 19 },
{ id: "Janet", age: 56 },
],
});
const players = await Player.findMany();
// [
// { id: "Jim", age: 34 },
// { id: "Andrew", age: 19 },
// { id: "Janet", age: 56 }
// ]
updateMany
updateMany
updates multiple entities in a single operation using the same update logic. Like the update
method, updateMany
also optionally accepts an update function.
Options
name | type | |
---|---|---|
where | WhereInput<TEntity> | Filter matching entities to be updated |
data | Partial<TEntity> | Data to update |
data (function) | (args: { current: TEntity }) => Partial<TEntity> | Function returning data to update |
Returns
Promise<TEntity[]>
Examples
type Player @entity {
id: String!
age: Int!
}
await Player.create({ id: "Jim", age: 34 });
await Player.create({ id: "Andrew", age: 19 });
await Player.create({ id: "Janet", age: 56 });
await Player.updateMany({
where: {
id: {
startsWith: "J",
},
},
data: {
age: 50,
},
});
const players = await Player.findMany();
// [
// { id: "Jim", age: 50 },
// { id: "Andrew", age: 19 },
// { id: "Janet", age: 50 }
// ]