Skip to content

Commit

Permalink
Merge pull request typeorm#3231 from joelgallant/enumerable-lazy-rela…
Browse files Browse the repository at this point in the history
…tion-props

Uses defineProperty so that __has_ and __promise_ variables are not enumerable
  • Loading branch information
pleerock committed Jan 3, 2019
2 parents 97b3e3e + 2d36ba1 commit 7d95c1a
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 13 deletions.
55 changes: 42 additions & 13 deletions src/query-builder/RelationLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export class RelationLoader {
const promiseIndex = "__promise_" + relation.propertyName + "__"; // in what property of the entity loading promise will be stored
const resolveIndex = "__has_" + relation.propertyName + "__"; // indicates if relation data already was loaded or not, we need this flag if loaded data is empty

// using defineProperty in these so that private properties are enumerable: false
Object.defineProperty(entity, relation.propertyName, {
get: function() {
if (this[resolveIndex] === true || this[dataIndex]) // if related data already was loaded then simply return it
Expand All @@ -198,28 +199,56 @@ export class RelationLoader {
return this[promiseIndex];

// nothing is loaded yet, load relation data and save it in the model once they are loaded
this[promiseIndex] = relationLoader.load(relation, this, queryRunner).then(result => {
if (relation.isOneToOne || relation.isManyToOne) result = result[0];
this[dataIndex] = result;
this[resolveIndex] = true;
delete this[promiseIndex];
return this[dataIndex];
Object.defineProperty(this, promiseIndex, {
configurable: true,
value: relationLoader.load(relation, this, queryRunner).then(result => {
if (relation.isOneToOne || relation.isManyToOne) result = result[0];

Object.defineProperty(this, dataIndex, {
value: result,
writable: true,
});

Object.defineProperty(this, resolveIndex, {
value: true,
writable: true,
});

delete this[promiseIndex];
return this[dataIndex];
}),
});

return this[promiseIndex];
},
set: function(value: any|Promise<any>) {
if (value instanceof Promise) { // if set data is a promise then wait for its resolve and save in the object
if (value instanceof Promise) {
// if set data is a promise then wait for its resolve and save in the object
value.then(result => {
this[dataIndex] = result;
this[resolveIndex] = true;
Object.defineProperty(this, dataIndex, {
value: result,
writable: true,
});

Object.defineProperty(this, resolveIndex, {
value: true,
writable: true,
});
});
} else {
// if its direct data set (non promise, probably not safe-typed)
Object.defineProperty(this, dataIndex, {
value,
writable: true,
});

} else { // if its direct data set (non promise, probably not safe-typed)
this[dataIndex] = value;
this[resolveIndex] = true;
Object.defineProperty(this, resolveIndex, {
value: true,
writable: true,
});
}
},
configurable: true
configurable: true,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,32 @@ describe("basic-lazy-relations", () => {
const loadedPost = await loadedCategory!.onePost;
loadedPost.title.should.be.equal("post with great category");
})));

it("should not enumerate private resolved promises", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(Post);
const categoryRepository = connection.getRepository(Category);

const savedCategory = new Category();
savedCategory.name = "animals";

await categoryRepository.save(savedCategory);

const savedPost = new Post();
savedPost.title = "Hello post";
savedPost.text = "This is post about post";
savedPost.categories = Promise.resolve([ savedCategory ]);

await postRepository.save(savedPost);

const post = (await postRepository.findOne(1))!;
post.title.should.be.equal("Hello post");

const categories = await post.categories;

post.propertyIsEnumerable("__categories__").should.be.equal(false);
post.propertyIsEnumerable("__promise_categories__").should.be.equal(false);
post.propertyIsEnumerable("__has_categories__").should.be.equal(false);

categories.length.should.be.equal(1);
})));
});

0 comments on commit 7d95c1a

Please sign in to comment.