added ability to create indices and compound indices

This commit is contained in:
Umed Khudoiberdiev 2016-05-01 13:28:25 +05:00
parent 80abbb5e23
commit 8902402acc
28 changed files with 299 additions and 86 deletions

View File

@ -1,5 +1,13 @@
# TypeORM
> Note: docs are not always up to date because orm is in active development.
> Samples are more up to date, try to find your questions there.
> Otherwise create a github issue.
>
> Note: Current version of orm works with typescript >1.9. It means you need to install
> typescript@next to work with it. If you want to use older version of orm you can try
> to install typeorm@0.0.1
## What is TypeORM?
TypeORM is an [Object Relational Mapper](1) (ORM) for node.js written in
@ -49,10 +57,6 @@ need to do:
## Example
> Note: docs are not always up to date because orm is in active development.
> Samples are more up to date, try to find your questions there.
> Otherwise a github issue.
Lets create a sample application - a photo album.
#### create Photo entity class

View File

@ -21,7 +21,7 @@ createConnection(options).then(connection => {
post.title = "hello";
post.likesCount = 100;
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)

View File

@ -19,7 +19,7 @@ const options: CreateConnectionOptions = {
};
createConnection(options).then(connection => {
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
let postCover = new Cover();
postCover.url = "http://covers.com/post.jpg";

View File

@ -23,7 +23,7 @@ createConnection(options).then(connection => {
post.text = "Hello how are you?";
post.title = "hello";
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)

View File

@ -17,4 +17,11 @@ export class CustomNamingStrategy implements NamingStrategyInterface {
return _.snakeCase(propertyName);
}
indexName(target: Function, name: string, columns: string[]): string {
if (name)
return name;
return "index" + columns.join("_");
}
}

View File

@ -0,0 +1,30 @@
import {createConnection, CreateConnectionOptions} from "../../src/typeorm";
import {Post} from "./entity/Post";
const options: CreateConnectionOptions = {
driver: "mysql",
connection: {
host: "192.168.99.100",
port: 3306,
username: "root",
password: "admin",
database: "test",
autoSchemaCreate: true
},
entities: [Post]
};
createConnection(options).then(connection => {
let post = new Post();
post.text = "Hello how are you?";
post.title = "hello";
post.likesCount = 0;
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)
.then(post => console.log("Post has been saved"));
}, error => console.log("Cannot connect: ", error));

View File

@ -0,0 +1,25 @@
import {PrimaryColumn, Column} from "../../../src/columns";
import {Table} from "../../../src/tables";
import {Index} from "../../../src/decorator/indices/Index";
import {CompositeIndex} from "../../../src/decorator/indices/CompositeIndex";
@Table("sample16_post")
@CompositeIndex(["title", "text"])
@CompositeIndex(["title", "likesCount"])
export class Post {
@PrimaryColumn("int", { generated: true })
id: number;
@Column()
@Index()
title: string;
@Column()
text: string;
@Column()
@Index()
likesCount: number;
}

View File

@ -32,7 +32,7 @@ createConnection(options).then(connection => {
post.title = "hello";
post.details = details;
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)

View File

@ -31,7 +31,7 @@ createConnection(options).then(connection => {
post.title = "hello";
post.details = details;
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)

View File

@ -27,7 +27,7 @@ createConnection(options).then(connection => {
post.title = "hello";
post.details = [details1, details2];
let postRepository = connection.getRepository<Post>(Post);
let postRepository = connection.getRepository(Post);
postRepository
.persist(post)

View File

@ -0,0 +1,16 @@
import {CompositeIndexMetadata} from "../../metadata/CompositeIndexMetadata";
import {defaultMetadataStorage} from "../../typeorm";
/**
* Composite indexes must be set on entity classes and must specify fields to be indexed.
*/
export function CompositeIndex(name: string, fields: string[]): Function;
export function CompositeIndex(fields: string[]): Function;
export function CompositeIndex(nameOrFields: string|string[], maybeFields?: string[]): Function {
const name = typeof nameOrFields === "string" ? nameOrFields : undefined;
const fields = typeof nameOrFields === "string" ? <string[]> maybeFields : nameOrFields;
return function (cls: Function) {
defaultMetadataStorage().compositeIndexMetadatas.add(new CompositeIndexMetadata(cls, name, fields));
};
}

View File

@ -1,11 +0,0 @@
import {CompoundIndexMetadata} from "../../metadata/CompoundIndexMetadata";
import {defaultMetadataStorage} from "../../typeorm";
/**
* Compound indexes must be set on entity classes and must specify fields to be indexed.
*/
export function CompoundIndex(fields: string[]) {
return function (cls: Function) {
defaultMetadataStorage().compoundIndexMetadatas.add(new CompoundIndexMetadata(cls, fields));
};
}

View File

@ -1,2 +1,2 @@
export * from "./decorator/indices/Index";
export * from "./decorator/indices/CompoundIndex";
export * from "./decorator/indices/CompositeIndex";

View File

@ -13,6 +13,10 @@ import {UsingJoinColumnOnlyOnOneSideAllowedError} from "./error/UsingJoinColumnO
import {MissingJoinColumnError} from "./error/MissingJoinColumnError";
import {MissingJoinTableError} from "./error/MissingJoinTableError";
import {EntityMetadataValidator} from "./EntityMetadataValidator";
import {IndexMetadata} from "../metadata/IndexMetadata";
import {CompositeIndexMetadata} from "../metadata/CompositeIndexMetadata";
import {PropertyMetadataCollection} from "../metadata/collection/PropertyMetadataCollection";
import {TargetMetadataCollection} from "../metadata/collection/TargetMetadataCollection";
/**
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
@ -40,6 +44,17 @@ export class EntityMetadataBuilder {
// Public Methods
// -------------------------------------------------------------------------
private mergeIndicesAndCompositeIndices(indices: PropertyMetadataCollection<IndexMetadata>,
compositeIndices: TargetMetadataCollection<CompositeIndexMetadata>) {
indices.forEach(index => {
const compositeIndex = new CompositeIndexMetadata(index.target, index.name, [index.propertyName]);
compositeIndex.namingStrategy = index.namingStrategy;
compositeIndices.add(compositeIndex);
});
// later need to check if no duplicate keys in composite indices?
}
/**
* Builds a complete metadata aggregations for the given entity classes.
*/
@ -51,15 +66,31 @@ export class EntityMetadataBuilder {
const allTableMetadatas = allMetadataStorage.tableMetadatas.filterByClasses(entityClasses);
const tableMetadatas = allTableMetadatas.filterByClasses(entityClasses).filter(table => !table.isAbstract);
// set naming strategy
allMetadataStorage.tableMetadatas.forEach(tableMetadata => tableMetadata.namingStrategy = this.namingStrategy);
allTableMetadatas.forEach(column => column.namingStrategy = this.namingStrategy);
// entityMetadata.relations.forEach(relation => relation.namingStrategy = this.namingStrategy);
const entityMetadatas = tableMetadatas.map(tableMetadata => {
const mergedMetadata = allMetadataStorage.mergeWithAbstract(allTableMetadatas, tableMetadata);
// set naming strategy
tableMetadata.namingStrategy = this.namingStrategy;
mergedMetadata.columnMetadatas.forEach(column => column.namingStrategy = this.namingStrategy);
mergedMetadata.relationMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
mergedMetadata.indexMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
mergedMetadata.compositeIndexMetadatas.forEach(relation => relation.namingStrategy = this.namingStrategy);
// merge indices and composite indices because simple indices actually are compose indices with only one column
this.mergeIndicesAndCompositeIndices(mergedMetadata.indexMetadatas, mergedMetadata.compositeIndexMetadatas);
const entityMetadata = new EntityMetadata(
tableMetadata,
mergedMetadata.columnMetadatas,
mergedMetadata.relationMetadatas,
mergedMetadata.indexMetadatas,
mergedMetadata.compoundIndexMetadatas,
// mergedMetadata.indexMetadatas,
mergedMetadata.compositeIndexMetadatas,
[]
);
@ -76,11 +107,6 @@ export class EntityMetadataBuilder {
if (relationJoinColumn)
relation.joinColumn = relationJoinColumn;
});
// set naming strategies
tableMetadata.namingStrategy = this.namingStrategy;
entityMetadata.columns.forEach(column => column.namingStrategy = this.namingStrategy);
entityMetadata.relations.forEach(relation => relation.namingStrategy = this.namingStrategy);
return entityMetadata;
});
@ -164,7 +190,7 @@ export class EntityMetadataBuilder {
new ForeignKeyMetadata(tableMetadata, [columns[0]], metadata.table, [metadata.primaryColumn]),
new ForeignKeyMetadata(tableMetadata, [columns[1]], inverseSideMetadata.table, [inverseSideMetadata.primaryColumn]),
];
const junctionEntityMetadata = new EntityMetadata(tableMetadata, columns, [], [], [], foreignKeys);
const junctionEntityMetadata = new EntityMetadata(tableMetadata, columns, [], [], foreignKeys);
junctionEntityMetadatas.push(junctionEntityMetadata);
relation.junctionEntityMetadata = junctionEntityMetadata;
if (relation.inverseRelation)

View File

@ -1,7 +1,7 @@
import {TableMetadata} from "../metadata/TableMetadata";
import {RelationMetadata} from "../metadata/RelationMetadata";
import {IndexMetadata} from "../metadata/IndexMetadata";
import {CompoundIndexMetadata} from "../metadata/CompoundIndexMetadata";
import {CompositeIndexMetadata} from "../metadata/CompositeIndexMetadata";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {EventSubscriberMetadata} from "../metadata/EventSubscriberMetadata";
import {EntityListenerMetadata} from "../metadata/EntityListenerMetadata";
@ -29,7 +29,7 @@ export class MetadataStorage {
readonly tableMetadatas = new TargetMetadataCollection<TableMetadata>();
readonly namingStrategyMetadatas = new TargetMetadataCollection<NamingStrategyMetadata>();
readonly eventSubscriberMetadatas = new TargetMetadataCollection<EventSubscriberMetadata>();
readonly compoundIndexMetadatas = new TargetMetadataCollection<CompoundIndexMetadata>();
readonly compositeIndexMetadatas = new TargetMetadataCollection<CompositeIndexMetadata>();
readonly columnMetadatas = new PropertyMetadataCollection<ColumnMetadata>();
readonly relationMetadatas = new PropertyMetadataCollection<RelationMetadata>();
readonly joinColumnMetadatas = new PropertyMetadataCollection<JoinColumnMetadata>();
@ -44,7 +44,7 @@ export class MetadataStorage {
constructor(tableMetadatas?: TargetMetadataCollection<TableMetadata>,
namingStrategyMetadatas?: TargetMetadataCollection<NamingStrategyMetadata>,
eventSubscriberMetadatas?: TargetMetadataCollection<EventSubscriberMetadata>,
compoundIndexMetadatas?: TargetMetadataCollection<CompoundIndexMetadata>,
compositeIndexMetadatas?: TargetMetadataCollection<CompositeIndexMetadata>,
columnMetadatas?: PropertyMetadataCollection<ColumnMetadata>,
relationMetadatas?: PropertyMetadataCollection<RelationMetadata>,
joinColumnMetadatas?: PropertyMetadataCollection<JoinColumnMetadata>,
@ -57,8 +57,8 @@ export class MetadataStorage {
this.namingStrategyMetadatas = namingStrategyMetadatas;
if (eventSubscriberMetadatas)
this.eventSubscriberMetadatas = eventSubscriberMetadatas;
if (compoundIndexMetadatas)
this.compoundIndexMetadatas = compoundIndexMetadatas;
if (compositeIndexMetadatas)
this.compositeIndexMetadatas = compositeIndexMetadatas;
if (columnMetadatas)
this.columnMetadatas = columnMetadatas;
if (relationMetadatas)
@ -84,7 +84,7 @@ export class MetadataStorage {
mergeWithAbstract(allTableMetadatas: TargetMetadataCollection<TableMetadata>,
tableMetadata: TableMetadata) {
const compoundIndexMetadatas = this.compoundIndexMetadatas.filterByClass(tableMetadata.target);
const compositeIndexMetadatas = this.compositeIndexMetadatas.filterByClass(tableMetadata.target);
const columnMetadatas = this.columnMetadatas.filterByClass(tableMetadata.target);
const relationMetadatas = this.relationMetadatas.filterByClass(tableMetadata.target);
const joinColumnMetadatas = this.joinColumnMetadatas.filterByClass(tableMetadata.target);
@ -106,7 +106,7 @@ export class MetadataStorage {
});
return {
compoundIndexMetadatas: compoundIndexMetadatas,
compositeIndexMetadatas: compositeIndexMetadatas,
columnMetadatas: columnMetadatas,
relationMetadatas: relationMetadatas,
joinColumnMetadatas: joinColumnMetadatas,

View File

@ -0,0 +1,55 @@
import {TargetMetadata} from "./TargetMetadata";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategy";
/**
* This metadata interface contains all information about table's composite index.
*/
export class CompositeIndexMetadata extends TargetMetadata {
// ---------------------------------------------------------------------
// Public Properties
// ---------------------------------------------------------------------
/**
* Naming strategy used to generate and normalize index name.
*/
namingStrategy: NamingStrategyInterface;
// ---------------------------------------------------------------------
// Readonly Properties
// ---------------------------------------------------------------------
/**
* Columns combination to be used as index.
*/
readonly columns: string[];
// ---------------------------------------------------------------------
// Private Properties
// ---------------------------------------------------------------------
/**
* Composite index name.
*/
private readonly _name: string;
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(target: Function, name: string|undefined, columns: string[]) {
super(target);
this.columns = columns;
if (name)
this._name = name;
}
// ---------------------------------------------------------------------
// Accessors
// ---------------------------------------------------------------------
get name() { // throw exception if naming strategy is not set
return this.namingStrategy.indexName(this.target, this._name, this.columns);
}
}

View File

@ -1,26 +0,0 @@
import {TargetMetadata} from "./TargetMetadata";
/**
* This metadata interface contains all information about table's compound index.
*/
export class CompoundIndexMetadata extends TargetMetadata {
// ---------------------------------------------------------------------
// Readonly Properties
// ---------------------------------------------------------------------
/**
* Fields combination to be used as index.
*/
readonly fields: string[];
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(target: Function, fields: string[]) {
super(target);
this.fields = fields;
}
}

View File

@ -2,7 +2,7 @@ import {TableMetadata} from "./TableMetadata";
import {ColumnMetadata} from "./ColumnMetadata";
import {RelationMetadata} from "./RelationMetadata";
import {IndexMetadata} from "./IndexMetadata";
import {CompoundIndexMetadata} from "./CompoundIndexMetadata";
import {CompositeIndexMetadata} from "./CompositeIndexMetadata";
import {RelationTypes} from "./types/RelationTypes";
import {ForeignKeyMetadata} from "./ForeignKeyMetadata";
@ -18,8 +18,8 @@ export class EntityMetadata {
readonly table: TableMetadata;
readonly columns: ColumnMetadata[];
readonly relations: RelationMetadata[];
readonly indices: IndexMetadata[];
readonly compoundIndices: CompoundIndexMetadata[];
// readonly indices: IndexMetadata[];
readonly compositeIndices: CompositeIndexMetadata[];
readonly foreignKeys: ForeignKeyMetadata[];
// -------------------------------------------------------------------------
@ -29,14 +29,14 @@ export class EntityMetadata {
constructor(table: TableMetadata,
columns: ColumnMetadata[],
relations: RelationMetadata[],
indices: IndexMetadata[],
compoundIndices: CompoundIndexMetadata[],
// indices: IndexMetadata[],
compositeIndices: CompositeIndexMetadata[],
foreignKeys: ForeignKeyMetadata[]) {
this.table = table;
this.columns = columns;
this.relations = relations;
this.indices = indices;
this.compoundIndices = compoundIndices;
// this.indices = indices;
this.compositeIndices = compositeIndices;
this.foreignKeys = foreignKeys;
}

View File

@ -1,10 +1,20 @@
import {PropertyMetadata} from "./PropertyMetadata";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategy";
/**
* This metadata interface contains all information about some index on a field.
*/
export class IndexMetadata extends PropertyMetadata {
// ---------------------------------------------------------------------
// Public Properties
// ---------------------------------------------------------------------
/**
* Naming strategy used to generate and normalize index name.
*/
namingStrategy: NamingStrategyInterface;
// ---------------------------------------------------------------------
// Readonly Properties
// ---------------------------------------------------------------------

View File

@ -3,8 +3,6 @@ import {EntityMetadataNotFound} from "../error/EntityMetadataNotFound";
/**
* Array for the entity metadatas.
*
* @internal
*/
export class EntityMetadataCollection extends Array<EntityMetadata> {

View File

@ -3,6 +3,10 @@ import {PropertyMetadata} from "../PropertyMetadata";
export class PropertyMetadataCollection<T extends PropertyMetadata> extends TargetMetadataCollection<T> {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
filterRepeatedMetadatas(existsMetadatas: T[]): this {
const collection = new (<any> this.constructor)();
this

View File

@ -1,6 +1,11 @@
import {TargetMetadata} from "../TargetMetadata";
import {MetadataAlreadyExistsError} from "../../metadata-storage/error/MetadataAlreadyExistsError";
export class TargetMetadataCollection<T extends TargetMetadata> extends Array<T> {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
filterByClass(cls: Function): this {
return this.filterByClasses([cls]);
@ -13,17 +18,25 @@ export class TargetMetadataCollection<T extends TargetMetadata> extends Array<T>
return collection;
}
add(metadata: T) {
// if (this.hasWithClass(metadata.target))
// throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
// if (metadata.name && this.hasTableMetadataWithName(metadata.name))
// throw new MetadataWithSuchNameAlreadyExistsError("Table", metadata.name);
add(metadata: T, checkForDuplicateTargets = false) {
if (checkForDuplicateTargets && this.hasWithTarget(metadata.target))
throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
this.push(metadata);
}
private hasWithClass(constructor: Function): boolean {
addUniq(metadata: T) {
if (this.hasWithTarget(metadata.target))
throw new MetadataAlreadyExistsError((<any> metadata.constructor).name, metadata.target);
this.push(metadata);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private hasWithTarget(constructor: Function): boolean {
return !!this.find(metadata => metadata.target === constructor);
}

View File

@ -18,4 +18,11 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
return propertyName;
}
indexName(target: Function, name: string, columns: string[]): string {
if (name)
return name;
return "ind_" + columns.join("_");
}
}

View File

@ -19,4 +19,9 @@ export interface NamingStrategyInterface {
*/
relationName(propertyName: string): string;
/**
* Gets the name of the index - simple and compose index.
*/
indexName(target: Function, name: string, columns: string[]): string;
}

View File

@ -77,9 +77,9 @@ export class MysqlSchemaBuilder extends SchemaBuilder {
return this.query(sql).then(() => {});
}
getTableForeignQuery(table: TableMetadata): Promise<string[]> {
getTableForeignQuery(tableName: string): Promise<string[]> {
const sql = `SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = "${this.driver.db}" `
+ `AND TABLE_NAME = "${table.name}" AND REFERENCED_COLUMN_NAME IS NOT NULL`;
+ `AND TABLE_NAME = "${tableName}" AND REFERENCED_COLUMN_NAME IS NOT NULL`;
return this.query<any[]>(sql).then(results => results.map(result => result.CONSTRAINT_NAME));
}
@ -89,6 +89,23 @@ export class MysqlSchemaBuilder extends SchemaBuilder {
return this.query<any[]>(sql).then(results => results.map(result => result.CONSTRAINT_NAME));
}
getTableIndicesQuery(tableName: string): Promise<{ key: string, sequence: number, column: string }[]> {
const sql = `SHOW INDEX FROM ${tableName}`;
return this.query<any[]>(sql).then(results => {
// exclude foreign keys
return this.getTableForeignQuery(tableName).then(foreignKeys => {
return results
.filter(result => result.Key_name !== "PRIMARY" && foreignKeys.indexOf(result.Key_name) === -1)
.map(result => ({
key: result.Key_name,
sequence: result.Seq_in_index,
column: result.Column_name
}));
});
});
}
getPrimaryConstraintName(tableName: string): Promise<string> {
const sql = `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = "${this.driver.db}"`
+ ` AND TABLE_NAME = "${tableName}" AND CONSTRAINT_TYPE = 'PRIMARY KEY'`;
@ -100,6 +117,11 @@ export class MysqlSchemaBuilder extends SchemaBuilder {
return this.query(sql).then(() => {});
}
createIndex(tableName: string, indexName: string, columns: string[]): Promise<void> {
const sql = `CREATE INDEX \`${indexName}\` ON ${tableName}(${columns.join(", ")})`;
return this.query(sql).then(() => {});
}
addUniqueKey(tableName: string, columnName: string, keyName: string): Promise<void> {
const sql = `ALTER TABLE ${tableName} ADD CONSTRAINT ${keyName} UNIQUE (${columnName})`;
return this.query(sql).then(() => {});

View File

@ -14,10 +14,12 @@ export abstract class SchemaBuilder {
abstract addForeignKeyQuery(foreignKey: ForeignKeyMetadata): Promise<void>;
abstract dropForeignKeyQuery(foreignKey: ForeignKeyMetadata): Promise<void>;
abstract dropForeignKeyQuery(tableName: string, foreignKeyName: string): Promise<void>;
abstract getTableForeignQuery(table: TableMetadata): Promise<string[]>;
abstract getTableForeignQuery(tableName: string): Promise<string[]>;
abstract getTableUniqueKeysQuery(tableName: string): Promise<string[]>;
abstract getTableIndicesQuery(tableName: string): Promise<{ key: string, sequence: number, column: string }[]>;
abstract getPrimaryConstraintName(tableName: string): Promise<string>;
abstract dropIndex(tableName: string, indexName: string): Promise<void>;
abstract createIndex(tableName: string, indexName: string, columns: string[]): Promise<void>;
abstract addUniqueKey(tableName: string, columnName: string, keyName: string): Promise<void>;
abstract getTableColumns(tableName: string): Promise<string[]>;
abstract changeColumnQuery(tableName: string, columnName: string, newColumn: ColumnMetadata, skipPrimary?: boolean): Promise<void>;

View File

@ -4,6 +4,8 @@ import {ForeignKeyMetadata} from "../metadata/ForeignKeyMetadata";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
import {EntityMetadataCollection} from "../metadata/collection/EntityMetadataCollection";
import {IndexMetadata} from "../metadata/IndexMetadata";
import {CompositeIndexMetadata} from "../metadata/CompositeIndexMetadata";
/**
* Creates indexes based on the given metadata.
@ -38,6 +40,7 @@ export class SchemaCreator {
.then(_ => this.updateExistColumnsForAll(metadatas))
.then(_ => this.createForeignKeysForAll(metadatas))
.then(_ => this.updateUniqueKeysForAll(metadatas))
.then(_ => this.createIndicesForAll(metadatas))
.then(_ => this.removePrimaryKeyForAll(metadatas))
.then(_ => {});
}
@ -78,6 +81,10 @@ export class SchemaCreator {
return Promise.all(metadatas.map(metadata => this.updateUniqueKeys(metadata.table, metadata.columns)));
}
private createIndicesForAll(metadatas: EntityMetadata[]) {
return Promise.all(metadatas.map(metadata => this.createIndices(metadata.table, metadata.compositeIndices)));
}
private removePrimaryKeyForAll(metadatas: EntityMetadata[]) {
const queries = metadatas
.filter(metadata => !metadata.primaryColumn)
@ -89,7 +96,7 @@ export class SchemaCreator {
* Drops all (old) foreign keys that exist in the table, but does not exist in the metadata.
*/
private dropForeignKeys(table: TableMetadata, foreignKeys: ForeignKeyMetadata[]) {
return this.schemaBuilder.getTableForeignQuery(table).then(dbKeys => {
return this.schemaBuilder.getTableForeignQuery(table.name).then(dbKeys => {
const dropKeysQueries = dbKeys
.filter(dbKey => !foreignKeys.find(foreignKey => foreignKey.name === dbKey))
.map(dbKey => this.schemaBuilder.dropForeignKeyQuery(table.name, dbKey));
@ -168,7 +175,7 @@ export class SchemaCreator {
* Creates foreign keys which does not exist in the table yet.
*/
private createForeignKeys(table: TableMetadata, foreignKeys: ForeignKeyMetadata[]) {
return this.schemaBuilder.getTableForeignQuery(table).then(dbKeys => {
return this.schemaBuilder.getTableForeignQuery(table.name).then(dbKeys => {
const dropKeysQueries = foreignKeys
.filter(foreignKey => dbKeys.indexOf(foreignKey.name) === -1)
.map(foreignKey => this.schemaBuilder.addForeignKeyQuery(foreignKey));
@ -200,6 +207,27 @@ export class SchemaCreator {
});
}
/**
* Creates indices which are missing in db yet, and drops indices which exist in the db,
* but does not exist in the metadata anymore.
*/
private createIndices(table: TableMetadata, compositeIndices: CompositeIndexMetadata[]) {
return this.schemaBuilder.getTableIndicesQuery(table.name).then(tableIndices => {
// drop all indices that exist in the table, but does not exist in the given composite indices
const dropQueries = tableIndices
.filter(tableIndex => !compositeIndices.find(compositeIndex => compositeIndex.name === tableIndex.key))
.map(tableIndex => this.schemaBuilder.dropIndex(table.name, tableIndex.key));
// then create table indices for all composite indices we have
const addQueries = compositeIndices
.filter(compositeIndex => !tableIndices.find(i => i.key === compositeIndex.name))
.map(compositeIndex => this.schemaBuilder.createIndex(table.name, compositeIndex.name, compositeIndex.columns));
return Promise.all([dropQueries, addQueries]);
});
}
/**
* Removes primary key from the table (if it was before and does not exist in the metadata anymore).
*/

View File

@ -6,8 +6,6 @@ import {EntityMetadataCollection} from "../metadata/collection/EntityMetadataCol
/**
* Broadcaster provides a helper methods to broadcast events to the subscribers.
*
* @internal
*/
export class Broadcaster {