Skip to content

Wrong SQL generation while using Object.assign to mount FilterQuery #1537

@rodrigovilar

Description

@rodrigovilar

Describe the bug
I am using Object.assign in a process to create FilterQueries, however it is generating incomplete SQL queries.

Stack trace

{ "message": "select count(distinct(\"e0\".\"id\")) as \"count\" from \"subscriber\" as \"e0\" left join \"message\" as \"e2\" on \"e0\".\"id\" = \"e2\".\"recipient_id\" where \"e1\".\"date_clicked\" < '2021-03-05T20:47:01.090Z' and \"e0\".\"owner_id\" = 27 and not (\"e2\".\"date_clicked\" > '2021-03-05T20:47:01.090Z' and \"e0\".\"owner_id\" = 27) - missing FROM-clause entry for table \"e1\"" }

To Reproduce
Steps to reproduce the behavior:

  1. Define entities and relationships:
@Entity()
export class Account extends BaseEntity {
  @PrimaryKey()
  id!: number;

  @OneToMany({
    entity: () => Subscriber,
    mappedBy: 'owner',
    orphanRemoval: true,
  })
  subscribers = new Collection<Subscriber>(this);
...
}

@Entity()
export class Subscriber extends BaseEntity {
  @PrimaryKey()
  id!: number;

  @OneToMany({
    entity: () => Message,
    mappedBy: 'recipient',
    orphanRemoval: true,
    orderBy: { createdAt: QueryOrder.ASC },
  })
  messages = new Collection<Message>(this);

  @ManyToOne(() => Account)
  owner!: Account;
...
}

@Entity()
export class Message extends BaseEntity {
  @PrimaryKey()
  id!: number;

  @Property({ nullable: true })
  dateClicked?: Date;

  @ManyToOne(() => Subscriber)
  recipient!: Subscriber;
...
}
  1. Mount the FilterQuery (pseudo-code):
let owner: Account = ...
let date: Date = ...

let filterAfter = { messages: { dateClicked: { $gt: date } }};
Object.assign(filterAfter, { owner });

let filterBefore = { messages: { dateClicked: { $lt: date } } };
Object.assign(filterBefore, { owner });

filter  = {
  $and: [
    filterAfter,
    { $not: filterBefore }
  ]
}
  1. Run the query:

await orm.em.find(Subscriber, filter);

  1. MikroORM generates a wrong SQL query:
select 
	count(distinct("e0"."id")) as "count" 
from 
	"subscriber" as "e0" left join 
	"message" as "e2" on "e0"."id" = "e2"."recipient_id" 
where 
	"e1"."date_clicked" < $date and 
	"e0"."owner_id" = $owner and 
	not ("e2"."date_clicked" > $date and "e0"."owner_id" = $owner) 

Without declaring e1 in FROM clause

Expected behavior
Generate the following SQL query:

select 
	count(distinct("e0"."id")) as "count" 
from 
	"subscriber" as "e0" left join 
	"message" as "e1" on "e0"."id" = "e1"."recipient_id" 
where 
	"e1"."date_clicked" < $date and 
	"e0"."owner_id" = $owner and 
	not ("e1"."date_clicked" > $date and "e0"."owner_id" = $owner) 

Additional context
I suggest generating the code inside of not( ) using e1 instead of e0.

Versions

Dependency Version
node 14.15.4
typescript 3.8.3
mikro-orm 4.3.0
@mikro-orm/postgresql 4.3.0

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions