refactored connection manager and connection parts

This commit is contained in:
Umed Khudoiberdiev 2016-04-26 14:33:09 +05:00
parent 5a0d054d77
commit e00c5ffed3
52 changed files with 594 additions and 493 deletions

View File

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

View File

@ -0,0 +1,19 @@
import {PrimaryColumn, Column} from "../../../src/columns";
import {Table} from "../../../src/tables";
@Table("sample1_post")
export class Post {
@PrimaryColumn("int", { autoIncrement: true })
id: number;
@Column()
title: string;
@Column()
text: string;
@Column()
likesCount: number;
}

View File

@ -0,0 +1,20 @@
import * as _ from "lodash";
import {NamingStrategyInterface} from "../../../src/naming-strategy/NamingStrategy";
import {NamingStrategy} from "../../../src/decorator/NamingStrategy";
@NamingStrategy("custom_strategy")
export class CustomNamingStrategy implements NamingStrategyInterface {
tableName(className: string): string {
return _.snakeCase(className);
}
columnName(propertyName: string): string {
return _.snakeCase(propertyName);
}
relationName(propertyName: string): string {
return _.snakeCase(propertyName);
}
}

View File

@ -0,0 +1,93 @@
import {Connection} from "../connection/Connection";
import {ConnectionNotFoundError} from "./error/ConnectionNotFoundError";
import {MysqlDriver} from "../driver/MysqlDriver";
import {CreateConnectionOptions} from "./CreateConnectionOptions";
import {ConnectionOptions} from "../connection/ConnectionOptions";
import {Driver} from "../driver/Driver";
import {MissingDriverError} from "./error/MissingDriverError";
/**
* Connection manager holds all connections made to the databases and providers helper management functions
* for all exist connections.
*/
export class ConnectionManager {
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
private connections: Connection[] = [];
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Creates a new connection based on the given connection options and registers a new connection in the manager.
*/
create(options: CreateConnectionOptions): Promise<Connection> {
const driver = this.createDriver(options.driver);
const connection = this.createConnection(options.connectionName || "default", driver, options.connection);
if (options.entityDirectories && options.entityDirectories.length > 0)
connection.importEntitiesFromDirectories(options.entityDirectories);
if (options.entities)
connection.importEntities(options.entities);
if (options.subscriberDirectories && options.subscriberDirectories.length > 0)
connection.importSubscribersFromDirectories(options.subscriberDirectories);
if (options.subscribers)
connection.importSubscribers(options.subscribers);
if (options.namingStrategyDirectories && options.namingStrategyDirectories.length > 0)
connection.importNamingStrategiesFromDirectories(options.namingStrategyDirectories);
if (options.namingStrategies)
connection.importNamingStrategies(options.namingStrategies);
return connection.connect().then(() => connection);
}
/**
* Gets registered connection with the given name. If connection name is not given then it will get a default
* connection.
*/
get(name: string = "default"): Connection {
if (!name) name = "default";
const connection = this.connections.find(connection => connection.name === name);
if (!connection)
throw new ConnectionNotFoundError(name);
return connection;
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private createDriver(driverName: string) {
switch (driverName) {
case "mysql":
return new MysqlDriver();
default:
throw new MissingDriverError(driverName);
}
}
/**
* Creates a new connection and pushes a connection to the array.
*/
createConnection(name: string, driver: Driver, options: ConnectionOptions) {
const existConnection = this.connections.find(connection => connection.name === name);
if (existConnection)
this.connections.splice(this.connections.indexOf(existConnection), 1);
const connection = new Connection(name, <Driver> driver, options);
this.connections.push(connection);
return connection;
}
}

View File

@ -0,0 +1,53 @@
import {ConnectionOptions} from "../connection/ConnectionOptions";
/**
* All options to help to create a new connection.
*/
export interface CreateConnectionOptions {
/**
* Driver type. Mysql is the only driver supported at this moment.
*/
driver: "mysql";
/**
* Database connection options.
*/
connection: ConnectionOptions;
/**
* Connection name. By default its called "default". Different connections must have different names.
*/
connectionName?: string;
/**
* Entities to be loaded for the new connection.
*/
entities?: Function[];
/**
* Subscribers to be loaded for the new connection.
*/
subscribers?: Function[];
/**
* Naming strategies to be loaded.
*/
namingStrategies?: Function[];
/**
* List of directories from where entities will be loaded.
*/
entityDirectories?: string[];
/**
* List of directories from where subscribers will be loaded.
*/
subscriberDirectories?: string[];
/**
* List of directories from where naming strategies will be loaded.
*/
namingStrategyDirectories?: string[];
}

View File

@ -0,0 +1,12 @@
/**
* @internal
*/
export class MissingDriverError extends Error {
name = "MissingDriverError";
constructor(driverName: string) {
super();
this.message = `Wrong driver ${driverName} given. Supported drivers are: "mysql"`;
}
}

View File

@ -5,11 +5,19 @@ import {EventSubscriberInterface} from "../subscriber/EventSubscriberInterface";
import {RepositoryNotFoundError} from "./error/RepositoryNotFoundError";
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
import {SchemaCreator} from "../schema-creator/SchemaCreator";
import {MetadataNotFoundError} from "./error/MetadataNotFoundError";
import {ConstructorFunction} from "../common/ConstructorFunction";
import {EntityListenerMetadata} from "../metadata-builder/metadata/EntityListenerMetadata";
import {EntityManager} from "../repository/EntityManager";
import {importClassesFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {defaultMetadataStorage, getContainer} from "../typeorm";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy";
import {EntityMetadataArray} from "../metadata-builder/metadata/EntityMetadataArray";
import {NamingStrategyMetadata} from "../metadata-builder/metadata/NamingStrategyMetadata";
/**
* Temporary type to store and link both repository and its metadata.
*/
type RepositoryAndMetadata = { repository: Repository<any>, metadata: EntityMetadata };
/**
@ -27,11 +35,6 @@ export class Connection {
// Readonly properties
// -------------------------------------------------------------------------
/**
* Database connection options.
*/
readonly options: ConnectionOptions;
/**
* Gets EntityManager of this connection.
*/
@ -47,11 +50,6 @@ export class Connection {
*/
readonly driver: Driver;
/**
* All entity metadatas that are registered for this connection.
*/
private readonly entityMetadatas: EntityMetadata[] = [];
/**
* All entity listener metadatas that are registered for this connection.
*/
@ -60,7 +58,41 @@ export class Connection {
/**
* All subscribers that are registered for this connection.
*/
readonly subscribers: EventSubscriberInterface<any>[] = [];
readonly subscriberMetadatas: EventSubscriberInterface<any>[] = [];
// -------------------------------------------------------------------------
// Private Properties
// -------------------------------------------------------------------------
/**
* Connection options.
*/
private readonly options: ConnectionOptions;
/**
* All entity metadatas that are registered for this connection.
*/
private readonly entityMetadatas = new EntityMetadataArray();
/**
* All naming strategy metadatas that are registered for this connection.
*/
private readonly namingStrategyMetadatas: NamingStrategyMetadata[] = [];
/**
* Registered entity classes to be used for this connection.
*/
private readonly entityClasses: Function[] = [];
/**
* Registered subscriber classes to be used for this connection.
*/
private readonly subscriberClasses: Function[] = [];
/**
* Registered naming strategy classes to be used for this connection.
*/
private readonly namingStrategyClasses: Function[] = [];
// -------------------------------------------------------------------------
// Constructor
@ -74,17 +106,6 @@ export class Connection {
this.entityManager = new EntityManager(this);
}
// -------------------------------------------------------------------------
// Accessors
// -------------------------------------------------------------------------
/**
* All repositories that are registered for this connection.
*/
get repositories(): Repository<any>[] {
return this.repositoryAndMetadatas.map(repoAndMeta => repoAndMeta.repository);
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -94,6 +115,11 @@ export class Connection {
*/
connect(): Promise<void> {
return this.driver.connect().then(() => {
// build all metadata
this.registerMetadatas();
// second build schema
if (this.options.autoSchemaCreate === true)
return this.createSchema();
@ -101,14 +127,6 @@ export class Connection {
});
}
/**
* Creates database schema for all entities registered in this connection.
*/
createSchema() {
const schemaCreator = new SchemaCreator(this, this.entityMetadatas);
return schemaCreator.create();
}
/**
* Closes this connection.
*/
@ -116,12 +134,20 @@ export class Connection {
return this.driver.disconnect();
}
/**
* Creates database schema for all entities registered in this connection.
*/
createSchema() {
const schemaBuilder = this.driver.createSchemaBuilder();
const schemaCreator = new SchemaCreator(schemaBuilder, this.entityMetadatas);
return schemaCreator.create();
}
/**
* Gets repository for the given entity class.
*/
getRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function): Repository<Entity> {
// const metadata = this.getEntityMetadata(entityClass);
const metadata = this.entityMetadatas.find(metadata => metadata.target === entityClass);
const metadata = this.entityMetadatas.findByTarget(entityClass);
const repoMeta = this.repositoryAndMetadatas.find(repoMeta => repoMeta.metadata === metadata);
if (!repoMeta)
throw new RepositoryNotFoundError(entityClass);
@ -130,34 +156,97 @@ export class Connection {
}
/**
* Registers entity metadatas for the current connection.
* Imports entities from the given paths (directories) for the current connection.
*/
addEntityMetadatas(metadatas: EntityMetadata[]): Connection {
this.entityMetadatas.push(...metadatas);
this.repositoryAndMetadatas = this.repositoryAndMetadatas.concat(metadatas.map(metadata => this.createRepoMeta(metadata)));
importEntitiesFromDirectories(paths: string[]): void {
this.importEntities(importClassesFromDirectories(paths));
}
/**
* Imports subscribers from the given paths (directories) for the current connection.
*/
importSubscribersFromDirectories(paths: string[]): void {
this.importSubscribers(importClassesFromDirectories(paths));
}
/**
* Imports naming strategies from the given paths (directories) for the current connection.
*/
importNamingStrategiesFromDirectories(paths: string[]): void {
this.importEntities(importClassesFromDirectories(paths));
}
/**
* Imports entities for the current connection.
*/
importEntities(entities: Function[]): this {
this.entityClasses.push(...entities);
return this;
}
/**
* Registers entity listener metadatas for the current connection.
* Imports entities for the given connection. If connection name is not given then default connection is used.
*/
addEntityListenerMetadatas(metadatas: EntityListenerMetadata[]): Connection {
this.entityListeners.push(...metadatas);
importSubscribers(subscriberClasses: Function[]): this {
this.subscriberClasses.push(...subscriberClasses);
return this;
}
/**
* Registers subscribers for the current connection.
* Imports entities for the current connection.
*/
addSubscribers(subscribers: EventSubscriberInterface<any>[]): Connection {
this.subscribers.push(...subscribers);
importNamingStrategies(strategies: Function[]): this {
this.namingStrategyClasses.push(...strategies);
return this;
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private registerMetadatas() {
// first register naming strategies
const metadatas = defaultMetadataStorage().findNamingStrategiesForClasses(this.namingStrategyClasses);
this.namingStrategyMetadatas.push(...metadatas);
// second register subscriber metadatas
const subscribers = defaultMetadataStorage()
.findEventSubscribersForClasses(this.subscriberClasses)
.map(metadata => this.createContainerInstance(metadata.target));
this.subscriberMetadatas.push(...subscribers);
// third register entity and entity listener metadatas
const entityMetadataBuilder = new EntityMetadataBuilder(this.createNamingStrategy());
const entityMetadatas = entityMetadataBuilder.build(this.entityClasses);
const entityListenerMetadatas = defaultMetadataStorage().findEntityListenersForClasses(this.entityClasses);
this.entityMetadatas.push(...entityMetadatas);
this.entityListeners.push(...entityListenerMetadatas);
this.repositoryAndMetadatas.push(...entityMetadatas.map(metadata => this.createRepoMeta(metadata)));
}
/**
* Gets the naming strategy
*/
private createNamingStrategy() {
if (!this.options.namingStrategy)
return new DefaultNamingStrategy();
const namingMetadata = this.namingStrategyMetadatas.find(strategy => strategy.name === this.options.namingStrategy);
return this.createContainerInstance(namingMetadata.target);
}
/**
* Creates a new instance of the given constructor. If IOC Container is registered in the ORM
*/
private createContainerInstance(constructor: Function) {
return getContainer() ? getContainer().get(constructor) : new (<any> constructor)();
}
/**
* Creates a temporary object RepositoryAndMetadata to store mapping between repository and metadata.
*/
private createRepoMeta(metadata: EntityMetadata): RepositoryAndMetadata {
return {
metadata: metadata,

View File

@ -1,50 +0,0 @@
import {Connection} from "./Connection";
import {Driver} from "../driver/Driver";
import {ConnectionOptions} from "./ConnectionOptions";
/**
* Array for the connections.
*
* @internal
*/
export class ConnectionArray extends Array<Connection> {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Creates a new connection and pushes a connection to the array.
*/
createAndPush(name: string, driver: Driver, options: ConnectionOptions) {
this.removeByName(name);
const connection = new Connection(name, <Driver> driver, options);
this.push(connection);
return connection;
}
/**
* Gets connection with a given name.
*/
getWithName(name: string) {
return this.find(connection => connection.name === name);
}
/**
* Checks if connection with a given name exist.
*/
hasWithName(name: string) {
return !!this.getWithName(name);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
private removeByName(name: string) {
const existConnection = this.find(connection => connection.name === name);
if (existConnection)
this.splice(this.indexOf(existConnection), 1);
}
}

View File

@ -1,166 +0,0 @@
import {Connection} from "./Connection";
import {defaultMetadataStorage} from "../metadata-builder/MetadataStorage";
import {Driver} from "../driver/Driver";
import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy";
import {ConnectionNotFoundError} from "./error/ConnectionNotFoundError";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {importClassesFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {ConnectionOptions} from "tls";
import {NamingStrategy} from "../naming-strategy/NamingStrategy";
import {CannotSetNamingStrategyError} from "./error/CannotSetNamingStrategyError";
import {ConnectionArray} from "./ConnectionArray";
/**
* Connection manager holds all connections made to the databases and providers helper management functions
* for all exist connections.
*/
export class ConnectionManager {
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
private connections = new ConnectionArray();
private _entityMetadataBuilder: EntityMetadataBuilder;
private _namingStrategy: NamingStrategy;
private _container: { get(someClass: any): any };
// -------------------------------------------------------------------------
// Accessors
// -------------------------------------------------------------------------
/**
* Sets a container that can be used in custom user subscribers. This allows to inject services in subscribers.
*/
set container(container: { get(someClass: Function): any }) {
this._container = container;
}
/**
* Sets the naming strategy to be used instead of DefaultNamingStrategy.
*/
set namingStrategy(namingStrategy: NamingStrategy) {
// if entity metadata builder already initialized then strategy already is used there, and setting a new naming
// strategy is pointless
if (this._entityMetadataBuilder)
throw new CannotSetNamingStrategyError();
this._namingStrategy = namingStrategy;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Creates and adds a new connection with given driver.
*/
createConnection(driver: Driver, options: ConnectionOptions): Connection;
createConnection(name: string|undefined, driver: Driver, options: ConnectionOptions): Connection;
createConnection(nameOrDriver: string|undefined|Driver, driverOrOptions?: Driver|ConnectionOptions, maybeOptions?: ConnectionOptions): Connection {
const name = typeof nameOrDriver === "string" ? nameOrDriver : "default";
const driver = typeof nameOrDriver === "object" ? <Driver> nameOrDriver : <Driver> driverOrOptions;
const options = typeof nameOrDriver === "object" ? <ConnectionOptions> driverOrOptions : <ConnectionOptions> maybeOptions;
return this.connections.createAndPush(name, driver, options);
}
/**
* Gets registered connection with the given name. If connection name is not given then it will get a default
* connection.
*/
getConnection(name: string = "default"): Connection {
if (!name) name = "default";
if (!this.connections.hasWithName(name))
throw new ConnectionNotFoundError(name);
return this.connections.getWithName(name);
}
/**
* Imports entities from the given paths (directories) for the given connection. If connection name is not given
* then default connection is used.
*/
importEntitiesFromDirectories(paths: string[]): void;
importEntitiesFromDirectories(connectionName: string|undefined, paths: string[]): void;
importEntitiesFromDirectories(connectionNameOrPaths: string|string[]|undefined, maybePaths?: string[]): void {
const connectionName = typeof connectionNameOrPaths === "string" ? connectionNameOrPaths : "default";
const paths = maybePaths ? <string[]> maybePaths : <string[]> connectionNameOrPaths;
this.importEntities(connectionName, importClassesFromDirectories(paths));
}
/**
* Imports subscribers from the given paths (directories) for the given connection. If connection name is not given
* then default connection is used.
*/
importSubscribersFromDirectories(paths: string[]): void;
importSubscribersFromDirectories(connectionName: string|undefined, paths: string[]): void;
importSubscribersFromDirectories(connectionNameOrPaths: string|string[]|undefined, maybePaths?: string[]): void {
const connectionName = typeof connectionNameOrPaths === "string" ? connectionNameOrPaths : "default";
const paths = maybePaths ? <string[]> maybePaths : <string[]> connectionNameOrPaths;
this.importSubscribers(connectionName, importClassesFromDirectories(paths));
}
/**
* Imports entities for the given connection. If connection name is not given then default connection is used.
*/
importEntities(entities: Function[]): void;
importEntities(connectionName: string|undefined, entities: Function[]): void;
importEntities(connectionNameOrEntities: string|undefined|Function[], maybeEntities?: Function[]): void {
const connectionName = typeof connectionNameOrEntities === "string" ? connectionNameOrEntities : "default";
const entities = maybeEntities ? <Function[]> maybeEntities : <Function[]> connectionNameOrEntities;
// console.log("entities", entities);
const entityMetadatas = this.entityMetadataBuilder.build(entities);
const entityListenerMetadatas = defaultMetadataStorage.findEntityListenersForClasses(entities);
this.getConnection(connectionName)
.addEntityMetadatas(entityMetadatas)
.addEntityListenerMetadatas(entityListenerMetadatas);
}
/**
* Imports entities for the given connection. If connection name is not given then default connection is used.
*/
importSubscribers(subscriberClasses: Function[]): void;
importSubscribers(connectionName: string|undefined, subscriberClasses: Function[]): void;
importSubscribers(connectionNameOrSubscriberClasses: string|undefined|Function[], maybeSubscriberClasses?: Function[]): void {
const connectionName = typeof connectionNameOrSubscriberClasses === "string" ? connectionNameOrSubscriberClasses : "default";
const subscriberClasses = maybeSubscriberClasses ? <Function[]> maybeSubscriberClasses : <Function[]> connectionNameOrSubscriberClasses;
const subscribers = defaultMetadataStorage
.findEventSubscribersForClasses(subscriberClasses)
.map(metadata => this.createContainerInstance(metadata.target));
this.getConnection(connectionName).addSubscribers(subscribers);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
/**
* We need to lazily initialize EntityMetadataBuilder because naming strategy can be set before we use entityMetadataBuilder.
*/
private get entityMetadataBuilder() {
if (!this._entityMetadataBuilder) {
const namingStrategy = this._namingStrategy ? this._namingStrategy : new DefaultNamingStrategy();
this._entityMetadataBuilder = new EntityMetadataBuilder(defaultMetadataStorage, namingStrategy);
}
return this._entityMetadataBuilder;
}
/**
* Creates a new instance of the given constructor.
*/
private createContainerInstance(constructor: Function) {
return this._container ? this._container.get(constructor) : new (<any> constructor)();
}
}

View File

@ -38,6 +38,11 @@ export interface ConnectionOptions {
*/
autoSchemaCreate?: boolean;
/**
* Name of the naming strategy to be used on this connection.
*/
namingStrategy?: string;
/**
* Logging options.
*/

View File

@ -1,13 +0,0 @@
/**
* @internal
*/
export class BroadcasterNotFoundError extends Error {
name = "BroadcasterNotFoundError";
constructor(entityClassOrName: string|Function) {
super();
const name = entityClassOrName instanceof Function ? (<any> entityClassOrName).name : entityClassOrName;
this.message = `No broadcaster for "${name}" was found. Looks like this entity is not registered in your connection?`;
}
}

View File

@ -1,7 +0,0 @@
/**
* @internal
*/
export class CannotSetNamingStrategyError extends Error {
name = "CannotSetNamingStrategyError";
message = "Cannot set naming strategy. Naming strategy must be set right after ConnectionManager is created, and before any entity importing is done.";
}

View File

@ -1,12 +0,0 @@
/**
* @internal
*/
export class MetadataNotFoundError extends Error {
name = "MetadataNotFoundError";
constructor(entityClass: Function) {
super();
this.message = `No metadata for ${entityClass} has been found!`;
}
}

View File

@ -1,13 +0,0 @@
/**
* @internal
*/
export class SchemaNotFoundError extends Error {
name = "SchemaNotFoundError";
constructor(entityClassOrName: string|Function) {
super();
const name = entityClassOrName instanceof Function ? (<any> entityClassOrName).name : entityClassOrName;
this.message = `No schema for "${name}" was found. Looks like this entity is not registered in your connection?`;
}
}

View File

@ -0,0 +1,13 @@
import "reflect-metadata";
import {NamingStrategyMetadata} from "../metadata-builder/metadata/NamingStrategyMetadata";
import {defaultMetadataStorage} from "../typeorm";
/**
* Decorator registers a new naming strategy to be used in naming things.
*/
export function NamingStrategy(name?: string): Function {
return function (target: Function) {
const strategyName = name ? name : (<any> target).name;
defaultMetadataStorage().addNamingStrategyMetadata(new NamingStrategyMetadata(target, strategyName));
};
}

View File

@ -1,7 +1,7 @@
import {ColumnOptions} from "../../metadata-builder/options/ColumnOptions";
import {ColumnTypeUndefinedError} from "../error/ColumnTypeUndefinedError";
import {AutoIncrementOnlyForPrimaryError} from "../error/AutoIncrementOnlyForPrimaryError";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ColumnMetadata} from "../../metadata-builder/metadata/ColumnMetadata";
import {ColumnType, ColumnTypes} from "../../metadata-builder/types/ColumnTypes";
import "reflect-metadata";
@ -53,7 +53,7 @@ export function Column(typeOrOptions?: ColumnType|ColumnOptions, options?: Colum
throw new AutoIncrementOnlyForPrimaryError(object, propertyName);
// create and register a new column metadata
defaultMetadataStorage.addColumnMetadata(new ColumnMetadata({
defaultMetadataStorage().addColumnMetadata(new ColumnMetadata({
target: object.constructor,
propertyName: propertyName,
propertyType: reflectedType,

View File

@ -1,6 +1,6 @@
import {ColumnOptions} from "../../metadata-builder/options/ColumnOptions";
import {ColumnType, ColumnTypes} from "../../metadata-builder/types/ColumnTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ColumnMetadata} from "../../metadata-builder/metadata/ColumnMetadata";
import "reflect-metadata";
@ -20,7 +20,7 @@ export function CreateDateColumn(options?: ColumnOptions): Function {
columnOptions.type = ColumnTypes.DATETIME;
// create and register a new column metadata
defaultMetadataStorage.addColumnMetadata(new ColumnMetadata({
defaultMetadataStorage().addColumnMetadata(new ColumnMetadata({
target: object.constructor,
propertyName: propertyName,
propertyType: reflectedType,

View File

@ -1,7 +1,7 @@
import {ColumnOptions} from "../../metadata-builder/options/ColumnOptions";
import {ColumnType, ColumnTypes} from "../../metadata-builder/types/ColumnTypes";
import {ColumnTypeUndefinedError} from "../error/ColumnTypeUndefinedError";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ColumnMetadata} from "../../metadata-builder/metadata/ColumnMetadata";
import {PrimaryColumnCannotBeNullableError} from "../error/PrimaryColumnCannotBeNullableError";
import "reflect-metadata";
@ -56,7 +56,7 @@ export function PrimaryColumn(typeOrOptions?: ColumnType|ColumnOptions, options?
throw new PrimaryColumnCannotBeNullableError(object, propertyName);
// create and register a new column metadata
defaultMetadataStorage.addColumnMetadata(new ColumnMetadata({
defaultMetadataStorage().addColumnMetadata(new ColumnMetadata({
target: object.constructor,
propertyName: propertyName,
propertyType: reflectedType,

View File

@ -1,6 +1,6 @@
import {ColumnOptions} from "../../metadata-builder/options/ColumnOptions";
import {ColumnType, ColumnTypes} from "../../metadata-builder/types/ColumnTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ColumnMetadata} from "../../metadata-builder/metadata/ColumnMetadata";
import "reflect-metadata";
@ -20,7 +20,7 @@ export function UpdateDateColumn(options?: ColumnOptions): Function {
columnOptions.type = ColumnTypes.DATETIME;
// create and register a new column metadata
defaultMetadataStorage.addColumnMetadata(new ColumnMetadata({
defaultMetadataStorage().addColumnMetadata(new ColumnMetadata({
target: object.constructor,
propertyName: propertyName,
propertyType: reflectedType,

View File

@ -1,11 +1,11 @@
import {CompoundIndexMetadata} from "../../metadata-builder/metadata/CompoundIndexMetadata";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
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.addCompoundIndexMetadata(new CompoundIndexMetadata(cls, fields));
defaultMetadataStorage().addCompoundIndexMetadata(new CompoundIndexMetadata(cls, fields));
};
}

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {IndexMetadata} from "../../metadata-builder/metadata/IndexMetadata";
/**
@ -6,6 +6,6 @@ import {IndexMetadata} from "../../metadata-builder/metadata/IndexMetadata";
*/
export function Index(name?: string) {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addIndexMetadata(new IndexMetadata(object.constructor, propertyName, name));
defaultMetadataStorage().addIndexMetadata(new IndexMetadata(object.constructor, propertyName, name));
};
}

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function AfterInsert() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.AFTER_INSERT

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function AfterLoad() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.AFTER_LOAD

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function AfterRemove() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.AFTER_REMOVE

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function AfterUpdate() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.AFTER_UPDATE

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function BeforeInsert() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.BEFORE_INSERT

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function BeforeRemove() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.BEFORE_REMOVE

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventListenerTypes} from "../../metadata-builder/types/EventListenerTypes";
import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityListenerMetadata";
@ -7,7 +7,7 @@ import {EntityListenerMetadata} from "../../metadata-builder/metadata/EntityList
*/
export function BeforeUpdate() {
return function (object: Object, propertyName: string) {
defaultMetadataStorage.addEntityListenerMetadata(new EntityListenerMetadata(
defaultMetadataStorage().addEntityListenerMetadata(new EntityListenerMetadata(
object.constructor,
propertyName,
EventListenerTypes.BEFORE_UPDATE

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {EventSubscriberMetadata} from "../../metadata-builder/metadata/EventSubscriberMetadata";
/**
@ -7,6 +7,6 @@ import {EventSubscriberMetadata} from "../../metadata-builder/metadata/EventSubs
*/
export function EventSubscriber() {
return function (target: Function) {
defaultMetadataStorage.addEventSubscriberMetadata(new EventSubscriberMetadata(target));
defaultMetadataStorage().addEventSubscriberMetadata(new EventSubscriberMetadata(target));
};
}

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -39,7 +39,7 @@ export function ManyToMany<T>(typeFunction: (type?: any) => ConstructorFunction<
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.MANY_TO_MANY,

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -39,7 +39,7 @@ export function ManyToManyInverse<T>(typeFunction: (type?: any) => ConstructorFu
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.MANY_TO_MANY,

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -39,7 +39,7 @@ export function ManyToOne<T>(typeFunction: (type?: any) => ConstructorFunction<T
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.MANY_TO_ONE,

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -36,7 +36,7 @@ export function OneToMany<T>(typeFunction: (type?: any) => ConstructorFunction<T
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.ONE_TO_MANY,

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -36,7 +36,7 @@ export function OneToOne<T>(typeFunction: (type?: any) => ConstructorFunction<T>
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.ONE_TO_ONE,

View File

@ -1,7 +1,7 @@
import {RelationMetadata} from "../../metadata-builder/metadata/RelationMetadata";
import {RelationOptions} from "../../metadata-builder/options/RelationOptions";
import {RelationTypes} from "../../metadata-builder/types/RelationTypes";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {ConstructorFunction} from "../../common/ConstructorFunction";
/**
@ -39,7 +39,7 @@ export function OneToOneInverse<T>(typeFunction: (type?: any) => ConstructorFunc
const relationOptions = options ? options : {} as RelationOptions;
defaultMetadataStorage.addRelationMetadata(new RelationMetadata({
defaultMetadataStorage().addRelationMetadata(new RelationMetadata({
target: object.constructor,
propertyName: propertyName,
relationType: RelationTypes.ONE_TO_ONE,

View File

@ -1,11 +1,11 @@
import {TableMetadata} from "../../metadata-builder/metadata/TableMetadata";
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
/**
* Allows to use columns and relations data from the inherited metadata.
*/
export function AbstractTable() {
return function (cls: Function) {
defaultMetadataStorage.addTableMetadata(new TableMetadata(cls, true));
defaultMetadataStorage().addTableMetadata(new TableMetadata(cls, true));
};
}

View File

@ -1,4 +1,4 @@
import {defaultMetadataStorage} from "../../metadata-builder/MetadataStorage";
import {defaultMetadataStorage} from "../../typeorm";
import {TableMetadata} from "../../metadata-builder/metadata/TableMetadata";
/**
@ -7,6 +7,6 @@ import {TableMetadata} from "../../metadata-builder/metadata/TableMetadata";
*/
export function Table(name?: string) {
return function (cls: Function) {
defaultMetadataStorage.addTableMetadata(new TableMetadata(cls, name));
defaultMetadataStorage().addTableMetadata(new TableMetadata(cls, name));
};
}

View File

@ -2,11 +2,12 @@ import {MetadataStorage} from "./MetadataStorage";
import {PropertyMetadata} from "./metadata/PropertyMetadata";
import {TableMetadata} from "./metadata/TableMetadata";
import {EntityMetadata} from "./metadata/EntityMetadata";
import {NamingStrategy} from "../naming-strategy/NamingStrategy";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategy";
import {ColumnMetadata} from "./metadata/ColumnMetadata";
import {ColumnOptions} from "./options/ColumnOptions";
import {ForeignKeyMetadata} from "./metadata/ForeignKeyMetadata";
import {JunctionTableMetadata} from "./metadata/JunctionTableMetadata";
import {defaultMetadataStorage} from "../typeorm";
/**
* Aggregates all metadata: table, column, relation into one collection grouped by tables for a given set of classes.
@ -17,12 +18,13 @@ export class EntityMetadataBuilder {
// todo: type in function validation, inverse side function validation
private metadataStorage: MetadataStorage = defaultMetadataStorage();
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(private metadataStorage: MetadataStorage,
private namingStrategy: NamingStrategy) {
constructor(private namingStrategy: NamingStrategyInterface) {
}
// -------------------------------------------------------------------------

View File

@ -7,12 +7,11 @@ import {CompoundIndexMetadata} from "./metadata/CompoundIndexMetadata";
import {ColumnMetadata} from "./metadata/ColumnMetadata";
import {EventSubscriberMetadata} from "./metadata/EventSubscriberMetadata";
import {EntityListenerMetadata} from "./metadata/EntityListenerMetadata";
import {NamingStrategyMetadata} from "./metadata/NamingStrategyMetadata";
/**
* Storage all metadatas of all available types: tables, fields, subscribers, relations, etc.
* Each metadata represents some specifications of what it represents.
*
* @internal
*/
export class MetadataStorage {
@ -20,45 +19,14 @@ export class MetadataStorage {
// Properties
// -------------------------------------------------------------------------
private _tableMetadatas: TableMetadata[] = [];
private _eventSubscriberMetadatas: EventSubscriberMetadata[] = [];
private _columnMetadatas: ColumnMetadata[] = [];
private _indexMetadatas: IndexMetadata[] = [];
private _entityListenerMetadatas: EntityListenerMetadata[] = [];
private _compoundIndexMetadatas: CompoundIndexMetadata[] = [];
private _relationMetadatas: RelationMetadata[] = [];
// -------------------------------------------------------------------------
// Getter Methods
// -------------------------------------------------------------------------
get tableMetadatas(): TableMetadata[] {
return this._tableMetadatas;
}
get eventSubscriberMetadatas(): EventSubscriberMetadata[] {
return this._eventSubscriberMetadatas;
}
get columnMetadatas(): ColumnMetadata[] {
return this._columnMetadatas;
}
get indexMetadatas(): IndexMetadata[] {
return this._indexMetadatas;
}
get entityListenerMetadatas(): EntityListenerMetadata[] {
return this._entityListenerMetadatas;
}
get compoundIndexMetadatas(): CompoundIndexMetadata[] {
return this._compoundIndexMetadatas;
}
get relationMetadatas(): RelationMetadata[] {
return this._relationMetadatas;
}
private tableMetadatas: TableMetadata[] = [];
private eventSubscriberMetadatas: EventSubscriberMetadata[] = [];
private columnMetadatas: ColumnMetadata[] = [];
private indexMetadatas: IndexMetadata[] = [];
private entityListenerMetadatas: EntityListenerMetadata[] = [];
private compoundIndexMetadatas: CompoundIndexMetadata[] = [];
private namingStrategyMetadatas: NamingStrategyMetadata[] = [];
private relationMetadatas: RelationMetadata[] = [];
// -------------------------------------------------------------------------
// Adder Methods
@ -118,6 +86,13 @@ export class MetadataStorage {
this.compoundIndexMetadatas.push(metadata);
}
addNamingStrategyMetadata(metadata: NamingStrategyMetadata) {
if (this.hasNamingStrategyMetadataWithObjectConstructor(metadata.target))
throw new MetadataAlreadyExistsError("NamingStrategy", metadata.target);
this.namingStrategyMetadatas.push(metadata);
}
addEntityListenerMetadata(metadata: EntityListenerMetadata) {
if (this.hasFieldMetadataOnProperty(metadata.target, metadata.propertyName))
throw new MetadataAlreadyExistsError("EventListener", metadata.target);
@ -161,6 +136,15 @@ export class MetadataStorage {
return this.relationMetadatas.filter(metadata => classes.indexOf(metadata.target) !== -1);
}
findNamingStrategy(name: string): NamingStrategyMetadata {
// todo: throw error if naming strategy is not found.
return this.namingStrategyMetadatas.find(metadata => metadata.name === name);
}
findNamingStrategiesForClasses(classes: Function[]): NamingStrategyMetadata[] {
return this.namingStrategyMetadatas.filter(metadata => classes.indexOf(metadata.target) !== -1);
}
// -------------------------------------------------------------------------
// Private Methods
// -------------------------------------------------------------------------
@ -173,6 +157,10 @@ export class MetadataStorage {
return !!this.compoundIndexMetadatas.find(metadata => metadata.target === constructor);
}
private hasNamingStrategyMetadataWithObjectConstructor(constructor: Function): boolean {
return !!this.namingStrategyMetadatas.find(metadata => metadata.target === constructor);
}
private hasEventSubscriberWithObjectConstructor(constructor: Function): boolean {
return !!this.eventSubscriberMetadatas.find(metadata => metadata.target === constructor);
}
@ -197,9 +185,4 @@ export class MetadataStorage {
return !!this.relationMetadatas.find(metadata => metadata.target === constructor && metadata.name === name);
}
}
/**
* Default metadata storage used as singleton and can be used to storage all metadatas in the system.
*/
export const defaultMetadataStorage = new MetadataStorage();
}

View File

@ -1,6 +1,6 @@
import {PropertyMetadata} from "./PropertyMetadata";
import {ColumnOptions} from "../options/ColumnOptions";
import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategy";
import {ColumnType} from "../types/ColumnTypes";
/**
@ -61,7 +61,7 @@ export class ColumnMetadata extends PropertyMetadata {
/**
* Naming strategy to be used to generate column name.
*/
namingStrategy: NamingStrategy;
namingStrategy: NamingStrategyInterface;
// ---------------------------------------------------------------------
// Readonly Properties

View File

@ -0,0 +1,18 @@
import {EntityMetadata} from "./EntityMetadata";
/**
* Array for the entity metadatas.
*
* @internal
*/
export class EntityMetadataArray extends Array<EntityMetadata> {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
findByTarget(target: Function) {
return this.find(metadata => metadata.target === target);
}
}

View File

@ -0,0 +1,29 @@
/**
* This metadata interface contains all information about naming strategy.
*/
export class NamingStrategyMetadata {
// ---------------------------------------------------------------------
// Readonly Properties
// ---------------------------------------------------------------------
/**
* Class to which this decorator is applied.
*/
readonly target: Function;
/**
* Naming strategy name.
*/
readonly name: string;
// ---------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------
constructor(target: Function, name: string) {
this.target = target;
this.name = name;
}
}

View File

@ -1,7 +1,7 @@
import {PropertyMetadata} from "./PropertyMetadata";
import {RelationTypes, RelationType} from "../types/RelationTypes";
import {RelationOptions} from "../options/RelationOptions";
import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategy";
import {EntityMetadata} from "./EntityMetadata";
import {OnDeleteType} from "./ForeignKeyMetadata";
@ -69,7 +69,7 @@ export class RelationMetadata extends PropertyMetadata {
/**
* Naming strategy used to generate and normalize column name.
*/
namingStrategy: NamingStrategy;
namingStrategy: NamingStrategyInterface;
/**
* Related entity metadata.

View File

@ -1,4 +1,4 @@
import {NamingStrategy} from "../../naming-strategy/NamingStrategy";
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategy";
/**
* This metadata interface contains all information about specific table.
@ -12,7 +12,7 @@ export class TableMetadata {
/**
* Naming strategy used to generate and normalize table name.
*/
namingStrategy: NamingStrategy;
namingStrategy: NamingStrategyInterface;
// ---------------------------------------------------------------------
// Readonly Properties

View File

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

View File

@ -2,7 +2,7 @@
* Naming strategy defines how auto-generated names for such things like table name, or table column gonna be
* generated.
*/
export interface NamingStrategy {
export interface NamingStrategyInterface {
/**
* Gets the table name from the given class name.

View File

@ -448,7 +448,7 @@ export class QueryBuilder<Entity> {
protected createSelectExpression() {
// todo throw exception if selects or from is missing
let alias: string, tableName: string;
let alias: string = "", tableName: string;
const allSelects: string[] = [];
if (this.fromEntity) {

View File

@ -147,7 +147,7 @@ export class MysqlSchemaBuilder extends SchemaBuilder {
private normalizeType(column: ColumnMetadata) {
let realType: string;
let realType: string = "";
if (typeof column.type === "string") {
realType = column.type.toLowerCase();

View File

@ -1,9 +1,9 @@
import {Connection} from "../connection/Connection";
import {TableMetadata} from "../metadata-builder/metadata/TableMetadata";
import {ColumnMetadata} from "../metadata-builder/metadata/ColumnMetadata";
import {ForeignKeyMetadata} from "../metadata-builder/metadata/ForeignKeyMetadata";
import {EntityMetadata} from "../metadata-builder/metadata/EntityMetadata";
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
import {EntityMetadataArray} from "../metadata-builder/metadata/EntityMetadataArray";
/**
* Creates indexes based on the given metadata.
@ -12,20 +12,12 @@ import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
*/
export class SchemaCreator {
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
private connection: Connection;
private schemaBuilder: SchemaBuilder;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection, private entityMetadatas: EntityMetadata[]) {
this.connection = connection;
this.schemaBuilder = connection.driver.createSchemaBuilder();
constructor(private schemaBuilder: SchemaBuilder,
private entityMetadatas: EntityMetadataArray) {
}
// -------------------------------------------------------------------------

View File

@ -26,7 +26,7 @@ export class Broadcaster {
broadcastBeforeInsertEvent(entity: any): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.beforeInsert)
.map(subscriber => subscriber.beforeInsert({ entity: entity }));
@ -42,7 +42,7 @@ export class Broadcaster {
broadcastBeforeUpdateEvent(entity: any, updatedColumns: ColumnMetadata[]): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.beforeUpdate)
.map(subscriber => subscriber.beforeUpdate({ entity: entity, updatedColumns: updatedColumns }));
@ -58,7 +58,7 @@ export class Broadcaster {
broadcastBeforeRemoveEvent(entity: any, entityId: any): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.beforeRemove)
.map(subscriber => subscriber.beforeRemove({ entity: entity, entityId: entityId }));
@ -74,7 +74,7 @@ export class Broadcaster {
broadcastAfterInsertEvent(entity: any): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.afterInsert)
.map(subscriber => subscriber.afterInsert({ entity: entity }));
@ -90,7 +90,7 @@ export class Broadcaster {
broadcastAfterUpdateEvent(entity: any, updatedColumns: ColumnMetadata[]): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.afterUpdate)
.map(subscriber => subscriber.afterUpdate({ entity: entity, updatedColumns: updatedColumns }));
@ -106,7 +106,7 @@ export class Broadcaster {
broadcastAfterRemoveEvent(entity: any, entityId: any): Promise<void> {
const subscribers = this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.afterRemove)
.map(subscriber => subscriber.afterRemove({ entity: entity, entityId: entityId }));
@ -137,7 +137,7 @@ export class Broadcaster {
});
this.connection
.subscribers
.subscriberMetadatas
.filter(subscriber => this.isAllowedSubscribers(subscriber, entity))
.filter(subscriber => !!subscriber.afterLoad)
.forEach(subscriber => promises.push(<any> subscriber.afterLoad(entity)));

View File

@ -3,91 +3,92 @@
*/
import {ConnectionOptions} from "./connection/ConnectionOptions";
import {ConnectionManager} from "./connection/ConnectionManager";
import {ConnectionManager} from "./connection-manager/ConnectionManager";
import {Connection} from "./connection/Connection";
import {MysqlDriver} from "./driver/MysqlDriver";
import {MetadataStorage} from "./metadata-builder/MetadataStorage";
import {CreateConnectionOptions} from "./connection-manager/CreateConnectionOptions";
const connectionManager = new ConnectionManager();
// -------------------------------------------------------------------------
// Global Container
// -------------------------------------------------------------------------
/**
* All options to help to create a new connection.
* Container to be used by TypeORM for inversion control.
*/
export interface CreateConnectionOptions {
let container: { get(someClass: any): any };
/**
* Driver type. Mysql is the only driver supported at this moment.
*/
driver: "mysql";
/**
* Database connection options.
*/
connection: ConnectionOptions;
/**
* Connection name. By default its called "default". Different connections must have different names.
*/
connectionName?: string;
/**
* Entities to be loaded for the new connection.
*/
entities?: Function[];
/**
* Subscribers to be loaded for the new connection.
*/
subscribers?: Function[];
/**
* List of directories from where entities will be loaded.
*/
entityDirectories?: string[];
/**
* List of directories from where subscribers will be loaded.
*/
subscriberDirectories?: string[];
/**
* Sets container to be used by TypeORM.
*
* @param iocContainer
*/
export function useContainer(iocContainer: { get(someClass: any): any }) {
container = iocContainer;
}
/**
* Creates a new connection with the database.
*/
export function createConnection(options: CreateConnectionOptions): Promise<Connection> {
export function getContainer() {
return container;
}
let connection: Connection;
switch (options.driver) {
case "mysql":
connection = connectionManager.createConnection(options.connectionName, new MysqlDriver(), options.connection);
break;
default:
throw new Error(`Wrong driver ${options.driver} given. Supported drivers are: "mysql"`);
// -------------------------------------------------------------------------
// Global Metadata Storage
// -------------------------------------------------------------------------
/**
* Default metadata storage used as singleton and can be used to storage all metadatas in the system.
*/
let metadataStorage: MetadataStorage;
export function defaultMetadataStorage() {
if (!metadataStorage && container) {
metadataStorage = container.get(MetadataStorage);
} else if (!metadataStorage) {
metadataStorage = new MetadataStorage();
}
if (options.entityDirectories && options.entityDirectories.length > 0)
connectionManager.importEntitiesFromDirectories(options.connectionName, options.entityDirectories);
if (options.entities)
connectionManager.importEntities(options.connectionName, options.entities);
if (options.subscriberDirectories && options.subscriberDirectories.length > 0)
connectionManager.importSubscribersFromDirectories(options.connectionName, options.subscriberDirectories);
if (options.subscribers)
connectionManager.importSubscribers(options.subscribers);
return connection.connect().then(() => connection);
return metadataStorage;
}
// -------------------------------------------------------------------------
// Global Connection Manager
// -------------------------------------------------------------------------
/**
* Default export. Global connection manager.
*/
export default connectionManager;
let connectionManager: ConnectionManager;
/**
* Gets a ConnectionManager which creates connections.
*/
export function getConnectionManager() {
if (!connectionManager && container) {
connectionManager = container.get(ConnectionManager);
} else if (!connectionManager) {
connectionManager = new ConnectionManager();
}
return connectionManager;
}
/**
* Allows to quickly create a connection based on the given options. Uses ConnectionManager.
*/
export function createConnection(options: CreateConnectionOptions) {
return getConnectionManager().create(options);
}
// -------------------------------------------------------------------------
// Commonly Used exports
// -------------------------------------------------------------------------
// export everything commonly used
export {Connection} from "./connection/Connection";
export {ConnectionManager} from "./connection/ConnectionManager";
export {ConnectionOptions} from "./connection/ConnectionOptions";
export {ConnectionManager} from "./connection-manager/ConnectionManager";
export {CreateConnectionOptions} from "./connection-manager/CreateConnectionOptions";
export {Driver} from "./driver/Driver";
export {MysqlDriver} from "./driver/MysqlDriver";
export {QueryBuilder} from "./query-builder/QueryBuilder";