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

typeorm / typeorm / 15219332477

23 May 2025 09:13PM UTC coverage: 17.216% (-59.1%) from 76.346%
15219332477

Pull #11332

github

naorpeled
cr comments - move if block
Pull Request #11332: feat: add new undefined and null behavior flags

1603 of 12759 branches covered (12.56%)

Branch coverage included in aggregate %.

0 of 31 new or added lines in 3 files covered. (0.0%)

14132 existing lines in 166 files now uncovered.

4731 of 24033 relevant lines covered (19.69%)

60.22 hits per line

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

7.79
/src/query-builder/RelationQueryBuilder.ts
1
import { QueryBuilder } from "./QueryBuilder"
1✔
2
import { RelationUpdater } from "./RelationUpdater"
1✔
3
import { RelationRemover } from "./RelationRemover"
1✔
4
import { TypeORMError } from "../error"
1✔
5
import { ObjectUtils } from "../util/ObjectUtils"
1✔
6
import { ObjectLiteral } from "../common/ObjectLiteral"
7

8
/**
9
 * Allows to work with entity relations and perform specific operations with those relations.
10
 *
11
 * todo: add transactions everywhere
12
 */
13
export class RelationQueryBuilder<
1✔
14
    Entity extends ObjectLiteral,
15
> extends QueryBuilder<Entity> {
UNCOV
16
    readonly "@instanceof" = Symbol.for("RelationQueryBuilder")
×
17

18
    // -------------------------------------------------------------------------
19
    // Public Implemented Methods
20
    // -------------------------------------------------------------------------
21

22
    /**
23
     * Gets generated SQL query without parameters being replaced.
24
     */
25
    getQuery(): string {
26
        return ""
×
27
    }
28

29
    // -------------------------------------------------------------------------
30
    // Public Methods
31
    // -------------------------------------------------------------------------
32

33
    /**
34
     * Sets entity (target) which relations will be updated.
35
     */
36
    of(entity: any | any[]): this {
UNCOV
37
        this.expressionMap.of = entity
×
UNCOV
38
        return this
×
39
    }
40

41
    /**
42
     * Sets entity relation's value.
43
     * Value can be entity, entity id or entity id map (if entity has composite ids).
44
     * Works only for many-to-one and one-to-one relations.
45
     * For many-to-many and one-to-many relations use #add and #remove methods instead.
46
     */
47
    async set(value: any): Promise<void> {
UNCOV
48
        const relation = this.expressionMap.relationMetadata
×
49

UNCOV
50
        if (!this.expressionMap.of)
×
51
            // todo: move this check before relation query builder creation?
52
            throw new TypeORMError(
×
53
                `Entity whose relation needs to be set is not set. Use .of method to define whose relation you want to set.`,
54
            )
55

UNCOV
56
        if (relation.isManyToMany || relation.isOneToMany)
×
57
            throw new TypeORMError(
×
58
                `Set operation is only supported for many-to-one and one-to-one relations. ` +
59
                    `However given "${relation.propertyPath}" has ${relation.relationType} relation. ` +
60
                    `Use .add() method instead.`,
61
            )
62

63
        // if there are multiple join columns then user must send id map as "value" argument. check if he really did it
UNCOV
64
        if (
×
65
            relation.joinColumns &&
×
66
            relation.joinColumns.length > 1 &&
67
            (!ObjectUtils.isObject(value) ||
68
                Object.keys(value).length < relation.joinColumns.length)
69
        )
70
            throw new TypeORMError(
×
71
                `Value to be set into the relation must be a map of relation ids, for example: .set({ firstName: "...", lastName: "..." })`,
72
            )
73

UNCOV
74
        const updater = new RelationUpdater(this, this.expressionMap)
×
UNCOV
75
        return updater.update(value)
×
76
    }
77

78
    /**
79
     * Adds (binds) given value to entity relation.
80
     * Value can be entity, entity id or entity id map (if entity has composite ids).
81
     * Value also can be array of entities, array of entity ids or array of entity id maps (if entity has composite ids).
82
     * Works only for many-to-many and one-to-many relations.
83
     * For many-to-one and one-to-one use #set method instead.
84
     */
85
    async add(value: any | any[]): Promise<void> {
UNCOV
86
        if (Array.isArray(value) && value.length === 0) return
×
87

UNCOV
88
        const relation = this.expressionMap.relationMetadata
×
89

UNCOV
90
        if (!this.expressionMap.of)
×
91
            // todo: move this check before relation query builder creation?
92
            throw new TypeORMError(
×
93
                `Entity whose relation needs to be set is not set. Use .of method to define whose relation you want to set.`,
94
            )
95

UNCOV
96
        if (relation.isManyToOne || relation.isOneToOne)
×
97
            throw new TypeORMError(
×
98
                `Add operation is only supported for many-to-many and one-to-many relations. ` +
99
                    `However given "${relation.propertyPath}" has ${relation.relationType} relation. ` +
100
                    `Use .set() method instead.`,
101
            )
102

103
        // if there are multiple join columns then user must send id map as "value" argument. check if he really did it
UNCOV
104
        if (
×
105
            relation.joinColumns &&
×
106
            relation.joinColumns.length > 1 &&
107
            (!ObjectUtils.isObject(value) ||
108
                Object.keys(value).length < relation.joinColumns.length)
109
        )
110
            throw new TypeORMError(
×
111
                `Value to be set into the relation must be a map of relation ids, for example: .set({ firstName: "...", lastName: "..." })`,
112
            )
113

UNCOV
114
        const updater = new RelationUpdater(this, this.expressionMap)
×
UNCOV
115
        return updater.update(value)
×
116
    }
117

118
    /**
119
     * Removes (unbinds) given value from entity relation.
120
     * Value can be entity, entity id or entity id map (if entity has composite ids).
121
     * Value also can be array of entities, array of entity ids or array of entity id maps (if entity has composite ids).
122
     * Works only for many-to-many and one-to-many relations.
123
     * For many-to-one and one-to-one use #set method instead.
124
     */
125
    async remove(value: any | any[]): Promise<void> {
UNCOV
126
        if (Array.isArray(value) && value.length === 0) return
×
127

UNCOV
128
        const relation = this.expressionMap.relationMetadata
×
129

UNCOV
130
        if (!this.expressionMap.of)
×
131
            // todo: move this check before relation query builder creation?
132
            throw new TypeORMError(
×
133
                `Entity whose relation needs to be set is not set. Use .of method to define whose relation you want to set.`,
134
            )
135

UNCOV
136
        if (relation.isManyToOne || relation.isOneToOne)
×
137
            throw new TypeORMError(
×
138
                `Add operation is only supported for many-to-many and one-to-many relations. ` +
139
                    `However given "${relation.propertyPath}" has ${relation.relationType} relation. ` +
140
                    `Use .set(null) method instead.`,
141
            )
142

UNCOV
143
        const remover = new RelationRemover(this, this.expressionMap)
×
UNCOV
144
        return remover.remove(value)
×
145
    }
146

147
    /**
148
     * Adds (binds) and removes (unbinds) given values to/from entity relation.
149
     * Value can be entity, entity id or entity id map (if entity has composite ids).
150
     * Value also can be array of entities, array of entity ids or array of entity id maps (if entity has composite ids).
151
     * Works only for many-to-many and one-to-many relations.
152
     * For many-to-one and one-to-one use #set method instead.
153
     */
154
    async addAndRemove(
155
        added: any | any[],
156
        removed: any | any[],
157
    ): Promise<void> {
UNCOV
158
        await this.remove(removed)
×
UNCOV
159
        await this.add(added)
×
160
    }
161

162
    /**
163
     * Gets entity's relation id.
164
    async getId(): Promise<any> {
165

166
    }*/
167

168
    /**
169
     * Gets entity's relation ids.
170
    async getIds(): Promise<any[]> {
171
        return [];
172
    }*/
173

174
    /**
175
     * Loads a single entity (relational) from the relation.
176
     * You can also provide id of relational entity to filter by.
177
     */
178
    async loadOne<T = any>(): Promise<T | undefined> {
UNCOV
179
        return this.loadMany<T>().then((results) => results[0])
×
180
    }
181

182
    /**
183
     * Loads many entities (relational) from the relation.
184
     * You can also provide ids of relational entities to filter by.
185
     */
186
    async loadMany<T = any>(): Promise<T[]> {
UNCOV
187
        let of = this.expressionMap.of
×
UNCOV
188
        if (!ObjectUtils.isObject(of)) {
×
UNCOV
189
            const metadata = this.expressionMap.mainAlias!.metadata
×
UNCOV
190
            if (metadata.hasMultiplePrimaryKeys)
×
191
                throw new TypeORMError(
×
192
                    `Cannot load entity because only one primary key was specified, however entity contains multiple primary keys`,
193
                )
194

UNCOV
195
            of = metadata.primaryColumns[0].createValueMap(of)
×
196
        }
197

UNCOV
198
        return this.connection.relationLoader.load(
×
199
            this.expressionMap.relationMetadata,
200
            of,
201
            this.queryRunner,
202
        )
203
    }
204
}
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