Now we want to add the relationship with POST
and USER
. This is a one-to-many relationship. In the MikrORM documentation, the many-to-one relationship can create by adding @ManyToOne
in the entity. In example,
// mikro orm documentation example
@Entity()
export class Book {
@ManyToOne()
author!: Author;
}
But when we set the value of author
to Book
entity, we need to manually get the author
and set it. If we searched more, we can set the author
like this,
// mikro orm documentation exaple
book.auther = orm.em.getReference < Author > (Author, "...id...");
So, because of that, we are moving to TypeORM.
Yeah, kinda huge change.
To add TypeORM to the server project, use this yarn command.
yarn add typeorm
Then we need to change the index.ts
file in the server project. First we need to add the config object to TypeORM
. I created a new database for typeorm
.
const conn = await createConnection({
type: "postgresql",
database: "redditdev03",
username: "postgresql",
password: mySecretKeys.myDbPassword,
logging: true,
synchronize: true,
entities: [],
});
In the above code, I need to add entities. Before that, we need to change our current entities to match with typeorm
.
I change the User
and Post
Files. We need to change Property to Column and there are other annotations related to type-orm
and replace with mikro-orm
annotation. I will mention new annotations here and you can check the full changed file in GitHub.
PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, Column;
Now we can fill entities
array from type-orm
config object. We can remove mikro-orm
related things from index.ts
file. Also we don’t need to pass anything to context object. Now our ApolloServer
context object like this.
context: ({ req, res }: RedditDbContext) => ({
res,
redis,
}
We can extend BaseEntity
in User
and Post
entity classes. Because of that, we can use pre-defined methods for data manipulation. In the RedditDbContext
object form types.ts
file, we don’t need mikro-orm
object. We can remove it. We used that mikro-orm
object to access context in our resolvers. Let’s go and fix those. Because we extended the BaseEntity
type from User
and Post
entities, we can use those methods in resolvers like Post.find()
.
For reference here is the insert query.
return Post.create({ title }).save();
So, now we just change the post
resolver and user
resolver. (There are so many small changes to match with type-orm
each method. So please refer to the Github files.)
If we try to find something without a primary key we need to use where
property in findOne
method.
await User.findOne({ where: { email } });
While moving to type-orm
we can use its query builder. Here is code for that.
const result = await getConnection()
.createQueryBuilder()
.insert()
.into(User)
.values({
username: options.username,
email: options.email,
password: hashedPassword,
})
.returning("*")
.execute();
Now we all set the type-orm
. Let’s add the relationship to Post
entity.
@Field()
@Column()
creatorId: number;
// posts need to match with User's property name
@ManyToOne(() => User, user => user.posts)
creator: User;
So we need to add the posts
property in the User
entity.
@OneToMany(() => Post, (post) => post.creator)
posts: Post[];
Also, we are adding new fields to Post
entity. Because these are not null fields, we need to clear Post
table and start it again.
@Field()
@Column()
text!: string;
@Field()
@Column({type: "int", default: 0})
points!: number;
Then we are creating a InputType
for the post. This will easier to work with the front-end.
@InputType()
class PostInput {
@Field()
title: string;
@Field()
text: string;
}
Then we need to change the createPost
method in post
resolver.
@Mutation(() => Post)
async createPost(
@Arg("input") input: PostInput,
@Ctx() { req }: RedditDbContext
): Promise<Post> {
return Post.create({ ...input, creatorId: req.session.userId }).save();
}
Now we have a slight error that event anyone can create a post without login to the system. We can avoid it by checking user id in the session, but any place that we need to check user logging status we need to add a if
statement. To avoid that we can use middleware. Let’s see how can we use middleware from the next post.
Thanks for reading this. If you have anything to ask regarding this please leave a comment here. Also, I wrote this according to my understanding. So if any point is wrong, don’t hesitate to correct me. I really appreciate you. That’s for today friends. See you soon. Thank you.
References:
This article series based on the Ben Award - Fullstack React GraphQL TypeScript Tutorial. This is amazing tutorial and I highly recommend you to check that out.
Main image credit