mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixed bug with duplicate entity columns in inheritance tree
This commit is contained in:
parent
85f7def856
commit
9d5288d82f
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "typeorm",
|
||||
"private": true,
|
||||
"version": "0.1.0-alpha.49",
|
||||
"version": "0.1.0-alpha.50",
|
||||
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL, MongoDB databases.",
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md",
|
||||
|
||||
@ -52,20 +52,16 @@ export class MetadataArgsStorage {
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
filterTables(target?: Function|string): TableMetadataArgs[];
|
||||
filterTables(target?: (Function|string)[]): TableMetadataArgs[];
|
||||
filterTables(target?: (Function|string)|(Function|string)[]): TableMetadataArgs[] {
|
||||
return this.tables.filter(table => {
|
||||
return target instanceof Array ? target.indexOf(table.target) !== -1 : table.target === target;
|
||||
});
|
||||
filterTables(target: Function|string): TableMetadataArgs[];
|
||||
filterTables(target: (Function|string)[]): TableMetadataArgs[];
|
||||
filterTables(target: (Function|string)|(Function|string)[]): TableMetadataArgs[] {
|
||||
return this.filterByTarget(this.tables, target);
|
||||
}
|
||||
|
||||
filterColumns(target: Function|string): ColumnMetadataArgs[];
|
||||
filterColumns(target: (Function|string)[]): ColumnMetadataArgs[];
|
||||
filterColumns(target: (Function|string)|(Function|string)[]): ColumnMetadataArgs[] {
|
||||
return this.columns.filter(column => {
|
||||
return target instanceof Array ? target.indexOf(column.target) !== -1 : column.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.columns, target);
|
||||
}
|
||||
|
||||
findGenerated(target: Function|string, propertyName: string): GeneratedMetadataArgs|undefined;
|
||||
@ -79,30 +75,25 @@ export class MetadataArgsStorage {
|
||||
filterRelations(target: Function|string): RelationMetadataArgs[];
|
||||
filterRelations(target: (Function|string)[]): RelationMetadataArgs[];
|
||||
filterRelations(target: (Function|string)|(Function|string)[]): RelationMetadataArgs[] {
|
||||
return this.relations.filter(relation => {
|
||||
return target instanceof Array ? target.indexOf(relation.target) !== -1 : relation.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.relations, target);
|
||||
}
|
||||
|
||||
filterRelationIds(target: Function|string): RelationIdMetadataArgs[];
|
||||
filterRelationIds(target: (Function|string)[]): RelationIdMetadataArgs[];
|
||||
filterRelationIds(target: (Function|string)|(Function|string)[]): RelationIdMetadataArgs[] {
|
||||
return this.relationIds.filter(relationId => {
|
||||
return target instanceof Array ? target.indexOf(relationId.target) !== -1 : relationId.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.relationIds, target);
|
||||
}
|
||||
|
||||
filterRelationCounts(target: Function|string): RelationCountMetadataArgs[];
|
||||
filterRelationCounts(target: (Function|string)[]): RelationCountMetadataArgs[];
|
||||
filterRelationCounts(target: (Function|string)|(Function|string)[]): RelationCountMetadataArgs[] {
|
||||
return this.relationCounts.filter(relationCount => {
|
||||
return target instanceof Array ? target.indexOf(relationCount.target) !== -1 : relationCount.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.relationCounts, target);
|
||||
}
|
||||
|
||||
filterIndices(target: Function|string): IndexMetadataArgs[];
|
||||
filterIndices(target: (Function|string)[]): IndexMetadataArgs[];
|
||||
filterIndices(target: (Function|string)|(Function|string)[]): IndexMetadataArgs[] {
|
||||
// todo: implement parent-entity overrides?
|
||||
return this.indices.filter(index => {
|
||||
return target instanceof Array ? target.indexOf(index.target) !== -1 : index.target === target;
|
||||
});
|
||||
@ -111,17 +102,13 @@ export class MetadataArgsStorage {
|
||||
filterListeners(target: Function|string): EntityListenerMetadataArgs[];
|
||||
filterListeners(target: (Function|string)[]): EntityListenerMetadataArgs[];
|
||||
filterListeners(target: (Function|string)|(Function|string)[]): EntityListenerMetadataArgs[] {
|
||||
return this.entityListeners.filter(index => {
|
||||
return target instanceof Array ? target.indexOf(index.target) !== -1 : index.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.entityListeners, target);
|
||||
}
|
||||
|
||||
filterEmbeddeds(target: Function|string): EmbeddedMetadataArgs[];
|
||||
filterEmbeddeds(target: (Function|string)[]): EmbeddedMetadataArgs[];
|
||||
filterEmbeddeds(target: (Function|string)|(Function|string)[]): EmbeddedMetadataArgs[] {
|
||||
return this.embeddeds.filter(embedded => {
|
||||
return target instanceof Array ? target.indexOf(embedded.target) !== -1 : embedded.target === target;
|
||||
});
|
||||
return this.filterByTargetAndWithoutDuplicateProperties(this.embeddeds, target);
|
||||
}
|
||||
|
||||
findJoinTable(target: Function|string, propertyName: string): JoinTableMetadataArgs|undefined {
|
||||
@ -131,6 +118,7 @@ export class MetadataArgsStorage {
|
||||
}
|
||||
|
||||
filterJoinColumns(target: Function|string, propertyName: string): JoinColumnMetadataArgs[] {
|
||||
// todo: implement parent-entity overrides?
|
||||
return this.joinColumns.filter(joinColumn => {
|
||||
return joinColumn.target === target && joinColumn.propertyName === propertyName;
|
||||
});
|
||||
@ -139,33 +127,25 @@ export class MetadataArgsStorage {
|
||||
filterSubscribers(target: Function|string): EntitySubscriberMetadataArgs[];
|
||||
filterSubscribers(target: (Function|string)[]): EntitySubscriberMetadataArgs[];
|
||||
filterSubscribers(target: (Function|string)|(Function|string)[]): EntitySubscriberMetadataArgs[] {
|
||||
return this.entitySubscribers.filter(subscriber => {
|
||||
return target instanceof Array ? target.indexOf(subscriber.target) !== -1 : subscriber.target === target;
|
||||
});
|
||||
return this.filterByTarget(this.entitySubscribers, target);
|
||||
}
|
||||
|
||||
filterNamingStrategies(target: Function|string): NamingStrategyMetadataArgs[];
|
||||
filterNamingStrategies(target: (Function|string)[]): NamingStrategyMetadataArgs[];
|
||||
filterNamingStrategies(target: (Function|string)|(Function|string)[]): NamingStrategyMetadataArgs[] {
|
||||
return this.namingStrategies.filter(subscriber => {
|
||||
return target instanceof Array ? target.indexOf(subscriber.target) !== -1 : subscriber.target === target;
|
||||
});
|
||||
return this.filterByTarget(this.namingStrategies, target);
|
||||
}
|
||||
|
||||
filterTransactionEntityManagers(target: Function|string): TransactionEntityMetadataArgs[];
|
||||
filterTransactionEntityManagers(target: (Function|string)[]): TransactionEntityMetadataArgs[];
|
||||
filterTransactionEntityManagers(target: (Function|string)|(Function|string)[]): TransactionEntityMetadataArgs[] {
|
||||
return this.transactionEntityManagers.filter(subscriber => {
|
||||
return target instanceof Array ? target.indexOf(subscriber.target) !== -1 : subscriber.target === target;
|
||||
});
|
||||
return this.filterByTarget(this.transactionEntityManagers, target);
|
||||
}
|
||||
|
||||
filterTransactionRepository(target: Function|string): TransactionRepositoryMetadataArgs[];
|
||||
filterTransactionRepository(target: (Function|string)[]): TransactionRepositoryMetadataArgs[];
|
||||
filterTransactionRepository(target: (Function|string)|(Function|string)[]): TransactionRepositoryMetadataArgs[] {
|
||||
return this.transactionRepositories.filter(subscriber => {
|
||||
return target instanceof Array ? target.indexOf(subscriber.target) !== -1 : subscriber.target === target;
|
||||
});
|
||||
return this.filterByTarget(this.transactionRepositories, target);
|
||||
}
|
||||
|
||||
filterSingleTableChildren(target: Function|string): TableMetadataArgs[] {
|
||||
@ -185,4 +165,32 @@ export class MetadataArgsStorage {
|
||||
return this.discriminatorValues.find(discriminatorValue => discriminatorValue.target === target);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Filters given array by a given target or targets.
|
||||
*/
|
||||
protected filterByTarget<T extends { target: Function|string }>(array: T[], target: (Function|string)|(Function|string)[]): T[] {
|
||||
return array.filter(table => {
|
||||
return target instanceof Array ? target.indexOf(table.target) !== -1 : table.target === target;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters given array by a given target or targets and prevents duplicate property names.
|
||||
*/
|
||||
protected filterByTargetAndWithoutDuplicateProperties<T extends { target: Function|string, propertyName: string }>(array: T[], target: (Function|string)|(Function|string)[]): T[] {
|
||||
const newArray: T[] = [];
|
||||
array.forEach(item => {
|
||||
const sameTarget = target instanceof Array ? target.indexOf(item.target) !== -1 : item.target === target;
|
||||
if (sameTarget) {
|
||||
if (!newArray.find(newItem => newItem.propertyName === item.propertyName))
|
||||
newArray.push(item);
|
||||
}
|
||||
});
|
||||
return newArray;
|
||||
}
|
||||
|
||||
}
|
||||
@ -280,14 +280,16 @@ export class EntityMetadataBuilder {
|
||||
entityMetadata.discriminatorValue = discriminatorValue ? discriminatorValue.value : (tableArgs.target as any).name; // todo: pass this to naming strategy to generate a name
|
||||
|
||||
entityMetadata.embeddeds = this.createEmbeddedsRecursively(entityMetadata, this.metadataArgsStorage.filterEmbeddeds(inheritanceTree));
|
||||
entityMetadata.ownColumns = this.metadataArgsStorage.filterColumns(inheritanceTree).map(args => {
|
||||
const column = new ColumnMetadata({ connection: this.connection, entityMetadata, args });
|
||||
// console.log(column.propertyName);
|
||||
// if single table inheritance used, we need to mark all inherit table columns as nullable
|
||||
if (singleTableChildrenTargets && singleTableChildrenTargets.indexOf(args.target) !== -1)
|
||||
column.isNullable = true;
|
||||
return column;
|
||||
});
|
||||
entityMetadata.ownColumns = this.metadataArgsStorage
|
||||
.filterColumns(inheritanceTree)
|
||||
.map(args => {
|
||||
const column = new ColumnMetadata({ connection: this.connection, entityMetadata, args });
|
||||
// console.log(column.propertyName);
|
||||
// if single table inheritance used, we need to mark all inherit table columns as nullable
|
||||
if (singleTableChildrenTargets && singleTableChildrenTargets.indexOf(args.target) !== -1)
|
||||
column.isNullable = true;
|
||||
return column;
|
||||
});
|
||||
|
||||
entityMetadata.ownRelations = this.metadataArgsStorage.filterRelations(inheritanceTree).map(args => {
|
||||
return new RelationMetadata({ entityMetadata, args });
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
|
||||
export class BaseContent {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {BaseContent} from "./BaseContent";
|
||||
|
||||
export class BasePost extends BaseContent {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
import {Entity} from "../../../../src/decorator/entity/Entity";
|
||||
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {Column} from "../../../../src/decorator/columns/Column";
|
||||
import {BasePost} from "./BasePost";
|
||||
|
||||
@Entity()
|
||||
export class Post extends BasePost {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
@Column({ default: false })
|
||||
active: boolean;
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
import "reflect-metadata";
|
||||
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
|
||||
import {Connection} from "../../../src/connection/Connection";
|
||||
import {Post} from "./entity/Post";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe("other issues > double inheritance produces multiple duplicated columns", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
dropSchema: true,
|
||||
}));
|
||||
beforeEach(() => reloadTestingDatabases(connections));
|
||||
after(() => closeTestingConnections(connections));
|
||||
|
||||
it("should not produce duplicate columns", () => Promise.all(connections.map(async function(connection) {
|
||||
|
||||
// insert a post
|
||||
const post = new Post();
|
||||
post.title = "hello";
|
||||
await connection.manager.save(post);
|
||||
|
||||
// check if it was inserted correctly
|
||||
const loadedPost = await connection.manager.findOne(Post);
|
||||
expect(loadedPost).not.to.be.empty;
|
||||
loadedPost!.title.should.be.equal("hello");
|
||||
|
||||
})));
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user