import { assert } from "chai" import { DataSource, ObjectLiteral, TreeRepository } from "../../../src" import { NestedSetMultipleRootError } from "../../../src/error/NestedSetMultipleRootError" import { closeTestingConnections, createTestingConnections, reloadTestingDatabases, } from "../../utils/test-utils" import { OtherRelation, Relation, RelationClosure, RelationMaterialized, RelationNested, } from "./entity/RelationEntities" import { MultiIdMaterialized, MultiIdNested, SingleIdClosure, SingleIdMaterialized, SingleIdNested, } from "./entity/RemainingTreeEntities" import { SqlServerMultiIdMaterialized, SqlServerMultiIdNested, SqlServerSingleIdClosure, SqlServerSingleIdMaterialized, SqlServerSingleIdNested, } from "./entity/SqlServerTreeEntities" describe("github issues > #7155", () => { let connections: DataSource[] before(async () => (connections = await generateConnections())) beforeEach(() => reloadTestingDatabases(connections)) after(() => closeTestingConnections(connections)) /** * ------------------ SINGLE ID ------------------ * * Closure table */ it("(Closure/SingleID/Save) Update without parent", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) entry2.name = "entry2" await repo.save(entry2) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(1) }), )) it("(Closure/SingleID/Save) Update without tree change", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) entry11.name = "entry11" await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(2) }), )) it("(Closure/SingleID/Save) Set leaf entity as root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) entry11.parent = null await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Closure/SingleID/Save) Move leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) // Assing entry11 from entry1 to entry2 entry11.parent = entry2 await repo.save(entry11) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(2) }), )) it("(Closure/SingleID/Save) Move branch with single root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry121.parent = entry11 await repo.save(entry121) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Closure/SingleID/Save) Move branch with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry11.children = [entry121] await repo.save(entry11) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Closure/SingleID/Save) Move multiple branches with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 // And entry111 from entry11 to entry12 entry11.children = [entry121] entry12.children = [entry111] await repo.save([entry11, entry12]) let descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Closure/SingleID/Save) Remove and re-add parent", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) entry11.parent = null await repo.save(entry11) descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) entry11.parent = entry1 await repo.save(entry11) descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) }), )) it("(Closure/SingleID/Remove) Remove leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) // Remove entry11 from entry1 await repo.remove(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Closure/SingleID/Remove) Remove branch with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry1111 = new Entity() entry1111.parent = entry111 await repo.save(entry1111) // Remove entry111 from entry11 await repo.remove(entry111) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(1) }), )) it("(Closure/SingleID/Remove) Remove multiple branches with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "single_closure") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Remove entry11 and entry1211 await repo.remove([entry11, entry1211]) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) /** * Nested set */ it("(Nested/SingleID/Save) Update without tree change", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { id: 1, left: 1, right: 4 }, { id: 2, left: 2, right: 3 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) entry11.name = "entry11" await repo.save(entry11) const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(2) }), )) it("(Nested/SingleID/Save) Set multiple root entities", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) try { const entry2 = new Entity() await repo.save(entry2) } catch (error) { assert.instanceOf(error, NestedSetMultipleRootError) return } assert.fail("Should have thrown an error.") }), )) it("(Nested/SingleID/Save) Set leaf entity as root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) try { entry11.parent = null await repo.save(entry11) } catch (error) { assert.instanceOf(error, NestedSetMultipleRootError) return } assert.fail("Should have thrown an error.") }), )) it("(Nested/SingleID/Save) Move leaf with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { id: 1, left: 1, right: 6 }, { id: 2, left: 3, right: 4 }, { id: 3, left: 2, right: 5 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) // Assing entry11 from entry1 to entry12 entry11.parent = entry12 await repo.save(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Nested/SingleID/Save) Move branch with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { id: 1, left: 1, right: 10 }, { id: 2, left: 2, right: 7 }, { id: 3, left: 8, right: 9 }, { id: 4, left: 3, right: 6 }, { id: 5, left: 4, right: 5 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) const entry121 = new Entity() entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ id: nestedSet.id }) const entry1211 = new Entity() entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ id: nestedSet.id }) // Assing entry121 from entry12 to entry11 entry121.parent = entry11 await repo.save(entry121) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Nested/SingleID/Save) Move branch with single root via children", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { id: 1, left: 1, right: 10 }, { id: 2, left: 2, right: 7 }, { id: 3, left: 8, right: 9 }, { id: 4, left: 3, right: 6 }, { id: 5, left: 4, right: 5 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) const entry121 = new Entity() entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ id: nestedSet.id }) const entry1211 = new Entity() entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ id: nestedSet.id }) // Assing entry121 from entry12 to entry11 entry11.children = [entry121] await repo.save(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Nested/SingleID/Save) Move multiple branches with single root via children", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { id: 1, left: 1, right: 12 }, { id: 2, left: 2, right: 7 }, { id: 3, left: 9, right: 10 }, { id: 4, left: 8, right: 11 }, { id: 5, left: 3, right: 6 }, { id: 6, left: 4, right: 5 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry111 = new Entity() entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) const entry121 = new Entity() entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ id: nestedSet.id }) const entry1211 = new Entity() entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ id: nestedSet.id }) // Assing entry121 from entry12 to entry11 // And entry111 from entry11 to entry12 entry11.children = [entry121] entry12.children = [entry111] await repo.save([entry11, entry12]) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) let descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Nested/SingleID/Remove) Remove leaf with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [{ id: 1, left: 1, right: 2 }] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) // Remove entry11 from entry1 await repo.remove(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Nested/SingleID/Remove) Remove branch with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const expectedResults = [ { id: 1, left: 1, right: 6 }, { id: 2, left: 2, right: 3 }, { id: 3, left: 4, right: 5 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) const entry111 = new Entity() entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ id: nestedSet.id }) const entry1111 = new Entity() entry1111.parent = entry111 nestedSet = await repo.save(entry1111) ids.push({ id: nestedSet.id }) // Remove entry111 from entry11 await repo.remove(entry111) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(1) }), )) it("(Nested/SingleID/Remove) Remove multiple branches with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const expectedResults = [ { id: 1, left: 1, right: 6 }, { id: 4, left: 2, right: 5 }, { id: 5, left: 3, right: 4 }, ] const Entity = getEntity(connection, "single_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: SingleIdNested const entry1 = new Entity() nestedSet = await repo.save(entry1) ids.push({ id: nestedSet.id }) const entry11 = new Entity() entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ id: nestedSet.id }) const entry111 = new Entity() entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ id: nestedSet.id }) const entry12 = new Entity() entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ id: nestedSet.id }) const entry121 = new Entity() entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ id: nestedSet.id }) const entry1211 = new Entity() entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ id: nestedSet.id }) // Remove entry11 and entry1211 await repo.remove([entry11, entry1211]) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) /** * Materialized path */ it("(Materialized/SingleID/Save) Update without parent", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) entry2.name = "entry2" await repo.save(entry2) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(1) }), )) it("(Materialized/SingleID/Save) Update without tree change", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) entry11.name = "entry11" await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(2) }), )) it("(Materialized/SingleID/Save) Set leaf entity as root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) entry11.parent = null await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Materialized/SingleID/Save) Move leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) // Assing entry11 from entry1 to entry2 entry11.parent = entry2 await repo.save(entry11) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(2) }), )) it("(Materialized/SingleID/Save) Move branch with single root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry121.parent = entry11 await repo.save(entry121) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Materialized/SingleID/Save) Move branch with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry11.children = [entry121] await repo.save(entry11) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Materialized/SingleID/Save) Move multiple branches with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 // And entry111 from entry11 to entry12 entry11.children = [entry121] entry12.children = [entry111] await repo.save([entry11, entry12]) let descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Materialized/SingleID/Remove) Remove leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry2 = new Entity() await repo.save(entry2) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) // Remove entry11 from entry1 await repo.remove(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Materialized/SingleID/Remove) Remove branch with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry1111 = new Entity() entry1111.parent = entry111 await repo.save(entry1111) // Remove entry111 from entry11 await repo.remove(entry111) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(1) }), )) it("(Materialized/SingleID/Remove) Remove multiple branches with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "single_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() await repo.save(entry1) const entry11 = new Entity() entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.parent = entry121 await repo.save(entry1211) // Remove entry11 and entry1211 await repo.remove([entry11, entry1211]) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) /** * ------------------ MULTI ID ------------------ * * Nested set */ it("(Nested/MultiID/Save) Update without tree change", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 4 }, { column: "A", row: 2, left: 2, right: 3 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) entry11.name = "entry11" await repo.save(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(2) }), )) it("(Nested/MultiID/Save) Set multiple root entities", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) try { const entry2 = new Entity() entry2.column = "B" entry2.row = 1 await repo.save(entry2) } catch (error) { assert.instanceOf(error, NestedSetMultipleRootError) return } assert.fail("Should have thrown an error.") }), )) it("(Nested/MultiID/Save) Set leaf entity as root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 await repo.save(entry11) try { entry11.parent = null await repo.save(entry11) } catch (error) { assert.instanceOf(error, NestedSetMultipleRootError) return } assert.fail("Should have thrown an error.") }), )) it("(Nested/MultiID/Save) Move leaf with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 6 }, { column: "A", row: 2, left: 3, right: 4 }, { column: "A", row: 3, left: 2, right: 5 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Assing entry11 from entry1 to entry12 entry11.parent = entry12 await repo.save(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Nested/MultiID/Save) Move branch with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 10 }, { column: "A", row: 2, left: 2, right: 7 }, { column: "A", row: 3, left: 8, right: 9 }, { column: "B", row: 3, left: 3, right: 6 }, { column: "C", row: 3, left: 4, right: 5 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry121 = new Entity() entry121.column = "B" entry121.row = 3 entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry1211 = new Entity() entry1211.column = "C" entry1211.row = 3 entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Assing entry121 from entry12 to entry11 entry121.parent = entry11 await repo.save(entry121) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Nested/MultiID/Save) Move branch with single root via children", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 10 }, { column: "A", row: 2, left: 2, right: 7 }, { column: "A", row: 3, left: 8, right: 9 }, { column: "B", row: 3, left: 3, right: 6 }, { column: "C", row: 3, left: 4, right: 5 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry121 = new Entity() entry121.column = "B" entry121.row = 3 entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry1211 = new Entity() entry1211.column = "C" entry1211.row = 3 entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Assing entry121 from entry12 to entry11 entry11.children = [entry121] await repo.save(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Nested/MultiID/Save) Move multiple branches with single root via children", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 12 }, { column: "A", row: 2, left: 2, right: 7 }, { column: "A", row: 3, left: 8, right: 11 }, { column: "B", row: 2, left: 9, right: 10 }, { column: "B", row: 3, left: 3, right: 6 }, { column: "C", row: 3, left: 4, right: 5 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.parent = entry1 entry11.column = "A" entry11.row = 2 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry111 = new Entity() entry111.column = "B" entry111.row = 2 entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry121 = new Entity() entry121.column = "B" entry121.row = 3 entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry1211 = new Entity() entry1211.column = "C" entry1211.row = 3 entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Assing entry121 from entry12 to entry11 // And entry111 from entry11 to entry12 entry11.children = [entry121] entry12.children = [entry111] await repo.save([entry11, entry12]) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) let descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Nested/MultiID/Remove) Remove leaf with single root", () => Promise.all( connections.map(async (connection) => { const expectedResults = [ { column: "A", row: 1, left: 1, right: 2 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Remove entry11 from entry1 await repo.remove(entry11) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Nested/MultiID/Remove) Remove branch with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const expectedResults = [ { column: "A", row: 1, left: 1, right: 6 }, { column: "A", row: 2, left: 2, right: 3 }, { column: "A", row: 3, left: 4, right: 5 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry111 = new Entity() entry111.column = "B" entry111.row = 2 entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry1111 = new Entity() entry1111.column = "C" entry1111.row = 2 entry1111.parent = entry111 nestedSet = await repo.save(entry1111) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Remove entry111 from entry11 await repo.remove(entry111) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(1) }), )) it("(Nested/MultiID/Remove) Remove multiple branches with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const expectedResults = [ { column: "A", row: 1, left: 1, right: 6 }, { column: "A", row: 3, left: 2, right: 5 }, { column: "B", row: 3, left: 3, right: 4 }, ] const Entity = getEntity(connection, "multi_nested") const repo = connection.getTreeRepository(Entity) const ids: ObjectLiteral[] = [] let nestedSet: MultiIdNested const entry1 = new Entity() entry1.column = "A" entry1.row = 1 nestedSet = await repo.save(entry1) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 nestedSet = await repo.save(entry11) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry111 = new Entity() entry111.column = "B" entry111.row = 2 entry111.parent = entry11 nestedSet = await repo.save(entry111) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry12 = new Entity() entry12.column = "A" entry12.row = 3 entry12.parent = entry1 nestedSet = await repo.save(entry12) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry121 = new Entity() entry121.column = "B" entry121.row = 3 entry121.parent = entry12 nestedSet = await repo.save(entry121) ids.push({ column: nestedSet.column, row: nestedSet.row }) const entry1211 = new Entity() entry1211.column = "C" entry1211.row = 3 entry1211.parent = entry121 nestedSet = await repo.save(entry1211) ids.push({ column: nestedSet.column, row: nestedSet.row }) // Remove entry11 and entry1211 await repo.remove([entry11, entry1211]) // Assertions const results = await getNestedSetIds(repo, ids) assert.isTrue(isResultExpected(results, expectedResults)) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) /** * Materialized path */ it("(Materialized/MultiID/Save) Update without parent", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry2 = new Entity() entry2.column = "B" entry2.row = 1 await repo.save(entry2) entry2.name = "entry2" await repo.save(entry2) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(1) }), )) it("(Materialized/MultiID/Save) Update without tree change", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 await repo.save(entry11) entry11.name = "entry11" await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(2) }), )) it("(Materialized/MultiID/Save) Set leaf entity as root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 await repo.save(entry11) entry11.parent = null await repo.save(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Materialized/MultiID/Save) Move leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry2 = new Entity() entry2.column = "A" entry2.row = 2 await repo.save(entry2) const entry11 = new Entity() entry11.column = "B" entry11.row = 1 entry11.parent = entry1 await repo.save(entry11) // Assing entry11 from entry1 to entry2 entry11.parent = entry2 await repo.save(entry11) const descendants = await repo.findDescendants(entry2) descendants.length.should.be.eql(2) }), )) it("(Materialized/MultiID/Save) Move branch with single root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "B" entry11.row = 1 entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.column = "B" entry12.row = 2 entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.column = "C" entry121.row = 2 entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.column = "D" entry1211.row = 2 entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry121.parent = entry11 await repo.save(entry121) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Materialized/MultiID/Save) Move branch with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "B" entry11.row = 1 entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.column = "B" entry12.row = 2 entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.column = "C" entry121.row = 2 entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.column = "D" entry1211.row = 2 entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 entry11.children = [entry121] await repo.save(entry11) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) }), )) it("(Materialized/MultiID/Save) Move multiple branches with single root via children", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "B" entry11.row = 1 entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.column = "C" entry111.row = 1 entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.column = "B" entry12.row = 2 entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.column = "C" entry121.row = 2 entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.column = "D" entry1211.row = 2 entry1211.parent = entry121 await repo.save(entry1211) // Assing entry121 from entry12 to entry11 // And entry111 from entry11 to entry12 entry11.children = [entry121] entry12.children = [entry111] await repo.save([entry11, entry12]) let descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) it("(Materialized/MultiID/Remove) Remove leaf with multi root", () => Promise.all( connections.map(async (connection) => { const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry2 = new Entity() entry2.column = "B" entry2.row = 1 await repo.save(entry2) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 await repo.save(entry11) // Remove entry11 from entry1 await repo.remove(entry11) const descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(1) }), )) it("(Materialized/MultiID/Remove) Remove branch with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "A" entry11.row = 2 entry11.parent = entry1 await repo.save(entry11) const entry12 = new Entity() entry12.column = "B" entry12.row = 2 entry12.parent = entry1 await repo.save(entry12) const entry111 = new Entity() entry111.column = "C" entry111.row = 1 entry111.parent = entry11 await repo.save(entry111) const entry1111 = new Entity() entry1111.column = "D" entry1111.row = 1 entry1111.parent = entry111 await repo.save(entry1111) // Remove entry111 from entry11 await repo.remove(entry111) const descendants = await repo.findDescendants(entry11) descendants.length.should.be.eql(1) }), )) it("(Materialized/MultiID/Remove) Remove multiple branches with single root", () => Promise.all( connections.map(async (connection) => { if (connection.driver.options.type === "mssql") { // This test will not working on sql server return } const Entity = getEntity(connection, "multi_materialized") const repo = connection.getTreeRepository(Entity) const entry1 = new Entity() entry1.column = "A" entry1.row = 1 await repo.save(entry1) const entry11 = new Entity() entry11.column = "B" entry11.row = 1 entry11.parent = entry1 await repo.save(entry11) const entry111 = new Entity() entry111.column = "C" entry111.row = 1 entry111.parent = entry11 await repo.save(entry111) const entry12 = new Entity() entry12.column = "B" entry12.row = 2 entry12.parent = entry1 await repo.save(entry12) const entry121 = new Entity() entry121.column = "C" entry121.row = 2 entry121.parent = entry12 await repo.save(entry121) const entry1211 = new Entity() entry1211.column = "D" entry1211.row = 2 entry1211.parent = entry121 await repo.save(entry1211) // Remove entry11 and entry1211 await repo.remove([entry11, entry1211]) let descendants = await repo.findDescendants(entry1) descendants.length.should.be.eql(3) descendants = await repo.findDescendants(entry12) descendants.length.should.be.eql(2) }), )) }) describe("github issues > #7155 > tree relations", () => { let connections: DataSource[] before( async () => (connections = await createTestingConnections({ entities: [__dirname + "/entity/RelationEntities{.js,.ts}"], enabledDrivers: ["mysql", "postgres", "mssql"], })), ) beforeEach(() => reloadTestingDatabases(connections)) after(() => closeTestingConnections(connections)) it("(Closure) Validate relations", () => Promise.all( connections.map(async (connection) => { const repo = connection.getTreeRepository(RelationClosure) const relationRepo = connection.getRepository(Relation) const relation = new Relation() await relationRepo.save(relation) const relationEntity = new RelationClosure() relationEntity.relation = relation relationEntity.otherRelation = new OtherRelation() const result = await repo.save(relationEntity) result.should.exist }), )) it("(Nested) Validate relations", () => Promise.all( connections.map(async (connection) => { const repo = connection.getTreeRepository(RelationNested) const relationRepo = connection.getRepository(Relation) const relation = new Relation() await relationRepo.save(relation) const relationEntity = new RelationNested() relationEntity.relation = relation relationEntity.otherRelation = new OtherRelation() const result = await repo.save(relationEntity) result.should.exist }), )) it("(Materialized) Validate relations", () => Promise.all( connections.map(async (connection) => { const repo = connection.getTreeRepository(RelationMaterialized) const relationRepo = connection.getRepository(Relation) const relation = new Relation() await relationRepo.save(relation) const relationEntity = new RelationMaterialized() relationEntity.relation = relation relationEntity.otherRelation = new OtherRelation() const result = await repo.save(relationEntity) result.should.exist }), )) }) /** * HELPER FUNCTIONS */ function getNestedSetIds( repo: TreeRepository, ids: ObjectLiteral[], ): Promise { const escape = (alias: string) => repo.manager.connection.driver.escape(alias) const select = { left: `${repo.metadata.targetName}.${ repo.metadata.nestedSetLeftColumn!.propertyPath }`, right: `${repo.metadata.targetName}.${ repo.metadata.nestedSetRightColumn!.propertyPath }`, } const queryBuilder = repo.createQueryBuilder() if (ids.length > 0) { let setFirstSelect = true Object.keys(ids[0]).forEach((key) => { key = escape(key) if (setFirstSelect) { queryBuilder.select(key) queryBuilder.orderBy(key) setFirstSelect = false } else { queryBuilder.addSelect(key) queryBuilder.addOrderBy(key) } }) Object.entries(select).forEach(([key, value]) => { queryBuilder.addSelect(value, key) }) return queryBuilder .whereInIds(ids) .getRawMany() .then((results) => { const data = [] for (const result of results) { const entry: any = {} for (const key of Object.keys(result)) { const value = result[key] // CockroachDB returns numeric types as string const parsedValue = parseInt(value) entry[key] = isNaN(parsedValue) ? value : parsedValue } data.push(entry) } return data }) } return Promise.resolve() } function isResultExpected( results: ObjectLiteral[], expectedResults: ObjectLiteral[], ): boolean { return results.every((result, index) => { return ( Object.keys(result).length === Object.keys(expectedResults[index]).length && Object.keys(result).every( (key) => result[key] === expectedResults[index][key], ) ) }) } async function generateConnections(): Promise { const connections = await Promise.all([ createTestingConnections({ entities: [__dirname + "/entity/Remaining*{.js,.ts}"], enabledDrivers: ["mysql", "postgres"], }), createTestingConnections({ entities: [__dirname + "/entity/SqlServer*{.js,.ts}"], enabledDrivers: ["mssql"], }), ]) let result: DataSource[] = [] for (const connection of connections) { result = result.concat(connection) } return result } function getEntity(connection: DataSource, type: EntityType): any { if (connection.driver.options.type === "mssql") { return entityMap[type]["mssql"] } return entityMap[type]["other"] } type EntityType = | "single_closure" | "single_nested" | "single_materialized" | "multi_nested" | "multi_materialized" const entityMap = { single_closure: { mssql: SqlServerSingleIdClosure, other: SingleIdClosure, }, single_nested: { mssql: SqlServerSingleIdNested, other: SingleIdNested, }, single_materialized: { mssql: SqlServerSingleIdMaterialized, other: SingleIdMaterialized, }, multi_nested: { mssql: SqlServerMultiIdNested, other: MultiIdNested, }, multi_materialized: { mssql: SqlServerMultiIdMaterialized, other: MultiIdMaterialized, }, }