refactored connection options, how they are loaded and how connection manager works; implemented loading from multiple configuration sources; implemented including in cli (now can load from env)

This commit is contained in:
Umed Khudoiberdiev 2017-06-09 13:08:43 +05:00
parent 34bbd9a3ad
commit 31c3b70eb2
19 changed files with 429 additions and 524 deletions

View File

@ -33,6 +33,9 @@ Now naming strategy should be registered by passing naming strategy instance dir
* removed `usePool` option from the connection options
* connection options interface has changed and now each platform has its own set of connection options
* `storage` in sqlite options has been renamed to `database`
* env variable names for connection were changed (`TYPEORM_DRIVER_TYPE` has been renamed to `TYPEORM_CONNECTION`, some other renaming).
More env variable names you can find in `ConnectionOptionsEnvReader` class.
* some api changes in `ConnectionManager` and `createConnection` / `createConnections` methods of typeorm main entrypoint
### OTHER API CHANGES
@ -44,6 +47,10 @@ Now naming strategy should be registered by passing naming strategy instance dir
* added `mongodb` support
* entity now can be saved partially within `update` method
* added prefix support to embeddeds
* now embeddeds inside other embeddeds are supported
* now relations are supported inside embeds
* now relations for multiple primary keys are generated properly
* now ormconfig is read from `.env`, `.js`, `.json`, `.yml`, `.xml` formats
### BUG FIXES

View File

@ -1,5 +1,5 @@
import * as fs from "fs";
import {ConnectionOptions} from "../connection/ConnectionOptions";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Generates a new entity.
@ -26,7 +26,7 @@ export class EntityCreateCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -39,15 +39,9 @@ export class EntityCreateCommand {
// if directory is not set then try to open tsconfig and find default path there
if (!directory) {
try {
const connections: ConnectionOptions[] = require(process.cwd() + "/" + argv.config);
if (connections) {
const connection = connections.find(connection => { // todo: need to implement "environment" support in the ormconfig too
return connection.name === argv.connection || ((argv.connection === "default" || !argv.connection) && !connection.name);
});
if (connection && connection.cli) {
directory = connection.cli.entitiesDir;
}
}
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
directory = connectionOptions.cli ? connectionOptions.cli.entitiesDir : undefined;
} catch (err) { }
}

View File

@ -1,5 +1,6 @@
import * as fs from "fs";
import {ConnectionOptions} from "../connection/ConnectionOptions";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Creates a new migration file.
@ -27,7 +28,7 @@ export class MigrationCreateCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -41,15 +42,9 @@ export class MigrationCreateCommand {
// if directory is not set then try to open tsconfig and find default path there
if (!directory) {
try {
const connections: ConnectionOptions[] = require(process.cwd() + "/" + argv.config);
if (connections) {
const connection = connections.find(connection => { // todo: need to implement "environment" support in the ormconfig too
return connection.name === argv.connection || ((argv.connection === "default" || !argv.connection) && !connection.name);
});
if (connection && connection.cli) {
directory = connection.cli.migrationsDir;
}
}
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
directory = connectionOptions.cli ? connectionOptions.cli.migrationsDir : undefined;
} catch (err) { }
}

View File

@ -1,4 +1,5 @@
import {createConnection} from "../index";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Reverts last migration command.
@ -17,7 +18,7 @@ export class MigrationRevertCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -25,9 +26,11 @@ export class MigrationRevertCommand {
async handler(argv: any) {
try {
process.env.SKIP_SCHEMA_CREATION = true;
process.env.SKIP_SUBSCRIBERS_LOADING = true;
const connection = await createConnection(argv.connection, process.cwd() + "/" + argv.config);
process.env.SKIP_SCHEMA_CREATION = true; // todo: maybe simply re-assign connection options?
process.env.SKIP_SUBSCRIBERS_LOADING = true; // todo: maybe simply re-assign connection options?
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
const connection = await createConnection(connectionOptions);
try {
await connection.undoLastMigration();

View File

@ -1,4 +1,5 @@
import {createConnection} from "../index";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Runs migration command.
@ -17,7 +18,7 @@ export class MigrationRunCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -27,7 +28,10 @@ export class MigrationRunCommand {
try {
process.env.SKIP_SCHEMA_CREATION = true;
process.env.SKIP_SUBSCRIBERS_LOADING = true;
const connection = await createConnection(argv.connection, process.cwd() + "/" + argv.config);
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
const connection = await createConnection(connectionOptions);
try {
await connection.runMigrations();

View File

@ -1,5 +1,6 @@
import {createConnection} from "../index";
import {QueryRunner} from "../query-runner/QueryRunner";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Executes an sql query on the given connection.
@ -17,14 +18,17 @@ export class QueryCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
async handler(argv: any) {
process.env.SKIP_SCHEMA_CREATION = true;
const connection = await createConnection(argv.connection, process.cwd() + "/" + argv.config);
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
const connection = await createConnection(connectionOptions);
let queryRunner: QueryRunner|undefined = undefined;
try {
queryRunner = await connection.driver.createQueryRunner();

View File

@ -1,5 +1,6 @@
import {createConnections, createConnection} from "../index";
import {Connection} from "../connection/Connection";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Drops all tables of the database from the given connection.
@ -18,7 +19,7 @@ export class SchemaDropCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -29,12 +30,16 @@ export class SchemaDropCommand {
try {
process.env.LOGGER_CLI_SCHEMA_SYNC = true;
process.env.SKIP_SCHEMA_CREATION = true;
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
if (argv.connection) {
connection = await createConnection(argv.connection, process.cwd() + "/" + argv.config);
const connectionOptions = await connectionOptionsReader.get(argv.connection);
connection = await createConnection(connectionOptions);
await connection.dropDatabase();
} else {
connections = await createConnections();
const connectionOptions = await connectionOptionsReader.all();
connections = await createConnections(connectionOptions);
await Promise.all(connections.map(connection => connection.dropDatabase()));
}

View File

@ -1,5 +1,6 @@
import {createConnections, createConnection} from "../index";
import {Connection} from "../connection/Connection";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Synchronizes database schema with entities.
@ -18,7 +19,7 @@ export class SchemaSyncCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -29,12 +30,16 @@ export class SchemaSyncCommand {
try {
process.env.LOGGER_CLI_SCHEMA_SYNC = true;
process.env.SKIP_SCHEMA_CREATION = true;
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
if (argv.connection) {
connection = await createConnection(argv.connection, process.cwd() + "/" + argv.config);
const connectionOptions = await connectionOptionsReader.get(argv.connection);
connection = await createConnection(connectionOptions); // process.cwd()
await connection.syncSchema(false);
} else {
connections = await createConnections();
const connectionOptions = await connectionOptionsReader.all();
connections = await createConnections(connectionOptions);
await Promise.all(connections.map(connection => connection.syncSchema(false)));
}

View File

@ -1,5 +1,6 @@
import * as fs from "fs";
import {ConnectionOptions} from "../connection/ConnectionOptions";
import {ConnectionOptionsReader} from "../connection/ConnectionOptionsReader";
/**
* Generates a new subscriber.
@ -26,7 +27,7 @@ export class SubscriberCreateCommand {
})
.option("cf", {
alias: "config",
default: "ormconfig.json",
default: "ormconfig",
describe: "Name of the file with connection configuration."
});
}
@ -39,15 +40,9 @@ export class SubscriberCreateCommand {
// if directory is not set then try to open tsconfig and find default path there
if (!directory) {
try {
const connections: ConnectionOptions[] = require(process.cwd() + "/" + argv.config);
if (connections) {
const connection = connections.find(connection => { // todo: need to implement "environment" support in the ormconfig too
return connection.name === argv.connection || ((argv.connection === "default" || !argv.connection) && !connection.name);
});
if (connection && connection.cli) {
directory = connection.cli.subscribersDir;
}
}
const connectionOptionsReader = new ConnectionOptionsReader({ root: process.cwd(), configName: argv.config });
const connectionOptions = await connectionOptionsReader.get(argv.connection);
directory = connectionOptions.cli ? connectionOptions.cli.subscribersDir : undefined;
} catch (err) { }
}

View File

@ -142,10 +142,23 @@ export class Connection {
// set connected status for the current connection
Object.assign(this, { isConnected: true });
// build all metadatas registered in the current connection
try {
// build all metadatas registered in the current connection
this.buildMetadatas();
// if option is set - drop schema once connection is done
if (this.options.dropSchemaOnConnection && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
await this.dropDatabase();
// if option is set - automatically synchronize a schema
if (this.options.autoSchemaSync && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
await this.syncSchema();
// if option is set - automatically synchronize a schema
if (this.options.autoMigrationsRun && !PlatformTools.getEnvVariable("SKIP_MIGRATIONS_RUN"))
await this.runMigrations();
} catch (error) {
// if for some reason build metadata fail (for example validation error during entity metadata check)
@ -300,7 +313,7 @@ export class Connection {
const usedQueryRunnerProvider = queryRunnerProvider || new QueryRunnerProvider(this.driver, true);
const queryRunner = await usedQueryRunnerProvider.provide();
const transactionEntityManager = new EntityManager(this, usedQueryRunnerProvider);
const transactionEntityManager = new EntityManagerFactory().create(this, usedQueryRunnerProvider);
try {
await queryRunner.beginTransaction();
@ -371,7 +384,7 @@ export class Connection {
/**
* Creates a new entity manager with a single opened connection to the database.
* This may be useful if you want to perform all db queries within one connection.
* After finishing with entity manager, don't forget to release it, to release connection back to pool.
* After finishing with entity manager, don't forget to release it (to release database connection back to pool).
*/
createIsolatedManager(queryRunnerProvider?: QueryRunnerProvider): EntityManager {
if (!queryRunnerProvider)
@ -383,7 +396,7 @@ export class Connection {
/**
* Creates a new repository with a single opened connection to the database.
* This may be useful if you want to perform all db queries within one connection.
* After finishing with entity manager, don't forget to release it, to release connection back to pool.
* After finishing with entity manager, don't forget to release it (to release database connection back to pool).
*/
createIsolatedRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, queryRunnerProvider?: QueryRunnerProvider): Repository<Entity> {
if (!queryRunnerProvider)
@ -395,7 +408,7 @@ export class Connection {
/**
* Creates a new specific repository with a single opened connection to the database.
* This may be useful if you want to perform all db queries within one connection.
* After finishing with entity manager, don't forget to release it, to release connection back to pool.
* After finishing with entity manager, don't forget to release it (to release database connection back to pool).
*/
createIsolatedSpecificRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, queryRunnerProvider?: QueryRunnerProvider): SpecificRepository<Entity> {
if (!queryRunnerProvider)
@ -435,7 +448,7 @@ export class Connection {
// -------------------------------------------------------------------------
/**
* Finds entity metadata exist for the given entity class, target name or table name.
* Finds exist entity metadata by the given entity class, target name or table name.
*/
protected findMetadata(target: Function|string): EntityMetadata|undefined {
return this.entityMetadatas.find(metadata => {
@ -449,7 +462,7 @@ export class Connection {
}
/**
* Builds all registered metadatas.
* Builds metadatas for all registered classes inside this connection.
*/
protected buildMetadatas(): void {
@ -457,7 +470,7 @@ export class Connection {
const repositoryFactory = new RepositoryFactory();
const entityMetadataValidator = new EntityMetadataValidator();
// build subscribers if they are not disallowed from high-level (for example they can disallowed from migrations run process)
// create subscribers instances if they are not disallowed from high-level (for example they can disallowed from migrations run process)
if (!PlatformTools.getEnvVariable("SKIP_SUBSCRIBERS_LOADING")) {
const subscribers = connectionMetadataBuilder.buildSubscribers(this.options.subscribers || []);
Object.assign(this, { subscribers: subscribers });

View File

@ -2,12 +2,9 @@ import {Connection} from "./Connection";
import {ConnectionNotFoundError} from "./error/ConnectionNotFoundError";
import {ConnectionOptions} from "./ConnectionOptions";
import {AlreadyHasActiveConnectionError} from "./error/AlreadyHasActiveConnectionError";
import {OrmUtils} from "../util/OrmUtils";
import {CannotDetermineConnectionOptionsError} from "./error/CannotDetermineConnectionOptionsError";
import {PlatformTools} from "../platform/PlatformTools";
/**
* ConnectionManager is used to store and manage all these different connections.
* ConnectionManager is used to store and manage multiple orm connections.
* It also provides useful factory methods to simplify connection creation.
*/
export class ConnectionManager {
@ -19,7 +16,7 @@ export class ConnectionManager {
/**
* List of connections registered in this connection manager.
*/
protected connections: Connection[] = [];
protected readonly connections: Connection[] = [];
// -------------------------------------------------------------------------
// Public Methods
@ -35,7 +32,7 @@ export class ConnectionManager {
/**
* Gets registered connection with the given name.
* If connection name is not given then it will get a default connection.
* Throws exception if connection with the given name was not found.
* Throws error if connection with the given name was not found.
*/
get(name: string = "default"): Connection {
const connection = this.connections.find(connection => connection.name === name);
@ -47,9 +44,7 @@ export class ConnectionManager {
/**
* Creates a new connection based on the given connection options and registers it in the manager.
* You need to manually call #connect method to establish connection.
* Note that dropSchemaOnConnection and autoSchemaSync options of a ConnectionOptions will not work there - use
* createAndConnect method to use them.
* Connection won't be established, you'll need to manually call connect method to establish connection.
*/
create(options: ConnectionOptions): Connection {
@ -57,343 +52,22 @@ export class ConnectionManager {
if (options.driver)
Object.assign(options, options.driver);
// check if such connection is already registered
const existConnection = this.connections.find(connection => connection.name === (options.name || "default"));
if (existConnection) {
// if connection is registered and its not closed then throw an error
if (existConnection.isConnected)
throw new AlreadyHasActiveConnectionError(options.name || "default");
// if its registered but closed then simply remove it from the manager
this.connections.splice(this.connections.indexOf(existConnection), 1);
}
// create a new connection
const connection = new Connection(options);
this.connections.push(connection);
return connection;
}
/**
* Creates a new connection and registers it in the manager.
*
* If connection options were not specified, then it will try to create connection automatically.
*
* First, it will try to find a "default" configuration from ormconfig.json.
* You can also specify a connection name to use from ormconfig.json,
* and you even can specify a path to custom ormconfig.json file.
*
* In the case if options were not specified, and ormconfig.json file also wasn't found,
* it will try to create connection from environment variables.
* There are several environment variables you can set:
*
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
* - TYPEORM_URL - database connection url. Should be a string.
* - TYPEORM_HOST - database host. Should be a string.
* - TYPEORM_PORT - database access port. Should be a number.
* - TYPEORM_USERNAME - database username. Should be a string.
* - TYPEORM_PASSWORD - database user's password. Should be a string.
* - TYPEORM_SID - database's SID. Used only for oracle databases. Should be a string.
* - TYPEORM_STORAGE - database's storage url. Used only for sqlite databases. Should be a string.
* - TYPEORM_USE_POOL - indicates if connection pooling should be enabled. By default its enabled. Should be boolean-like value.
* - TYPEORM_DRIVER_EXTRA - extra options to be passed to the driver. Should be a serialized json string of options.
* - TYPEORM_AUTO_SCHEMA_SYNC - indicates if automatic schema synchronization will be performed on each application run. Should be boolean-like value.
* - TYPEORM_ENTITIES - list of directories containing entities to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_SUBSCRIBERS - list of directories containing subscribers to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_ENTITY_SCHEMAS - list of directories containing entity schemas to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_NAMING_STRATEGIES - list of directories containing custom naming strategies to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_LOGGING_QUERIES - indicates if each executed query must be logged. Should be boolean-like value.
* - TYPEORM_LOGGING_FAILED_QUERIES - indicates if logger should log failed query's error. Should be boolean-like value.
* - TYPEORM_LOGGING_ONLY_FAILED_QUERIES - indicates if only failed queries must be logged. Should be boolean-like value.
*
* TYPEORM_DRIVER_TYPE variable is required. Depend on the driver type some other variables may be required too.
*/
async createAndConnect(): Promise<Connection>;
/**
* Creates connection from the given connection options and registers it in the manager.
*/
async createAndConnect(options: ConnectionOptions): Promise<Connection>;
/**
* Creates connection with the given connection name from the ormconfig.json file and registers it in the manager.
* Optionally you can specify a path to custom ormconfig.json file.
*/
async createAndConnect(connectionNameFromConfig: string, ormConfigPath?: string): Promise<Connection>;
/**
* Creates connection and and registers it in the manager.
*/
async createAndConnect(optionsOrConnectionNameFromConfig?: ConnectionOptions|string, ormConfigPath?: string): Promise<Connection> {
// if connection options are given, then create connection from them
if (optionsOrConnectionNameFromConfig && optionsOrConnectionNameFromConfig instanceof Object)
return this.createAndConnectByConnectionOptions(optionsOrConnectionNameFromConfig as ConnectionOptions);
// if connection name is specified then explicitly try to load connection options from it
if (typeof optionsOrConnectionNameFromConfig === "string")
return this.createFromConfigAndConnect(optionsOrConnectionNameFromConfig || "default", ormConfigPath);
// if nothing is specified then try to silently load config from ormconfig.json
if (this.hasDefaultConfigurationInConfigurationFile())
return this.createFromConfigAndConnect("default");
// if driver type is set in environment variables then try to create connection from env variables
if (this.hasDefaultConfigurationInEnvironmentVariables())
return this.createFromEnvAndConnect();
throw new CannotDetermineConnectionOptionsError();
}
/**
* Creates new connections and registers them in the manager.
*
* If array of connection options were not specified, then it will try to create them automatically
* from ormconfig.json. You can also specify path to your custom ormconfig.json file.
*
* In the case if options were not specified, and ormconfig.json file also wasn't found,
* it will try to create connection from environment variables.
* There are several environment variables you can set:
*
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
* - TYPEORM_URL - database connection url. Should be a string.
* - TYPEORM_HOST - database host. Should be a string.
* - TYPEORM_PORT - database access port. Should be a number.
* - TYPEORM_USERNAME - database username. Should be a string.
* - TYPEORM_PASSWORD - database user's password. Should be a string.
* - TYPEORM_SID - database's SID. Used only for oracle databases. Should be a string.
* - TYPEORM_STORAGE - database's storage url. Used only for sqlite databases. Should be a string.
* - TYPEORM_USE_POOL - indicates if connection pooling should be enabled. By default its enabled. Should be boolean-like value.
* - TYPEORM_DRIVER_EXTRA - extra options to be passed to the driver. Should be a serialized json string of options.
* - TYPEORM_AUTO_SCHEMA_SYNC - indicates if automatic schema synchronization will be performed on each application run. Should be boolean-like value.
* - TYPEORM_ENTITIES - list of directories containing entities to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_SUBSCRIBERS - list of directories containing subscribers to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_ENTITY_SCHEMAS - list of directories containing entity schemas to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_NAMING_STRATEGIES - list of directories containing custom naming strategies to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_LOGGING_QUERIES - indicates if each executed query must be logged. Should be boolean-like value.
* - TYPEORM_LOGGING_FAILED_QUERIES - indicates if logger should log failed query's error. Should be boolean-like value.
* - TYPEORM_LOGGING_ONLY_FAILED_QUERIES - indicates if only failed queries must be logged. Should be boolean-like value.
*
* TYPEORM_DRIVER_TYPE variable is required. Depend on the driver type some other variables may be required too.
*/
async createAndConnectToAll(): Promise<Connection[]>;
/**
* Creates connections from the given connection options and registers them in the manager.
*/
async createAndConnectToAll(options?: ConnectionOptions[]): Promise<Connection[]>;
/**
* Creates connections from the ormconfig.json file.
* Optionally you can specify a path to custom ormconfig.json file.
*/
async createAndConnectToAll(ormConfigPath?: string): Promise<Connection[]>;
/**
* Creates connections and and registers them in the manager.
*/
async createAndConnectToAll(optionsOrOrmConfigFilePath?: ConnectionOptions[]|string): Promise<Connection[]> {
// if connection options are given, then create connection from them
if (optionsOrOrmConfigFilePath && optionsOrOrmConfigFilePath instanceof Array)
return Promise.all(optionsOrOrmConfigFilePath.map(options => {
return this.createAndConnectByConnectionOptions(options as ConnectionOptions);
}));
// if connection name is specified then explicitly try to load connection options from it
if (typeof optionsOrOrmConfigFilePath === "string")
return this.createFromConfigAndConnectToAll(optionsOrOrmConfigFilePath as string);
// if nothing is specified then try to silently load config from ormconfig.json
if (this.hasOrmConfigurationFile())
return this.createFromConfigAndConnectToAll();
// if driver type is set in environment variables then try to create connection from env variables
if (this.hasDefaultConfigurationInEnvironmentVariables())
return [await this.createFromEnvAndConnect()];
throw new CannotDetermineConnectionOptionsError();
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* Checks if ormconfig.json exists.
*/
protected hasOrmConfigurationFile(): boolean {
const path = PlatformTools.load("app-root-path").path + "/ormconfig.json";
if (!PlatformTools.fileExist(path))
return false;
const configuration: ConnectionOptions[]|ConnectionOptions = PlatformTools.load(path);
if (configuration instanceof Array) {
return configuration
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV"))
.length > 0;
} else if (configuration instanceof Object) {
if (configuration.environment && configuration.environment !== PlatformTools.getEnvVariable("NODE_ENV"))
return false;
return Object.keys(configuration).length > 0;
}
return false;
}
/**
* Checks if there is a default connection in the ormconfig.json file.
*/
protected hasDefaultConfigurationInConfigurationFile(): boolean {
const path = PlatformTools.load("app-root-path").path + "/ormconfig.json";
if (!PlatformTools.fileExist(path))
return false;
const configuration: ConnectionOptions[]|ConnectionOptions = PlatformTools.load(path);
if (configuration instanceof Array) {
return !!configuration
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV"))
.find(config => !!config.name || config.name === "default");
} else if (configuration instanceof Object) {
if (!configuration.name ||
configuration.name !== "default")
return false;
if (configuration.environment && configuration.environment !== PlatformTools.getEnvVariable("NODE_ENV"))
return false;
return true;
}
return false;
}
/**
* Checks if environment variables contains connection options.
*/
protected hasDefaultConfigurationInEnvironmentVariables(): boolean {
return !!PlatformTools.getEnvVariable("TYPEORM_DRIVER_TYPE");
}
/**
* Allows to quickly create a connection based on the environment variable values.
*/
protected async createFromEnvAndConnect(): Promise<Connection> {
return this.createAndConnectByConnectionOptions({
type: PlatformTools.getEnvVariable("TYPEORM_DRIVER_TYPE"),
url: PlatformTools.getEnvVariable("TYPEORM_URL"),
host: PlatformTools.getEnvVariable("TYPEORM_HOST"),
port: PlatformTools.getEnvVariable("TYPEORM_PORT"),
username: PlatformTools.getEnvVariable("TYPEORM_USERNAME"),
password: PlatformTools.getEnvVariable("TYPEORM_PASSWORD"),
database: PlatformTools.getEnvVariable("TYPEORM_DATABASE"),
sid: PlatformTools.getEnvVariable("TYPEORM_SID"),
extra: PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA") ? JSON.parse(PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA")) : undefined,
autoSchemaSync: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_AUTO_SCHEMA_SYNC")),
entities: PlatformTools.getEnvVariable("TYPEORM_ENTITIES") ? PlatformTools.getEnvVariable("TYPEORM_ENTITIES").split(",") : [],
subscribers: PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS") ? PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS").split(",") : [],
entitySchemas: PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS") ? PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS").split(",") : [],
logging: {
logQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_QUERIES")),
logFailedQueryError: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_FAILED_QUERIES")),
logOnlyFailedQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_ONLY_FAILED_QUERIES")),
}
});
}
/**
* Creates a new connection based on the connection options from "ormconfig.json"
* and registers a new connection in the manager.
* Optionally you can specify a path to the json configuration.
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
*/
protected async createFromConfigAndConnectToAll(path?: string): Promise<Connection[]> {
let optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
if (!(optionsArray instanceof Array)) optionsArray = [optionsArray]; // cast options to array if ormconfig contains a single connection options object
if (!optionsArray)
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);
const promises = optionsArray
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV")) // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
.map(options => this.createAndConnectByConnectionOptions(options));
return Promise.all(promises);
}
/**
* Creates a new connection based on the connection options from "ormconfig.json"
* and registers a new connection in the manager.
* Optionally you can specify a path to the json configuration.
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
*/
protected async createFromConfigAndConnect(connectionName: string, path?: string): Promise<Connection> {
let optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
if (!(optionsArray instanceof Array)) optionsArray = [optionsArray]; // cast options to array if ormconfig contains a single connection options object
if (!optionsArray)
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);
const environmentLessOptions = optionsArray.filter(options => (options.name || "default") === connectionName);
const options = environmentLessOptions.find(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV")); // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
if (!options)
throw new Error(`Connection "${connectionName}" ${PlatformTools.getEnvVariable("NODE_ENV") ? "for the environment " + PlatformTools.getEnvVariable("NODE_ENV") + " " : ""}was not found in the json configuration file.` +
(environmentLessOptions.length ? ` However there are such configurations for other environments: ${environmentLessOptions.map(options => options.environment).join(", ")}.` : ""));
let connectionOptions: ConnectionOptions = Object.assign({}, options);
// normalize directory paths
if (options.entities) {
const entities = (options.entities as any[]).map(entity => {
if (typeof entity === "string" || entity.substr(0, 1) !== "/")
return PlatformTools.load("app-root-path").path + "/" + entity;
return entity;
});
Object.assign(connectionOptions, { entities: entities });
}
if (options.subscribers) {
const subscribers = (options.subscribers as any[]).map(subscriber => {
if (typeof subscriber === "string" || subscriber.substr(0, 1) !== "/")
return PlatformTools.load("app-root-path").path + "/" + subscriber;
return subscriber;
});
Object.assign(connectionOptions, { subscribers: subscribers });
}
if (options.migrations) {
const migrations = (options.migrations as any[]).map(migration => {
if (typeof migration === "string" || migration.substr(0, 1) !== "/")
return PlatformTools.load("app-root-path").path + "/" + migration;
return migration;
});
Object.assign(connectionOptions, { migrations: migrations });
}
return this.createAndConnectByConnectionOptions(options);
}
/**
* Creates a new connection based on the given connection options and registers a new connection in the manager.
*/
protected async createAndConnectByConnectionOptions(options: ConnectionOptions): Promise<Connection> {
const connection = this.create(options);
// connect to the database
await connection.connect();
// if option is set - drop schema once connection is done
if (options.dropSchemaOnConnection && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
await connection.dropDatabase();
// if option is set - automatically synchronize a schema
if (options.autoSchemaSync && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
await connection.syncSchema();
// if option is set - automatically synchronize a schema
if (options.autoMigrationsRun && !PlatformTools.getEnvVariable("SKIP_MIGRATIONS_RUN"))
await connection.runMigrations();
return connection;
}
}

View File

@ -10,6 +10,9 @@ import {EntitySchema} from "../entity-schema/EntitySchema";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {EntitySubscriberInterface} from "../subscriber/EntitySubscriberInterface";
/**
* Builds migration instances, subscriber instances and entity metadatas for the given classes.
*/
export class ConnectionMetadataBuilder {
// -------------------------------------------------------------------------
@ -23,12 +26,18 @@ export class ConnectionMetadataBuilder {
// Public Methods
// -------------------------------------------------------------------------
/**
* Builds migration instances for the given classes or directories.
*/
buildMigrations(migrations: Function[]|string[]): MigrationInterface[] {
const [migrationClasses, migrationDirectories] = OrmUtils.splitClassesAndStrings(migrations);
const allMigrationClasses = [...migrationClasses, ...importClassesFromDirectories(migrationDirectories)];
return allMigrationClasses.map(migrationClass => getFromContainer<MigrationInterface>(migrationClass));
}
/**
* Builds subscriber instances for the given classes or directories.
*/
buildSubscribers(subscribers: Function[]|string[]): EntitySubscriberInterface<any>[] {
const [subscriberClasses, subscriberDirectories] = OrmUtils.splitClassesAndStrings(subscribers || []);
const allSubscriberClasses = [...subscriberClasses, ...importClassesFromDirectories(subscriberDirectories)];
@ -37,6 +46,9 @@ export class ConnectionMetadataBuilder {
.map(metadata => getFromContainer<EntitySubscriberInterface<any>>(metadata.target));
}
/**
* Builds entity metadatas for the given classes or directories.
*/
buildEntityMetadatas(entities: Function[]|string[], schemas: EntitySchema[]|string[]): EntityMetadata[] {
const [entityClasses, entityDirectories] = OrmUtils.splitClassesAndStrings(entities || []);
const allEntityClasses = [...entityClasses, ...importClassesFromDirectories(entityDirectories)];

View File

@ -11,7 +11,8 @@ import {MongoConnectionOptions} from "../driver/mongodb/MongoConnectionOptions";
* Options contain database and other connection-related settings.
* Consumer must provide connection options for each of your connections.
*/
export type ConnectionOptions = MysqlConnectionOptions|
export type ConnectionOptions =
MysqlConnectionOptions|
PostgresConnectionOptions|
SqliteConnectionOptions|
SqlServerConnectionOptions|

View File

@ -0,0 +1,173 @@
import {ConnectionOptions} from "./ConnectionOptions";
import {PlatformTools} from "../platform/PlatformTools";
import {ConnectionOptionsEnvReader} from "./options-reader/ConnectionOptionsEnvReader";
import {ConnectionOptionsYmlReader} from "./options-reader/ConnectionOptionsYmlReader";
import {ConnectionOptionsXmlReader} from "./options-reader/ConnectionOptionsXmlReader";
/**
* Reads connection options from the ormconfig.
* Can read from multiple file extensions including env, json, js, xml and yml.
*/
export class ConnectionOptionsReader {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(protected options?: {
/**
* Directory where ormconfig should be read from.
* By default its your application root (where your app package.json is located).
*/
root?: string,
/**
* Filename of the ormconfig configuration. By default its equal to "ormconfig".
*/
configName?: string
}) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Returns all connection options read from the ormconfig.
*/
async all(): Promise<ConnectionOptions[]> {
return this.load();
}
/**
* Gets a connection with a given name read from ormconfig.
* If connection with such name would not be found then it throw error.
*/
async get(name: string): Promise<ConnectionOptions> {
const allOptions = await this.all();
const targetOptions = allOptions.find(options => options.name === name || (name === "default" && !options.name));
if (!targetOptions)
throw new Error(`Cannot find connection ${name} because its not defined in any orm configuration files.`);
return targetOptions;
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* Loads all connection options from a configuration file.
*
* todo: get in count NODE_ENV somehow
*/
protected async load(): Promise<ConnectionOptions[]> {
// try to find any of following configuration formats
const foundFileFormat = ["env", "js", "json", "yml", "yaml", "xml"].find(format => {
return PlatformTools.fileExist(this.baseFilePath + "." + format);
});
// if .env file found then load all its variables into process.env using dotenv package
if (foundFileFormat === "env") {
const dotenv = PlatformTools.load("dotenv");
dotenv.config({ path: this.baseFilePath + ".env" });
}
// try to find connection options from any of available sources of configuration
let connectionOptions: ConnectionOptions|ConnectionOptions[];
if (PlatformTools.getEnvVariable("TYPEORM_CONNECTION")) {
connectionOptions = new ConnectionOptionsEnvReader().read();
} else if (foundFileFormat === "js") {
connectionOptions = PlatformTools.load(this.baseFilePath + ".js");
} else if (foundFileFormat === "json") {
connectionOptions = PlatformTools.load(this.baseFilePath + ".json");
} else if (foundFileFormat === "yml") {
connectionOptions = new ConnectionOptionsYmlReader().read(this.baseFilePath + ".yml");
} else if (foundFileFormat === "yaml") {
connectionOptions = new ConnectionOptionsYmlReader().read(this.baseFilePath + ".yaml");
} else if (foundFileFormat === "xml") {
connectionOptions = await new ConnectionOptionsXmlReader().read(this.baseFilePath + ".xml");
} else {
throw new Error(`No connection options were found in any of configurations file.`);
}
// normalize and return connection options
return this.normalizeConnectionOptions(connectionOptions);
}
/**
* Normalize connection options.
*/
protected normalizeConnectionOptions(connectionOptions: ConnectionOptions|ConnectionOptions[]): ConnectionOptions[] {
if (!(connectionOptions instanceof Array))
connectionOptions = [connectionOptions];
connectionOptions.forEach(options => {
if (options.entities) {
const entities = (options.entities as any[]).map(entity => {
if (typeof entity === "string" || entity.substr(0, 1) !== "/")
return this.baseFilePath + "/" + entity;
return entity;
});
Object.assign(connectionOptions, { entities: entities });
}
if (options.subscribers) {
const subscribers = (options.subscribers as any[]).map(subscriber => {
if (typeof subscriber === "string" || subscriber.substr(0, 1) !== "/")
return this.baseFilePath + "/" + subscriber;
return subscriber;
});
Object.assign(connectionOptions, { subscribers: subscribers });
}
if (options.migrations) {
const migrations = (options.migrations as any[]).map(migration => {
if (typeof migration === "string" || migration.substr(0, 1) !== "/")
return this.baseFilePath + "/" + migration;
return migration;
});
Object.assign(connectionOptions, { migrations: migrations });
}
});
return connectionOptions;
}
/**
* Gets directory where configuration file should be located and configuration file name without extension.
*/
protected get baseFilePath(): string {
return this.baseDirectory + "/" + this.baseConfigName;
}
/**
* Gets directory where configuration file should be located.
*/
protected get baseDirectory(): string {
if (this.options && this.options.root)
return this.options.root;
return PlatformTools.load("app-root-path").path;
}
/**
* Gets configuration file name.
*/
protected get baseConfigName(): string {
if (this.options && this.options.configName)
return this.options.configName;
return "ormconfig";
}
}

View File

@ -0,0 +1,42 @@
import {ConnectionOptions} from "../ConnectionOptions";
import {PlatformTools} from "../../platform/PlatformTools";
import {OrmUtils} from "../../util/OrmUtils";
/**
* Reads connection options from environment variables.
* Environment variables can have only a single connection.
* Its strongly required to define TYPEORM_CONNECTION env variable.
*/
export class ConnectionOptionsEnvReader {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Reads connection options from environment variables.
*/
read(): ConnectionOptions {
return {
type: PlatformTools.getEnvVariable("TYPEORM_CONNECTION"),
url: PlatformTools.getEnvVariable("TYPEORM_URL"),
host: PlatformTools.getEnvVariable("TYPEORM_HOST"),
port: PlatformTools.getEnvVariable("TYPEORM_PORT"),
username: PlatformTools.getEnvVariable("TYPEORM_USERNAME"),
password: PlatformTools.getEnvVariable("TYPEORM_PASSWORD"),
database: PlatformTools.getEnvVariable("TYPEORM_DATABASE"),
sid: PlatformTools.getEnvVariable("TYPEORM_SID"),
extra: PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA") ? JSON.parse(PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA")) : undefined,
autoSchemaSync: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_AUTO_SCHEMA_SYNC")),
entities: PlatformTools.getEnvVariable("TYPEORM_ENTITIES") ? PlatformTools.getEnvVariable("TYPEORM_ENTITIES").split(",") : [],
subscribers: PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS") ? PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS").split(",") : [],
entitySchemas: PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS") ? PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS").split(",") : [],
logging: {
logQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_QUERIES")),
logFailedQueryError: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_FAILED_QUERIES")),
logOnlyFailedQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_ONLY_FAILED_QUERIES")),
}
};
}
}

View File

@ -0,0 +1,59 @@
import * as fs from "fs";
import {PlatformTools} from "../../platform/PlatformTools";
import {ConnectionOptions} from "../ConnectionOptions";
/**
* Reads connection options defined in the xml file.
*/
export class ConnectionOptionsXmlReader {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Reads connection options from given xml file.
*/
async read(path: string): Promise<ConnectionOptions[]> {
const xml = await this.readXml(path);
return (xml.connection as any[]).map(connection => {
return {
name: connection.$.name,
type: connection.$.type,
url: connection.url ? connection.url[0] : undefined,
host: connection.host ? connection.host[0] : undefined,
port: connection.port && connection.port[0] ? parseInt(connection.port[0]) : undefined,
username: connection.username ? connection.username[0] : undefined,
password: connection.password ? connection.password[0] : undefined,
database: connection.database ? connection.database[0] : undefined,
sid: connection.sid ? connection.sid[0] : undefined,
extra: connection.extra ? connection.extra[0] : undefined,
autoSchemaSync: connection.autoSchemaSync ? connection.autoSchemaSync[0] : undefined,
entities: connection.entities ? connection.entities[0].entity : [],
subscribers: connection.subscribers ? connection.subscribers[0].entity : [],
entitySchemas: connection.entitySchemas ? connection.entitySchemas[0].entity : [],
logging: {
logQueries: connection.logging && connection.logging[0].logQueries ? connection.logging[0].logQueries[0] : undefined,
logFailedQueryError: connection.logging && connection.logging[0].logFailedQueryError ? connection.logging[0].logFailedQueryError[0] : undefined,
logOnlyFailedQueries: connection.logging && connection.logging[0].logOnlyFailedQueries ? connection.logging[0].logOnlyFailedQueries[0] : undefined,
}
};
});
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* Reads xml file contents and returns them in a promise.
*/
protected readXml(path: string): Promise<any> {
const xmlParser = PlatformTools.load("xml2js").parseString;
const xmlOptions = { trim: true, explicitRoot: false };
return new Promise((ok, fail) => {
xmlParser(fs.readFileSync(path), xmlOptions, (err: any, result: any) => err ? fail(err) : ok(result));
});
}
}

View File

@ -0,0 +1,25 @@
import * as fs from "fs";
import {PlatformTools} from "../../platform/PlatformTools";
import {ConnectionOptions} from "../ConnectionOptions";
/**
* Reads connection options defined in the yml file.
*/
export class ConnectionOptionsYmlReader {
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
/**
* Reads connection options from given yml file.
*/
read(path: string): ConnectionOptions[] {
const ymlParser = PlatformTools.load("js-yaml");
const config = ymlParser.safeLoad(fs.readFileSync(path));
return Object.keys(config).map(connectionName => {
return Object.assign({ name: connectionName }, config[connectionName]);
});
}
}

View File

@ -12,6 +12,7 @@ import {EntityManager} from "./entity-manager/EntityManager";
import {PlatformTools} from "./platform/PlatformTools";
import {TreeRepository} from "./repository/TreeRepository";
import {MongoRepository} from "./repository/MongoRepository";
import {ConnectionOptionsReader} from "./connection/ConnectionOptionsReader";
// -------------------------------------------------------------------------
// Commonly Used exports
@ -135,106 +136,29 @@ export function getConnectionManager(): ConnectionManager {
/**
* Creates a new connection and registers it in the manager.
*
* If connection options were not specified, then it will try to create connection automatically.
*
* First, it will try to find a "default" configuration from ormconfig.json.
* You can also specify a connection name to use from ormconfig.json,
* and you even can specify a path to your custom ormconfig.json.
*
* In the case if options were not specified, and ormconfig.json file also wasn't found,
* it will try to create connection from environment variables.
* There are several environment variables you can set:
*
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
* - TYPEORM_URL - database connection url. Should be a string.
* - TYPEORM_HOST - database host. Should be a string.
* - TYPEORM_PORT - database access port. Should be a number.
* - TYPEORM_USERNAME - database username. Should be a string.
* - TYPEORM_PASSWORD - database user's password. Should be a string.
* - TYPEORM_SID - database's SID. Used only for oracle databases. Should be a string.
* - TYPEORM_STORAGE - database's storage url. Used only for sqlite databases. Should be a string.
* - TYPEORM_USE_POOL - indicates if connection pooling should be enabled. By default its enabled. Should be boolean-like value.
* - TYPEORM_DRIVER_EXTRA - extra options to be passed to the driver. Should be a serialized json string of options.
* - TYPEORM_AUTO_SCHEMA_SYNC - indicates if automatic schema synchronization will be performed on each application run. Should be boolean-like value.
* - TYPEORM_ENTITIES - list of directories containing entities to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_SUBSCRIBERS - list of directories containing subscribers to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_ENTITY_SCHEMAS - list of directories containing entity schemas to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_NAMING_STRATEGIES - list of directories containing custom naming strategies to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_LOGGING_QUERIES - indicates if each executed query must be logged. Should be boolean-like value.
* - TYPEORM_LOGGING_FAILED_QUERIES - indicates if logger should log failed query's error. Should be boolean-like value.
* - TYPEORM_LOGGING_ONLY_FAILED_QUERIES - indicates if only failed queries must be logged. Should be boolean-like value.
*
* TYPEORM_DRIVER_TYPE variable is required. Depend on the driver type some other variables may be required too.
* If connection options were not specified, then it will try to create connection automatically,
* based on content of ormconfig (json/js/yml/xml/env) file or environment variables.
* Only one connection from ormconfig will be created (name "default" or connection without name).
*/
export function createConnection(): Promise<Connection>;
export async function createConnection(options?: ConnectionOptions): Promise<Connection> {
if (!options)
options = await new ConnectionOptionsReader().get("default");
/**
* Creates connection from the given connection options and registers it in the manager.
*/
export function createConnection(options?: ConnectionOptions): Promise<Connection>;
/**
* Creates connection with the given connection name from the ormconfig.json file and registers it in the manager.
* Optionally you can specify a path to custom ormconfig.json file.
*/
export function createConnection(connectionNameFromConfig: string, ormConfigPath?: string): Promise<Connection>;
/**
* Creates connection and and registers it in the manager.
*/
export function createConnection(optionsOrConnectionNameFromConfig?: ConnectionOptions|string, ormConfigPath?: string): Promise<Connection> {
return getConnectionManager().createAndConnect(optionsOrConnectionNameFromConfig as any, ormConfigPath);
return getConnectionManager().create(options).connect();
}
/**
* Creates new connections and registers them in the manager.
*
* If array of connection options were not specified, then it will try to create them automatically
* from ormconfig.json. You can also specify path to your custom ormconfig.json.
*
* In the case if options were not specified, and ormconfig.json file also wasn't found,
* it will try to create connection from environment variables.
* There are several environment variables you can set:
*
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
* - TYPEORM_URL - database connection url. Should be a string.
* - TYPEORM_HOST - database host. Should be a string.
* - TYPEORM_PORT - database access port. Should be a number.
* - TYPEORM_USERNAME - database username. Should be a string.
* - TYPEORM_PASSWORD - database user's password. Should be a string.
* - TYPEORM_SID - database's SID. Used only for oracle databases. Should be a string.
* - TYPEORM_STORAGE - database's storage url. Used only for sqlite databases. Should be a string.
* - TYPEORM_USE_POOL - indicates if connection pooling should be enabled. By default its enabled. Should be boolean-like value.
* - TYPEORM_DRIVER_EXTRA - extra options to be passed to the driver. Should be a serialized json string of options.
* - TYPEORM_AUTO_SCHEMA_SYNC - indicates if automatic schema synchronization will be performed on each application run. Should be boolean-like value.
* - TYPEORM_ENTITIES - list of directories containing entities to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_SUBSCRIBERS - list of directories containing subscribers to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_ENTITY_SCHEMAS - list of directories containing entity schemas to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_NAMING_STRATEGIES - list of directories containing custom naming strategies to load. Should be string - directory names (can be patterns) split by a comma.
* - TYPEORM_LOGGING_QUERIES - indicates if each executed query must be logged. Should be boolean-like value.
* - TYPEORM_LOGGING_FAILED_QUERIES - indicates if logger should log failed query's error. Should be boolean-like value.
* - TYPEORM_LOGGING_ONLY_FAILED_QUERIES - indicates if only failed queries must be logged. Should be boolean-like value.
*
* TYPEORM_DRIVER_TYPE variable is required. Depend on the driver type some other variables may be required too.
* If connection options were not specified, then it will try to create connection automatically,
* based on content of ormconfig (json/js/yml/xml/env) file or environment variables.
* All connections from the ormconfig will be created.
*/
export function createConnections(): Promise<Connection[]>;
export async function createConnections(options?: ConnectionOptions[]): Promise<Connection[]> {
if (!options)
options = await new ConnectionOptionsReader().all();
/**
* Creates connections from the given connection options and registers them in the manager.
*/
export function createConnections(options?: ConnectionOptions[]): Promise<Connection[]>;
/**
* Creates connection with the given connection name from the ormconfig.json file and registers it in the manager.
* Optionally you can specify a path to custom ormconfig.json file.
*/
export function createConnections(ormConfigPath?: string): Promise<Connection[]>;
/**
* Creates connections and and registers them in the manager.
*/
export function createConnections(optionsOrOrmConfigFilePath?: ConnectionOptions[]|string): Promise<Connection[]> {
return getConnectionManager().createAndConnectToAll(optionsOrOrmConfigFilePath as any);
return Promise.all(options.map(options => getConnectionManager().create(options).connect()));
}
/**
@ -256,50 +180,20 @@ export function getEntityManager(connectionName: string = "default"): EntityMana
/**
* Gets repository for the given entity class.
*/
export function getRepository<Entity>(entityClass: ObjectType<Entity>, connectionName?: string): Repository<Entity>;
/**
* Gets repository for the given entity name.
*/
export function getRepository<Entity>(entityName: string, connectionName?: string): Repository<Entity>;
/**
* Gets repository for the given entity class or name.
*/
export function getRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, connectionName: string = "default"): Repository<Entity> {
return getConnectionManager().get(connectionName).getRepository<Entity>(entityClassOrName as any);
export function getRepository<Entity>(entityClass: ObjectType<Entity>|string, connectionName: string = "default"): Repository<Entity> {
return getConnectionManager().get(connectionName).getRepository<Entity>(entityClass);
}
/**
* Gets tree repository for the given entity class.
*/
export function getTreeRepository<Entity>(entityClass: ObjectType<Entity>, connectionName?: string): TreeRepository<Entity>;
/**
* Gets tree repository for the given entity name.
*/
export function getTreeRepository<Entity>(entityName: string, connectionName?: string): TreeRepository<Entity>;
/**
* Gets tree repository for the given entity class or name.
*/
export function getTreeRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, connectionName: string = "default"): TreeRepository<Entity> {
return getConnectionManager().get(connectionName).getTreeRepository<Entity>(entityClassOrName as any);
export function getTreeRepository<Entity>(entityClass: ObjectType<Entity>|string, connectionName: string = "default"): TreeRepository<Entity> {
return getConnectionManager().get(connectionName).getTreeRepository<Entity>(entityClass);
}
/**
* Gets mongodb repository for the given entity class.
*/
export function getMongoRepository<Entity>(entityClass: ObjectType<Entity>, connectionName?: string): MongoRepository<Entity>;
/**
* Gets mongodb repository for the given entity name.
*/
export function getMongoRepository<Entity>(entityName: string, connectionName?: string): MongoRepository<Entity>;
/**
* Gets mongodb repository for the given entity class or name.
*/
export function getMongoRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, connectionName: string = "default"): MongoRepository<Entity> {
return getConnectionManager().get(connectionName).getMongoRepository<Entity>(entityClassOrName as any);
export function getMongoRepository<Entity>(entityClass: ObjectType<Entity>|string, connectionName: string = "default"): MongoRepository<Entity> {
return getConnectionManager().get(connectionName).getMongoRepository<Entity>(entityClass);
}

View File

@ -54,7 +54,7 @@ describe("ConnectionManager", () => {
});
describe("createAndConnect", function() {
/*describe("createAndConnect", function() {
it("should create a mysql connection when mysql driver is specified AND connect to it", async () => {
const options: ConnectionOptions = setupSingleTestingConnection("mysql", {
@ -69,7 +69,7 @@ describe("ConnectionManager", () => {
await connection.close();
});
/* it("should create a postgres connection when postgres driver is specified AND connect to it", async () => {
/!* it("should create a postgres connection when postgres driver is specified AND connect to it", async () => {
const options: ConnectionOptions = {
name: "myPostgresConnection",
driver: createTestingConnectionOptions("postgres")
@ -80,9 +80,9 @@ describe("ConnectionManager", () => {
connection.driver.should.be.instanceOf(PostgresDriver);
connection.isConnected.should.be.true;
await connection.close();
});*/
});*!/
});
});*/
describe("get", function() {
@ -121,13 +121,13 @@ describe("ConnectionManager", () => {
const connectionManager = new ConnectionManager();
// create connection, save post and close connection
let connection = await connectionManager.createAndConnect(options);
let connection = await connectionManager.create(options).connect();
const post = new Post(1, "Hello post");
await connection.manager.save(post);
await connection.close();
// recreate connection and find previously saved post
connection = await connectionManager.createAndConnect(options);
connection = await connectionManager.create(options).connect();
const loadedPost = (await connection.manager.findOneById(Post, 1))!;
loadedPost.should.be.instanceof(Post);
loadedPost.should.be.eql({ id: 1, title: "Hello post" });
@ -144,13 +144,13 @@ describe("ConnectionManager", () => {
const connectionManager = new ConnectionManager();
// create connection, save post and close connection
let connection = await connectionManager.createAndConnect(options);
let connection = await connectionManager.create(options).connect();
const post = new Post(1, "Hello post");
await connection.manager.save(post);
await connection.close();
// recreate connection and find previously saved post
connection = await connectionManager.createAndConnect(options);
connection = await connectionManager.create(options).connect();
const loadedPost = await connection.manager.findOneById(Post, 1);
expect(loadedPost).to.be.undefined;
await connection.close();