Entity Relationships

Define one-to-one, one-to-many and many-to-many relationships between entities

One-To-One (1:1) Relationships

In One-To-One relation, one entity instance is related to only one instance of another entity. One side of the relationship should always derive.

type User @entity {
    name: String!
    profile: Profile! @derivedFrom(field: "user")
}

type Profile @entity {
    avatar: String!
    user: User!
}

Database tables:

          user
| Column  | Type
----------|-------
| id      | character varying
| name    | character varying
          profile
| Column  | Type
----------|-------
| id      | character varying
| avatar  | character varying
| userId  | character varying FOREIGN KEY UNIQUE CONSTRAINT

One-To-Many (1:n) Relationships

In One-To-Many relation, one entity instance is related to multiple instances of the other entity.

type User @entity {
    name: String
}

type Post @entity {
    title: String
    author: User!
}

Database table for the Post entity:

          post
| Column  | Type
----------|-------
| id      | character varying
| avatar  | character varying
| authorId  | character varying FOREIGN KEY

The only difference between 1:1 and 1:n is the unique constraint that 1:1 has.

Many-To-Many (n:n) Relationships

Many-To-Many is a relationship where one entity instance is related to a collection of instances of other entities and vice-versa. In this relationship, one side of the relation must derive.

type User @entity {
    name: String
    books: [Book!] @derivedFrom(field: "authors")
}

type Book @entity {
    title: String
    authors: [User!]
}

A junction table is created for n:n relationship.

Database tables:

          book
| Column  | Type
----------|-------
| id      | character varying
| title   | character varying
          book_user
| Column  | Type
----------|-------
| book_id | character varying
| user_id | character varying

Reverse Lookups

Defining reverse lookups on an entity allows you to query the other side of the relation. Use @derivedFrom directive to add a reverse lookup to an entity.

Example If we want to access a user's posts from the user entity we should add a derived field to User entity:

type User @entity {
    name: String
    posts: [Post!] @derivedField(field: "author")
}

type Post @entity {
    title: String
    author: User!
}

Relationships In Mappings

Each GraphQL entity has a corresponding TypeORM entity and we use these entities to perform CRUD operations.

Example

We will create a new post for an existing user:

export async function handleNewPost(db: DB, event: SubstrateEvent) {
    const { userId, title } = event.params;
    const user = await db.get(User, { where: { id: userId } });

    const newPost = new Post();
    newPost.title = title;
    newPost.author = user;

    db.save<Post>(newPost);
}

Last updated