5. Defining Entities.
In this section we are going to take a look how you can structure and link your data. This is a prerequisite before actually defining entities. This is so important because every single query will be made against the entities indexed by your subgraphs and the data model you are going to define in the subgraph schema. Make sure to define the subgraph schema to match your dApp’s needs. Think of entities not as events or functions but as objects containing data.
Defining entity types with The Graph is straightforward with
schema.graphql. The Graph Node was due to rest by generating top-level fields for querying single instances and collections of that entity type. Just make sure to annotate each type that should be an entity with an
A) Good example
To come back to our sample Gravatar contract, let’s have a look at a good example of defining entities correctly. You can see that the Gravatar entity shown below is structured around a Gravatar object.
B) Bad example
In contrast to the example above, defining entities based around events (like the
GravatarDeclined entities) is not the way an entity should be defined. Mapping events or function calls 1:1 two entities is not recommended.
C) Optional and Required Fields
Please note that Entity feels can be defined as either required or optional. A
! in the schema indicates that a field is required. An error message will be shown if a required field is not set in the mapping:
Is necessary for each entity to have an
id field, which is of type
ID! (string). Note that the
id field needs to be unique among all entities of the same type as it serves as the primary key.
D) Built-In Scalar Types
GraphQL Supported Scalars
The following scalars are supported in the GraphQL API:
||Byte array, represented as a hexadecimal string. Commonly used for Ethereum hashes and addresses.
||Stored as a string.
||Scalar for string values. Null characters are not supported and are automatically removed.
||Scalar for boolean values.
||The GraphQL spec defines Int to have size of 32 bytes.
||Large integers. Used for Ethereum’s uint32, int64, uint64, …, uint256 types. Note: Everything below uint32, such as int32, uint24 or int8 is represented as i32.
||BigDecimal High precision decimals represented as a signficand and an exponent. The exponent range is from −6143 to +6144. Rounded to 34 significant digits.
The syntax for creating enums within a schema is as follows:
After you have defined the enum in the schema, set an enum field on an entity by using the string representation of the enum value.
Let’s have a look how this all works with an example. Let’s say you want to set the
SecondOwner. You would do this by defining your entity first and settin the field with
entity.tokenStatus = "SecondOwner".
Here’s an example how the
Token entity with an enum field would look like:
If you want to learn more about writing enums, have a look at the GraphQL documentation.
E) Entity Relationships
Let’s have a look at entity relationships next. In your schema, an entity may have a relationship to one or more entities. The relationships are unidirectional in The Graph and may be traversed in your queries. Bidirectional relationships can be simulated by defining a unidirectional relationship on either “end” of the relationship.
You can define relationships in the same manner as with other fields. However, it is important to note that the type specified needs to be that of another entity.
There are two relationship types: one-to-one relationships and one-to-many relationships. We will discuss both in the following and give you examples for each.
Here is how you can define an optional one-to-one relationship between a a
Transaction entity type and a
TransactionReceipt entity type:
If you want to define a required one-to-many relationship for a
TokenBalance entity type with a
Token entity, use the following:
F) Reverse Lookups
Defining reverse lookups on an entity is accomplished through the
@derivedFrom field. You can define reverse lookups for entities that may be queried but cannot be set manually through the mappings API. Doing so will create a virtual field on the entity that is derived from the relationship defined on the other entity.