fixes and refactoring

This commit is contained in:
Zotov Dmitry 2017-05-17 10:50:51 +05:00
parent e03f54f341
commit 296ed7baf2
9 changed files with 81 additions and 56 deletions

View File

@ -3,7 +3,6 @@ import {ObjectLiteral} from "../common/ObjectLiteral";
import {Connection} from "../connection/Connection";
import {Subject} from "./Subject";
import {QueryRunnerProvider} from "../query-runner/QueryRunnerProvider";
import {SpecificRepository} from "../repository/SpecificRepository";
import {MongoDriver} from "../driver/mongodb/MongoDriver";
import {OrmUtils} from "../util/OrmUtils";
@ -342,7 +341,6 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
// (example) "relation" - is a relation in post with details.
// (example) "valueMetadata" - is an entity metadata of the Details object.
// (example) "persistValue" - is a detailsId from the persisted entity
// todo: fix joinColumns[0] usages
// note that if databaseEntity has relation, it can only be a relation id,
// because of query builder option "RELATION_ID_VALUES" we used
@ -732,18 +730,14 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
* Options specifies which junction operations should be built - insert, remove or both.
*/
private async buildJunctionOperations(options: { insert: boolean, remove: boolean }): Promise<void> {
const promises = this.operateSubjects.filter(subject => subject.hasEntity).map(subject => {
const promises = subject.metadata.manyToManyRelations.map(async relation => {
// if subject marked to be removed then all its junctions must be removed
if (subject.mustBeRemoved && options.remove) {
// load from db all relation ids of inverse entities that are "bind" to the currently persisted entity
// this way we gonna check which relation ids are missing and which are new (e.g. inserted or removed)
const specificRepository = new SpecificRepository(this.connection, subject.metadata, this.queryRunnerProvider);
const existInverseEntityRelationIds = await specificRepository
.findRelationIds(relation, subject.databaseEntity);
const existInverseEntityRelationIds = relation.getEntityValue(subject.databaseEntity);
// finally create a new junction remove operation and push it to the array of such operations
if (existInverseEntityRelationIds.length > 0) {
@ -775,10 +769,8 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
// if subject don't have database entity it means its new and we don't need to remove something that is not exist
if (subject.hasDatabaseEntity) {
const specificRepository = new SpecificRepository(this.connection, subject.metadata, this.queryRunnerProvider);
existInverseEntityRelationIds = await specificRepository
.findRelationIds(relation, subject.databaseEntity);
// console.log(existInverseEntityRelationIds);
existInverseEntityRelationIds = relation.getEntityValue(subject.databaseEntity);
// console.log("existInverseEntityRelationIds:", existInverseEntityRelationIds);
}
// get all inverse entities relation ids that are "bind" to the currently persisted entity
@ -797,8 +789,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
return relation.inverseEntityMetadata.compareIds(changedRelationId, existRelationId);
});
});
// console.log("removedJunctionEntityIds: ", removedJunctionEntityIds);
// console.log("removedJunctionEntityIds:", removedJunctionEntityIds);
// now from all entities in the persisted entity find only those which aren't found in the db
const newJunctionEntities = relatedValue.filter(subRelatedValue => {

View File

@ -530,6 +530,12 @@ export class QueryBuilder<Entity> {
*/
loadRelationIdAndMap(mapToProperty: string, relationName: string): this;
/**
* LEFT JOINs relation id and maps it into some entity's property.
* Optionally, you can add condition and parameters used in condition.
*/
loadRelationIdAndMap(mapToProperty: string, relationName: string, options: { disableMixedMap: boolean }): this;
/**
* LEFT JOINs relation id and maps it into some entity's property.
* Optionally, you can add condition and parameters used in condition.
@ -540,11 +546,18 @@ export class QueryBuilder<Entity> {
* LEFT JOINs relation id and maps it into some entity's property.
* Optionally, you can add condition and parameters used in condition.
*/
loadRelationIdAndMap(mapToProperty: string, relationName: string, aliasName?: string, queryBuilderFactory?: (qb: QueryBuilder<any>) => QueryBuilder<any>): this {
loadRelationIdAndMap(mapToProperty: string,
relationName: string,
aliasNameOrOptions?: string|{ disableMixedMap?: boolean },
queryBuilderFactory?: (qb: QueryBuilder<any>) => QueryBuilder<any>): this {
const relationIdAttribute = new RelationIdAttribute(this.expressionMap);
relationIdAttribute.mapToProperty = mapToProperty;
relationIdAttribute.relationName = relationName;
relationIdAttribute.alias = aliasName;
if (typeof aliasNameOrOptions === "string")
relationIdAttribute.alias = aliasNameOrOptions;
if (aliasNameOrOptions instanceof Object && (aliasNameOrOptions as any).disableMixedMap)
relationIdAttribute.disableMixedMap = true;
relationIdAttribute.queryBuilderFactory = queryBuilderFactory;
this.expressionMap.relationIdAttributes.push(relationIdAttribute);
return this;
@ -1149,7 +1162,9 @@ export class QueryBuilder<Entity> {
*/
enableAutoRelationIdsLoad(): this {
this.expressionMap.mainAlias!.metadata.relations.forEach(relation => {
this.loadRelationIdAndMap(this.expressionMap.mainAlias!.name + "." + relation.propertyPath, this.expressionMap.mainAlias!.name + "." + relation.propertyPath);
this.loadRelationIdAndMap(this.expressionMap.mainAlias!.name + "." + relation.propertyPath,
this.expressionMap.mainAlias!.name + "." + relation.propertyPath,
{ disableMixedMap: true});
});
return this;
}

View File

@ -33,6 +33,11 @@ export class RelationIdAttribute {
*/
queryBuilderFactory?: (qb: QueryBuilder<any>) => QueryBuilder<any>;
/**
* Indicates if relation id should NOT be loaded as id map.
*/
disableMixedMap = false;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------

View File

@ -166,14 +166,14 @@ export class RawSqlResultsToEntityTransformer {
}
return columns.reduce((idMap, joinColumn) => {
if (columns.length > 1) {
if (columns.length === 1 && rawRelationIdResult.relationIdAttribute.disableMixedMap === false) {
idMap = result[joinColumn.databaseName];
} else {
if (relation.isOneToMany || relation.isOneToOneNotOwner) {
idMap[joinColumn.propertyName] = result[joinColumn.databaseName];
} else {
idMap[joinColumn.referencedColumn!.propertyName] = result[joinColumn.databaseName];
}
} else {
idMap = result[joinColumn.databaseName];
}
return idMap;
}, {} as ObjectLiteral);

View File

@ -7,7 +7,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase
import {Subcounters} from "./entity/Subcounters";
import {User} from "./entity/User";
describe.skip("embedded > embedded-many-to-many-case3", () => {
describe("embedded > embedded-many-to-many-case3", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({

View File

@ -18,7 +18,7 @@ describe("embedded > embedded-many-to-many-case4", () => {
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
describe.skip("owner side", () => {
describe("owner side", () => {
it("should insert, load, update and remove entities with embeddeds when embedded entity having ManyToMany relation with multiple primary keys (multiple keys in related entity)", () => Promise.all(connections.map(async connection => {

View File

@ -7,7 +7,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase
import {Subcounters} from "./entity/Subcounters";
import {User} from "./entity/User";
describe.skip("embedded > embedded-many-to-many-case5", () => {
describe("embedded > embedded-many-to-many-case5", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({

View File

@ -1,11 +1,17 @@
import "reflect-metadata";
import {expect} from "chai";
import {Post} from "./entity/Post";
import {Counters} from "./entity/Counters";
import {Connection} from "../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
sleep
} from "../../../utils/test-utils";
import {Subcounters} from "../embedded-many-to-one-case2/entity/Subcounters";
describe.skip("embedded > embedded-with-special-columns", () => {
describe("embedded > embedded-with-special-columns", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
@ -40,41 +46,43 @@ describe.skip("embedded > embedded-with-special-columns", () => {
post2.counters.subcounters.watches = 10;
await connection.getRepository(Post).persist(post2);
let loadedPosts = await connection.manager
const loadedPosts = await connection.manager
.createQueryBuilder(Post, "post")
.orderBy("post.id")
.getMany();
console.log(loadedPosts);
/*expect(loadedPosts[0].should.be.eql(
{
id: 1,
title: "About cars",
counters: {
comments: 1,
favorites: 2,
likes: 3,
subcounters: {
version: 1,
watches: 5
}
}
}
));
expect(loadedPosts[1].should.be.eql(
{
id: 2,
title: "About airplanes",
counters: {
comments: 2,
favorites: 3,
likes: 4,
subcounters: {
version: 1,
watches: 10
}
}
}
));*/
expect(loadedPosts[0].counters.createdDate.should.be.instanceof(Date));
expect(loadedPosts[0].counters.updatedDate.should.be.instanceof(Date));
expect(loadedPosts[0].counters.subcounters.version.should.be.equal(1));
expect(loadedPosts[1].counters.createdDate.should.be.instanceof(Date));
expect(loadedPosts[1].counters.updatedDate.should.be.instanceof(Date));
expect(loadedPosts[1].counters.subcounters.version.should.be.equal(1));
let loadedPost = await connection.manager
.createQueryBuilder(Post, "post")
.orderBy("post.id")
.where("post.id = :id", { id: 1 })
.getOne();
expect(loadedPost!.counters.createdDate.should.be.instanceof(Date));
expect(loadedPost!.counters.updatedDate.should.be.instanceof(Date));
expect(loadedPost!.counters.subcounters.version.should.be.equal(1));
const prevUpdateDate = loadedPost!.counters.updatedDate;
loadedPost!.title = "About cars #2";
await sleep(1000);
await connection.getRepository(Post).persist(loadedPost!);
loadedPost = await connection.manager
.createQueryBuilder(Post, "post")
.where("post.id = :id", { id: 1 })
.getOne();
expect((loadedPost!.counters.updatedDate.valueOf()).should.be.greaterThan(prevUpdateDate.valueOf()));
expect(loadedPost!.counters.subcounters.version.should.be.equal(2));
})));
});

View File

@ -204,4 +204,10 @@ export function generateRandomText(length: number): string {
text += characters.charAt(Math.floor(Math.random() * characters.length));
return text;
}
export function sleep(ms: number): Promise<void> {
return new Promise<void>(ok => {
setTimeout(ok, ms);
});
}