diff --git a/src/query-builder/QueryExpressionMap.ts b/src/query-builder/QueryExpressionMap.ts index 929652de4e..c65d337c78 100644 --- a/src/query-builder/QueryExpressionMap.ts +++ b/src/query-builder/QueryExpressionMap.ts @@ -46,6 +46,11 @@ export class QueryExpressionMap { */ selects: SelectQuery[] = []; + /** + * Whether SELECT is DISTINCT. + */ + selectDistinct: boolean = false; + /** * FROM-s to be selected. */ diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 07ca4e2327..3aac7587f4 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -158,6 +158,14 @@ export class SelectQueryBuilder extends QueryBuilder implements return this; } + /** + * Sets whether the selection is DISTINCT. + */ + distinct(distinct: boolean = true): this { + this.expressionMap.selectDistinct = distinct; + return this; + } + /** * Specifies FROM which entity's table select/update/delete will be executed. * Also sets a main string alias of the selection data. @@ -1400,8 +1408,9 @@ export class SelectQueryBuilder extends QueryBuilder implements return this.getTableName(alias.tablePath!) + " " + this.escape(alias.name); }); + const select = "SELECT " + (this.expressionMap.selectDistinct ? "DISTINCT " : ""); const selection = allSelects.map(select => select.selection + (select.aliasName ? " AS " + this.escape(select.aliasName) : "")).join(", "); - return "SELECT " + selection + " FROM " + froms.join(", ") + lock; + return select + selection + " FROM " + froms.join(", ") + lock; } /** diff --git a/test/functional/query-builder/select/query-builder-select.ts b/test/functional/query-builder/select/query-builder-select.ts index 725dcf9a54..6b1ba78e89 100644 --- a/test/functional/query-builder/select/query-builder-select.ts +++ b/test/functional/query-builder/select/query-builder-select.ts @@ -27,6 +27,21 @@ describe("query builder > select", () => { "FROM post post"); }))); + it("should append all entity mapped columns from main selection to SELECT DISTINCT statement", () => Promise.all(connections.map(async connection => { + const sql = connection.manager.createQueryBuilder(Post, "post") + .distinct() + .disableEscaping() + .getSql(); + + expect(sql).to.equal("SELECT DISTINCT post.id AS post_id, " + + "post.title AS post_title, " + + "post.description AS post_description, " + + "post.rating AS post_rating, " + + "post.version AS post_version, " + + "post.categoryId AS post_categoryId " + + "FROM post post"); + }))); + it("should append all entity mapped columns from both main selection and join selections to select statement", () => Promise.all(connections.map(async connection => { const sql = connection.createQueryBuilder(Post, "post") .leftJoinAndSelect("category", "category")