Skip to content

Commit c7dfa51

Browse files
authored
Merge pull request #156 from FTRLabs/bugfix/128
Fix circular checks breaking nested serialized types #128
2 parents 7979723 + 6fc9cc5 commit c7dfa51

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

src/TransformOperationExecutor.ts

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

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

1919
// -------------------------------------------------------------------------
2020
// Constructor
@@ -39,7 +39,7 @@ export class TransformOperationExecutor {
3939
const newValue = arrayType && this.transformationType === TransformationType.PLAIN_TO_CLASS ? new (arrayType as any)() : [];
4040
(value as any[]).forEach((subValue, index) => {
4141
const subSource = source ? source[index] : undefined;
42-
if (!this.options.enableCircularCheck || !this.isCircular(subValue, level)) {
42+
if (!this.options.enableCircularCheck || !this.isCircular(subValue)) {
4343
const value = this.transform(subSource, subValue, targetType, undefined, subValue instanceof Map, level + 1);
4444
if (newValue instanceof Set) {
4545
newValue.add(value);
@@ -88,7 +88,7 @@ export class TransformOperationExecutor {
8888

8989
if (this.options.enableCircularCheck) {
9090
// add transformed type to prevent circular references
91-
this.transformedTypesMap.set(value, {level: level, object: value});
91+
this.recursionStack.add(value);
9292
}
9393

9494
const keys = this.getKeys(targetType, value);
@@ -168,7 +168,7 @@ export class TransformOperationExecutor {
168168
continue;
169169
}
170170

171-
if (!this.options.enableCircularCheck || !this.isCircular(subValue, level)) {
171+
if (!this.options.enableCircularCheck || !this.isCircular(subValue)) {
172172
let transformKey = this.transformationType === TransformationType.PLAIN_TO_CLASS ? newValueKey : key;
173173
let finalValue;
174174

@@ -202,6 +202,11 @@ export class TransformOperationExecutor {
202202
}
203203

204204
}
205+
206+
if (this.options.enableCircularCheck) {
207+
this.recursionStack.delete(value);
208+
}
209+
205210
return newValue;
206211

207212
} else {
@@ -244,9 +249,8 @@ export class TransformOperationExecutor {
244249
}
245250

246251
// preventing circular references
247-
private isCircular(object: Object, level: number) {
248-
const transformed = this.transformedTypesMap.get(object);
249-
return transformed !== undefined && transformed.level < level;
252+
private isCircular(object: Object) {
253+
return this.recursionStack.has(object);
250254
}
251255

252256
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)