refactored optional metadata properties

This commit is contained in:
Umed Khudoiberdiev 2017-05-17 15:13:19 +05:00
parent 6467371d81
commit 0b7bdd15ab
24 changed files with 119 additions and 124 deletions

View File

@ -95,7 +95,7 @@ export class LazyRelationsWrapper {
* INNER JOIN post Post ON Post.category=category.id WHERE Post.id=1
*/
protected loadManyToOneOrOneToOneOwner(relation: RelationMetadata, entity: ObjectLiteral): Promise<any> {
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation!.joinColumns;
const conditions = joinColumns.map(joinColumn => {
return `${relation.entityMetadata.name}.${relation.propertyName} = ${relation.propertyName}.${joinColumn.referencedColumn!.propertyName}`;
}).join(" AND ");
@ -122,9 +122,9 @@ export class LazyRelationsWrapper {
protected loadOneToManyOrOneToOneNotOwner(relation: RelationMetadata, entity: ObjectLiteral): Promise<any> {
const qb = new QueryBuilder(this.connection)
.select(relation.propertyName)
.from(relation.inverseRelation.entityMetadata.target, relation.propertyName);
.from(relation.inverseRelation!.entityMetadata.target, relation.propertyName);
relation.inverseRelation.joinColumns.forEach(joinColumn => {
relation.inverseRelation!.joinColumns.forEach(joinColumn => {
qb.andWhere(`${relation.propertyName}.${joinColumn.propertyName} = :${joinColumn.referencedColumn!.propertyName}`)
.setParameter(`${joinColumn.referencedColumn!.propertyName}`, joinColumn.referencedColumn!.getEntityValue(entity));
});
@ -142,7 +142,7 @@ export class LazyRelationsWrapper {
*/
protected loadManyToManyOwner(relation: RelationMetadata, entity: ObjectLiteral): Promise<any> {
const mainAlias = relation.propertyName;
const joinAlias = relation.junctionEntityMetadata.tableName;
const joinAlias = relation.junctionEntityMetadata!.tableName;
const joinColumnConditions = relation.joinColumns.map(joinColumn => {
return `${joinAlias}.${joinColumn.propertyName} = :${joinColumn.propertyName}`;
});
@ -173,14 +173,14 @@ export class LazyRelationsWrapper {
*/
protected loadManyToManyNotOwner(relation: RelationMetadata, entity: ObjectLiteral): Promise<any> {
const mainAlias = relation.propertyName;
const joinAlias = relation.junctionEntityMetadata.tableName;
const joinColumnConditions = relation.inverseRelation.joinColumns.map(joinColumn => {
const joinAlias = relation.junctionEntityMetadata!.tableName;
const joinColumnConditions = relation.inverseRelation!.joinColumns.map(joinColumn => {
return `${joinAlias}.${joinColumn.propertyName} = ${mainAlias}.${joinColumn.referencedColumn!.propertyName}`;
});
const inverseJoinColumnConditions = relation.inverseRelation.inverseJoinColumns.map(inverseJoinColumn => {
const inverseJoinColumnConditions = relation.inverseRelation!.inverseJoinColumns.map(inverseJoinColumn => {
return `${joinAlias}.${inverseJoinColumn.propertyName} = :${inverseJoinColumn.propertyName}`;
});
const parameters = relation.inverseRelation.inverseJoinColumns.reduce((parameters, joinColumn) => {
const parameters = relation.inverseRelation!.inverseJoinColumns.reduce((parameters, joinColumn) => {
parameters[joinColumn.propertyName] = joinColumn.referencedColumn!.getEntityValue(entity);
return parameters;
}, {} as ObjectLiteral);

View File

@ -1,6 +1,6 @@
import {RelationType} from "../metadata/types/RelationTypes";
import {RelationOptions} from "../decorator/options/RelationOptions";
import {PropertyTypeInFunction} from "../metadata/types/PropertyTypeInFunction";
import {PropertyTypeFactory} from "../metadata/types/PropertyTypeInFunction";
import {RelationTypeInFunction} from "../metadata/types/RelationTypeInFunction";
/**
@ -50,7 +50,7 @@ export interface RelationMetadataArgs {
/**
* Inverse side of the relation.
*/
readonly inverseSideProperty?: PropertyTypeInFunction<any>;
readonly inverseSideProperty?: PropertyTypeFactory<any>;
/**
* Additional relation options.

View File

@ -254,7 +254,6 @@ export class EntityMetadataBuilder {
// and compute inverse relation and mark if it has such
relation.inverseRelation = inverseEntityMetadata.relations.find(foundRelation => foundRelation.propertyPath === relation.inverseSidePropertyPath)!; // todo: remove ! later
relation.hasInverseSide = !!relation.inverseRelation; // todo: do we really need this flag
});
}

View File

@ -128,9 +128,9 @@ export class EntityMetadataValidator {
// make sure cascade remove is not set for both sides of relationships (can be set in OneToOne decorators)
entityMetadata.relations.forEach(relation => {
const isCircularCascadeRemove = relation.isCascadeRemove && relation.hasInverseSide && relation.inverseRelation.isCascadeRemove;
const isCircularCascadeRemove = relation.isCascadeRemove && relation.inverseRelation && relation.inverseRelation!.isCascadeRemove;
if (isCircularCascadeRemove)
throw new Error(`Relation ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseRelation.entityMetadata.name}#${relation.inverseRelation.propertyName} both has cascade remove set. ` +
throw new Error(`Relation ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseRelation!.entityMetadata.name}#${relation.inverseRelation!.propertyName} both has cascade remove set. ` +
`This may lead to unexpected circular removals. Please set cascade remove only from one side of relationship.`);
}); // todo: maybe better just deny removal from one to one relation without join column?
}

View File

@ -34,7 +34,7 @@ export class JunctionEntityMetadataBuilder {
relation.entityMetadata.tableNameWithoutPrefix,
relation.inverseEntityMetadata.tableNameWithoutPrefix,
relation.propertyPath,
relation.hasInverseSide ? relation.inverseRelation.propertyName : ""
relation.inverseRelation ? relation.inverseRelation.propertyName : ""
);
const entityMetadata = new EntityMetadata({

View File

@ -8,7 +8,7 @@ export class MissingJoinColumnError extends Error {
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
super();
if (relation.hasInverseSide) {
if (relation.inverseRelation) {
this.message = `JoinColumn is missing on both sides of ${entityMetadata.name}#${relation.propertyName} and ` +
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} one-to-one relationship. ` +
`You need to put JoinColumn decorator on one of the sides.`;

View File

@ -9,7 +9,7 @@ export class MissingJoinTableError extends Error {
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
super();
if (relation.hasInverseSide) {
if (relation.inverseRelation) {
this.message = `JoinTable is missing on both sides of ${entityMetadata.name}#${relation.propertyName} and ` +
`${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} many-to-many relationship. ` +
`You need to put decorator decorator on one of the sides.`;

View File

@ -9,7 +9,7 @@ export class UsingJoinColumnOnlyOnOneSideAllowedError extends Error {
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
super();
this.message = `Using JoinColumn is allowed only on one side of the one-to-one relationship. ` +
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} ` +
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation!.propertyName} ` +
`has JoinTable decorators. Choose one of them and left JoinTable decorator only on it.`;
}

View File

@ -9,7 +9,7 @@ export class UsingJoinTableOnlyOnOneSideAllowedError extends Error {
constructor(entityMetadata: EntityMetadata, relation: RelationMetadata) {
super();
this.message = `Using JoinTable is allowed only on one side of the many-to-many relationship. ` +
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation.propertyName} ` +
`Both ${entityMetadata.name}#${relation.propertyName} and ${relation.inverseEntityMetadata.name}#${relation.inverseRelation!.propertyName} ` +
`has JoinTable decorators. Choose one of them and left JoinColumn decorator only on it.`;
}

View File

@ -24,13 +24,13 @@ export class ColumnMetadata {
* Embedded metadata where this column metadata is.
* If this column is not in embed then this property value is undefined.
*/
embeddedMetadata: EmbeddedMetadata;
embeddedMetadata?: EmbeddedMetadata;
/**
* If column is a foreign key of some relation then this relation's metadata will be there.
* If this column does not have a foreign key then this property value is undefined.
*/
relationMetadata: RelationMetadata;
relationMetadata?: RelationMetadata;
/**
* Class's property name on which this column is applied.
@ -58,7 +58,7 @@ export class ColumnMetadata {
isGenerated: boolean = false;
/**
* Indicates if value in the database should be unique or not.
* Indicates if column value in the database should be unique or not.
*/
isUnique: boolean = false;

View File

@ -21,7 +21,7 @@ export class EmbeddedMetadata {
/**
* Parent embedded in the case if this embedded inside other embedded.
*/
parentEmbeddedMetadata: EmbeddedMetadata;
parentEmbeddedMetadata?: EmbeddedMetadata;
/**
* Embedded target type.

View File

@ -13,7 +13,7 @@ import {OrmUtils} from "../util/OrmUtils";
import {TableMetadataArgs} from "../metadata-args/TableMetadataArgs";
import {Connection} from "../connection/Connection";
import {EntityListenerMetadata} from "./EntityListenerMetadata";
import {PropertyTypeInFunction} from "./types/PropertyTypeInFunction";
import {PropertyTypeFactory} from "./types/PropertyTypeInFunction";
/**
* Contains all entity metadata.
@ -445,7 +445,7 @@ export class EntityMetadata {
/**
* Computes property name of the entity using given PropertyTypeInFunction.
*/
computePropertyPath(nameOrFn: PropertyTypeInFunction<any>) {
computePropertyPath(nameOrFn: PropertyTypeFactory<any>) {
return typeof nameOrFn === "string" ? nameOrFn : nameOrFn(this.propertiesMap);
}

View File

@ -20,7 +20,7 @@ export class IndexMetadata {
/**
* Indicates if this index must be unique.
*/
isUnique: boolean;
isUnique: boolean = false;
/**
* Target class to which metadata is applied.
@ -28,8 +28,9 @@ export class IndexMetadata {
target?: Function|string;
/**
* Indexed columns.
*/
columns: ColumnMetadata[];
columns: ColumnMetadata[] = [];
/**
* User specified index name.

View File

@ -7,7 +7,7 @@ import {EmbeddedMetadata} from "./EmbeddedMetadata";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {RelationMetadataArgs} from "../metadata-args/RelationMetadataArgs";
import {OnDeleteType} from "./types/OnDeleteType";
import {PropertyTypeInFunction} from "./types/PropertyTypeInFunction";
import {PropertyTypeFactory} from "./types/PropertyTypeInFunction";
/**
* Contains all information about some entity's relation.
@ -41,13 +41,13 @@ export class RelationMetadata {
* Entity metadata of the junction table.
* Defined only for many-to-many relations.
*/
junctionEntityMetadata: EntityMetadata; // todo: optional
junctionEntityMetadata?: EntityMetadata;
/**
* Embedded metadata where this relation is.
* If this relation is not in embed then this property value is undefined.
*/
embeddedMetadata: EmbeddedMetadata; // todo: optional
embeddedMetadata?: EmbeddedMetadata;
/**
* Foreign keys created for this relation.
@ -92,27 +92,27 @@ export class RelationMetadata {
* Indicates if this relation's column is a primary key.
* Can be used only for many-to-one and owner one-to-one relations.
*/
isPrimary: boolean;
isPrimary: boolean = false;
/**
* Indicates if this relation is lazily loaded.
*/
isLazy: boolean;
isLazy: boolean = false;
/**
* If set to true then related objects are allowed to be inserted to the database.
*/
isCascadeInsert: boolean;
isCascadeInsert: boolean = false;
/**
* If set to true then related objects are allowed to be updated in the database.
*/
isCascadeUpdate: boolean;
isCascadeUpdate: boolean = false;
/**
* If set to true then related objects are allowed to be remove from the database.
*/
isCascadeRemove: boolean;
isCascadeRemove: boolean = false;
/**
* Indicates if relation column value can be nullable or not.
@ -208,24 +208,19 @@ export class RelationMetadata {
isManyToManyNotOwner: boolean = false;
/**
* Checks if inverse side is specified by a relation.
* Gets the property path of the inverse side of the relation.
*/
hasInverseSide: boolean = false;
/**
* Gets the property name of the inverse side of the relation.
*/
inverseSidePropertyPath: string; // todo: should be called inverseSidePropertyName ?
inverseSidePropertyPath: string;
/**
* Inverse side of the relation.
*/
inverseSideProperty: PropertyTypeInFunction<any>;
givenInverseSidePropertyFactory: PropertyTypeFactory<any>;
/**
* Gets the relation metadata of the inverse side of this relation.
*/
inverseRelation: RelationMetadata;
inverseRelation?: RelationMetadata;
// ---------------------------------------------------------------------
// Constructor
@ -244,7 +239,7 @@ export class RelationMetadata {
this.relationType = args.relationType;
if (args.inverseSideProperty)
this.inverseSideProperty = args.inverseSideProperty;
this.givenInverseSidePropertyFactory = args.inverseSideProperty;
this.isLazy = args.isLazy || false;
this.isCascadeInsert = args.options.cascadeInsert || args.options.cascadeAll || false;
@ -398,13 +393,13 @@ export class RelationMetadata {
*/
buildInverseSidePropertyPath(): string {
if (this.inverseSideProperty) {
if (this.givenInverseSidePropertyFactory) {
const ownerEntityPropertiesMap = this.inverseEntityMetadata.propertiesMap;
if (typeof this.inverseSideProperty === "function")
return this.inverseSideProperty(ownerEntityPropertiesMap);
if (typeof this.givenInverseSidePropertyFactory === "function")
return this.givenInverseSidePropertyFactory(ownerEntityPropertiesMap);
if (typeof this.inverseSideProperty === "string")
return this.inverseSideProperty;
if (typeof this.givenInverseSidePropertyFactory === "string")
return this.givenInverseSidePropertyFactory;
} else if (this.isTreeParent && this.entityMetadata.treeChildrenRelation) {
return this.entityMetadata.treeChildrenRelation.propertyName;

View File

@ -1,4 +1,4 @@
/**
* Contains the name of the property of the object, or the function that returns this name.
*/
export type PropertyTypeInFunction<T> = string|((t: T) => string|any);
export type PropertyTypeFactory<T> = string|((t: T) => string|any);

View File

@ -429,12 +429,12 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
let persistValueRelationId: any = undefined;
if (subject.hasEntity && !subject.mustBeRemoved) {
const persistValue = relation.getEntityValue(subject.entity);
if (persistValue) persistValueRelationId = relation.inverseRelation.getEntityValue(persistValue);
if (persistValue) persistValueRelationId = relation.inverseRelation!.getEntityValue(persistValue);
if (persistValueRelationId === undefined) return; // skip undefined properties
}
// (example) returns us referenced column (detail's id)
const relationIdInDatabaseEntity = relation.inverseRelation.joinColumns[0].referencedColumn!.getEntityValue(subject.databaseEntity);
const relationIdInDatabaseEntity = relation.inverseRelation!.joinColumns[0].referencedColumn!.getEntityValue(subject.databaseEntity);
// if database relation id does not exist then nothing to remove (but can this be possible?)
if (relationIdInDatabaseEntity === null || relationIdInDatabaseEntity === undefined)
@ -450,7 +450,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
// (example) here we seek a Post loaded from the database in the subjects
// (example) here relatedSubject.databaseEntity is a Post
// (example) and we need to compare post.detailsId === details.id
return relation.inverseRelation.getEntityValue(relatedSubject.databaseEntity) === relationIdInDatabaseEntity;
return relation.inverseRelation!.getEntityValue(relatedSubject.databaseEntity) === relationIdInDatabaseEntity;
});
// if not loaded yet then load it from the database
@ -479,7 +479,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
// (example) persistValue is a postFromPersistedDetails here
// (example) alreadyLoadedRelatedDatabaseSubject.databaseEntity is a postFromDatabaseDetails here
// (example) postFromPersistedDetails.id === postFromDatabaseDetails - means nothing changed
const inverseEntityRelationId = relation.inverseRelation.getEntityValue(alreadyLoadedRelatedDatabaseSubject.databaseEntity);
const inverseEntityRelationId = relation.inverseRelation!.getEntityValue(alreadyLoadedRelatedDatabaseSubject.databaseEntity);
if (persistValueRelationId && persistValueRelationId === inverseEntityRelationId)
return;
@ -561,7 +561,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
databaseEntities = await this.connection
.getRepository<ObjectLiteral>(valueMetadata.target)
.createQueryBuilder(qbAlias, this.queryRunnerProvider) // todo: this wont work for mongodb. implement this in some method and call it here instead?
.innerJoin(relation.junctionEntityMetadata.tableName, joinAlias, conditions)
.innerJoin(relation.junctionEntityMetadata!.tableName, joinAlias, conditions)
.setParameters(parameters)
.enableAutoRelationIdsLoad()
.getMany();
@ -584,7 +584,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
const conditions = joinColumnConditions.concat(inverseJoinColumnConditions).join(" AND ");
// (example) returns us referenced column (detail's id)
const parameters = relation.inverseRelation.inverseJoinColumns.reduce((parameters, joinColumn) => {
const parameters = relation.inverseRelation!.inverseJoinColumns.reduce((parameters, joinColumn) => {
parameters[joinColumn.propertyName] = joinColumn.referencedColumn!.getEntityValue(subject.databaseEntity);
return parameters;
}, {} as ObjectLiteral);
@ -592,7 +592,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
databaseEntities = await this.connection
.getRepository<ObjectLiteral>(valueMetadata.target)
.createQueryBuilder(qbAlias, this.queryRunnerProvider) // todo: this wont work for mongodb. implement this in some method and call it here instead?
.innerJoin(relation.junctionEntityMetadata.tableName, joinAlias, conditions)
.innerJoin(relation.junctionEntityMetadata!.tableName, joinAlias, conditions)
.setParameters(parameters)
.enableAutoRelationIdsLoad()
.getMany();
@ -600,7 +600,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
} else { // this case can only be a oneToMany relation
// todo: fix issues with joinColumn[0]
// (example) returns us referenced column (detail's id)
const relationIdInDatabaseEntity = relation.inverseRelation.joinColumns[0].referencedColumn!.getEntityValue(subject.databaseEntity);
const relationIdInDatabaseEntity = relation.inverseRelation!.joinColumns[0].referencedColumn!.getEntityValue(subject.databaseEntity);
// in this case we need inverse entities not only because of cascade removes
// because we also need inverse entities to be able to perform update of entities
@ -663,7 +663,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
if (loadedSubject) {
loadedSubject.relationUpdates.push({
relation: relation.inverseRelation,
relation: relation.inverseRelation!,
value: subject.entity
});
}
@ -776,7 +776,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
// get all inverse entities relation ids that are "bind" to the currently persisted entity
const changedInverseEntityRelationIds = relatedValue
.map(subRelationValue => {
const joinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation!.joinColumns;
return joinColumns.reduce((ids, joinColumn) => {
return OrmUtils.mergeDeep(ids, joinColumn.referencedColumn!.createValueMap(joinColumn.referencedColumn!.getEntityValue(subRelationValue))); // todo: duplicate. relation.createJoinColumnsIdMap(entity) ?
}, {} as ObjectLiteral);
@ -795,7 +795,7 @@ export class SubjectBuilder<Entity extends ObjectLiteral> {
const newJunctionEntities = relatedValue.filter(subRelatedValue => {
// console.log(subRelatedValue);
const joinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation!.joinColumns;
const ids = joinColumns.reduce((ids, joinColumn) => {
return OrmUtils.mergeDeep(ids, joinColumn.referencedColumn!.createValueMap(joinColumn.referencedColumn!.getEntityValue(subRelatedValue))); // todo: duplicate. relation.createJoinColumnsIdMap(entity) ?
}, {} as ObjectLiteral);

View File

@ -329,7 +329,7 @@ export class SubjectOperationExecutor {
// console.log(oneToManyAndOneToOneNonOwnerRelations);
subject.metadata.extractRelationValuesFromEntity(subject.entity, oneToManyAndOneToOneNonOwnerRelations)
.forEach(([relation, subRelatedEntity, inverseEntityMetadata]) => {
relation.inverseRelation.joinColumns.forEach(joinColumn => {
relation.inverseRelation!.joinColumns.forEach(joinColumn => {
const referencedColumn = joinColumn.referencedColumn!;
const columns = inverseEntityMetadata.parentEntityMetadata ? inverseEntityMetadata.primaryColumns : inverseEntityMetadata.primaryColumns;
@ -515,12 +515,12 @@ export class SubjectOperationExecutor {
if (referencedColumn.isVersion)
relationValue = this.connection.driver.preparePersistentValue(1, referencedColumn);
}
} else if (relation.hasInverseSide) {
} else if (relation.inverseRelation) {
const inverseSubject = this.allSubjects.find(subject => {
if (!subject.hasEntity || subject.entityTarget !== relation.inverseRelation.target)
if (!subject.hasEntity || subject.entityTarget !== relation.inverseRelation!.target)
return false;
const inverseRelationValue = relation.inverseRelation.getEntityValue(subject.entity);
const inverseRelationValue = relation.inverseRelation!.getEntityValue(subject.entity);
if (inverseRelationValue) {
if (inverseRelationValue instanceof Array) {
return inverseRelationValue.find(subValue => subValue === subValue);
@ -896,7 +896,7 @@ export class SubjectOperationExecutor {
};
const relation = junctionInsert.relation;
const joinColumns = relation.isManyToManyOwner ? relation.joinColumns : relation.inverseRelation.inverseJoinColumns;
const joinColumns = relation.isManyToManyOwner ? relation.joinColumns : relation.inverseRelation!.inverseJoinColumns;
const ownId = getRelationId(subject.entity, joinColumns);
if (!ownId.length)
@ -905,17 +905,17 @@ export class SubjectOperationExecutor {
const promises = junctionInsert.junctionEntities.map(newBindEntity => {
// get relation id from the newly bind entity
const joinColumns = relation.isManyToManyOwner ? relation.inverseJoinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isManyToManyOwner ? relation.inverseJoinColumns : relation.inverseRelation!.joinColumns;
const relationId = getRelationId(newBindEntity, joinColumns);
// if relation id still does not exist - we arise an error
if (!relationId)
throw new Error(`Cannot insert object of ${(newBindEntity.constructor as any).name} type. Looks like its not persisted yet, or cascades are not set on the relation.`); // todo: better error message
const columns = relation.junctionEntityMetadata.columns.map(column => column.databaseName);
const columns = relation.junctionEntityMetadata!.columns.map(column => column.databaseName);
const values = relation.isOwning ? [...ownId, ...relationId] : [...relationId, ...ownId];
return this.queryRunner.insert(relation.junctionEntityMetadata.tableName, OrmUtils.zipObject(columns, values));
return this.queryRunner.insert(relation.junctionEntityMetadata!.tableName, OrmUtils.zipObject(columns, values));
});
await Promise.all(promises);
@ -943,11 +943,11 @@ export class SubjectOperationExecutor {
* Removes from database junction table all given subject's removal junction data.
*/
private async removeJunctions(subject: Subject, junctionRemove: JunctionRemove) {
const junctionMetadata = junctionRemove.relation.junctionEntityMetadata;
const junctionMetadata = junctionRemove.relation.junctionEntityMetadata!;
const entity = subject.hasEntity ? subject.entity : subject.databaseEntity;
const firstJoinColumns = junctionRemove.relation.isOwning ? junctionRemove.relation.joinColumns : junctionRemove.relation.inverseRelation.inverseJoinColumns;
const secondJoinColumns = junctionRemove.relation.isOwning ? junctionRemove.relation.inverseJoinColumns : junctionRemove.relation.inverseRelation.joinColumns;
const firstJoinColumns = junctionRemove.relation.isOwning ? junctionRemove.relation.joinColumns : junctionRemove.relation.inverseRelation!.inverseJoinColumns;
const secondJoinColumns = junctionRemove.relation.isOwning ? junctionRemove.relation.inverseJoinColumns : junctionRemove.relation.inverseRelation!.joinColumns;
let conditions: ObjectLiteral = {};
firstJoinColumns.forEach(joinColumn => {
conditions[joinColumn.databaseName] = joinColumn.referencedColumn!.getEntityValue(entity);

View File

@ -1483,15 +1483,15 @@ export class QueryBuilder<Entity> {
} else if (relation.isOneToMany || relation.isOneToOneNotOwner) {
// JOIN `post` `post` ON `post`.`categoryId` = `category`.`id`
const condition = relation.inverseRelation.joinColumns.map(joinColumn => {
return destinationTableAlias + "." + relation.inverseRelation.propertyPath + "." + joinColumn.referencedColumn!.propertyPath + "=" +
const condition = relation.inverseRelation!.joinColumns.map(joinColumn => {
return destinationTableAlias + "." + relation.inverseRelation!.propertyPath + "." + joinColumn.referencedColumn!.propertyPath + "=" +
parentAlias + "." + joinColumn.referencedColumn!.propertyPath;
}).join(" AND ");
return " " + joinAttr.direction + " JOIN " + et(destinationTableName) + " " + ea(destinationTableAlias) + " ON " + this.replacePropertyNames(condition + appendedCondition);
} else { // means many-to-many
const junctionTableName = relation.junctionEntityMetadata.tableName;
const junctionTableName = relation.junctionEntityMetadata!.tableName;
const junctionAlias = joinAttr.junctionAlias;
let junctionCondition = "", destinationCondition = "";
@ -1509,12 +1509,12 @@ export class QueryBuilder<Entity> {
}).join(" AND ");
} else {
junctionCondition = relation.inverseRelation.inverseJoinColumns.map(joinColumn => {
junctionCondition = relation.inverseRelation!.inverseJoinColumns.map(joinColumn => {
// `post_category`.`categoryId` = `category`.`id`
return junctionAlias + "." + joinColumn.propertyPath + "=" + parentAlias + "." + joinColumn.referencedColumn!.propertyPath;
}).join(" AND ");
destinationCondition = relation.inverseRelation.joinColumns.map(joinColumn => {
destinationCondition = relation.inverseRelation!.joinColumns.map(joinColumn => {
// `post`.`id` = `post_category`.`postId`
return destinationTableAlias + "." + joinColumn.referencedColumn!.propertyPath + "=" + junctionAlias + "." + joinColumn.propertyPath;
}).join(" AND ");

View File

@ -31,7 +31,7 @@ export class RelationCountLoader {
// todo(dima): fix issues wit multiple primary keys and remove joinColumns[0]
const relation = relationCountAttr.relation; // "category.posts"
const inverseRelation = relation.inverseRelation; // "post.category"
const inverseRelation = relation.inverseRelation!; // "post.category"
const referenceColumnName = inverseRelation.joinColumns[0].referencedColumn!.propertyName; // post id
const inverseSideTable = relation.inverseEntityMetadata.target; // Post
const inverseSideTableName = relation.inverseEntityMetadata.tableName; // post
@ -80,14 +80,14 @@ export class RelationCountLoader {
if (relationCountAttr.relation.isOwning) { // todo fix joinColumns[0] and inverseJoinColumns[0].
joinTableColumnName = relationCountAttr.relation.joinColumns[0].referencedColumn!.databaseName;
inverseJoinColumnName = relationCountAttr.relation.inverseJoinColumns[0].referencedColumn!.databaseName;
firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata.columns[0];
secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata.columns[1];
firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[0];
secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[1];
} else {
joinTableColumnName = relationCountAttr.relation.inverseRelation.inverseJoinColumns[0].referencedColumn!.databaseName;
inverseJoinColumnName = relationCountAttr.relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName;
firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata.columns[1];
secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata.columns[0];
joinTableColumnName = relationCountAttr.relation.inverseRelation!.inverseJoinColumns[0].referencedColumn!.databaseName;
inverseJoinColumnName = relationCountAttr.relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName;
firstJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[1];
secondJunctionColumn = relationCountAttr.relation.junctionEntityMetadata!.columns[0];
}
const referenceColumnValues = rawEntities
@ -102,7 +102,7 @@ export class RelationCountLoader {
const junctionAlias = relationCountAttr.junctionAlias;
const inverseSideTableName = relationCountAttr.joinInverseSideMetadata.tableName;
const inverseSideTableAlias = relationCountAttr.alias || inverseSideTableName;
const junctionTableName = relationCountAttr.relation.junctionEntityMetadata.tableName;
const junctionTableName = relationCountAttr.relation.junctionEntityMetadata!.tableName;
const condition = junctionAlias + "." + firstJunctionColumn.propertyName + " IN (" + referenceColumnValues + ")" +
" AND " + junctionAlias + "." + secondJunctionColumn.propertyName + " = " + inverseSideTableAlias + "." + inverseJoinColumnName;

View File

@ -111,7 +111,7 @@ export class RelationIdAttribute {
* If extra condition without entity was joined, then it will return undefined.
*/
get junctionMetadata(): EntityMetadata {
return this.relation.junctionEntityMetadata;
return this.relation.junctionEntityMetadata!;
}
get mapToPropertyParentAlias(): string {

View File

@ -55,7 +55,7 @@ export class RelationIdLoader {
// we expect it to load array of category ids
const relation = relationIdAttr.relation; // "post.categories"
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation!.joinColumns;
const table = relation.inverseEntityMetadata.target; // category
const tableName = relation.inverseEntityMetadata.tableName; // category
const tableAlias = relationIdAttr.alias || tableName; // if condition (custom query builder factory) is set then relationIdAttr.alias defined
@ -83,7 +83,7 @@ export class RelationIdLoader {
qb.addSelect(tableAlias + "." + joinColumn.databaseName, joinColumn.databaseName);
});
relation.inverseRelation.entityMetadata.primaryColumns.forEach(primaryColumn => {
relation.inverseRelation!.entityMetadata.primaryColumns.forEach(primaryColumn => {
qb.addSelect(tableAlias + "." + primaryColumn.databaseName, primaryColumn.databaseName);
});
@ -107,12 +107,12 @@ export class RelationIdLoader {
// we expect it to load array of post ids
const relation = relationIdAttr.relation;
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation.inverseJoinColumns;
const inverseJoinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation.joinColumns;
const joinColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation!.inverseJoinColumns;
const inverseJoinColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation!.joinColumns;
const junctionAlias = relationIdAttr.junctionAlias;
const inverseSideTableName = relationIdAttr.joinInverseSideMetadata.tableName;
const inverseSideTableAlias = relationIdAttr.alias || inverseSideTableName;
const junctionTableName = relation.junctionEntityMetadata.tableName;
const junctionTableName = relation.junctionEntityMetadata!.tableName;
const mappedColumns = rawEntities.map(rawEntity => {
return joinColumns.reduce((map, joinColumn) => {

View File

@ -161,7 +161,7 @@ export class RawSqlResultsToEntityTransformer {
if (relation.isOwning) {
columns = relation.inverseJoinColumns.map(joinColumn => joinColumn);
} else {
columns = relation.inverseRelation.joinColumns.map(joinColumn => joinColumn);
columns = relation.inverseRelation!.joinColumns.map(joinColumn => joinColumn);
}
}
@ -212,10 +212,10 @@ export class RawSqlResultsToEntityTransformer {
let referenceColumnName: string;
if (relation.isOneToMany) {
referenceColumnName = relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName; // todo: fix joinColumns[0]
referenceColumnName = relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName; // todo: fix joinColumns[0]
} else {
referenceColumnName = relation.isOwning ? relation.joinColumns[0].referencedColumn!.databaseName : relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName;
referenceColumnName = relation.isOwning ? relation.joinColumns[0].referencedColumn!.databaseName : relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName;
}
const referenceColumnValue = rawSqlResults[0][alias.name + "_" + referenceColumnName]; // we use zero index since its grouped data // todo: selection with alias for entity columns wont work
@ -238,12 +238,12 @@ export class RawSqlResultsToEntityTransformer {
if (relation.isManyToOne || relation.isOneToOneOwner) {
columns = relation.entityMetadata.primaryColumns.map(joinColumn => joinColumn);
} else if (relation.isOneToMany || relation.isOneToOneNotOwner) {
columns = relation.inverseRelation.joinColumns.map(joinColumn => joinColumn);
columns = relation.inverseRelation!.joinColumns.map(joinColumn => joinColumn);
} else {
if (relation.isOwning) {
columns = relation.joinColumns.map(joinColumn => joinColumn);
} else {
columns = relation.inverseRelation.inverseJoinColumns.map(joinColumn => joinColumn);
columns = relation.inverseRelation!.inverseJoinColumns.map(joinColumn => joinColumn);
}
}
return columns.reduce((valueMap, column) => {
@ -264,12 +264,12 @@ export class RawSqlResultsToEntityTransformer {
if (relation.isManyToOne || relation.isOneToOneOwner) {
columns = relation.entityMetadata.primaryColumns.map(joinColumn => joinColumn);
} else if (relation.isOneToMany || relation.isOneToOneNotOwner) {
columns = relation.inverseRelation.joinColumns.map(joinColumn => joinColumn);
columns = relation.inverseRelation!.joinColumns.map(joinColumn => joinColumn);
} else {
if (relation.isOwning) {
columns = relation.joinColumns.map(joinColumn => joinColumn);
} else {
columns = relation.inverseRelation.inverseJoinColumns.map(joinColumn => joinColumn);
columns = relation.inverseRelation!.inverseJoinColumns.map(joinColumn => joinColumn);
}
}
return columns.reduce((data, column) => {

View File

@ -66,8 +66,8 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
conditions[relation.joinColumns[0].referencedColumn!.databaseName] = entityId;
} else {
table = relation.inverseEntityMetadata.tableName;
values[relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName] = relatedEntityId;
conditions[relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName] = entityId;
values[relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName] = relatedEntityId;
conditions[relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName] = entityId;
}
@ -111,8 +111,8 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
let table: string, values: any = {}, conditions: any = {};
if (relation.isOwning) {
table = relation.inverseEntityMetadata.tableName;
values[relation.inverseRelation.joinColumns[0].databaseName] = relatedEntityId;
conditions[relation.inverseRelation.joinColumns[0].referencedColumn!.databaseName] = entityId;
values[relation.inverseRelation!.joinColumns[0].databaseName] = relatedEntityId;
conditions[relation.inverseRelation!.joinColumns[0].referencedColumn!.databaseName] = entityId;
} else {
table = relation.entityMetadata.tableName;
values[relation.joinColumns[0].databaseName] = relatedEntityId;
@ -158,14 +158,14 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
const insertPromises = relatedEntityIds.map(relatedEntityId => {
const values: any = {};
if (relation.isOwning) {
values[relation.junctionEntityMetadata.columns[0].databaseName] = entityId;
values[relation.junctionEntityMetadata.columns[1].databaseName] = relatedEntityId;
values[relation.junctionEntityMetadata!.columns[0].databaseName] = entityId;
values[relation.junctionEntityMetadata!.columns[1].databaseName] = relatedEntityId;
} else {
values[relation.junctionEntityMetadata.columns[1].databaseName] = entityId;
values[relation.junctionEntityMetadata.columns[0].databaseName] = relatedEntityId;
values[relation.junctionEntityMetadata!.columns[1].databaseName] = entityId;
values[relation.junctionEntityMetadata!.columns[0].databaseName] = relatedEntityId;
}
return queryRunner.insert(relation.junctionEntityMetadata.tableName, values);
return queryRunner.insert(relation.junctionEntityMetadata!.tableName, values);
});
await Promise.all(insertPromises);
@ -206,14 +206,14 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
const insertPromises = entityIds.map(entityId => {
const values: any = {};
if (relation.isOwning) {
values[relation.junctionEntityMetadata.columns[0].databaseName] = entityId;
values[relation.junctionEntityMetadata.columns[1].databaseName] = relatedEntityId;
values[relation.junctionEntityMetadata!.columns[0].databaseName] = entityId;
values[relation.junctionEntityMetadata!.columns[1].databaseName] = relatedEntityId;
} else {
values[relation.junctionEntityMetadata.columns[1].databaseName] = entityId;
values[relation.junctionEntityMetadata.columns[0].databaseName] = relatedEntityId;
values[relation.junctionEntityMetadata!.columns[1].databaseName] = entityId;
values[relation.junctionEntityMetadata!.columns[0].databaseName] = relatedEntityId;
}
return queryRunner.insert(relation.junctionEntityMetadata.tableName, values);
return queryRunner.insert(relation.junctionEntityMetadata!.tableName, values);
});
await Promise.all(insertPromises);
@ -256,10 +256,10 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
const qb = new QueryBuilder(this.connection, this.queryRunnerProvider)
.delete()
.fromTable(relation.junctionEntityMetadata.tableName, "junctionEntity");
.fromTable(relation.junctionEntityMetadata!.tableName, "junctionEntity");
const firstColumnName = this.connection.driver.escapeColumnName(relation.isOwning ? relation.junctionEntityMetadata.columns[0].databaseName : relation.junctionEntityMetadata.columns[1].databaseName);
const secondColumnName = this.connection.driver.escapeColumnName(relation.isOwning ? relation.junctionEntityMetadata.columns[1].databaseName : relation.junctionEntityMetadata.columns[0].databaseName);
const firstColumnName = this.connection.driver.escapeColumnName(relation.isOwning ? relation.junctionEntityMetadata!.columns[0].databaseName : relation.junctionEntityMetadata!.columns[1].databaseName);
const secondColumnName = this.connection.driver.escapeColumnName(relation.isOwning ? relation.junctionEntityMetadata!.columns[1].databaseName : relation.junctionEntityMetadata!.columns[0].databaseName);
relatedEntityIds.forEach((relatedEntityId, index) => {
qb.orWhere(`(${firstColumnName}=:entityId AND ${secondColumnName}=:relatedEntity_${index})`)
@ -304,10 +304,10 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
const qb = new QueryBuilder(this.connection, this.queryRunnerProvider)
.delete()
.from(relation.junctionEntityMetadata.tableName, "junctionEntity");
.from(relation.junctionEntityMetadata!.tableName, "junctionEntity");
const firstColumnName = relation.isOwning ? relation.junctionEntityMetadata.columns[1].databaseName : relation.junctionEntityMetadata.columns[0].databaseName;
const secondColumnName = relation.isOwning ? relation.junctionEntityMetadata.columns[0].databaseName : relation.junctionEntityMetadata.columns[1].databaseName;
const firstColumnName = relation.isOwning ? relation.junctionEntityMetadata!.columns[1].databaseName : relation.junctionEntityMetadata!.columns[0].databaseName;
const secondColumnName = relation.isOwning ? relation.junctionEntityMetadata!.columns[0].databaseName : relation.junctionEntityMetadata!.columns[1].databaseName;
entityIds.forEach((entityId, index) => {
qb.orWhere(`(${firstColumnName}=:relatedEntityId AND ${secondColumnName}=:entity_${index})`)
@ -431,10 +431,10 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
const relation = this.convertMixedRelationToMetadata(relationOrName);
if (!(entityOrEntities instanceof Array)) entityOrEntities = [entityOrEntities];
const entityReferencedColumns = relation.isOwning ? relation.joinColumns.map(joinColumn => joinColumn.referencedColumn!) : relation.inverseRelation.inverseJoinColumns.map(joinColumn => joinColumn.referencedColumn!);
const ownerEntityColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation.inverseJoinColumns;
const inverseEntityColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation.joinColumns;
const inverseEntityColumnNames = relation.isOwning ? relation.inverseJoinColumns.map(joinColumn => joinColumn.databaseName) : relation.inverseRelation.joinColumns.map(joinColumn => joinColumn.databaseName);
const entityReferencedColumns = relation.isOwning ? relation.joinColumns.map(joinColumn => joinColumn.referencedColumn!) : relation.inverseRelation!.inverseJoinColumns.map(joinColumn => joinColumn.referencedColumn!);
const ownerEntityColumns = relation.isOwning ? relation.joinColumns : relation.inverseRelation!.inverseJoinColumns;
const inverseEntityColumns = relation.isOwning ? relation.inverseJoinColumns : relation.inverseRelation!.joinColumns;
const inverseEntityColumnNames = relation.isOwning ? relation.inverseJoinColumns.map(joinColumn => joinColumn.databaseName) : relation.inverseRelation!.joinColumns.map(joinColumn => joinColumn.databaseName);
let entityIds = this.convertEntityOrEntitiesToIdOrIds(entityReferencedColumns, entityOrEntities);
if (!(entityIds instanceof Array)) entityIds = [entityIds];
@ -458,7 +458,7 @@ export class SpecificRepository<Entity extends ObjectLiteral> {
inverseEntityColumnNames.forEach(columnName => {
qb.select(ea("junction") + "." + ec(columnName) + " AS " + ea(columnName));
});
qb.fromTable(relation.junctionEntityMetadata.tableName, "junction");
qb.fromTable(relation.junctionEntityMetadata!.tableName, "junction");
Object.keys(entityId).forEach((columnName) => {
const junctionColumnName = ownerEntityColumns.find(joinColumn => joinColumn.referencedColumn!.databaseName === columnName);
qb.andWhere(ea("junction") + "." + ec(junctionColumnName!.databaseName) + "=:" + junctionColumnName!.databaseName + "_entityId", {[junctionColumnName!.databaseName + "_entityId"]: entityId[columnName]});

View File

@ -4,7 +4,7 @@ import {Record} from "./entity/Record";
import {Connection} from "../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
describe.skip("uuid type", () => {
describe("uuid type", () => {
let connections: Connection[];
before(async () => {