description |
---|
Define one-to-one, one-to-many and many-to-many relationships between entities |
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
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 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
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!
}
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);
}