removed class table inheritance support

This commit is contained in:
Umed Khudoiberdiev 2017-12-07 15:58:28 +05:00
parent a15dbfb7c2
commit 2a0ae48dac
74 changed files with 214 additions and 1241 deletions

View File

@ -18,7 +18,6 @@ feel free to ask us and community.
* now you can disable persistence on any relation by setting `@OneToMany(type => Post, post => tag, { persistence: false })`. This can dramatically improve entity save performance.
* `loadAllRelationIds` method of `QueryBuilder` now accepts list of relation paths that needs to be loaded, also `disableMixedMap` option is now by default set to false, but you can enable it via new method parameter `options`
* lot of changes affect closure table pattern which is planned for fix in 0.3.0
* lot of changes affect table inheritance patterns which are planned for fix in 0.3.0
* now `returning` and `output` statements of `InsertQueryBuilder` support array of columns as argument
* now when many-to-many and one-to-many relation set to `null` all items from that relation are removed, just like it would be set to empty array
* fixed issues with relation updation from one-to-one non-owner side
@ -46,6 +45,12 @@ Use `findOne(id)` method instead now.
* added ability to disable listeners and subscribers in `save` and `remove` operations
* added ability to save and remove objects in chunks
* added ability to disable entity reloading after insertion and updation
* class table inheritance functionality has been completely dropped
* single table inheritance functionality has been fixed
* `@SingleEntityChild` has been renamed to `@ChildEntity`
* `@DiscriminatorValue` has been removed, instead parameter in `@ChildEntity` must be used, e.g. `@ChildEntity("value")`
* `@DiscriminatorColumn` decorator has been removed, use `@TableInheritance` options instead now
## 0.1.7

View File

@ -31,7 +31,6 @@ npm i typeorm@next
- [ ] implement soft deletion
- [ ] research ability to create one-to-many relations without inverse sides
- [ ] research ability to create a single relation with multiple entities at once
- [ ] fix all table-inheritance issues, better class-table and single-table inheritance support
- [ ] add more tree-table features: nested set and materialized path; more repository methods
- [ ] cli: create database backup command
- [ ] extend `query` method functionality
@ -50,3 +49,4 @@ npm i typeorm@next
- [x] fix all issues with cascades and make stable functionality
- [ ] implement API for manual migration creation
- [x] add sql.js driver
- [x] fix inheritance support issues

View File

@ -1,8 +1,8 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {SingleEntityChild} from "../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../src/decorator/entity/ChildEntity";
@SingleEntityChild()
@ChildEntity()
export class Employee extends Person {
@Column()

View File

@ -1,10 +1,8 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {DiscriminatorValue} from "../../../src/decorator/DiscriminatorValue";
import {SingleEntityChild} from "../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../src/decorator/entity/ChildEntity";
@SingleEntityChild()
@DiscriminatorValue("home-sitter") // can be omitted
@ChildEntity("home-sitter")
export class Homesitter extends Person {
@Column()

View File

@ -1,6 +1,5 @@
import {Column} from "../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
@ -8,8 +7,7 @@ import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
// * check how it works when is join (conditions are not added in the joins right now)
@Entity("sample28_person")
@TableInheritance("single-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export abstract class Person {
@PrimaryColumn("int")

View File

@ -1,8 +1,8 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {SingleEntityChild} from "../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../src/decorator/entity/ChildEntity";
@SingleEntityChild()
@ChildEntity()
export class Student extends Person {
@Column()

View File

@ -1,108 +0,0 @@
import "reflect-metadata";
import {ConnectionOptions, createConnection} from "../../src/index";
import {Employee} from "./entity/Employee";
import {Homesitter} from "./entity/Homesitter";
import {Student} from "./entity/Student";
import {Person} from "./entity/Person";
const options: ConnectionOptions = {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test",
logging: ["query", "error"],
synchronize: true,
entities: [
Person,
Employee,
Homesitter,
Student
]
};
createConnection(options).then(async connection => {
let employeeRepository = connection.getRepository(Employee);
const employee = new Employee();
employee.id = 1;
employee.firstName = "umed";
employee.lastName = "khudoiberdiev";
employee.salary = 300000;
console.log("saving the employee: ");
await employeeRepository.save(employee);
console.log("employee has been saved: ", employee);
console.log("updating the employee: ");
employee.firstName = "zuma";
employee.lastName += "a";
await employeeRepository.save(employee);
console.log("employee has been updated: ", employee);
console.log("now loading the employee: ");
const loadedEmployee = (await employeeRepository.findOne(1))!;
console.log("loaded employee: ", loadedEmployee);
loadedEmployee.firstName = "dima";
await employeeRepository.save(loadedEmployee);
const allEmployees = await employeeRepository.findAndCount();
console.log("all employees: ", allEmployees);
console.log("deleting employee: ", loadedEmployee);
await employeeRepository.remove(loadedEmployee);
console.log("employee deleted");
console.log("-----------------");
/*let homesitterRepository = connection.getRepository(Homesitter);
const homesitter = new Homesitter();
homesitter.id = 2;
homesitter.firstName = "umed";
homesitter.lastName = "khudoiberdiev";
homesitter.numberOfKids = 5;
console.log("saving the homesitter: ");
await homesitterRepository.save(homesitter);
console.log("homesitter has been saved: ", homesitter);
console.log("now loading the homesitter: ");
const loadedHomesitter = await homesitterRepository.findOne(2);
console.log("loaded homesitter: ", loadedHomesitter);
console.log("-----------------");
let studentRepository = connection.getRepository(Student);
const student = new Student();
student.id = 3;
student.firstName = "umed";
student.lastName = "khudoiberdiev";
student.faculty = "computer science";
console.log("saving the student: ");
await studentRepository.save(student);
console.log("student has been saved: ", student);
console.log("now loading the student: ");
const loadedStudent = await studentRepository.findOne(3);
console.log("loaded student: ", loadedStudent);
console.log("-----------------");
const secondEmployee = await employeeRepository.findOne(2);
console.log("Non exist employee: ", secondEmployee);
const thirdEmployee = await employeeRepository.findOne(3);
console.log("Non exist employee: ", thirdEmployee);
console.log("-----------------");
const secondHomesitter = await homesitterRepository.findOne(1);
console.log("Non exist homesitter: ", secondHomesitter);
const thirdHomesitter = await homesitterRepository.findOne(3);
console.log("Non exist homesitter: ", thirdHomesitter);
console.log("-----------------");
const secondStudent = await studentRepository.findOne(1);
console.log("Non exist student: ", secondStudent);
const thirdStudent = await studentRepository.findOne(2);
console.log("Non exist student: ", thirdStudent);*/
}).catch(error => console.log("Error: ", error));

View File

@ -1,11 +0,0 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {ClassEntityChild} from "../../../src/decorator/entity/ClassEntityChild";
@ClassEntityChild("sample29_employee")
export class Employee extends Person {
@Column()
salary: number;
}

View File

@ -1,13 +0,0 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {DiscriminatorValue} from "../../../src/decorator/DiscriminatorValue";
import {ClassEntityChild} from "../../../src/decorator/entity/ClassEntityChild";
@ClassEntityChild("sample29_homesitter")
@DiscriminatorValue("home-sitter") // can be omitted
export class Homesitter extends Person {
@Column()
numberOfKids: number;
}

View File

@ -1,21 +0,0 @@
import {Column} from "../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
@Entity("sample29_person")
@TableInheritance("class-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
export abstract class Person {
@PrimaryColumn("int")
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
}

View File

@ -1,12 +0,0 @@
import {Column} from "../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {ClassEntityChild} from "../../../src/decorator/entity/ClassEntityChild";
@ClassEntityChild("sample29_student")
@ClassEntityChild()
export class Student extends Person {
@Column()
faculty: string;
}

View File

@ -1,16 +0,0 @@
import {getMetadataArgsStorage} from "../index";
import {DiscriminatorValueMetadataArgs} from "../metadata-args/DiscriminatorValueMetadataArgs";
/**
* If entity is a child table of some table, it should have a discriminator value.
* This decorator sets custom discriminator value for the entity.
*/
export function DiscriminatorValue(value: any): Function {
return function (target: Function) {
const args: DiscriminatorValueMetadataArgs = {
target: target,
value: value
};
getMetadataArgsStorage().discriminatorValues.push(args);
};
}

View File

@ -1,30 +0,0 @@
import {ColumnOptions} from "../options/ColumnOptions";
import {ColumnType} from "../../driver/types/ColumnTypes";
import {getMetadataArgsStorage} from "../../index";
import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs";
/**
* DiscriminatorColumn is a special type column used on entity class (not entity property)
* and creates a special column which will contain an entity type.
* This type is required for entities which use single table inheritance pattern.
*/
export function DiscriminatorColumn(discriminatorOptions: { name: string, type: ColumnType }): Function {
return function (target: Function) {
// if column options are not given then create a new empty options
const options: ColumnOptions = {
name: discriminatorOptions.name,
type: discriminatorOptions.type
};
// create and register a new column metadata
const args: ColumnMetadataArgs = {
target: target,
mode: "discriminator",
propertyName: discriminatorOptions.name,
options: options
};
getMetadataArgsStorage().columns.push(args);
};
}

View File

@ -0,0 +1,28 @@
import {getMetadataArgsStorage} from "../../index";
import {TableMetadataArgs} from "../../metadata-args/TableMetadataArgs";
import {DiscriminatorValueMetadataArgs} from "../../metadata-args/DiscriminatorValueMetadataArgs";
/**
* Special type of the table used in the single-table inherited tables.
*/
export function ChildEntity(discriminatorValue?: string) {
return function (target: Function) {
const tableMetadataArgs: TableMetadataArgs = {
target: target,
name: undefined,
type: "entity-child",
orderBy: undefined
};
getMetadataArgsStorage().tables.push(tableMetadataArgs);
if (discriminatorValue) {
const discriminatorValueMetadataArgs: DiscriminatorValueMetadataArgs = {
target: target,
value: discriminatorValue
};
getMetadataArgsStorage().discriminatorValues.push(discriminatorValueMetadataArgs);
}
};
}

View File

@ -1,19 +0,0 @@
import {getMetadataArgsStorage} from "../../index";
import {TableMetadataArgs} from "../../metadata-args/TableMetadataArgs";
import {EntityOptions} from "../options/EntityOptions";
/**
* Special type of the entity used in the class-table inherited tables.
*/
export function ClassEntityChild(tableName?: string, options?: EntityOptions) {
return function (target: Function) {
const args: TableMetadataArgs = {
target: target,
name: tableName,
type: "class-table-child",
orderBy: options && options.orderBy ? options.orderBy : undefined,
skipSync: !!(options && options.skipSync === true)
};
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -1,17 +0,0 @@
import {getMetadataArgsStorage} from "../../index";
import {TableMetadataArgs} from "../../metadata-args/TableMetadataArgs";
/**
* Special type of the table used in the single-table inherited tables.
*/
export function SingleEntityChild() {
return function (target: Function) {
const args: TableMetadataArgs = {
target: target,
name: undefined,
type: "single-table-child",
orderBy: undefined
};
getMetadataArgsStorage().tables.push(args);
};
}

View File

@ -1,14 +1,16 @@
import {getMetadataArgsStorage} from "../../index";
import {InheritanceMetadataArgs} from "../../metadata-args/InheritanceMetadataArgs";
import {ColumnOptions} from "../options/ColumnOptions";
/**
* Sets what kind of table-inheritance table will use.
* Sets for entity to use table inheritance pattern.
*/
export function TableInheritance(type: "single-table"|"class-table") { // todo: create two decorators instead?
export function TableInheritance(options?: { pattern?: "STI"/*|"CTI"*/, column?: string|ColumnOptions }) {
return function (target: Function) {
const args: InheritanceMetadataArgs = {
target: target,
type: type
pattern: options && options.pattern ? options.pattern : "STI",
column: options && options.column ? typeof options.column === "string" ? { name: options.column } : options.column : undefined
};
getMetadataArgsStorage().inheritances.push(args);
};

View File

@ -26,7 +26,6 @@ export * from "./common/ObjectLiteral";
export * from "./error/QueryFailedError";
export * from "./decorator/columns/Column";
export * from "./decorator/columns/CreateDateColumn";
export * from "./decorator/columns/DiscriminatorColumn";
export * from "./decorator/columns/PrimaryGeneratedColumn";
export * from "./decorator/columns/PrimaryColumn";
export * from "./decorator/columns/UpdateDateColumn";
@ -56,9 +55,8 @@ export * from "./decorator/relations/OneToOne";
export * from "./decorator/relations/RelationCount";
export * from "./decorator/relations/RelationId";
export * from "./decorator/entity/Entity";
export * from "./decorator/entity/ClassEntityChild";
export * from "./decorator/entity/ClosureEntity";
export * from "./decorator/entity/SingleEntityChild";
export * from "./decorator/entity/ChildEntity";
export * from "./decorator/entity/TableInheritance";
export * from "./decorator/transaction/Transaction";
export * from "./decorator/transaction/TransactionManager";
@ -68,7 +66,6 @@ export * from "./decorator/tree/TreeParent";
export * from "./decorator/tree/TreeChildren";
export * from "./decorator/Index";
export * from "./decorator/Generated";
export * from "./decorator/DiscriminatorValue";
export * from "./decorator/EntityRepository";
export * from "./find-options/FindOneOptions";
export * from "./find-options/FindManyOptions";

View File

@ -1,3 +1,5 @@
import {ColumnOptions} from "../decorator/options/ColumnOptions";
/**
* Arguments for InheritanceMetadata class.
*/
@ -9,8 +11,13 @@ export interface InheritanceMetadataArgs {
readonly target?: Function|string;
/**
* Inheritance type.
* Inheritance pattern.
*/
readonly type: "single-table"|"class-table";
readonly pattern: "STI"/*|"CTI"*/;
/**
* Column used as inheritance discriminator column.
*/
readonly column?: ColumnOptions;
}

View File

@ -153,7 +153,7 @@ export class MetadataArgsStorage {
return table.target instanceof Function
&& target instanceof Function
&& MetadataUtils.isInherited(table.target, target)
&& table.type === "single-table-child";
&& table.type === "entity-child";
});
}

View File

@ -4,4 +4,4 @@
* For example, "primary" means that it will be a primary column, or "createDate" means that it will create a create
* date column.
*/
export type ColumnMode = "regular"|"virtual"|"createDate"|"updateDate"|"version"|"treeChildrenCount"|"treeLevel"|"discriminator"|"parentId"|"objectId"|"array";
export type ColumnMode = "regular"|"virtual"|"createDate"|"updateDate"|"version"|"treeChildrenCount"|"treeLevel"|"objectId"|"array";

View File

@ -14,8 +14,6 @@ import {ClosureJunctionEntityMetadataBuilder} from "./ClosureJunctionEntityMetad
import {RelationJoinColumnBuilder} from "./RelationJoinColumnBuilder";
import {Connection} from "../connection/Connection";
import {EntityListenerMetadata} from "../metadata/EntityListenerMetadata";
import {ColumnOptions} from "../decorator/options/ColumnOptions";
import {ForeignKeyMetadata} from "../metadata/ForeignKeyMetadata";
import {LazyRelationsWrapper} from "../lazy-loading/LazyRelationsWrapper";
/**
@ -67,7 +65,7 @@ export class EntityMetadataBuilder {
const allTables = entityClasses ? this.metadataArgsStorage.filterTables(entityClasses) : this.metadataArgsStorage.tables;
// filter out table metadata args for those we really create entity metadatas and tables in the db
const realTables = allTables.filter(table => table.type === "regular" || table.type === "closure" || table.type === "class-table-child" || table.type === "single-table-child");
const realTables = allTables.filter(table => table.type === "regular" || table.type === "closure" || table.type === "entity-child");
// create entity metadatas for a user defined entities (marked with @Entity decorator or loaded from entity schemas)
const entityMetadatas = realTables.map(tableArgs => this.createEntityMetadata(tableArgs));
@ -77,22 +75,22 @@ export class EntityMetadataBuilder {
// build entity metadata (step0), first for non-single-table-inherited entity metadatas (dependant)
entityMetadatas
.filter(entityMetadata => entityMetadata.tableType !== "single-table-child")
.filter(entityMetadata => entityMetadata.tableType !== "entity-child")
.forEach(entityMetadata => entityMetadata.build());
// build entity metadata (step0), now for single-table-inherited entity metadatas (dependant)
entityMetadatas
.filter(entityMetadata => entityMetadata.tableType === "single-table-child")
.filter(entityMetadata => entityMetadata.tableType === "entity-child")
.forEach(entityMetadata => entityMetadata.build());
// compute entity metadata columns, relations, etc. first for the regular, non-single-table-inherited entity metadatas
entityMetadatas
.filter(entityMetadata => entityMetadata.tableType !== "single-table-child")
.filter(entityMetadata => entityMetadata.tableType !== "entity-child")
.forEach(entityMetadata => this.computeEntityMetadataStep1(entityMetadatas, entityMetadata));
// then do it for single table inheritance children (since they are depend on their parents to be built)
entityMetadatas
.filter(entityMetadata => entityMetadata.tableType === "single-table-child")
.filter(entityMetadata => entityMetadata.tableType === "entity-child")
.forEach(entityMetadata => this.computeEntityMetadataStep1(entityMetadatas, entityMetadata));
// calculate entity metadata computed properties and all its sub-metadatas
@ -103,7 +101,7 @@ export class EntityMetadataBuilder {
// go through all entity metadatas and create foreign keys / junction entity metadatas for their relations
entityMetadatas
.filter(entityMetadata => entityMetadata.tableType !== "single-table-child")
.filter(entityMetadata => entityMetadata.tableType !== "entity-child")
.forEach(entityMetadata => {
// create entity's relations join columns (for many-to-one and one-to-one owner)
@ -148,7 +146,7 @@ export class EntityMetadataBuilder {
entityMetadatas.push(closureJunctionEntityMetadata);
});
// after all metadatas created we set child entity metadatas for class-table inheritance
// after all metadatas created we set child entity metadatas for table inheritance
entityMetadatas.forEach(metadata => {
metadata.childEntityMetadatas = entityMetadatas.filter(childMetadata => {
return metadata.target instanceof Function
@ -159,7 +157,7 @@ export class EntityMetadataBuilder {
// generate keys for tables with single-table inheritance
entityMetadatas
.filter(metadata => metadata.inheritanceType === "single-table" && metadata.discriminatorColumn)
.filter(metadata => metadata.inheritancePattern === "STI" && metadata.discriminatorColumn)
.forEach(entityMetadata => this.createKeysForTableInheritance(entityMetadata));
// build all indices (need to do it after relations and their join columns are built)
@ -167,46 +165,6 @@ export class EntityMetadataBuilder {
entityMetadata.indices.forEach(index => index.build(this.connection.namingStrategy));
});
entityMetadatas
.filter(metadata => !!metadata.parentEntityMetadata && metadata.tableType === "class-table-child")
.forEach(metadata => {
const parentPrimaryColumns = metadata.parentEntityMetadata.primaryColumns;
const parentRelationColumns = parentPrimaryColumns.map(parentPrimaryColumn => {
const columnName = this.connection.namingStrategy.classTableInheritanceParentColumnName(metadata.parentEntityMetadata.tableName, parentPrimaryColumn.propertyPath);
const column = new ColumnMetadata({
connection: this.connection,
entityMetadata: metadata,
referencedColumn: parentPrimaryColumn,
args: {
target: metadata.target,
propertyName: columnName,
mode: "parentId",
options: <ColumnOptions> {
name: columnName,
type: parentPrimaryColumn.type,
unique: false,
nullable: false,
primary: true
}
}
});
metadata.registerColumn(column);
column.build(this.connection);
return column;
});
metadata.foreignKeys = [
new ForeignKeyMetadata({
entityMetadata: metadata,
referencedEntityMetadata: metadata.parentEntityMetadata,
namingStrategy: this.connection.namingStrategy,
columns: parentRelationColumns,
referencedColumns: parentPrimaryColumns,
onDelete: "CASCADE"
})
];
});
// add lazy initializer for entity relations
entityMetadatas
.filter(metadata => metadata.target instanceof Function)
@ -258,43 +216,37 @@ export class EntityMetadataBuilder {
// if single table inheritance used, we need to copy all children columns in to parent table
let singleTableChildrenTargets: any[];
if ((tableInheritance && tableInheritance.type === "single-table") || tableArgs.type === "single-table-child") {
if ((tableInheritance && tableInheritance.pattern === "STI") || tableArgs.type === "entity-child") {
singleTableChildrenTargets = this.metadataArgsStorage
.filterSingleTableChildren(tableArgs.target)
.map(args => args.target)
.filter(target => target instanceof Function);
inheritanceTree.push(...singleTableChildrenTargets);
} else if ((tableInheritance && tableInheritance.type === "class-table") || tableArgs.type === "class-table-child") {
inheritanceTree.forEach(inheritanceTreeItem => {
const isParent = !!this.metadataArgsStorage.inheritances.find(i => i.target === inheritanceTreeItem);
if (isParent)
inheritanceTree.splice(inheritanceTree.indexOf(inheritanceTreeItem), 1);
});
}
return new EntityMetadata({
connection: this.connection,
args: tableArgs,
inheritanceTree: inheritanceTree,
inheritanceType: tableInheritance ? tableInheritance.type : undefined
inheritancePattern: tableInheritance ? tableInheritance.pattern : undefined
});
}
protected computeParentEntityMetadata(allEntityMetadatas: EntityMetadata[], entityMetadata: EntityMetadata) {
// after all metadatas created we set parent entity metadata for table inheritance
if (entityMetadata.tableType === "single-table-child" || entityMetadata.tableType === "class-table-child") {
if (entityMetadata.tableType === "entity-child") {
entityMetadata.parentEntityMetadata = allEntityMetadatas.find(allEntityMetadata => {
return allEntityMetadata.inheritanceTree.indexOf(entityMetadata.target as Function) !== -1 &&
(allEntityMetadata.inheritanceType === "single-table" || allEntityMetadata.inheritanceType === "class-table");
return allEntityMetadata.inheritanceTree.indexOf(entityMetadata.target as Function) !== -1 && allEntityMetadata.inheritancePattern === "STI";
})!;
}
}
protected computeEntityMetadataStep1(allEntityMetadatas: EntityMetadata[], entityMetadata: EntityMetadata) {
const entityInheritance = this.metadataArgsStorage.findInheritanceType(entityMetadata.target);
const discriminatorValue = this.metadataArgsStorage.findDiscriminatorValue(entityMetadata.target);
entityMetadata.discriminatorValue = discriminatorValue ? discriminatorValue.value : (entityMetadata.target as any).name; // todo: pass this to naming strategy to generate a name
@ -304,22 +256,50 @@ export class EntityMetadataBuilder {
.map(args => {
// for single table children we reuse columns created for their parents
if (entityMetadata.tableType === "single-table-child")
if (entityMetadata.tableType === "entity-child")
return entityMetadata.parentEntityMetadata.ownColumns.find(column => column.propertyName === args.propertyName)!;
const column = new ColumnMetadata({ connection: this.connection, entityMetadata, args });
// if single table inheritance used, we need to mark all inherit table columns as nullable
const columnInSingleTableInheritedChild = allEntityMetadatas.find(otherEntityMetadata => otherEntityMetadata.tableType === "single-table-child" && otherEntityMetadata.target === args.target);
const columnInSingleTableInheritedChild = allEntityMetadatas.find(otherEntityMetadata => otherEntityMetadata.tableType === "entity-child" && otherEntityMetadata.target === args.target);
if (columnInSingleTableInheritedChild)
column.isNullable = true;
return column;
});
// for table inheritance we need to add a discriminator column
//
if (entityInheritance && entityInheritance.column) {
const discriminatorColumnName = entityInheritance.column && entityInheritance.column.name ? entityInheritance.column.name : "type";
let discriminatorColumn = entityMetadata.ownColumns.find(column => column.propertyName === discriminatorColumnName);
if (!discriminatorColumn) {
discriminatorColumn = new ColumnMetadata({
connection: this.connection,
entityMetadata: entityMetadata,
args: {
target: entityMetadata.target,
mode: "virtual",
propertyName: discriminatorColumnName,
options: entityInheritance.column || {
name: "type",
type: "varchar",
nullable: false
}
}
});
discriminatorColumn.isVirtual = true;
discriminatorColumn.isDiscriminator = true;
entityMetadata.ownColumns.push(discriminatorColumn);
} else {
discriminatorColumn.isDiscriminator = true;
}
}
entityMetadata.ownRelations = this.metadataArgsStorage.filterRelations(entityMetadata.inheritanceTree).map(args => {
// for single table children we reuse relations created for their parents
if (entityMetadata.tableType === "single-table-child")
if (entityMetadata.tableType === "entity-child")
return entityMetadata.parentEntityMetadata.ownRelations.find(relation => relation.propertyName === args.propertyName)!;
return new RelationMetadata({ entityMetadata, args });
@ -327,7 +307,7 @@ export class EntityMetadataBuilder {
entityMetadata.relationIds = this.metadataArgsStorage.filterRelationIds(entityMetadata.inheritanceTree).map(args => {
// for single table children we reuse relation ids created for their parents
if (entityMetadata.tableType === "single-table-child")
if (entityMetadata.tableType === "entity-child")
return entityMetadata.parentEntityMetadata.relationIds.find(relationId => relationId.propertyName === args.propertyName)!;
return new RelationIdMetadata({ entityMetadata, args });
@ -335,7 +315,7 @@ export class EntityMetadataBuilder {
entityMetadata.relationCounts = this.metadataArgsStorage.filterRelationCounts(entityMetadata.inheritanceTree).map(args => {
// for single table children we reuse relation counts created for their parents
if (entityMetadata.tableType === "single-table-child")
if (entityMetadata.tableType === "entity-child")
return entityMetadata.parentEntityMetadata.relationCounts.find(relationCount => relationCount.propertyName === args.propertyName)!;
return new RelationCountMetadata({ entityMetadata, args });
@ -424,7 +404,6 @@ export class EntityMetadataBuilder {
entityMetadata.versionColumn = entityMetadata.columns.find(column => column.isVersion);
entityMetadata.discriminatorColumn = entityMetadata.columns.find(column => column.isDiscriminator);
entityMetadata.treeLevelColumn = entityMetadata.columns.find(column => column.isTreeLevel);
entityMetadata.parentIdColumns = entityMetadata.columns.filter(column => column.isParentId);
entityMetadata.objectIdColumn = entityMetadata.columns.find(column => column.isObjectId);
entityMetadata.foreignKeys.forEach(foreignKey => foreignKey.build(this.connection.namingStrategy));
entityMetadata.propertiesMap = entityMetadata.createPropertiesMap();
@ -479,135 +458,4 @@ export class EntityMetadataBuilder {
);
}
}
// generate virtual column with foreign key for class-table inheritance
/*entityMetadatas.forEach(entityMetadata => {
if (!entityMetadata.parentEntityMetadata)
return;
const parentPrimaryColumns = entityMetadata.parentEntityMetadata.primaryColumns;
const parentIdColumns = parentPrimaryColumns.map(primaryColumn => {
const columnName = this.namingStrategy.classTableInheritanceParentColumnName(entityMetadata.parentEntityMetadata.tableName, primaryColumn.propertyName);
const column = new ColumnMetadataBuilder(entityMetadata);
column.type = primaryColumn.type;
column.propertyName = primaryColumn.propertyName; // todo: check why needed
column.givenName = columnName;
column.mode = "parentId";
column.isUnique = true;
column.isNullable = false;
// column.entityTarget = entityMetadata.target;
return column;
});
// add foreign key
const foreignKey = new ForeignKeyMetadataBuilder(
entityMetadata,
parentIdColumns,
entityMetadata.parentEntityMetadata,
parentPrimaryColumns,
"CASCADE"
);
entityMetadata.ownColumns.push(...parentIdColumns);
entityMetadata.foreignKeys.push(foreignKey);
});*/
/*protected createEntityMetadata(metadata: EntityMetadata, options: {
userSpecifiedTableName?: string,
closureOwnerTableName?: string,
}) {
const tableNameUserSpecified = options.userSpecifiedTableName;
const isClosureJunction = metadata.tableType === "closure-junction";
const targetName = metadata.target instanceof Function ? (metadata.target as any).name : metadata.target;
const tableNameWithoutPrefix = isClosureJunction
? this.namingStrategy.closureJunctionTableName(options.closureOwnerTableName!)
: this.namingStrategy.tableName(targetName, options.userSpecifiedTableName);
const tableName = this.namingStrategy.prefixTableName(this.driver.options.tablesPrefix, tableNameWithoutPrefix);
// for virtual tables (like junction table) target is equal to undefined at this moment
// we change this by setting virtual's table name to a target name
// todo: add validation so targets with same schema names won't conflicts with virtual table names
metadata.target = metadata.target ? metadata.target : tableName;
metadata.targetName = targetName;
metadata.givenTableName = tableNameUserSpecified;
metadata.tableNameWithoutPrefix = tableNameWithoutPrefix;
metadata.tableName = tableName;
metadata.name = targetName ? targetName : tableName;
// metadata.namingStrategy = this.namingStrategy;
}*/
/*protected createEntityMetadata(tableArgs: any, argsForTable: any, ): EntityMetadata {
const metadata = new EntityMetadata({
junction: false,
target: tableArgs.target,
tablesPrefix: this.driver.options.tablesPrefix,
namingStrategy: this.namingStrategy,
tableName: argsForTable.name,
tableType: argsForTable.type,
orderBy: argsForTable.orderBy,
engine: argsForTable.engine,
skipSchemaSync: argsForTable.skipSchemaSync,
columnMetadatas: columns,
relationMetadatas: relations,
relationIdMetadatas: relationIds,
relationCountMetadatas: relationCounts,
indexMetadatas: indices,
embeddedMetadatas: embeddeds,
inheritanceType: mergedArgs.inheritance ? mergedArgs.inheritance.type : undefined,
discriminatorValue: discriminatorValueArgs ? discriminatorValueArgs.value : (tableArgs.target as any).name // todo: pass this to naming strategy to generate a name
}, this.lazyRelationsWrapper);
return metadata;
}*/
// const tables = [mergedArgs.table].concat(mergedArgs.children);
// tables.forEach(tableArgs => {
// find embeddable tables for embeddeds registered in this table and create EmbeddedMetadatas from them
// const findEmbeddedsRecursively = (embeddedArgs: EmbeddedMetadataArgs[]) => {
// const embeddeds: EmbeddedMetadata[] = [];
// embeddedArgs.forEach(embedded => {
// const embeddableTable = embeddableMergedArgs.find(embeddedMergedArgs => embeddedMergedArgs.table.target === embedded.type());
// if (embeddableTable) {
// const columns = embeddableTable.columns.toArray().map(args => new ColumnMetadata(args));
// const relations = embeddableTable.relations.toArray().map(args => new RelationMetadata(args));
// const subEmbeddeds = findEmbeddedsRecursively(embeddableTable.embeddeds.toArray());
// embeddeds.push(new EmbeddedMetadata(columns, relations, subEmbeddeds, embedded));
// }
// });
// return embeddeds;
// };
// const embeddeds = findEmbeddedsRecursively(mergedArgs.embeddeds.toArray());
// create metadatas from args
// const argsForTable = mergedArgs.inheritance && mergedArgs.inheritance.type === "single-table" ? mergedArgs.table : tableArgs;
// const table = new TableMetadata(argsForTable);
// const columns = mergedArgs.columns.toArray().map(args => {
//
// // if column's target is a child table then this column should have all nullable columns
// if (mergedArgs.inheritance &&
// mergedArgs.inheritance.type === "single-table" &&
// args.target !== mergedArgs.table.target && !!mergedArgs.children.find(childTable => childTable.target === args.target)) {
// args.options.nullable = true;
// }
// return new ColumnMetadata(args);
// });
// const discriminatorValueArgs = mergedArgs.discriminatorValues.find(discriminatorValueArgs => {
// return discriminatorValueArgs.target === tableArgs.target;
// });
// after all metadatas created we set parent entity metadata for class-table inheritance
// entityMetadatas.forEach(entityMetadata => {
// const mergedArgs = realTables.find(args => args.target === entityMetadata.target);
// if (mergedArgs && mergedArgs.parent) {
// const parentEntityMetadata = entityMetadatas.find(entityMetadata => entityMetadata.target === (mergedArgs!.parent! as any).target); // todo: weird compiler error here, thats why type casing is used
// if (parentEntityMetadata)
// entityMetadata.parentEntityMetadata = parentEntityMetadata;
// }
// });
}

View File

@ -47,12 +47,12 @@ export class EntityMetadataValidator {
validate(entityMetadata: EntityMetadata, allEntityMetadatas: EntityMetadata[], driver: Driver) {
// check if table metadata has an id
if (!entityMetadata.isClassTableChild && !entityMetadata.primaryColumns.length && !entityMetadata.isJunction)
if (!entityMetadata.primaryColumns.length && !entityMetadata.isJunction)
throw new MissingPrimaryColumnError(entityMetadata);
// validate if table is using inheritance it has a discriminator
// also validate if discriminator values are not empty and not repeated
if (entityMetadata.inheritanceType === "single-table") {
if (entityMetadata.inheritancePattern === "STI") {
if (!entityMetadata.discriminatorColumn)
throw new Error(`Entity ${entityMetadata.name} using single-table inheritance, it should also have a discriminator column. Did you forget to put @DiscriminatorColumn decorator?`);

View File

@ -175,11 +175,6 @@ export class ColumnMetadata {
*/
isVirtual: boolean = false;
/**
* Indicates if column is a parent id. Parent id columns are not mapped to the entity.
*/
isParentId: boolean = false;
/**
* Indicates if column is discriminator. Discriminator columns are not mapped to the entity.
*/
@ -286,8 +281,6 @@ export class ColumnMetadata {
this.isArray = options.args.options.array;
if (options.args.mode) {
this.isVirtual = options.args.mode === "virtual";
this.isParentId = options.args.mode === "parentId";
this.isDiscriminator = options.args.mode === "discriminator";
this.isTreeLevel = options.args.mode === "treeLevel";
this.isCreateDate = options.args.mode === "createDate";
this.isUpdateDate = options.args.mode === "updateDate";

View File

@ -290,7 +290,7 @@ export class EntityMetadata {
* If this entity metadata's table using one of the inheritance patterns,
* then this will contain what pattern it uses.
*/
inheritanceType?: "single-table"|"class-table";
inheritancePattern?: "STI"/*|"CTI"*/;
/**
* If this entity metadata is a child table of some table, it should have a discriminator value.
@ -348,11 +348,6 @@ export class EntityMetadata {
*/
primaryColumns: ColumnMetadata[] = [];
/**
* Id columns in the parent table (used in table inheritance).
*/
parentIdColumns: ColumnMetadata[] = [];
/**
* Gets only one-to-one relations of the entity.
*/
@ -435,18 +430,6 @@ export class EntityMetadata {
*/
isEmbeddable: boolean;
/**
* Checks if this table is a single table child.
* Special table type for tables that are mapped into single table using Single Table Inheritance pattern.
*/
isSingleTableChild: boolean;
/**
* Checks if this table is a class table child.
* Special table type for tables that are mapped into multiple tables using Class Table Inheritance pattern.
*/
isClassTableChild: boolean;
/**
* Map of columns and relations of the entity.
*
@ -463,13 +446,13 @@ export class EntityMetadata {
constructor(options: {
connection: Connection,
inheritanceTree?: Function[],
inheritanceType?: "single-table"|"class-table",
inheritancePattern?: "STI"/*|"CTI"*/,
parentClosureEntityMetadata?: EntityMetadata,
args: TableMetadataArgs
}) {
this.connection = options.connection;
this.inheritanceTree = options.inheritanceTree || [];
this.inheritanceType = options.inheritanceType;
this.inheritancePattern = options.inheritancePattern;
this.lazyRelationsWrapper = new LazyRelationsWrapper(options.connection);
this.parentClosureEntityMetadata = options.parentClosureEntityMetadata!;
this.tableMetadataArgs = options.args;
@ -548,16 +531,14 @@ export class EntityMetadata {
* Checks if there is an embedded with a given property path.
*/
hasEmbeddedWithPropertyPath(propertyPath: string): boolean {
return !!this.findEmbeddedWithPropertyPath(propertyPath);
return this.allEmbeddeds.some(embedded => embedded.propertyPath === propertyPath);
}
/**
* Finds embedded with a given property path.
*/
findEmbeddedWithPropertyPath(propertyPath: string): EmbeddedMetadata|undefined {
return this.allEmbeddeds.find(embedded => {
return embedded.propertyPath === propertyPath;
});
return this.allEmbeddeds.find(embedded => embedded.propertyPath === propertyPath);
}
/**
@ -699,24 +680,6 @@ export class EntityMetadata {
return map;
}
/**
* Same as getEntityIdMap, but instead of id column property names it returns database column names.
*/
getDatabaseEntityIdMap(entity: ObjectLiteral): ObjectLiteral|undefined {
const map: ObjectLiteral = {};
this.primaryColumns.forEach(column => {
const entityValue = column.getEntityValue(entity);
if (entityValue === null || entityValue === undefined)
return;
map[column.databaseName] = entityValue;
});
const hasAllIds = Object.keys(map).every(key => {
return map[key] !== undefined && map[key] !== null;
});
return hasAllIds ? map : undefined;
}
/**
* Creates a "mixed id map".
* If entity has multiple primary keys (ids) then it will return just regular id map, like what getEntityIdMap returns.
@ -775,7 +738,6 @@ export class EntityMetadata {
registerColumn(column: ColumnMetadata) {
this.ownColumns.push(column);
this.columns = this.embeddeds.reduce((columns, embedded) => columns.concat(embedded.columnsFromTree), this.ownColumns);
this.parentIdColumns = this.columns.filter(column => column.isParentId);
this.primaryColumns = this.columns.filter(column => column.isPrimary);
this.hasMultiplePrimaryKeys = this.primaryColumns.length > 1;
this.hasUUIDGeneratedColumns = this.columns.filter(column => column.isGenerated || column.generationStrategy === "uuid").length > 0;
@ -807,12 +769,12 @@ export class EntityMetadata {
this.engine = this.tableMetadataArgs.engine;
this.database = this.tableMetadataArgs.database;
this.schema = this.tableMetadataArgs.schema;
this.givenTableName = this.tableType === "single-table-child" && this.parentEntityMetadata ? this.parentEntityMetadata.givenTableName : this.tableMetadataArgs.name;
this.givenTableName = this.tableType === "entity-child" && this.parentEntityMetadata ? this.parentEntityMetadata.givenTableName : this.tableMetadataArgs.name;
this.skipSync = this.tableMetadataArgs.skipSync || false;
this.targetName = this.tableMetadataArgs.target instanceof Function ? (this.tableMetadataArgs.target as any).name : this.tableMetadataArgs.target;
if (this.tableType === "closure-junction") {
this.tableNameWithoutPrefix = namingStrategy.closureJunctionTableName(this.givenTableName!);
} else if (this.tableType === "single-table-child" && this.parentEntityMetadata) {
} else if (this.tableType === "entity-child" && this.parentEntityMetadata) {
this.tableNameWithoutPrefix = namingStrategy.tableName(this.parentEntityMetadata.targetName, this.parentEntityMetadata.givenTableName);
} else {
this.tableNameWithoutPrefix = namingStrategy.tableName(this.targetName, this.givenTableName);
@ -824,8 +786,6 @@ export class EntityMetadata {
this.schemaPath = this.buildSchemaPath();
this.orderBy = (this.tableMetadataArgs.orderBy instanceof Function) ? this.tableMetadataArgs.orderBy(this.propertiesMap) : this.tableMetadataArgs.orderBy; // todo: is propertiesMap available here? Looks like its not
this.isClassTableChild = this.tableType === "class-table-child";
this.isSingleTableChild = this.tableType === "single-table-child";
this.isEmbeddable = this.tableType === "embeddable";
this.isJunction = this.tableType === "closure-junction" || this.tableType === "junction";
this.isClosureJunction = this.tableType === "closure-junction";

View File

@ -2,4 +2,4 @@
* Table type. Tables can be abstract, closure, junction, embedded, etc.
*/
export type TableType = "regular"|"abstract"|"junction"|"closure"|"closure-junction"|
"embeddable"|"single-table-child"|"class-table-child";
"embeddable"|"entity-child";

View File

@ -69,10 +69,6 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
return "fk_" + RandomGenerator.sha1(key).substr(0, 27); // todo: use crypto instead?
}
classTableInheritanceParentColumnName(parentTableName: any, parentTableIdPropertyName: any): string {
return camelCase(parentTableName + "_" + parentTableIdPropertyName);
}
/**
* Adds globally set prefix to the table name.
* This method is executed no matter if prefix was set or not.

View File

@ -68,11 +68,6 @@ export interface NamingStrategyInterface {
*/
foreignKeyName(tableName: string, columnNames: string[], referencedTableName: string, referencedColumnNames: string[]): string;
/**
* Gets the column name of the column with foreign key to the parent table used in the class table inheritance.
*/
classTableInheritanceParentColumnName(parentTableName: any, parentTableIdPropertyName: any): string;
/**
* Adds globally set prefix to the table name.
* This method is executed no matter if prefix was set or not.

View File

@ -38,7 +38,6 @@ export class SubjectChangedColumnsComputer {
// ignore special columns
if (column.isVirtual ||
column.isParentId ||
column.isDiscriminator ||
column.isUpdateDate ||
column.isVersion ||

View File

@ -695,13 +695,6 @@ export abstract class QueryBuilder<Entity> {
this.expressionMap.nativeParameters[parameterName] = primaryColumn.getEntityValue(id);
parameterIndex++;
});
metadata.parentIdColumns.forEach((parentIdColumn, secondIndex) => {
// whereSubStrings.push(alias + this.escape(parentIdColumn.databaseName) + "=:parentId_" + index + "_" + secondIndex);
const parameterName = "parentId_" + index + "_" + secondIndex;
whereSubStrings.push(alias + this.escape(parentIdColumn.databaseName) + " = " + this.connection.driver.createParameter(parameterName, parameterIndex));
this.expressionMap.nativeParameters[parameterName] = parentIdColumn.getEntityValue(id);
parameterIndex++;
});
return whereSubStrings.join(" AND ");
});

View File

@ -148,11 +148,6 @@ export class QueryExpressionMap {
*/
disableEscaping: boolean = true;
/**
* todo: needs more information.
*/
ignoreParentTablesJoins: boolean = false;
/**
* Indicates if virtual columns should be included in entity result.
*
@ -382,7 +377,6 @@ export class QueryExpressionMap {
map.lockVersion = this.lockVersion;
map.parameters = Object.assign({}, this.parameters);
map.disableEscaping = this.disableEscaping;
map.ignoreParentTablesJoins = this.ignoreParentTablesJoins;
map.enableRelationIdValues = this.enableRelationIdValues;
map.extraAppendedAndWhereCondition = this.extraAppendedAndWhereCondition;
map.subQuery = this.subQuery;

View File

@ -1331,39 +1331,6 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
}
});
if (!this.expressionMap.ignoreParentTablesJoins && this.expressionMap.mainAlias.hasMetadata) {
const metadata = this.expressionMap.mainAlias.metadata;
if (metadata.parentEntityMetadata && metadata.parentEntityMetadata.inheritanceType === "class-table" && metadata.parentIdColumns) {
const alias = "parentIdColumn_" + metadata.parentEntityMetadata.tableName;
metadata.parentEntityMetadata.columns.forEach(column => {
// TODO implement partial select
allSelects.push({ selection: this.escape(alias) + "." + this.escape(column.databaseName), aliasName: alias + "_" + column.databaseName });
});
}
}
// add selects from relation id joins
// this.relationIdAttributes.forEach(relationIdAttr => {
// });
/*if (this.enableRelationIdValues) {
const parentMetadata = this.aliasMap.getEntityMetadataByAlias(this.aliasMap.mainAlias);
if (!parentMetadata)
throw new Error("Cannot get entity metadata for the given alias " + this.aliasMap.mainAlias.name);
const metadata = this.connection.entityMetadatas.findByTarget(this.aliasMap.mainAlias.target);
metadata.manyToManyRelations.forEach(relation => {
const junctionMetadata = relation.junctionEntityMetadata;
junctionMetadata.columns.forEach(column => {
const select = ea(this.aliasMap.mainAlias.name + "_" + junctionMetadata.table.name + "_ids") + "." +
ec(column.name) + " AS " +
ea(this.aliasMap.mainAlias.name + "_" + relation.name + "_ids_" + column.name);
allSelects.push(select);
});
});
}*/
// add all other selects
this.expressionMap.selects
.filter(select => excludedSelects.indexOf(select) === -1)
@ -1487,18 +1454,6 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
}
});
if (!this.expressionMap.ignoreParentTablesJoins && this.expressionMap.mainAlias!.hasMetadata) {
const metadata = this.expressionMap.mainAlias!.metadata;
if (metadata.parentEntityMetadata && metadata.parentEntityMetadata.inheritanceType === "class-table" && metadata.parentIdColumns) {
const alias = "parentIdColumn_" + metadata.parentEntityMetadata.tableName;
const condition = metadata.parentIdColumns.map(parentIdColumn => {
return this.expressionMap.mainAlias!.name + "." + parentIdColumn.propertyPath + " = " + this.escape(alias) + "." + this.escape(parentIdColumn.referencedColumn!.propertyPath);
}).join(" AND ");
const join = " JOIN " + this.getTableName(metadata.parentEntityMetadata.tableName) + " " + this.escape(alias) + " ON " + this.replacePropertyNames(condition);
joins.push(join);
}
}
return joins.join(" ");
}
@ -1721,7 +1676,6 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
}
const results = await this.clone()
.mergeExpressionMap({ ignoreParentTablesJoins: true })
.orderBy()
.groupBy()
.offset(undefined)

View File

@ -72,9 +72,7 @@ export class DocumentToEntityTransformer {
if (valueInObject !== undefined &&
valueInObject !== null &&
column.propertyName &&
!column.isVirtual &&
!column.isParentId &&
!column.isDiscriminator) {
!column.isVirtual) {
// const value = this.driver.prepareHydratedValue(valueInObject, column);
entity[column.propertyName] = valueInObject;

View File

@ -111,7 +111,7 @@ export class RawSqlResultsToEntityTransformer {
return;
const value = rawResults[0][alias.name + "_" + column.databaseName];
if (value === undefined || column.isVirtual || column.isParentId || column.isDiscriminator)
if (value === undefined || column.isVirtual)
return;
// if user does not selected the whole entity or he used partial selection and does not select this particular column
@ -123,18 +123,6 @@ export class RawSqlResultsToEntityTransformer {
if (value !== null) // we don't mark it as has data because if we will have all nulls in our object - we don't need such object
hasData = true;
});
if (metadata.parentEntityMetadata) { // todo: revisit
metadata.parentEntityMetadata.columns.forEach(column => {
const value = rawResults[0]["parentIdColumn_" + metadata.parentEntityMetadata.tableName + "_" + column.databaseName];
if (value === undefined || column.isVirtual || column.isParentId || column.isDiscriminator)
return;
column.setEntityValue(entity, this.driver.prepareHydratedValue(value, column));
if (value !== null) // we don't mark it as has data because if we will have all nulls in our object - we don't need such object
hasData = true;
});
}
return hasData;
}

View File

@ -123,7 +123,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder {
* Returns only entities that should be synced in the database.
*/
protected get entityToSyncMetadatas(): EntityMetadata[] {
return this.connection.entityMetadatas.filter(metadata => !metadata.skipSync && metadata.tableType !== "single-table-child");
return this.connection.entityMetadatas.filter(metadata => !metadata.skipSync && metadata.tableType !== "entity-child");
}
/**

View File

@ -1,254 +0,0 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
import {Connection} from "../../../../../src/connection/Connection";
import {Student} from "./entity/Student";
import {Teacher} from "./entity/Teacher";
import {Accountant} from "./entity/Accountant";
describe.skip("table-inheritance > class-table > basic-functionality", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should correctly insert, update and delete data with class-table-inheritance pattern", () => Promise.all(connections.map(async connection => {
// -------------------------------------------------------------------------
// Create
// -------------------------------------------------------------------------
const student1 = new Student();
student1.name = "Alice";
student1.faculty = "Economics";
await connection.getRepository(Student).save(student1);
const student2 = new Student();
student2.name = "Bob";
student2.faculty = "Programming";
await connection.getRepository(Student).save(student2);
const teacher1 = new Teacher();
teacher1.name = "Mr. Garrison";
teacher1.specialization = "Geography";
teacher1.salary = 2000;
await connection.getRepository(Teacher).save(teacher1);
const teacher2 = new Teacher();
teacher2.name = "Mr. Adler";
teacher2.specialization = "Mathematics";
teacher2.salary = 4000;
await connection.getRepository(Teacher).save(teacher2);
const accountant1 = new Accountant();
accountant1.name = "Mr. Burns";
accountant1.department = "Bookkeeping";
accountant1.salary = 3000;
await connection.getRepository(Accountant).save(accountant1);
const accountant2 = new Accountant();
accountant2.name = "Mr. Trump";
accountant2.department = "Director";
accountant2.salary = 5000;
await connection.getRepository(Accountant).save(accountant2);
// -------------------------------------------------------------------------
// Select
// -------------------------------------------------------------------------
let loadedStudents = await connection.manager
.createQueryBuilder(Student, "students")
// .orderBy("students.id")
.getMany();
loadedStudents[0].should.have.all.keys("id", "name", "faculty");
loadedStudents[0].id.should.equal(1);
loadedStudents[0].name.should.equal("Alice");
loadedStudents[0].faculty.should.equal("Economics");
loadedStudents[1].should.have.all.keys("id", "name", "faculty");
loadedStudents[1].id.should.equal(2);
loadedStudents[1].name.should.equal("Bob");
loadedStudents[1].faculty.should.equal("Programming");
let loadedTeachers = await connection.manager
.createQueryBuilder(Teacher, "teachers")
.getMany();
loadedTeachers[0].should.have.all.keys("id", "name", "specialization", "salary");
loadedTeachers[0].id.should.equal(3);
loadedTeachers[0].name.should.equal("Mr. Garrison");
loadedTeachers[0].specialization.should.equal("Geography");
loadedTeachers[0].salary.should.equal(2000);
loadedTeachers[1].should.have.all.keys("id", "name", "specialization", "salary");
loadedTeachers[1].id.should.equal(4);
loadedTeachers[1].name.should.equal("Mr. Adler");
loadedTeachers[1].specialization.should.equal("Mathematics");
loadedTeachers[1].salary.should.equal(4000);
let loadedAccountants = await connection.manager
.createQueryBuilder(Accountant, "accountants")
.getMany();
loadedAccountants[0].should.have.all.keys("id", "name", "department", "salary");
loadedAccountants[0].id.should.equal(5);
loadedAccountants[0].name.should.equal("Mr. Burns");
loadedAccountants[0].department.should.equal("Bookkeeping");
loadedAccountants[0].salary.should.equal(3000);
loadedAccountants[1].should.have.all.keys("id", "name", "department", "salary");
loadedAccountants[1].id.should.equal(6);
loadedAccountants[1].name.should.equal("Mr. Trump");
loadedAccountants[1].department.should.equal("Director");
loadedAccountants[1].salary.should.equal(5000);
// -------------------------------------------------------------------------
// Update
// -------------------------------------------------------------------------
let loadedStudent = await connection.manager
.createQueryBuilder(Student, "student")
.where("student.name = :name", { name: "Bob" })
.getOne();
console.log(loadedStudent);
loadedStudent!.faculty = "Chemistry";
await connection.getRepository(Student).save(loadedStudent!);
loadedStudent = await connection.manager
.createQueryBuilder(Student, "student")
.where("student.name = :name", { name: "Bob" })
.getOne();
loadedStudent!.should.have.all.keys("id", "name", "faculty");
loadedStudent!.id.should.equal(2);
loadedStudent!.name.should.equal("Bob");
loadedStudent!.faculty.should.equal("Chemistry");
let loadedTeacher = await connection.manager
.createQueryBuilder(Teacher, "teacher")
.where("teacher.name = :name", { name: "Mr. Adler" })
.getOne();
loadedTeacher!.salary = 1000;
await connection.getRepository(Teacher).save(loadedTeacher!);
loadedTeacher = await connection.manager
.createQueryBuilder(Teacher, "teacher")
.where("teacher.name = :name", { name: "Mr. Adler" })
.getOne();
loadedTeacher!.should.have.all.keys("id", "name", "specialization", "salary");
loadedTeacher!.id.should.equal(4);
loadedTeacher!.name.should.equal("Mr. Adler");
loadedTeacher!.specialization.should.equal("Mathematics");
loadedTeacher!.salary.should.equal(1000);
let loadedAccountant = await connection.manager
.createQueryBuilder(Accountant, "accountant")
.where("accountant.name = :name", { name: "Mr. Trump" })
.getOne();
loadedAccountant!.salary = 1000;
await connection.getRepository(Accountant).save(loadedAccountant!);
loadedAccountant = await connection.manager
.createQueryBuilder(Accountant, "accountant")
.where("accountant.name = :name", { name: "Mr. Trump" })
.getOne();
loadedAccountant!.should.have.all.keys("id", "name", "department", "salary");
loadedAccountant!.id.should.equal(6);
loadedAccountant!.name.should.equal("Mr. Trump");
loadedAccountant!.department.should.equal("Director");
loadedAccountant!.salary.should.equal(1000);
// -------------------------------------------------------------------------
// Delete
// -------------------------------------------------------------------------
/*await connection.getRepository(Student).remove(loadedStudent!);
loadedStudents = await connection.manager
.createQueryBuilder(Student, "students")
.getMany();
loadedStudents.length.should.equal(1);
loadedStudents[0].should.have.all.keys("id", "name", "faculty");
loadedStudents[0].id.should.equal(1);
loadedStudents[0].name.should.equal("Alice");
loadedStudents[0].faculty.should.equal("Economics");
await connection.getRepository(Teacher).remove(loadedTeacher!);
loadedTeachers = await connection.manager
.createQueryBuilder(Teacher, "teachers")
.getMany();
loadedTeachers.length.should.equal(1);
loadedTeachers[0].should.have.all.keys("id", "name", "specialization", "salary");
loadedTeachers[0].id.should.equal(3);
loadedTeachers[0].name.should.equal("Mr. Garrison");
loadedTeachers[0].specialization.should.equal("Geography");
loadedTeachers[0].salary.should.equal(2000);
await connection.getRepository(Accountant).remove(loadedAccountant!);
loadedAccountants = await connection.manager
.createQueryBuilder(Accountant, "accountants")
.getMany();
loadedAccountants.length.should.equal(1);
loadedAccountants[0].should.have.all.keys("id", "name", "department", "salary");
loadedAccountants[0].id.should.equal(5);
loadedAccountants[0].name.should.equal("Mr. Burns");
loadedAccountants[0].department.should.equal("Bookkeeping");
loadedAccountants[0].salary.should.equal(3000);*/
// -------------------------------------------------------------------------
// Select parent objects
// -------------------------------------------------------------------------
/*const loadedEmployees = await connection.manager
.createQueryBuilder(Employee, "employees")
.getMany();
loadedEmployees[0].should.have.all.keys("id", "name", "salary", "specialization");
loadedEmployees[0].should.be.instanceof(Teacher);
loadedEmployees[0].id.should.equal(3);
loadedEmployees[0].name.should.equal("Mr. Garrison");
(loadedEmployees[0] as Teacher).specialization = "Geography";
loadedEmployees[0].salary.should.equal(2000);
loadedEmployees[1].should.have.all.keys("id", "name", "salary", "department");
loadedEmployees[1].should.be.instanceof(Accountant);
loadedEmployees[1].id.should.equal(5);
loadedEmployees[1].name.should.equal("Mr. Burns");
(loadedEmployees[1] as Accountant).department = "Bookkeeping";
loadedEmployees[1].salary.should.equal(3000);
const loadedPersons = await connection.manager
.createQueryBuilder(Person, "persons")
.getMany();
loadedPersons[0].should.have.all.keys("id", "name", "faculty");
loadedPersons[0].should.be.instanceof(Student);
loadedPersons[0].id.should.equal(1);
loadedPersons[0].name.should.equal("Alice");
(loadedPersons[0] as Student).faculty = "Economics";
loadedPersons[1].should.have.all.keys("id", "name", "salary", "specialization");
loadedPersons[1].should.be.instanceof(Teacher);
loadedPersons[1].id.should.equal(3);
loadedPersons[1].name.should.equal("Mr. Garrison");
(loadedPersons[1] as Teacher).specialization = "Geography";
(loadedPersons[1] as Teacher).salary.should.equal(2000);
loadedPersons[2].should.have.all.keys("id", "name", "salary", "department");
loadedPersons[2].should.be.instanceof(Accountant);
loadedPersons[2].id.should.equal(5);
loadedPersons[2].name.should.equal("Mr. Burns");
(loadedPersons[2] as Accountant).department = "Bookkeeping";
(loadedPersons[2] as Accountant).salary.should.equal(3000);*/
})));
});

View File

@ -1,11 +0,0 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {ClassEntityChild} from "../../../../../../src/decorator/entity/ClassEntityChild";
import {Employee} from "./Employee";
@ClassEntityChild()
export class Accountant extends Employee {
@Column()
department: string;
}

View File

@ -1,11 +0,0 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {ClassEntityChild} from "../../../../../../src/decorator/entity/ClassEntityChild";
import {Employee} from "./Employee";
@ClassEntityChild()
export class Teacher extends Employee {
@Column()
specialization: string;
}

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Employee} from "./Employee";
@SingleEntityChild()
@ChildEntity()
export class Accountant extends Employee {
@Column()

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@SingleEntityChild()
@ChildEntity()
export class Employee extends Person {
@Column()

View File

@ -1,12 +1,10 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@Entity()
@TableInheritance("single-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export class Person {
@PrimaryGeneratedColumn()

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@SingleEntityChild()
@ChildEntity()
export class Student extends Person {
@Column()

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Employee} from "./Employee";
@SingleEntityChild()
@ChildEntity()
export class Teacher extends Employee {
@Column()

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {ClassEntityChild} from "../../../../../../src/decorator/entity/ClassEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@ClassEntityChild()
@ChildEntity("employee-type")
export class Employee extends Person {
@Column()

View File

@ -1,12 +1,10 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@Entity()
@TableInheritance("class-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export class Person {
@PrimaryGeneratedColumn()
@ -15,4 +13,7 @@ export class Person {
@Column()
name: string;
@Column()
type: string;
}

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {ClassEntityChild} from "../../../../../../src/decorator/entity/ClassEntityChild";
import {ChildEntity} from "../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@ClassEntityChild()
@ChildEntity("student-type")
export class Student extends Person {
@Column()

View File

@ -0,0 +1,54 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
import {Connection} from "../../../../../src/connection/Connection";
import {Student} from "./entity/Student";
import {Employee} from "./entity/Employee";
import {Person} from "./entity/Person";
describe("table-inheritance > single-table > non-virtual-discriminator-column", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"]
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should return non virtual discriminator column as well", () => Promise.all(connections.map(async connection => {
// -------------------------------------------------------------------------
// Create
// -------------------------------------------------------------------------
const student = new Student();
student.name = "Alice";
student.faculty = "Economics";
await connection.getRepository(Student).save(student);
const employee = new Employee();
employee.name = "Roger";
employee.salary = 1000;
await connection.getRepository(Employee).save(employee);
// -------------------------------------------------------------------------
// Select
// -------------------------------------------------------------------------
let persons = await connection.manager
.createQueryBuilder(Person, "person")
.getMany();
console.log(persons);
persons[0].id.should.be.equal(1);
persons[0].type.should.be.equal("student-type");
persons[0].name.should.be.equal("Alice");
(persons[0] as Student).faculty.should.be.equal("Economics");
persons[1].id.should.be.equal(2);
persons[1].type.should.be.equal("employee-type");
persons[1].name.should.be.equal("Roger");
(persons[1] as Employee).salary.should.be.equal(1000);
})));
});

View File

@ -1,10 +1,10 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {ManyToMany} from "../../../../../../../src/decorator/relations/ManyToMany";
import {JoinTable} from "../../../../../../../src/decorator/relations/JoinTable";
import {Employee} from "./Employee";
import {Department} from "./Department";
@SingleEntityChild()
@ChildEntity()
export class Accountant extends Employee {
@ManyToMany(type => Department, department => department.accountants)

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@SingleEntityChild()
@ChildEntity()
export class Employee extends Person {
@Column()

View File

@ -1,12 +1,10 @@
import {Column} from "../../../../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@Entity()
@TableInheritance("single-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export class Person {
@PrimaryGeneratedColumn()

View File

@ -1,10 +1,10 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {ManyToMany} from "../../../../../../../src/decorator/relations/ManyToMany";
import {Person} from "./Person";
import {Faculty} from "./Faculty";
import {JoinTable} from "../../../../../../../src/decorator/relations/JoinTable";
@SingleEntityChild()
@ChildEntity()
export class Student extends Person {
@ManyToMany(type => Faculty, faculty => faculty.students)

View File

@ -1,10 +1,10 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {ManyToMany} from "../../../../../../../src/decorator/relations/ManyToMany";
import {JoinTable} from "../../../../../../../src/decorator/relations/JoinTable";
import {Employee} from "./Employee";
import {Specialization} from "./Specialization";
@SingleEntityChild()
@ChildEntity()
export class Teacher extends Employee {
@ManyToMany(type => Specialization, specialization => specialization.teachers)

View File

@ -1,9 +1,9 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {OneToMany} from "../../../../../../../src/decorator/relations/OneToMany";
import {Employee} from "./Employee";
import {Department} from "./Department";
@SingleEntityChild()
@ChildEntity()
export class Accountant extends Employee {
@OneToMany(type => Department, department => department.accountant)

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../../../../src/decorator/columns/Column";
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {Person} from "./Person";
@SingleEntityChild()
@ChildEntity()
export class Employee extends Person {
@Column()

View File

@ -1,12 +1,10 @@
import {Column} from "../../../../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@Entity()
@TableInheritance("single-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export class Person {
@PrimaryGeneratedColumn()

View File

@ -1,9 +1,9 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {OneToMany} from "../../../../../../../src/decorator/relations/OneToMany";
import {Person} from "./Person";
import {Faculty} from "./Faculty";
@SingleEntityChild()
@ChildEntity()
export class Student extends Person {
@OneToMany(type => Faculty, faculty => faculty.student)

View File

@ -1,9 +1,9 @@
import {SingleEntityChild} from "../../../../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../../../../src/decorator/entity/ChildEntity";
import {OneToMany} from "../../../../../../../src/decorator/relations/OneToMany";
import {Employee} from "./Employee";
import {Specialization} from "./Specialization";
@SingleEntityChild()
@ChildEntity()
export class Teacher extends Employee {
@OneToMany(type => Specialization, specialization => specialization.teacher)

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {SingleEntityChild} from "../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../src/decorator/entity/ChildEntity";
@SingleEntityChild()
@ChildEntity()
export class Employee extends Person {
@Column()

View File

@ -1,12 +1,10 @@
import {Column} from "../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../src/decorator/columns/DiscriminatorColumn";
import {Entity} from "../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../src/decorator/columns/PrimaryColumn";
@Entity()
@TableInheritance("single-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
@TableInheritance({ column: { name: "type", type: "varchar" } })
export class Person {
@PrimaryColumn("int")

View File

@ -1,8 +1,8 @@
import {Column} from "../../../../src/decorator/columns/Column";
import {Person} from "./Person";
import {SingleEntityChild} from "../../../../src/decorator/entity/SingleEntityChild";
import {ChildEntity} from "../../../../src/decorator/entity/ChildEntity";
@SingleEntityChild()
@ChildEntity()
export class Student extends Person {
@Column()

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Employee extends Person {
@Column()
salary: number;
}

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Homesitter extends Person {
@Column()
numberOfKids: number;
}

View File

@ -1,21 +0,0 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import {TableInheritance} from "../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../src/decorator/columns/DiscriminatorColumn";
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../src/decorator/columns/Column";
@Entity()
@TableInheritance("class-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
export class Person {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
}

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Student extends Person {
@Column()
faculty: string;
}

View File

@ -1,30 +0,0 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {Student} from "./entity/Student";
// todo fix this test once class table inheritance support is back
describe.skip("github issues > #144 Class Table Inheritance doesn't seem to work", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should persist class table child successfully", () => Promise.all(connections.map(async connection => {
const studentRepository = connection.getRepository(Student);
const student = new Student();
student.firstName = "Hello";
student.lastName = "World";
student.faculty = "University";
await studentRepository.save(student);
})));
});

View File

@ -1,24 +0,0 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../src/decorator/columns/Column";
import {OneToOne} from "../../../../src/decorator/relations/OneToOne";
import {JoinColumn} from "../../../../src/decorator/relations/JoinColumn";
import {Employee} from "./Employee";
@Entity()
export class Department {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToOne(type => Employee, {
cascade: ["insert"],
nullable: false
})
@JoinColumn()
manager: Employee;
}

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Employee extends Person {
@Column()
salary: number;
}

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Homesitter extends Person {
@Column()
numberOfKids: number;
}

View File

@ -1,21 +0,0 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import {TableInheritance} from "../../../../src/decorator/entity/TableInheritance";
import {DiscriminatorColumn} from "../../../../src/decorator/columns/DiscriminatorColumn";
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../src/decorator/columns/Column";
@Entity()
@TableInheritance("class-table")
@DiscriminatorColumn({ name: "type", type: "varchar" })
export class Person {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
}

View File

@ -1,11 +0,0 @@
import {Person} from "./Person";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
import {Column} from "../../../../src/decorator/columns/Column";
@ClassEntityChild()
export class Student extends Person {
@Column()
faculty: string;
}

View File

@ -1,40 +0,0 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {Department} from "./entity/Department";
import {Employee} from "./entity/Employee";
// unskip once table inheritance support is back
describe.skip("github issues > #159 Referencing ClassTableChild build table error", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("entity should be successfully referenced to class-table entity", () => Promise.all(connections.map(async connection => {
let department = new Department();
department.name = "Software";
let employee = new Employee();
employee.firstName = "Hello";
employee.lastName = "World";
employee.salary = 1;
department.manager = employee;
await connection.manager.save(department);
department.id.should.be.equal(1);
department.name.should.be.equal("Software");
department.manager.id.should.be.equal(1);
department.manager.firstName.should.be.equal("Hello");
department.manager.lastName.should.be.equal("World");
department.manager.salary.should.be.equal(1);
})));
});

View File

@ -1,11 +0,0 @@
import {Column} from "../../../../src/decorator/columns/Column";
import {Document} from "./Document";
import {ClassEntityChild} from "../../../../src/decorator/entity/ClassEntityChild";
@ClassEntityChild()
export class DeliveryNote extends Document {
@Column()
invoice: string = "";
}

View File

@ -1,42 +0,0 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../src/decorator/columns/Column";
import {TableInheritance} from "../../../../src/decorator/entity/TableInheritance";
import {CreateDateColumn} from "../../../../src/decorator/columns/CreateDateColumn";
import {UpdateDateColumn} from "../../../../src/decorator/columns/UpdateDateColumn";
@Entity()
@TableInheritance("class-table")
export class Document {
@PrimaryGeneratedColumn()
id: number;
@Column()
dollarRate: number = 0;
@Column()
orderBy: string = "";
@Column()
comments: string = "";
@Column()
subTotal: number = 0;
@Column()
vat: number = 0;
@Column()
total: number = 0;
@Column()
createdBy: string = "";
@CreateDateColumn()
createdAt: string;
@UpdateDateColumn()
updatedAt: string;
}

View File

@ -1,49 +0,0 @@
import "reflect-metadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {DeliveryNote} from "./entity/DeliveryNote";
import {expect} from "chai";
// unskip when inheritance will repaired
describe.skip("github issues > #78 repository 'create' is skipping inherited fields", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should persist successfully and return persisted entity", () => Promise.all(connections.map(async connection => {
const repository = connection.getRepository(DeliveryNote);
const deliveryNoteEntity = repository.create({
id: 1,
dollarRate: 0.5,
orderBy: "money",
comments: "this is comment",
subTotal: 10,
vat: 50,
total: 60,
createdBy: "Amir",
invoice: "Total Invoice: 60"
});
expect(deliveryNoteEntity).not.to.be.empty;
deliveryNoteEntity.should.be.instanceof(DeliveryNote);
const simpleObject = Object.assign({}, deliveryNoteEntity);
simpleObject.should.be.eql({
dollarRate: 0.5,
orderBy: "money",
comments: "this is comment",
subTotal: 10,
vat: 50,
total: 60,
createdBy: "Amir",
invoice: "Total Invoice: 60",
id: 1
});
})));
});