-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Description
Issue Description
In find operations, when you have a condition in where that relates to an optional relation, the relation changes from "left" to "inner" incorrectly. That's a problem when the condition is written as an array (resulting in an OR operator), so a condition in one of the array elements may be optional if it is not described in all elements.
Expected Behavior
According to the documentation, FindOptionsRelations is a shortened version of join and leftJoinAndSelect, therefore, all relations described in them should always result in a left join.
Actual Behavior
All relations represented in a where statement that weren't explicitly described in relations are then created as an inner join. That's iffy, but... sure why not. The problem is that even relations that were explicitly written in relations (therefore expected to be of type "left") are then converted to type "inner". That's invasive and corrupts the expected behavior of relations.
Steps to Reproduce
- Have an entity model with an optional many-to-one relation. For example: An employee may or may not have an office, but an office can house many employees if it's big enough.
- Create a repository of the model.
- Call
.find(), and in the options write where as an array. In one of the elements, have a condition that uses the optional many-to-one relation and in another element write other conditions that don't depend on the optional relation.
import { Entity, Column, PrimaryGeneratedColumn, JoinColumn, ManyToOne } from 'typeorm';
@Entity('employee')
export class Employee {
@Column()
name: string;
@Column()
office_id?: string;
@ManyToOne(() => Office)
@JoinColumn({ name: 'office_id' })
office?: Office;
}
@Entity('office')
export class Office {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
hasWindow: boolean;
}import myDataSource from 'path/to/myDataSource';
import Employee from 'path/to/Employee';
const rep = myDataSource.getRepository(Employee);
const result = await rep.find({
where: [
{ name: 'Jhon' },
{ office: { hasWindow: false } },
],
relations: { office: true },
});In the above example, an employee named Jhon who doesn't have an office would not appear in the results, even though he perfectly suffices the first condition of the where (his name is Jhon). It shouldn't matter that he doesn't have an office, but the join relation "office" was wrongfully converted to an "inner".
My Environment
| Dependency | Version |
|---|---|
| Operating System | Windows 10 |
| Node.js version | v14.17.4 |
| Typescript version | 4.8.3 |
| TypeORM version | 0.3.9 |
Additional Context
--
Relevant Database Driver(s)
I've only tested in mysql.
| DB Type | Reproducible |
|---|---|
aurora-mysql |
no |
aurora-postgres |
no |
better-sqlite3 |
no |
cockroachdb |
no |
cordova |
no |
expo |
no |
mongodb |
no |
mysql |
yes |
nativescript |
no |
oracle |
no |
postgres |
no |
react-native |
no |
sap |
no |
spanner |
no |
sqlite |
no |
sqlite-abstract |
no |
sqljs |
no |
sqlserver |
no |
Are you willing to resolve this issue by submitting a Pull Request?
- ✖️ Yes, I have the time, and I know how to start.
- ✅ Yes, I have the time, but I don't know how to start. I would need guidance.
- ✖️ No, I don’t have the time, but I can support (using donations) development.
- ✖️ No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.