Skip to content

Commit 01007d4

Browse files
authored
Merge branch 'develop' into polymorph
2 parents aeb42ad + c7dfa51 commit 01007d4

File tree

2 files changed

+32
-10
lines changed

2 files changed

+32
-10
lines changed

src/TransformOperationExecutor.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class TransformOperationExecutor {
1515
// Private Properties
1616
// -------------------------------------------------------------------------
1717

18-
private transformedTypesMap = new Map<Object, { level: number, object: Object }>();
18+
private recursionStack = new Set<Object>();
1919

2020
// -------------------------------------------------------------------------
2121
// Constructor
@@ -40,7 +40,7 @@ export class TransformOperationExecutor {
4040
const newValue = arrayType && this.transformationType === TransformationType.PLAIN_TO_CLASS ? new (arrayType as any)() : [];
4141
(value as any[]).forEach((subValue, index) => {
4242
const subSource = source ? source[index] : undefined;
43-
if (!this.options.enableCircularCheck || !this.isCircular(subValue, level)) {
43+
if (!this.options.enableCircularCheck || !this.isCircular(subValue)) {
4444
let realTargetType;
4545
if (typeof targetType !== "function" && targetType && targetType.options && targetType.options.discriminator && targetType.options.discriminator.property && targetType.options.discriminator.subTypes) {
4646
if (this.transformationType === TransformationType.PLAIN_TO_CLASS) {
@@ -60,6 +60,7 @@ export class TransformOperationExecutor {
6060
realTargetType = targetType;
6161
}
6262
const value = this.transform(subSource, subValue, realTargetType, undefined, subValue instanceof Map, level + 1);
63+
6364
if (newValue instanceof Set) {
6465
newValue.add(value);
6566
} else {
@@ -106,7 +107,7 @@ export class TransformOperationExecutor {
106107

107108
if (this.options.enableCircularCheck) {
108109
// add transformed type to prevent circular references
109-
this.transformedTypesMap.set(value, { level: level, object: value });
110+
this.recursionStack.add(value);
110111
}
111112

112113
const keys = this.getKeys((targetType as Function), value);
@@ -208,7 +209,7 @@ export class TransformOperationExecutor {
208209
continue;
209210
}
210211

211-
if (!this.options.enableCircularCheck || !this.isCircular(subValue, level)) {
212+
if (!this.options.enableCircularCheck || !this.isCircular(subValue)) {
212213
let transformKey = this.transformationType === TransformationType.PLAIN_TO_CLASS ? newValueKey : key;
213214
let finalValue;
214215

@@ -242,6 +243,11 @@ export class TransformOperationExecutor {
242243
}
243244

244245
}
246+
247+
if (this.options.enableCircularCheck) {
248+
this.recursionStack.delete(value);
249+
}
250+
245251
return newValue;
246252

247253
} else {
@@ -284,9 +290,8 @@ export class TransformOperationExecutor {
284290
}
285291

286292
// preventing circular references
287-
private isCircular(object: Object, level: number) {
288-
const transformed = this.transformedTypesMap.get(object);
289-
return transformed !== undefined && transformed.level < level;
293+
private isCircular(object: Object) {
294+
return this.recursionStack.has(object);
290295
}
291296

292297
private getReflectedType(target: Function, propertyName: string) {

test/functional/circular-reference-problem.spec.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,26 @@ import * as sinon from "sinon";
77

88
describe("circular reference problem", () => {
99

10-
it("should skip circular reference objects", () => {
10+
it("should skip circular reference objects in classToPlain operation", () => {
1111
defaultMetadataStorage.clear();
1212

13+
class Caption {
14+
text: string;
15+
}
16+
1317
class Photo {
1418
id: number;
1519
filename: string;
1620
user: User;
1721
users: User[];
22+
23+
caption: Caption;
1824
}
1925

2026
class User {
2127
id: number;
2228
firstName: string;
29+
caption: Caption;
2330
photos: Photo[];
2431
}
2532

@@ -31,7 +38,11 @@ describe("circular reference problem", () => {
3138
photo2.id = 2;
3239
photo2.filename = "she.jpg";
3340

41+
const caption = new Caption();
42+
caption.text = "cool photo";
43+
3444
const user = new User();
45+
user.caption = caption;
3546
user.firstName = "Umed Khudoiberdiev";
3647
user.photos = [photo1, photo2];
3748

@@ -40,17 +51,23 @@ describe("circular reference problem", () => {
4051
photo1.users = [user];
4152
photo2.users = [user];
4253

54+
photo1.caption = caption;
55+
photo2.caption = caption;
56+
4357
const plainUser = classToPlain(user, { enableCircularCheck: true });
4458
plainUser.should.be.eql({
4559
firstName: "Umed Khudoiberdiev",
60+
caption: { text: "cool photo" },
4661
photos: [{
4762
id: 1,
4863
filename: "me.jpg",
49-
users: []
64+
users: [],
65+
caption: { text: "cool photo" }
5066
}, {
5167
id: 2,
5268
filename: "she.jpg",
53-
users: []
69+
users: [],
70+
caption: { text: "cool photo" }
5471
}]
5572
});
5673

0 commit comments

Comments
 (0)