Skip to content

Commit

Permalink
fix: ordering by joined columns for PostgreSQL (#3736) (#8118)
Browse files Browse the repository at this point in the history
  • Loading branch information
antonku committed Nov 5, 2021
1 parent 6558295 commit 1649882
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
25 changes: 21 additions & 4 deletions src/query-builder/SelectQueryBuilder.ts
Expand Up @@ -1954,7 +1954,7 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements

// we are skipping order by here because its not working in subqueries anyway
// to make order by working we need to apply it on a distinct query
const [selects, orderBys] = this.createOrderByCombinedWithSelectExpression("distinctAlias");
const [selects, orderBys, subquerySelect] = this.createOrderByCombinedWithSelectExpression("distinctAlias");
const metadata = this.expressionMap.mainAlias.metadata;
const mainAliasName = this.expressionMap.mainAlias.name;

Expand All @@ -1976,7 +1976,7 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
rawResults = await new SelectQueryBuilder(this.connection, queryRunner)
.select(`DISTINCT ${querySelects.join(", ")}`)
.addSelect(selects)
.from(`(${this.clone().orderBy().getQuery()})`, "distinctAlias")
.from(`(${this.clone().orderBy().addSelect(subquerySelect).getQuery()})`, "distinctAlias")
.offset(this.expressionMap.skip)
.limit(this.expressionMap.take)
.orderBy(orderBys)
Expand Down Expand Up @@ -2043,7 +2043,7 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
};
}

protected createOrderByCombinedWithSelectExpression(parentAlias: string): [ string, OrderByCondition] {
protected createOrderByCombinedWithSelectExpression(parentAlias: string): [ string, OrderByCondition, string] {

// if table has a default order then apply it
const orderBys = this.expressionMap.allOrderBys;
Expand Down Expand Up @@ -2083,7 +2083,24 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
}
});

return [selectString, orderByObject];
const subquerySelectString = Object.keys(orderBys)
.filter(orderCriteria => orderCriteria.includes("."))
.map(orderCriteria => {
const criteriaParts = orderCriteria.split(".");
const aliasName = criteriaParts[0];
const propertyPath = criteriaParts.slice(1).join(".");
const alias = this.expressionMap.findAliasByName(aliasName);
if (alias.type !== "join") {
return "";
}
const column = alias.metadata.findColumnWithPropertyPath(propertyPath);
const property = this.escape(alias.name) + "." + this.escape(column!.databaseName);
const propertyAlias = this.escape(DriverUtils.buildAlias(this.connection.driver, aliasName, column!.databaseName));
return [property, "AS", propertyAlias].join(" ");
})
.join(", ");

return [selectString, orderByObject, subquerySelectString];
}

/**
Expand Down
16 changes: 16 additions & 0 deletions test/github-issues/3736/entity/Photo.ts
@@ -0,0 +1,16 @@
import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "../../../../src";
import {User} from "./User";

@Entity()
export class Photo {

@PrimaryGeneratedColumn()
id: number;

@Column()
url: string;

@ManyToOne(() => User, user => user.photos)
user: User;

}
16 changes: 16 additions & 0 deletions test/github-issues/3736/entity/User.ts
@@ -0,0 +1,16 @@
import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "../../../../src";
import {Photo} from "./Photo";

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;

@Column()
name: string;

@OneToMany(() => Photo, photo => photo.user)
photos: Photo[];

}
40 changes: 40 additions & 0 deletions test/github-issues/3736/issue-3736.ts
@@ -0,0 +1,40 @@
import "reflect-metadata";
import { createTestingConnections, closeTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Connection } from "../../../src/connection/Connection";
import { expect } from "chai";
import { Photo } from "./entity/Photo";
import { User } from "./entity/User";
import { SelectQueryBuilder } from "../../../src";


describe("github issues > #3736 Order by joined column broken in Postgres", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
logging: true
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should return photos ordered by user.name", () => Promise.all(connections.map(async connection => {
const [user1, user2] = await connection.getRepository(User).save([
{ name: "userA" },
{ name: "userB" },
]);
const [photo1, photo2] = await connection.getRepository(Photo).save([
{ url: "https://example.com", user: user2 },
{ url: "https://example.com", user: user1 },
]);
const queryBuilder: SelectQueryBuilder<Photo> = await connection.getRepository(Photo).createQueryBuilder("photo");
const [results] = await queryBuilder
.select()
.leftJoin("photo.user", "user")
.take(5)
.orderBy("user.name")
.getManyAndCount();
expect(results[0].id).to.equal(photo2.id);
expect(results[1].id).to.equal(photo1.id);
})));
})

0 comments on commit 1649882

Please sign in to comment.