From b53e410e5abe930ab489ff4c8c16f62306910f6a Mon Sep 17 00:00:00 2001 From: Tolga Paksoy Date: Fri, 29 Dec 2023 17:18:11 +0100 Subject: [PATCH] fix: empty objects being hydrated when eager loading relations that have a `@VirtualColumn` (#10432) * test: add scenario for #10431 * fix: empty objects being hydrated by unselected virtual properties --- src/query-builder/SelectQueryBuilder.ts | 5 +++ test/github-issues/10431/entity/Category.ts | 26 +++++++++++++ test/github-issues/10431/entity/Product.ts | 25 ++++++++++++ test/github-issues/10431/entity/index.ts | 2 + test/github-issues/10431/issue-10431.ts | 42 +++++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 test/github-issues/10431/entity/Category.ts create mode 100644 test/github-issues/10431/entity/Product.ts create mode 100644 test/github-issues/10431/entity/index.ts create mode 100644 test/github-issues/10431/issue-10431.ts diff --git a/src/query-builder/SelectQueryBuilder.ts b/src/query-builder/SelectQueryBuilder.ts index 25aabeef0..24c2a9858 100644 --- a/src/query-builder/SelectQueryBuilder.ts +++ b/src/query-builder/SelectQueryBuilder.ts @@ -2882,6 +2882,11 @@ export class SelectQueryBuilder }) }) } else { + if (column.isVirtualProperty) { + // Do not add unselected virtual properties to final select + return + } + finalSelects.push({ selection: selectionPath, aliasName: DriverUtils.buildAlias( diff --git a/test/github-issues/10431/entity/Category.ts b/test/github-issues/10431/entity/Category.ts new file mode 100644 index 000000000..7afdfe353 --- /dev/null +++ b/test/github-issues/10431/entity/Category.ts @@ -0,0 +1,26 @@ +import { + Column, + Entity, + ManyToMany, + PrimaryGeneratedColumn, + VirtualColumn, +} from "../../../../src" +import { Product } from "./Product" + +@Entity() +export class Category { + @PrimaryGeneratedColumn() + id: number + + @VirtualColumn({ + query: (alias) => + `SELECT COUNT(*) FROM category WHERE id = ${alias}.id`, + }) + randomVirtualColumn: number + + @ManyToMany(() => Product, (product: Product) => product.categories) + products?: Product[] + + @Column("varchar") + name: string +} diff --git a/test/github-issues/10431/entity/Product.ts b/test/github-issues/10431/entity/Product.ts new file mode 100644 index 000000000..86e0c4700 --- /dev/null +++ b/test/github-issues/10431/entity/Product.ts @@ -0,0 +1,25 @@ +import { + Column, + Entity, + JoinTable, + ManyToMany, + PrimaryGeneratedColumn, +} from "../../../../src" +import { Category } from "./Category" + +@Entity() +export class Product { + @PrimaryGeneratedColumn() + id: number + + @Column("varchar") + name: string + + @ManyToMany(() => Category, (category: Category) => category.products, { + eager: true, + cascade: ["insert", "update", "remove"], + orphanedRowAction: "delete", + }) + @JoinTable() + categories: Category[] +} diff --git a/test/github-issues/10431/entity/index.ts b/test/github-issues/10431/entity/index.ts new file mode 100644 index 000000000..aa04377bb --- /dev/null +++ b/test/github-issues/10431/entity/index.ts @@ -0,0 +1,2 @@ +export * from "./Category" +export * from "./Product" diff --git a/test/github-issues/10431/issue-10431.ts b/test/github-issues/10431/issue-10431.ts new file mode 100644 index 000000000..5487032f9 --- /dev/null +++ b/test/github-issues/10431/issue-10431.ts @@ -0,0 +1,42 @@ +import "reflect-metadata" +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, +} from "../../utils/test-utils" +import { DataSource } from "../../../src" +import { expect } from "chai" + +import { Category, Product } from "./entity" + +describe("github issues > #10431 When requesting nested relations on foreign key primary entities, relation becomes empty entity rather than null", () => { + let connections: DataSource[] + before( + async () => + (connections = await createTestingConnections({ + entities: [Category, Product], + schemaCreate: true, + dropSchema: true, + })), + ) + beforeEach(() => reloadTestingDatabases(connections)) + after(() => closeTestingConnections(connections)) + + it("should return [] when requested nested relations are empty on ManyToMany relation with @VirtualColumn definitions", () => + Promise.all( + connections.map(async (connection) => { + const productRepo = connection.getRepository(Product) + const testProduct = new Product() + testProduct.name = "foo" + await productRepo.save(testProduct) + const foundProduct = await productRepo.findOne({ + where: { + id: testProduct.id, + }, + relations: { categories: true }, + }) + expect(foundProduct?.name).eq("foo") + expect(foundProduct?.categories).eql([]) + }), + )) +})