diff --git a/src/repository/TreeRepository.ts b/src/repository/TreeRepository.ts index 504bb848d3..7a337e8227 100644 --- a/src/repository/TreeRepository.ts +++ b/src/repository/TreeRepository.ts @@ -137,7 +137,7 @@ export class TreeRepository extends Repository { if (this.manager.connection.driver instanceof AbstractSqliteDriver) { return `${alias}.${this.metadata.materializedPathColumn!.propertyPath} LIKE ${subQuery.getQuery()} || '%'`; } else { - return `${alias}.${this.metadata.materializedPathColumn!.propertyPath} LIKE CONCAT(${subQuery.getQuery()}, '%')`; + return `${alias}.${this.metadata.materializedPathColumn!.propertyPath} LIKE NULLIF(CONCAT(${subQuery.getQuery()}, '%'), '%')`; } }); } diff --git a/test/github-issues/8556/entity/category.entity.ts b/test/github-issues/8556/entity/category.entity.ts new file mode 100644 index 0000000000..8f3e57fa94 --- /dev/null +++ b/test/github-issues/8556/entity/category.entity.ts @@ -0,0 +1,19 @@ +import {Column, PrimaryGeneratedColumn, Tree, TreeParent, TreeChildren} from "../../../../src"; +import {Entity} from "../../../../src/decorator/entity/Entity"; + +@Entity() +@Tree("materialized-path") +export class Category { + + @PrimaryGeneratedColumn() + id: number; + + @Column() + name: string; + + @TreeChildren() + children: Category[]; + + @TreeParent() + parent: Category; +} diff --git a/test/github-issues/8556/issue-8556.ts b/test/github-issues/8556/issue-8556.ts new file mode 100644 index 0000000000..e1372cd954 --- /dev/null +++ b/test/github-issues/8556/issue-8556.ts @@ -0,0 +1,59 @@ +import "reflect-metadata"; +import { + createTestingConnections, + closeTestingConnections, + reloadTestingDatabases, + generateRandomText +} from "../../utils/test-utils"; +import {Connection} from "../../../src/connection/Connection"; +import {expect} from "chai"; +import {Category} from "./entity/category.entity"; +import {TreeRepository} from "../../../src"; + +describe("github issues > #8556 TreeRepository.findDescendants/Tree should return empty if tree parent entity does not exist", () => { + let connections: Connection[]; + before( + async () => + (connections = await createTestingConnections({ + entities: [__dirname + "/entity/*{.js,.ts}"], + dropSchema: true, + schemaCreate: true, + name: generateRandomText(10)// Use a different name to avoid a random failure in build pipeline + })) + ); + + beforeEach(() => reloadTestingDatabases(connections)); + after(() => closeTestingConnections(connections)); + + it("should load descendants when findDescendants is called for a tree entity", () => + Promise.all( + connections.map(async connection => { + const repo: TreeRepository = connection.getTreeRepository(Category); + const root: Category = await repo.save({ id: 1, name: "root" } as Category); + await repo.save({ id: 2, name: "child", parent: root } as Category); + const descendantsIncludingParent = await repo.findDescendants(root); + expect(descendantsIncludingParent.length).to.be.equal(2); + const descendantTree = await repo.findDescendantsTree(root); + expect(descendantTree.children.length).to.be.equal(1); + const countDescendantsIncludingParent = await repo.countDescendants(root) + expect(countDescendantsIncludingParent).to.be.equal(2); + }) + ) + ); + + it("should return empty when findDescendants is called for a non existing tree entity", () => + Promise.all( + connections.map(async connection => { + const repo: TreeRepository = connection.getTreeRepository(Category); + const root: Category = await repo.save({ id: 1, name: "root" } as Category); + await repo.save({ id: 2, name: "child", parent: root } as Category); + const descendantsOfNonExistingParent = await repo.findDescendants({id: -1} as Category); + expect(descendantsOfNonExistingParent.length).to.be.equal(0); + const descendantTree = await repo.findDescendantsTree({id: -1} as Category); + expect(descendantTree.children.length).to.be.equal(0); + const countDescendantsIncludingParent = await repo.countDescendants({id: -1} as Category) + expect(countDescendantsIncludingParent).to.be.equal(0); + }) + ) + ); +});