mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
connection and connection manager refactorings
This commit is contained in:
parent
e00c5ffed3
commit
901248cfa4
@ -9,10 +9,10 @@ You start using ORM by creating a connection with the database. In this section
|
||||
|
||||
### Connection Manager
|
||||
|
||||
Connection manager allows to create a new connections and retrive previously created connections. Also it allows to import
|
||||
Connection manager allows to create a new connections and retrieve previously created connections. Also it allows to import
|
||||
entities and subscribers into specific connection. These are main public methods of the `ConnectionManager`:
|
||||
|
||||
* `createConnection(connectionName: string = "default", driver: Driver, options: ConnectionOptions): Connection`
|
||||
* `createConnection(options: CreateConnectionOptions): Connection`
|
||||
|
||||
Creates a new connection and registers it in the connection manager. It returns a newly created connection.
|
||||
New connection will have a given *connection name*. If connection name is not given then "default" will be used as a
|
||||
|
||||
@ -47,7 +47,7 @@ export class ConnectionManager {
|
||||
if (options.namingStrategies)
|
||||
connection.importNamingStrategies(options.namingStrategies);
|
||||
|
||||
return connection.connect().then(() => connection);
|
||||
return connection.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -14,6 +14,10 @@ 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";
|
||||
import {NoConnectionForRepositoryError} from "./error/NoConnectionForRepositoryError";
|
||||
import {CannotImportAlreadyConnectedError} from "./error/CannotImportAlreadyConnectedError";
|
||||
import {CannotCloseNotConnectedError} from "./error/CannotCloseNotConnectedError";
|
||||
import {CannotConnectAlreadyConnectedError} from "./error/CannotConnectAlreadyConnectedError";
|
||||
|
||||
/**
|
||||
* Temporary type to store and link both repository and its metadata.
|
||||
@ -94,6 +98,11 @@ export class Connection {
|
||||
*/
|
||||
private readonly namingStrategyClasses: Function[] = [];
|
||||
|
||||
/**
|
||||
* Indicates if connection has been done or not.
|
||||
*/
|
||||
private _isConnected = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
@ -106,6 +115,17 @@ export class Connection {
|
||||
this.entityManager = new EntityManager(this);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Accessors
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if connection to the database already established for this connection.
|
||||
*/
|
||||
get isConnected() {
|
||||
return this._isConnected;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
@ -113,17 +133,24 @@ export class Connection {
|
||||
/**
|
||||
* Performs connection to the database.
|
||||
*/
|
||||
connect(): Promise<void> {
|
||||
connect(): Promise<this> {
|
||||
if (this.isConnected)
|
||||
throw new CannotConnectAlreadyConnectedError(this.name);
|
||||
|
||||
return this.driver.connect().then(() => {
|
||||
|
||||
// build all metadata
|
||||
this.registerMetadatas();
|
||||
// first build all metadata
|
||||
this.buildMetadatas();
|
||||
|
||||
// second build schema
|
||||
if (this.options.autoSchemaCreate === true)
|
||||
return this.createSchema();
|
||||
return this.syncSchema();
|
||||
|
||||
return undefined;
|
||||
return Promise.resolve();
|
||||
|
||||
}).then(() => {
|
||||
this._isConnected = true;
|
||||
return this;
|
||||
});
|
||||
}
|
||||
|
||||
@ -131,55 +158,52 @@ export class Connection {
|
||||
* Closes this connection.
|
||||
*/
|
||||
close(): Promise<void> {
|
||||
if (!this.isConnected)
|
||||
throw new CannotCloseNotConnectedError(this.name);
|
||||
|
||||
return this.driver.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates database schema for all entities registered in this connection.
|
||||
*/
|
||||
createSchema() {
|
||||
syncSchema() {
|
||||
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.entityMetadatas.findByTarget(entityClass);
|
||||
const repoMeta = this.repositoryAndMetadatas.find(repoMeta => repoMeta.metadata === metadata);
|
||||
if (!repoMeta)
|
||||
throw new RepositoryNotFoundError(entityClass);
|
||||
|
||||
return repoMeta.repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports entities from the given paths (directories) for the current connection.
|
||||
*/
|
||||
importEntitiesFromDirectories(paths: string[]): void {
|
||||
importEntitiesFromDirectories(paths: string[]): this {
|
||||
this.importEntities(importClassesFromDirectories(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports subscribers from the given paths (directories) for the current connection.
|
||||
*/
|
||||
importSubscribersFromDirectories(paths: string[]): void {
|
||||
importSubscribersFromDirectories(paths: string[]): this {
|
||||
this.importSubscribers(importClassesFromDirectories(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports naming strategies from the given paths (directories) for the current connection.
|
||||
*/
|
||||
importNamingStrategiesFromDirectories(paths: string[]): void {
|
||||
importNamingStrategiesFromDirectories(paths: string[]): this {
|
||||
this.importEntities(importClassesFromDirectories(paths));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports entities for the current connection.
|
||||
*/
|
||||
importEntities(entities: Function[]): this {
|
||||
if (this.isConnected)
|
||||
throw new CannotImportAlreadyConnectedError("entities", this.name);
|
||||
|
||||
this.entityClasses.push(...entities);
|
||||
return this;
|
||||
}
|
||||
@ -188,6 +212,9 @@ export class Connection {
|
||||
* Imports entities for the given connection. If connection name is not given then default connection is used.
|
||||
*/
|
||||
importSubscribers(subscriberClasses: Function[]): this {
|
||||
if (this.isConnected)
|
||||
throw new CannotImportAlreadyConnectedError("event subscribers", this.name);
|
||||
|
||||
this.subscriberClasses.push(...subscriberClasses);
|
||||
return this;
|
||||
}
|
||||
@ -196,15 +223,36 @@ export class Connection {
|
||||
* Imports entities for the current connection.
|
||||
*/
|
||||
importNamingStrategies(strategies: Function[]): this {
|
||||
if (this.isConnected)
|
||||
throw new CannotImportAlreadyConnectedError("naming strategies", this.name);
|
||||
|
||||
this.namingStrategyClasses.push(...strategies);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets repository for the given entity class.
|
||||
*/
|
||||
getRepository<Entity>(entityClass: ConstructorFunction<Entity>|Function): Repository<Entity> {
|
||||
if (!this.isConnected)
|
||||
throw new NoConnectionForRepositoryError(this.name);
|
||||
|
||||
const metadata = this.entityMetadatas.findByTarget(entityClass);
|
||||
const repoMeta = this.repositoryAndMetadatas.find(repoMeta => repoMeta.metadata === metadata);
|
||||
if (!repoMeta)
|
||||
throw new RepositoryNotFoundError(this.name, entityClass);
|
||||
|
||||
return repoMeta.repository;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private registerMetadatas() {
|
||||
|
||||
/**
|
||||
* Builds all registered metadatas.
|
||||
*/
|
||||
private buildMetadatas() {
|
||||
|
||||
// first register naming strategies
|
||||
const metadatas = defaultMetadataStorage().findNamingStrategiesForClasses(this.namingStrategyClasses);
|
||||
@ -227,7 +275,7 @@ export class Connection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the naming strategy
|
||||
* Gets the naming strategy to be used for this connection.
|
||||
*/
|
||||
private createNamingStrategy() {
|
||||
if (!this.options.namingStrategy)
|
||||
@ -238,14 +286,15 @@ export class Connection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given constructor. If IOC Container is registered in the ORM
|
||||
* Creates a new instance of the given constructor. If service container is registered in the ORM, then it will
|
||||
* be used, otherwise new instance of naming strategy will be created.
|
||||
*/
|
||||
private createContainerInstance(constructor: Function) {
|
||||
return getContainer() ? getContainer().get(constructor) : new (<any> constructor)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary object RepositoryAndMetadata to store mapping between repository and metadata.
|
||||
* Creates a temporary object RepositoryAndMetadata to store relation between repository and metadata.
|
||||
*/
|
||||
private createRepoMeta(metadata: EntityMetadata): RepositoryAndMetadata {
|
||||
return {
|
||||
|
||||
12
src/connection/error/CannotCloseNotConnectedError.ts
Normal file
12
src/connection/error/CannotCloseNotConnectedError.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class CannotCloseNotConnectedError extends Error {
|
||||
name = "CannotCloseNotConnectedError";
|
||||
|
||||
constructor(connectionName: string) {
|
||||
super();
|
||||
this.message = `Cannot close "${connectionName}" connection because connection is not yet established.`;
|
||||
}
|
||||
|
||||
}
|
||||
12
src/connection/error/CannotConnectAlreadyConnectedError.ts
Normal file
12
src/connection/error/CannotConnectAlreadyConnectedError.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class CannotConnectAlreadyConnectedError extends Error {
|
||||
name = "CannotConnectAlreadyConnectedError";
|
||||
|
||||
constructor(connectionName: string) {
|
||||
super();
|
||||
this.message = `Cannot create a "${connectionName}" connection because connection to the database already established.`;
|
||||
}
|
||||
|
||||
}
|
||||
12
src/connection/error/CannotImportAlreadyConnectedError.ts
Normal file
12
src/connection/error/CannotImportAlreadyConnectedError.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class CannotImportAlreadyConnectedError extends Error {
|
||||
name = "CannotImportAlreadyConnected";
|
||||
|
||||
constructor(importStuff: string, connectionName: string) {
|
||||
super();
|
||||
this.message = `Cannot import ${importStuff} for "${connectionName}" connection because connection to the database already established.`;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/connection/error/NoConnectionForRepositoryError.ts
Normal file
13
src/connection/error/NoConnectionForRepositoryError.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class NoConnectionForRepositoryError extends Error {
|
||||
name = "NoConnectionForRepositoryError";
|
||||
|
||||
constructor(connectionName: string) {
|
||||
super();
|
||||
this.message = `Cannot get a Repository for "${connectionName} connection, because connection with the database ` +
|
||||
`is not established yet. Call connection#connect method to establish connection.`;
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,9 +4,11 @@
|
||||
export class RepositoryNotFoundError extends Error {
|
||||
name = "RepositoryNotFoundError";
|
||||
|
||||
constructor(entityClass: Function) {
|
||||
constructor(connectionName: string, entityClass: Function) {
|
||||
super();
|
||||
this.message = `No repository for "${entityClass}" was found. Looks like this entity is not registered in your connection?`;
|
||||
const targetName = (<any> entityClass).name ? (<any> entityClass).name : entityClass;
|
||||
this.message = `No repository for "${targetName}" was found. Looks like this entity is not registered in ` +
|
||||
`current "${connectionName}" connection?`;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/metadata-builder/error/EntityMetadataNotFound.ts
Normal file
13
src/metadata-builder/error/EntityMetadataNotFound.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class EntityMetadataNotFound extends Error {
|
||||
name = "EntityMetadataNotFound";
|
||||
|
||||
constructor(target: Function) {
|
||||
super();
|
||||
const targetName = (<any> target).name ? (<any> target).name : target;
|
||||
this.message = `No metadata for "${targetName}" was found.`;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import {EntityMetadata} from "./EntityMetadata";
|
||||
import {EntityMetadataNotFound} from "../error/EntityMetadataNotFound";
|
||||
|
||||
/**
|
||||
* Array for the entity metadatas.
|
||||
@ -11,8 +12,16 @@ export class EntityMetadataArray extends Array<EntityMetadata> {
|
||||
// Public Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
hasTarget(target: Function) {
|
||||
return !!this.find(metadata => metadata.target === target);
|
||||
}
|
||||
|
||||
findByTarget(target: Function) {
|
||||
return this.find(metadata => metadata.target === target);
|
||||
const metadata = this.find(metadata => metadata.target === target);
|
||||
if (!metadata)
|
||||
throw new EntityMetadataNotFound(target);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
}
|
||||
@ -42,7 +42,7 @@ describe("insertion", function() {
|
||||
function reloadDatabase() {
|
||||
return connection.driver
|
||||
.clearDatabase()
|
||||
.then(() => connection.createSchema())
|
||||
.then(() => connection.syncSchema())
|
||||
.catch(e => console.log("Error during schema re-creation: ", e));
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ describe("one-to-one", function() {
|
||||
function reloadDatabase() {
|
||||
return connection.driver
|
||||
.clearDatabase()
|
||||
.then(() => connection.createSchema());
|
||||
.then(() => connection.syncSchema());
|
||||
}
|
||||
|
||||
let postRepository: Repository<Post>,
|
||||
|
||||
@ -48,7 +48,7 @@ describe("many-to-one", function() {
|
||||
function reloadDatabase() {
|
||||
return connection.driver
|
||||
.clearDatabase()
|
||||
.then(() => connection.createSchema());
|
||||
.then(() => connection.syncSchema());
|
||||
}
|
||||
|
||||
let postRepository: Repository<Post>,
|
||||
|
||||
@ -51,7 +51,7 @@ describe("many-to-many", function() {
|
||||
function reloadDatabase() {
|
||||
return connection.driver
|
||||
.clearDatabase()
|
||||
.then(() => connection.createSchema());
|
||||
.then(() => connection.syncSchema());
|
||||
}
|
||||
|
||||
let postRepository: Repository<Post>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user