TypeORM: update item and return it
As far as I know, it's a best practice to return an item after it has been updated. TypeORM's updateById
returns void
, not the updated item though.
My question: Is it possible to update and return the modified item in a single line?
What I tried so far:
await this.taskRepository.updateById(id, { state, dueDate });
return this.taskRepository.findOne({ id });
What I'm looking for:
return this.taskRepository.updateById(id, { state, dueDate }); // returns updated task
Solution 1:
I just found out that I can do this with the .save
method:
return this.taskRepository.save({
id: task.id,
state,
dueDate
});
According to the docs (section save
), partial updates are supported as well:
Also supports partial updating since all undefined properties are skipped.
Solution 2:
To expand on sandrooco's answer, this is what I do:
const property = await this.propertyRepository.findOne({
where: { id }
});
return this.propertyRepository.save({
...property, // existing fields
...updatePropertyDto // updated fields
});
Solution 3:
The key is returning response.raw[0]
in order to get the type back.
Although I want await Table.update({}, {})
to return Table
it doesn't. I've found it easier to just work with the QueryBuilder
because it gives me more control in general, BUT if you don't like the QueryBuilder
or don't need it, you can do something like this:
const post = await Post.update({id}, {...input}).then(response => response.raw[0]);
return post; // returns post of type Post
If you however do want to use QueryBuilder
I suggest going with an approach like below.
Others above has mentioned the usage of Repository
and Table.save()
Which doesn't really return the original type
anywhere, so that approach is out of the picture for me.
An example of Table.update({}, {})
:
@Mutation(() => PostResponse, { nullable: true })
@UseMiddleware(isAuthorized)
async updatePost(
@Arg("id", () => Int) id: number,
@Arg("input") input: PostInput,
@Ctx() { req }: Context
): Promise<PostResponse | null> {
// ...
const post = await Post.update({id}, {...input}).then(response => response.raw[0]);
return { post };
}
An example of QueryBuilder
:
@Mutation(() => PostResponse, { nullable: true })
@UseMiddleware(isAuthorized)
async updatePost(
@Arg("id", () => Int) id: number,
@Arg("input") input: PostInput,
@Ctx() { req }: Context
): Promise<PostResponse | null> {
// ...
const post = await getConnection()
.createQueryBuilder()
.update(Post)
.set({ ...input })
.where('id = :id and "creatorId" = :creatorId', {
id,
creatorId: userId,
})
.returning("*")
.execute()
.then((response) => {
return response.raw[0];
});
return { post };
}
Helper function (if you don't wanna have to write response.raw[0]
all the time)
const typeReturn = async <T>(mutation: Promise<UpdateResult | DeleteResult | InsertResult>): Promise<T> => {
return await mutation.then((res) => res.raw[0]);
};
Usage:
const update = await typeReturn<Post>(Post.update(...));
const insert = await typeReturn<Attachment>(Attachment.insert(...));
const del = await typeReturn<User>(User.delete(...));
Note: I'm using TypeORM and Type-GraphQL here.
.returning("*")
does not work on MySQL, see comments below.