• 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

67.12
/src/query-builder/transformer/PlainObjectToDatabaseEntityTransformer.ts
1
import { ObjectLiteral } from "../../common/ObjectLiteral"
2
import { EntityMetadata } from "../../metadata/EntityMetadata"
3
import { EntityManager } from "../../entity-manager/EntityManager"
4
import { RelationMetadata } from "../../metadata/RelationMetadata"
5

6
/**
7
 */
8
class LoadMapItem {
9
    entity?: ObjectLiteral
10
    plainEntity: ObjectLiteral
11
    metadata: EntityMetadata
12
    parentLoadMapItem?: LoadMapItem
13
    relation?: RelationMetadata
14

15
    constructor(
16
        plainEntity: ObjectLiteral,
17
        metadata: EntityMetadata,
18
        parentLoadMapItem?: LoadMapItem,
19
        relation?: RelationMetadata,
20
    ) {
21
        this.plainEntity = plainEntity
1✔
22
        this.metadata = metadata
1✔
23
        this.parentLoadMapItem = parentLoadMapItem
1✔
24
        this.relation = relation
1✔
25
    }
26

27
    get target(): Function | string {
28
        return this.metadata.target
2✔
29
    }
30

31
    get id(): any {
32
        return this.metadata.getEntityIdMixedMap(this.plainEntity)
1✔
33
    }
34
}
35

36
class LoadMap {
37
    loadMapItems: LoadMapItem[] = []
1✔
38

39
    get mainLoadMapItem(): LoadMapItem | undefined {
40
        return this.loadMapItems.find(
2✔
41
            (item) => !item.relation && !item.parentLoadMapItem,
2✔
42
        )
43
    }
44

45
    addLoadMap(newLoadMap: LoadMapItem) {
46
        const item = this.loadMapItems.find(
1✔
47
            (item) =>
UNCOV
48
                item.target === newLoadMap.target && item.id === newLoadMap.id,
×
49
        )
50
        if (!item) this.loadMapItems.push(newLoadMap)
1✔
51
    }
52

53
    fillEntities(target: Function | string, entities: any[]) {
54
        entities.forEach((entity) => {
1✔
55
            const item = this.loadMapItems.find((loadMapItem) => {
1✔
56
                return (
1✔
57
                    loadMapItem.target === target &&
2✔
58
                    loadMapItem.metadata.compareEntities(
59
                        entity,
60
                        loadMapItem.plainEntity,
61
                    )
62
                )
63
            })
64
            if (item) item.entity = entity
1✔
65
        })
66
    }
67

68
    groupByTargetIds(): { target: Function | string; ids: any[] }[] {
69
        const groups: { target: Function | string; ids: any[] }[] = []
1✔
70
        this.loadMapItems.forEach((loadMapItem) => {
1✔
71
            let group = groups.find(
1✔
UNCOV
72
                (group) => group.target === loadMapItem.target,
×
73
            )
74
            if (!group) {
1✔
75
                group = { target: loadMapItem.target, ids: [] }
1✔
76
                groups.push(group)
1✔
77
            }
78

79
            group.ids.push(loadMapItem.id)
1✔
80
        })
81
        return groups
1✔
82
    }
83
}
84

85
/**
86
 * Transforms plain old javascript object
87
 * Entity is constructed based on its entity metadata.
88
 */
89
export class PlainObjectToDatabaseEntityTransformer {
1✔
90
    constructor(private manager: EntityManager) {}
1✔
91

92
    // -------------------------------------------------------------------------
93
    // Public Methods
94
    // -------------------------------------------------------------------------
95

96
    async transform(
97
        plainObject: ObjectLiteral,
98
        metadata: EntityMetadata,
99
    ): Promise<ObjectLiteral | undefined> {
100
        // if plain object does not have id then nothing to load really
101
        if (!metadata.hasAllPrimaryKeys(plainObject))
1!
102
            return Promise.reject(
×
103
                "Given object does not have a primary column, cannot transform it to database entity.",
104
            )
105

106
        // create a special load map that will hold all metadata that will be used to operate with entities easily
107
        const loadMap = new LoadMap()
1✔
108
        const fillLoadMap = (
1✔
109
            entity: ObjectLiteral,
110
            entityMetadata: EntityMetadata,
111
            parentLoadMapItem?: LoadMapItem,
112
            relation?: RelationMetadata,
113
        ) => {
114
            const item = new LoadMapItem(
1✔
115
                entity,
116
                entityMetadata,
117
                parentLoadMapItem,
118
                relation,
119
            )
120
            loadMap.addLoadMap(item)
1✔
121

122
            entityMetadata
1✔
123
                .extractRelationValuesFromEntity(entity, metadata.relations)
UNCOV
124
                .filter((value) => value !== null && value !== undefined)
×
125
                .forEach(([relation, value, inverseEntityMetadata]) =>
UNCOV
126
                    fillLoadMap(value, inverseEntityMetadata, item, relation),
×
127
                )
128
        }
129
        fillLoadMap(plainObject, metadata)
1✔
130
        // load all entities and store them in the load map
131
        await Promise.all(
1✔
132
            loadMap.groupByTargetIds().map((targetWithIds) => {
133
                // todo: fix type hinting
134
                return this.manager
1✔
135
                    .findByIds<ObjectLiteral>(
136
                        targetWithIds.target as any,
137
                        targetWithIds.ids,
138
                    )
139
                    .then((entities) =>
140
                        loadMap.fillEntities(targetWithIds.target, entities),
1✔
141
                    )
142
            }),
143
        )
144

145
        // go through each item in the load map and set their entity relationship using metadata stored in load map
146
        loadMap.loadMapItems.forEach((loadMapItem) => {
1✔
147
            if (
1✔
148
                !loadMapItem.relation ||
1!
149
                !loadMapItem.entity ||
150
                !loadMapItem.parentLoadMapItem ||
151
                !loadMapItem.parentLoadMapItem.entity
152
            )
153
                return
1✔
154

UNCOV
155
            if (
×
156
                loadMapItem.relation.isManyToMany ||
×
157
                loadMapItem.relation.isOneToMany
158
            ) {
UNCOV
159
                if (
×
160
                    !loadMapItem.parentLoadMapItem.entity[
161
                        loadMapItem.relation.propertyName
162
                    ]
163
                )
UNCOV
164
                    loadMapItem.parentLoadMapItem.entity[
×
165
                        loadMapItem.relation.propertyName
166
                    ] = []
UNCOV
167
                loadMapItem.parentLoadMapItem.entity[
×
168
                    loadMapItem.relation.propertyName
169
                ].push(loadMapItem.entity)
170
            } else {
UNCOV
171
                loadMapItem.parentLoadMapItem.entity[
×
172
                    loadMapItem.relation.propertyName
173
                ] = loadMapItem.entity
174
            }
175
        })
176

177
        return loadMap.mainLoadMapItem
1!
178
            ? loadMap.mainLoadMapItem.entity
179
            : undefined
180
    }
181
}
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