added table name auto generation, added onDelete support

This commit is contained in:
Umed Khudoiberdiev 2016-04-23 12:19:45 +05:00
parent 9d924926ea
commit bcc1c7e64b
12 changed files with 65 additions and 15 deletions

View File

@ -1,7 +1,7 @@
{
"name": "typeorm",
"private": true,
"version": "0.0.2-alpha.3",
"version": "0.0.2-alpha.4",
"description": "Data-mapper ORM for Typescript",
"license": "Apache-2.0",
"readmeFilename": "README.md",

View File

@ -5,7 +5,7 @@ import {TableMetadata} from "../../metadata-builder/metadata/TableMetadata";
* This decorator is used to mark classes that will be a tables. Database schema will be created for all classes
* decorated with it, and Repository can be retrieved and used for it.
*/
export function Table(name: string) {
export function Table(name?: string) {
return function (cls: Function) {
defaultMetadataStorage.addTableMetadata(new TableMetadata(cls, name, false));
};

View File

@ -105,7 +105,12 @@ export class EntityMetadataBuilder {
}
// create and add foreign key
const foreignKey = new ForeignKeyMetadata(metadata.table, [relationalColumn], inverseSideMetadata.table, [inverseSideMetadata.primaryColumn]);
const foreignKey = new ForeignKeyMetadata(metadata.table,
[relationalColumn],
inverseSideMetadata.table,
[inverseSideMetadata.primaryColumn],
relation.onDelete
);
metadata.foreignKeys.push(foreignKey);
});
});

View File

@ -196,9 +196,6 @@ export class ColumnMetadata extends PropertyMetadata {
this._precision = args.options.precision;
if (args.options.collation)
this._collation = args.options.collation;
if (!this._name)
this._name = args.propertyName;
}
// ---------------------------------------------------------------------
@ -209,7 +206,10 @@ export class ColumnMetadata extends PropertyMetadata {
* Column name in the database.
*/
get name(): string {
return this.namingStrategy ? this.namingStrategy.columnName(this._name) : this._name;
if (this._name)
return this._name;
return this.namingStrategy ? this.namingStrategy.columnName(this.propertyName) : this.propertyName;
}
/**

View File

@ -1,6 +1,8 @@
import {ColumnMetadata} from "./ColumnMetadata";
import {TableMetadata} from "./TableMetadata";
export type OnDeleteType = "RESTRICT"|"CASCADE"|"SET NULL";
/**
* This metadata interface contains all information foreign keys.
*/
@ -30,15 +32,25 @@ export class ForeignKeyMetadata {
*/
private _referencedColumns: ColumnMetadata[];
/**
* What to do with a relation on deletion of the row containing a foreign key.
*/
private _onDelete: OnDeleteType;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(table: TableMetadata, columns: ColumnMetadata[], referencedTable: TableMetadata, referencedColumns: ColumnMetadata[]) {
constructor(table: TableMetadata,
columns: ColumnMetadata[],
referencedTable: TableMetadata,
referencedColumns: ColumnMetadata[],
onDelete?: OnDeleteType) {
this._table = table;
this._columns = columns;
this._referencedTable = referencedTable;
this._referencedColumns = referencedColumns;
this._onDelete = onDelete;
}
// -------------------------------------------------------------------------
@ -96,4 +108,11 @@ export class ForeignKeyMetadata {
return "fk_" + require("sha1")(key); // todo: use crypto instead?
}
/**
* Array of referenced column names.
*/
get onDelete(): OnDeleteType {
return this._onDelete;
}
}

View File

@ -3,6 +3,7 @@ import {RelationTypes, RelationType} from "../types/RelationTypes";
import {RelationOptions} from "../options/RelationOptions";
import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
import {EntityMetadata} from "./EntityMetadata";
import {OnDeleteType} from "./ForeignKeyMetadata";
/**
* Function that returns a type of the field. Returned value must be a class used on the relation.
@ -134,6 +135,11 @@ export class RelationMetadata extends PropertyMetadata {
*/
private _junctionEntityMetadata: EntityMetadata;
/**
* What to do with a relation on deletion of the row containing a foreign key.
*/
private _onDelete: OnDeleteType;
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
@ -157,6 +163,8 @@ export class RelationMetadata extends PropertyMetadata {
this._oldColumnName = args.options.oldColumnName;
if (args.options.nullable)
this._isNullable = args.options.nullable;
if (args.options.onDelete)
this._onDelete = args.options.onDelete;
if (!this._name)
this._name = args.propertyName;
@ -242,6 +250,10 @@ export class RelationMetadata extends PropertyMetadata {
return this._oldColumnName;
}
get onDelete(): OnDeleteType {
return this._onDelete;
}
// ---------------------------------------------------------------------
// Private Methods
// ---------------------------------------------------------------------

View File

@ -59,7 +59,10 @@ export class TableMetadata {
* Table name in the database.
*/
get name() {
return this.namingStrategy ? this.namingStrategy.tableName(this._name) : this._name;
if (this._name)
return this._name;
return this.namingStrategy ? this.namingStrategy.tableName((<any>this._target).name) : (<any>this._target).name;
}
/**

View File

@ -1,3 +1,4 @@
import {OnDeleteType} from "../metadata/ForeignKeyMetadata";
/**
* Describes all relation's options.
*/
@ -37,6 +38,6 @@ export interface RelationOptions {
/**
* Database cascade action on delete.
*/
onDelete?: boolean;
onDelete?: OnDeleteType;
}

View File

@ -1,4 +1,5 @@
import {NamingStrategy} from "./NamingStrategy";
import * as _ from "lodash";
/**
* Naming strategy that is used by default.
@ -6,7 +7,7 @@ import {NamingStrategy} from "./NamingStrategy";
export class DefaultNamingStrategy implements NamingStrategy {
tableName(className: string): string {
return className;
return _.snakeCase(className);
}
columnName(propertyName: string): string {

View File

@ -325,7 +325,7 @@ export class EntityPersistOperationBuilder {
private diffColumns(metadata: EntityMetadata, newEntity: any, dbEntity: any) {
return metadata.columns
.filter(column => !column.isVirtual)
.filter(column => !column.isVirtual && !column.isUpdateDate && !column.isCreateDate)
.filter(column => newEntity[column.propertyName] !== dbEntity[column.propertyName]);
}

View File

@ -307,10 +307,10 @@ export class QueryBuilder<Entity> {
if (this.firstResult || this.maxResults) {
const metadata = this.connection.getEntityMetadata(this.fromEntity.alias.target);
let idsQuery = `SELECT DISTINCT(distinctAlias.${mainAlias}_${metadata.primaryColumn.name}) as ids`;
if (this.orderBys)
if (this.orderBys && this.orderBys.length > 0)
idsQuery += ", " + this.orderBys.map(orderBy => orderBy.sort.replace(".", "_")).join(", ");
idsQuery += ` FROM (${this.getSql()}) distinctAlias`;
if (this.orderBys)
if (this.orderBys && this.orderBys.length > 0)
idsQuery += " ORDER BY " + this.orderBys.map(order => "distinctAlias." + order.sort.replace(".", "_") + " " + order.order).join(", ");
if (this.maxResults)
idsQuery += " LIMIT " + this.maxResults;
@ -351,6 +351,13 @@ export class QueryBuilder<Entity> {
.then(results => parseInt(results[0]["cnt"]));
}
getResultsAndCount(): Promise<[Entity[], number]> {
return Promise.all<any>([
this.getResults(),
this.getCount()
]);
}
clone(options?: { skipOrderBys?: boolean }) {
const qb = new QueryBuilder(this.connection);

View File

@ -53,9 +53,11 @@ export class MysqlSchemaBuilder extends SchemaBuilder {
}
addForeignKeyQuery(foreignKey: ForeignKeyMetadata): Promise<void> {
const sql = `ALTER TABLE ${foreignKey.table.name} ADD CONSTRAINT \`${foreignKey.name}\` ` +
let sql = `ALTER TABLE ${foreignKey.table.name} ADD CONSTRAINT \`${foreignKey.name}\` ` +
`FOREIGN KEY (${foreignKey.columnNames.join(", ")}) ` +
`REFERENCES ${foreignKey.referencedTable.name}(${foreignKey.referencedColumnNames.join(",")})`;
if (foreignKey.onDelete)
sql += " ON DELETE " + foreignKey.onDelete;
return this.query(sql).then(() => {});
}