mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixes and refactoring
This commit is contained in:
parent
e03f54f341
commit
296ed7baf2
@ -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 => {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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 => {
|
||||
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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));
|
||||
|
||||
})));
|
||||
|
||||
});
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user