• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

typeorm / typeorm / 14796576772

02 May 2025 01:52PM UTC coverage: 45.367% (-30.9%) from 76.309%
14796576772

Pull #11434

github

web-flow
Merge ec4ce2d00 into fadad1a74
Pull Request #11434: feat: release PR releases using pkg.pr.new

5216 of 12761 branches covered (40.87%)

Branch coverage included in aggregate %.

11439 of 23951 relevant lines covered (47.76%)

15712.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.08
/src/persistence/tree/MaterializedPathSubjectExecutor.ts
1
import { Subject } from "../Subject"
2
import { QueryRunner } from "../../query-runner/QueryRunner"
3
import { OrmUtils } from "../../util/OrmUtils"
4✔
4
import { ObjectLiteral } from "../../common/ObjectLiteral"
5
import { ColumnMetadata } from "../../metadata/ColumnMetadata"
6
import { EntityMetadata } from "../../metadata/EntityMetadata"
4✔
7
import { Brackets } from "../../query-builder/Brackets"
4✔
8

9
/**
10
 * Executes subject operations for materialized-path tree entities.
11
 */
12
export class MaterializedPathSubjectExecutor {
4✔
13
    // -------------------------------------------------------------------------
14
    // Constructor
15
    // -------------------------------------------------------------------------
16

17
    constructor(protected queryRunner: QueryRunner) {}
656✔
18

19
    // -------------------------------------------------------------------------
20
    // Public Methods
21
    // -------------------------------------------------------------------------
22

23
    /**
24
     * Executes operations when subject is being inserted.
25
     */
26
    async insert(subject: Subject): Promise<void> {
27
        let parent = subject.metadata.treeParentRelation!.getEntityValue(
652✔
28
            subject.entity!,
29
        ) // if entity was attached via parent
30
        if (!parent && subject.parentSubject && subject.parentSubject.entity)
652✔
31
            // if entity was attached via children
32
            parent = subject.parentSubject.insertedValueSet
256✔
33
                ? subject.parentSubject.insertedValueSet
34
                : subject.parentSubject.entity
35

36
        const parentId = subject.metadata.getEntityIdMap(parent)
652✔
37

38
        let parentPath: string = ""
652✔
39
        if (parentId) {
652✔
40
            parentPath = await this.getEntityPath(subject, parentId)
432✔
41
        }
42

43
        const insertedEntityId = subject.metadata
652✔
44
            .treeParentRelation!.joinColumns.map((joinColumn) => {
45
                return joinColumn.referencedColumn!.getEntityValue(
652✔
46
                    subject.insertedValueSet!,
47
                )
48
            })
49
            .join("_")
50

51
        await this.queryRunner.manager
652✔
52
            .createQueryBuilder()
53
            .update(subject.metadata.target)
54
            .set({
55
                [subject.metadata.materializedPathColumn!.propertyPath]:
56
                    parentPath + insertedEntityId + ".",
57
            } as any)
58
            .where(subject.identifier!)
59
            .execute()
60
    }
61

62
    /**
63
     * Executes operations when subject is being updated.
64
     */
65
    async update(subject: Subject): Promise<void> {
66
        let newParent = subject.metadata.treeParentRelation!.getEntityValue(
4✔
67
            subject.entity!,
68
        ) // if entity was attached via parent
69
        if (!newParent && subject.parentSubject && subject.parentSubject.entity)
4!
70
            // if entity was attached via children
71
            newParent = subject.parentSubject.entity
×
72

73
        let entity = subject.databaseEntity // if entity was attached via parent
4✔
74
        if (!entity && newParent)
4!
75
            // if entity was attached via children
76
            entity = subject.metadata
×
77
                .treeChildrenRelation!.getEntityValue(newParent)
78
                .find((child: any) => {
79
                    return Object.entries(subject.identifier!).every(
×
80
                        ([key, value]) => child[key] === value,
×
81
                    )
82
                })
83

84
        const oldParent = subject.metadata.treeParentRelation!.getEntityValue(
4✔
85
            entity!,
86
        )
87
        const oldParentId = this.getEntityParentReferencedColumnMap(
4✔
88
            subject,
89
            oldParent,
90
        )
91
        const newParentId = this.getEntityParentReferencedColumnMap(
4✔
92
            subject,
93
            newParent,
94
        )
95

96
        // Exit if the new and old parents are the same
97
        if (OrmUtils.compareIds(oldParentId, newParentId)) {
4!
98
            return
×
99
        }
100

101
        let newParentPath: string = ""
4✔
102
        if (newParentId) {
4!
103
            newParentPath = await this.getEntityPath(subject, newParentId)
×
104
        }
105

106
        let oldParentPath: string = ""
4✔
107
        if (oldParentId) {
4✔
108
            oldParentPath =
4✔
109
                (await this.getEntityPath(subject, oldParentId)) || ""
4!
110
        }
111

112
        const entityPath = subject.metadata
4✔
113
            .treeParentRelation!.joinColumns.map((joinColumn) => {
114
                return joinColumn.referencedColumn!.getEntityValue(entity!)
4✔
115
            })
116
            .join("_")
117

118
        const propertyPath =
119
            subject.metadata.materializedPathColumn!.propertyPath
4✔
120
        await this.queryRunner.manager
4✔
121
            .createQueryBuilder()
122
            .update(subject.metadata.target)
123
            .set({
124
                [propertyPath]: () =>
125
                    `REPLACE(${this.queryRunner.connection.driver.escape(
4✔
126
                        propertyPath,
127
                    )}, '${oldParentPath}${entityPath}.', '${newParentPath}${entityPath}.')`,
128
            } as any)
129
            .where(`${propertyPath} LIKE :path`, {
130
                path: `${oldParentPath}${entityPath}.%`,
131
            })
132
            .execute()
133
    }
134

135
    private getEntityParentReferencedColumnMap(
136
        subject: Subject,
137
        entity: ObjectLiteral | undefined,
138
    ): ObjectLiteral | undefined {
139
        if (!entity) return undefined
8✔
140
        return EntityMetadata.getValueMap(
4✔
141
            entity,
142
            subject.metadata
143
                .treeParentRelation!.joinColumns.map(
144
                    (column) => column.referencedColumn,
4✔
145
                )
146
                .filter((v) => v != null) as ColumnMetadata[],
4✔
147
            { skipNulls: true },
148
        )
149
    }
150

151
    private getEntityPath(
152
        subject: Subject,
153
        id: ObjectLiteral,
154
    ): Promise<string> {
155
        const metadata = subject.metadata
436✔
156
        const normalized = (Array.isArray(id) ? id : [id]).map((id) =>
436!
157
            metadata.ensureEntityIdMap(id),
436✔
158
        )
159
        return this.queryRunner.manager
436✔
160
            .createQueryBuilder()
161
            .select(
162
                subject.metadata.targetName +
163
                    "." +
164
                    subject.metadata.materializedPathColumn!.propertyPath,
165
                "path",
166
            )
167
            .from(subject.metadata.target, subject.metadata.targetName)
168
            .where(
169
                new Brackets((qb) => {
170
                    for (const data of normalized) {
436✔
171
                        qb.orWhere(new Brackets((qb) => qb.where(data)))
436✔
172
                    }
173
                }),
174
            )
175
            .getRawOne()
176
            .then((result) => (result ? result["path"] : ""))
436✔
177
    }
178
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc