TypeORM Tips (Part 2: Use where() with care)

Hey everyone! This is the second post in my series on tips while developing with TypeORM, a popular typescript ORM library. In this post I will remark on a common pitfall when using the where() method in the library.

Use where() with care

T…


This content originally appeared on DEV Community and was authored by Rishit Bansal

Hey everyone! This is the second post in my series on tips while developing with TypeORM, a popular typescript ORM library. In this post I will remark on a common pitfall when using the where() method in the library.

Use where() with care

TypeORM's QueryBuilder provides a where() method to add SQL WHERE clauses in a your queries which allows you to specify a condition to control the records which your query processes. Here's a code snippet illustrating how you can use this method:

const query = await this.userRepository.createQueryBuilder()
             .select()
             .where("user.id=:userId", {userId: "123"})
             .getOne();

This method follows a similar pattern to several other methods of QueryBuilder which let you successively chain methods. Each method call returns back another QueryBuilder instance. Here is an example of a chain which performs multiple LEFT JOINS, filters by a where condition and finally limits the query result to just 10 rows:

const query = await this.userRepository.createQueryBuilder('user)
            .leftJoinAndSelect('user.posts', 'posts')
            .leftJoinAndSelect('user.comments', 'comments')
            .where('user.age > :minAge', { minAge: 18 })
            .limit(10)
            .getMany();

Neat! Now lets say I want to add another filter on this query to ensure that the user age is also under 65 years old. Naturally, if I were to follow the chain pattern offered by the library I might do the following:

const query = await this.userRepository.createQueryBuilder('user)
            .leftJoinAndSelect('user.posts', 'posts')
            .leftJoinAndSelect('user.comments', 'comments')
            .where('user.age > :minAge', { minAge: 18 })
            .where('user.age < :maxAge', { maxAge: 65 })
            .limit(10)
            .getMany();

TypeORM successfully executes the above and doesn't give any compile-time/runtime warnings at all. But this piece of code will not filter out records correctly!

What's the problem?

Adding multiple where() clauses to a query doesn't make sure all of them are satisfied. Rather, TypeORM only picks the last where() in the chain and uses that as the sole filter for the query. In other words, successive where() clauses just override previous clauses instead of adding new conditions. Thus the above code snippet will just return users whose age is less than 65 (i.e, The condition user > 18 won't be enforced!).

This is vague as the library doesn't complain with this usage and can sometimes blindside developers. If a developer didn't test the above code on corner-cases, he/she might unknowingly deploy this on production and may discover the edge case only much later when the bug is reported.

How do you fix this?

The correct usage is to use andWhere or orWhere depending on if you want to concatenate multiple conditions using AND or OR. For example, the above code snippet can be correct to:

const query = await this.userRepository.createQueryBuilder('user)
            .leftJoinAndSelect('user.posts', 'posts')
            .leftJoinAndSelect('user.comments', 'comments')
            .where('user.age > :minAge', { minAge: 18 })
            .andWhere('user.age < :maxAge', { maxAge: 65 })
            .limit(10)
            .getMany();

You can also use the Brackets function to create more complicated queries. Say I wanted to check if the user falls in either of two age ranges (18<age<35 OR 50<age<65), I could do the following:

const query = await this.userRepository.createQueryBuilder('user)
            .leftJoinAndSelect('user.posts', 'posts')
            .leftJoinAndSelect('user.comments', 'comments')
            .where(new Brackets(qb => 
                qb.where('user.age > :minAge', { minAge: 18 })
                  .andWhere('user.age < :maxAge', { maxAge: 35 }))
            .orWhere(new Brackets(qb => 
                qb.where('user.age > :minAge', { minAge: 50 })
                  .andWhere('user.age < :maxAge', { maxAge: 65 }))
            .limit(10)
            .getMany();

Note that here it was completely safe to use multiple where() clauses as the other usages actually operate on a seperate QueryBuilder instance and not the parent one. The basic rule to follow is to avoid multiple where() method calls on the same QueryBuilder instance.


This content originally appeared on DEV Community and was authored by Rishit Bansal


Print Share Comment Cite Upload Translate Updates
APA

Rishit Bansal | Sciencx (2022-01-22T19:15:01+00:00) TypeORM Tips (Part 2: Use where() with care). Retrieved from https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/

MLA
" » TypeORM Tips (Part 2: Use where() with care)." Rishit Bansal | Sciencx - Saturday January 22, 2022, https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/
HARVARD
Rishit Bansal | Sciencx Saturday January 22, 2022 » TypeORM Tips (Part 2: Use where() with care)., viewed ,<https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/>
VANCOUVER
Rishit Bansal | Sciencx - » TypeORM Tips (Part 2: Use where() with care). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/
CHICAGO
" » TypeORM Tips (Part 2: Use where() with care)." Rishit Bansal | Sciencx - Accessed . https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/
IEEE
" » TypeORM Tips (Part 2: Use where() with care)." Rishit Bansal | Sciencx [Online]. Available: https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/. [Accessed: ]
rf:citation
» TypeORM Tips (Part 2: Use where() with care) | Rishit Bansal | Sciencx | https://www.scien.cx/2022/01/22/typeorm-tips-part-2-use-where-with-care/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.