connection refactoring

This commit is contained in:
Umed Khudoiberdiev 2017-06-08 18:28:55 +05:00
parent edc6a31b57
commit df31b4a38a
30 changed files with 525 additions and 606 deletions

View File

@ -4,23 +4,14 @@ import {EntitySubscriberInterface} from "../subscriber/EntitySubscriberInterface
import {RepositoryNotFoundError} from "./error/RepositoryNotFoundError";
import {ObjectType} from "../common/ObjectType";
import {EntityManager} from "../entity-manager/EntityManager";
import {importClassesFromDirectories, importJsonsFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {getFromContainer, getMetadataArgsStorage} from "../index";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {DefaultNamingStrategy} from "../naming-strategy/DefaultNamingStrategy";
import {CannotImportAlreadyConnectedError} from "./error/CannotImportAlreadyConnectedError";
import {CannotCloseNotConnectedError} from "./error/CannotCloseNotConnectedError";
import {CannotConnectAlreadyConnectedError} from "./error/CannotConnectAlreadyConnectedError";
import {TreeRepository} from "../repository/TreeRepository";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {RepositoryNotTreeError} from "./error/RepositoryNotTreeError";
import {EntitySchema} from "../entity-schema/EntitySchema";
import {CannotSyncNotConnectedError} from "./error/CannotSyncNotConnectedError";
import {CannotUseNamingStrategyNotConnectedError} from "./error/CannotUseNamingStrategyNotConnectedError";
import {Broadcaster} from "../subscriber/Broadcaster";
import {LazyRelationsWrapper} from "../lazy-loading/LazyRelationsWrapper";
import {SpecificRepository} from "../repository/SpecificRepository";
import {RepositoryAggregator} from "../repository/RepositoryAggregator";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
import {Logger} from "../logger/Logger";
@ -33,21 +24,15 @@ import {PlatformTools} from "../platform/PlatformTools";
import {MongoRepository} from "../repository/MongoRepository";
import {MongoDriver} from "../driver/mongodb/MongoDriver";
import {MongoEntityManager} from "../entity-manager/MongoEntityManager";
import {EntitySchemaTransformer} from "../entity-schema/EntitySchemaTransformer";
import {EntityMetadataValidator} from "../metadata-builder/EntityMetadataValidator";
import {ConnectionOptions} from "./ConnectionOptions";
import {MysqlDriver} from "../driver/mysql/MysqlDriver";
import {PostgresDriver} from "../driver/postgres/PostgresDriver";
import {SqliteDriver} from "../driver/sqlite/SqliteDriver";
import {OracleDriver} from "../driver/oracle/OracleDriver";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
import {WebsqlDriver} from "../driver/websql/WebsqlDriver";
import {MissingDriverError} from "../driver/error/MissingDriverError";
import {OrmUtils} from "../util/OrmUtils";
import {QueryRunnerProviderAlreadyReleasedError} from "../query-runner/error/QueryRunnerProviderAlreadyReleasedError";
import {QueryBuilder} from "../query-builder/QueryBuilder";
import {DriverFactory} from "../driver/DriverFactory";
import {EntityManagerFactory} from "../entity-manager/EntityManagerFactory";
import {LoggerFactory} from "../logger/LoggerFactory";
import {RepositoryFactory} from "../repository/RepositoryFactory";
import {DriverFactory} from "../driver/DriverFactory";
import {ConnectionMetadataBuilder} from "./ConnectionMetadataBuilder";
/**
* Connection is a single database ORM connection to a specific DBMS database.
@ -105,19 +90,10 @@ export class Connection {
*/
readonly subscribers: EntitySubscriberInterface<any>[] = [];
// -------------------------------------------------------------------------
// Private Properties
// -------------------------------------------------------------------------
/**
* Stores all registered repositories.
*/
private repositoryAggregators: RepositoryAggregator[] = [];
/**
* All entity metadatas that are registered for this connection.
*/
private entityMetadatas: EntityMetadata[] = [];
readonly entityMetadatas: EntityMetadata[] = [];
// -------------------------------------------------------------------------
// Constructor
@ -126,14 +102,14 @@ export class Connection {
constructor(options: ConnectionOptions) {
this.name = options.name || "default";
this.options = options;
this.logger = new Logger(options.logging || {});
this.logger = this.createLogger();
this.driver = this.createDriver();
this.manager = this.createEntityManager();
this.namingStrategy = options.namingStrategy || new DefaultNamingStrategy();
this.driver = new DriverFactory().create(this);
this.manager = new EntityManagerFactory().create(this);
}
// -------------------------------------------------------------------------
// Accessors
// Public Accessors
// -------------------------------------------------------------------------
/**
@ -255,18 +231,6 @@ export class Connection {
await migrationExecutor.undoLastMigration();
}
/**
* 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.
*/
createIsolatedManager(queryRunnerProvider?: QueryRunnerProvider): EntityManager {
if (!queryRunnerProvider)
queryRunnerProvider = new QueryRunnerProvider(this.driver, true);
return new EntityManager(this, queryRunnerProvider);
}
/**
* Checks if entity metadata exist for the given entity class.
*/
@ -348,40 +312,40 @@ export class Connection {
* Gets repository for the given entity class or name.
*/
getRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): Repository<Entity> {
return this.findRepositoryAggregator(entityClassOrName).repository;
return this.getMetadata(entityClassOrName).repository;
}
/**
* Gets tree repository for the given entity class.
* Only tree-type entities can have a TreeRepository,
* like ones decorated with @ClosureEntity decorator.
* Only tree-type entities can have a TreeRepository, like ones decorated with @ClosureEntity decorator.
*/
getTreeRepository<Entity>(entityClass: ObjectType<Entity>): TreeRepository<Entity>;
/**
* Gets tree repository for the given entity class.
* Only tree-type entities can have a TreeRepository,
* like ones decorated with @ClosureEntity decorator.
* Only tree-type entities can have a TreeRepository, like ones decorated with @ClosureEntity decorator.
*/
getTreeRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): TreeRepository<Entity>;
/**
* Gets tree repository for the given entity class.
* Only tree-type entities can have a TreeRepository,
* like ones decorated with @ClosureEntity decorator.
* Only tree-type entities can have a TreeRepository, like ones decorated with @ClosureEntity decorator.
*/
getTreeRepository<Entity>(entityName: string): TreeRepository<Entity>;
/**
* Gets tree repository for the given entity class or name.
* Only tree-type entities can have a TreeRepository,
* like ones decorated with @ClosureEntity decorator.
* Only tree-type entities can have a TreeRepository, like ones decorated with @ClosureEntity decorator.
*/
getTreeRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): TreeRepository<Entity> {
// todo: add checks if tree repository is supported by driver (not supported by mongodb at least)
if (this.driver instanceof MongoDriver)
throw new Error(`You cannot use getTreeRepository for MongoDB connections.`);
const repository = this.findRepositoryAggregator(entityClassOrName).treeRepository;
if (!repository)
if (!this.hasMetadata(entityClassOrName))
throw new RepositoryNotFoundError(this.name, entityClassOrName);
const repository = this.getMetadata(entityClassOrName).repository;
if (!(repository instanceof TreeRepository))
throw new RepositoryNotTreeError(entityClassOrName);
return repository;
@ -409,7 +373,10 @@ export class Connection {
if (!(this.driver instanceof MongoDriver))
throw new Error(`You can use getMongoRepository only for MongoDB connections.`);
return this.findRepositoryAggregator(entityClassOrName).repository as MongoRepository<Entity>;
if (!this.hasMetadata(entityClassOrName))
throw new RepositoryNotFoundError(this.name, entityClassOrName);
return this.getMetadata(entityClassOrName).repository as MongoRepository<Entity>;
}
/**
@ -500,6 +467,42 @@ 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.
*/
createIsolatedManager(queryRunnerProvider?: QueryRunnerProvider): EntityManager {
if (!queryRunnerProvider)
queryRunnerProvider = new QueryRunnerProvider(this.driver, true);
return new EntityManagerFactory().create(this, queryRunnerProvider);
}
/**
* 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.
*/
createIsolatedRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, queryRunnerProvider?: QueryRunnerProvider): Repository<Entity> {
if (!queryRunnerProvider)
queryRunnerProvider = new QueryRunnerProvider(this.driver, true);
return new RepositoryFactory().createRepository(this, this.getMetadata(entityClassOrName), queryRunnerProvider);
}
/**
* 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.
*/
createIsolatedSpecificRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, queryRunnerProvider?: QueryRunnerProvider): SpecificRepository<Entity> {
if (!queryRunnerProvider)
queryRunnerProvider = new QueryRunnerProvider(this.driver, true);
return new RepositoryFactory().createSpecificRepository(this, this.getMetadata(entityClassOrName), queryRunnerProvider);
}
// -------------------------------------------------------------------------
// Deprecated Public Methods
// -------------------------------------------------------------------------
@ -544,7 +547,10 @@ export class Connection {
* @deprecated don't use it, it will be refactored or removed in the future versions
*/
getSpecificRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): SpecificRepository<Entity> {
return this.findRepositoryAggregator(entityClassOrName).specificRepository;
if (!this.hasMetadata(entityClassOrName))
throw new RepositoryNotFoundError(this.name, entityClassOrName);
return this.getMetadata(entityClassOrName).specificRepository;
}
// -------------------------------------------------------------------------
@ -552,77 +558,63 @@ export class Connection {
// -------------------------------------------------------------------------
/**
* Finds repository aggregator of the given entity class or name.
* Creates connection's Logger.
*/
protected findRepositoryAggregator(entityClassOrName: ObjectType<any>|string): RepositoryAggregator {
if (!this.hasMetadata(entityClassOrName))
throw new RepositoryNotFoundError(this.name, entityClassOrName);
protected createLogger(): Logger {
if (this.options.factories && this.options.factories.logger)
return this.options.factories.logger.create(this.options.logging || {});
const metadata = this.getMetadata(entityClassOrName);
const repositoryAggregator = this.repositoryAggregators.find(repositoryAggregate => repositoryAggregate.metadata === metadata);
if (!repositoryAggregator)
throw new RepositoryNotFoundError(this.name, entityClassOrName);
return new LoggerFactory().create(this.options.logging || {});
}
return repositoryAggregator;
/**
* Creates connection's Driver.
*/
protected createDriver(): Driver {
if (this.options.factories && this.options.factories.driver)
return this.options.factories.driver.create(this);
return new DriverFactory().create(this);
}
/**
* Creates EntityManager using its factory.
*/
protected createEntityManager(): EntityManager {
if (this.options.factories && this.options.factories.entityManager)
return this.options.factories.entityManager.create(this);
return new EntityManagerFactory().create(this);
}
/**
* Builds all registered metadatas.
*/
public buildMetadatas() {
protected buildMetadatas(): void {
const connectionMetadataBuilder = new ConnectionMetadataBuilder(this);
// import entity schemas
const [entitySchemaDirectories, entitySchemaClasses] = OrmUtils.splitStringsAndClasses(this.options.entitySchemas || []);
entitySchemaClasses.push(...importJsonsFromDirectories(entitySchemaDirectories));
const [entityDirectories, entityClasses] = OrmUtils.splitStringsAndClasses(this.options.entities || []);
entityClasses.push(...importClassesFromDirectories(entityDirectories));
const [subscriberDirectories, subscriberClasses] = OrmUtils.splitStringsAndClasses(this.options.subscribers || []);
subscriberClasses.push(...importClassesFromDirectories(subscriberDirectories));
const [migrationDirectories, migrationClasses] = OrmUtils.splitStringsAndClasses(this.options.migrations || []);
migrationClasses.push(...importClassesFromDirectories(migrationDirectories));
// create migration instances
const migrations = migrationClasses.map(migrationClass => {
return getFromContainer<MigrationInterface>(migrationClass);
});
Object.assign(this, { migrations });
this.subscribers.length = 0;
this.repositoryAggregators.length = 0;
this.entityMetadatas.length = 0;
const entityMetadataValidator = new EntityMetadataValidator();
// take imported event subscribers
// build subscribers if they are not disallowed from high-level (for example they can disallowed from migrations run process)
if (!PlatformTools.getEnvVariable("SKIP_SUBSCRIBERS_LOADING")) {
getMetadataArgsStorage()
.filterSubscribers(subscriberClasses)
.map(metadata => getFromContainer(metadata.target))
.forEach(subscriber => this.subscribers.push(subscriber));
const subscribers = connectionMetadataBuilder.buildSubscribers(this.options.subscribers || []);
Object.assign(this, { subscribers: subscribers });
}
// take imported entity listeners
// build entity metadatas from metadata args storage (collected from decorators)
new EntityMetadataBuilder(this, getMetadataArgsStorage())
.build(entityClasses)
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.repositoryAggregators.push(new RepositoryAggregator(this, metadata));
});
// build entity metadatas
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas(this.options.entities || [], this.options.entitySchemas || []);
Object.assign(this, { entityMetadatas: entityMetadatas });
// build entity metadatas from given entity schemas
const metadataArgsStorage = getFromContainer(EntitySchemaTransformer)
.transform(entitySchemaClasses);
new EntityMetadataBuilder(this, metadataArgsStorage)
.build()
.forEach(metadata => {
this.entityMetadatas.push(metadata);
this.repositoryAggregators.push(new RepositoryAggregator(this, metadata));
});
// create migration instances
const migrations = connectionMetadataBuilder.buildMigrations(this.options.migrations || []);
Object.assign(this, { migrations: migrations });
// initialize repositories for all entity metadatas
this.entityMetadatas.forEach(metadata => {
metadata.repository = new RepositoryFactory().createRepository(this, metadata);
metadata.specificRepository = new RepositoryFactory().createSpecificRepository(this, metadata);
});
// validate all created entity metadatas to make sure user created entities are valid and correct
const entityMetadataValidator = new EntityMetadataValidator();
entityMetadataValidator.validateMany(this.entityMetadatas);
}

View File

@ -0,0 +1,53 @@
import {importClassesFromDirectories, importJsonsFromDirectories} from "../util/DirectoryExportedClassesLoader";
import {OrmUtils} from "../util/OrmUtils";
import {getFromContainer} from "../container";
import {MigrationInterface} from "../migration/MigrationInterface";
import {getMetadataArgsStorage} from "../index";
import {EntityMetadataBuilder} from "../metadata-builder/EntityMetadataBuilder";
import {EntitySchemaTransformer} from "../entity-schema/EntitySchemaTransformer";
import {Connection} from "./Connection";
import {EntitySchema} from "../entity-schema/EntitySchema";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {EntitySubscriberInterface} from "../subscriber/EntitySubscriberInterface";
export class ConnectionMetadataBuilder {
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(protected connection: Connection) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
buildMigrations(migrations: Function[]|string[]): MigrationInterface[] {
const [migrationClasses, migrationDirectories] = OrmUtils.splitClassesAndStrings(migrations);
const allMigrationClasses = [...migrationClasses, ...importClassesFromDirectories(migrationDirectories)];
return allMigrationClasses.map(migrationClass => getFromContainer<MigrationInterface>(migrationClass));
}
buildSubscribers(subscribers: Function[]|string[]): EntitySubscriberInterface<any>[] {
const [subscriberClasses, subscriberDirectories] = OrmUtils.splitClassesAndStrings(subscribers || []);
const allSubscriberClasses = [...subscriberClasses, ...importClassesFromDirectories(subscriberDirectories)];
return getMetadataArgsStorage()
.filterSubscribers(allSubscriberClasses)
.map(metadata => getFromContainer<EntitySubscriberInterface<any>>(metadata.target));
}
buildEntityMetadatas(entities: Function[]|string[], schemas: EntitySchema[]|string[]): EntityMetadata[] {
const [entityClasses, entityDirectories] = OrmUtils.splitClassesAndStrings(entities || []);
const allEntityClasses = [...entityClasses, ...importClassesFromDirectories(entityDirectories)];
const decoratorEntityMetadatas = new EntityMetadataBuilder(this.connection, getMetadataArgsStorage()).build(allEntityClasses);
const [entitySchemaClasses, entitySchemaDirectories] = OrmUtils.splitClassesAndStrings(schemas || []);
const allEntitySchemaClasses = [...entitySchemaClasses, ...importJsonsFromDirectories(entitySchemaDirectories)];
const metadataArgsStorageFromSchema = new EntitySchemaTransformer().transform(allEntitySchemaClasses);
const schemaEntityMetadatas = new EntityMetadataBuilder(this.connection, metadataArgsStorageFromSchema).build();
return [...decoratorEntityMetadatas, ...schemaEntityMetadatas];
}
}

View File

@ -3,6 +3,9 @@ import {EntitySchema} from "../entity-schema/EntitySchema";
import {LoggerOptions} from "../logger/LoggerOptions";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {DriverType} from "../driver/DriverType";
import {LoggerFactory} from "../logger/LoggerFactory";
import {DriverFactory} from "../driver/DriverFactory";
import {EntityManagerFactory} from "../entity-manager/EntityManagerFactory";
/**
* ConnectionOptions is an interface with settings and options for specific connection.
@ -192,4 +195,27 @@ export interface ConnectionOptions {
};
/**
* Special factories used to override default connection objects behaviour.
* Advanced functionality.
*/
readonly factories?: {
/**
* Logger factory creates logger used to log events in the connection.
*/
readonly logger?: LoggerFactory;
/**
* Driver factory creates database driver based on the connection driver type.
*/
readonly driver?: DriverFactory;
/**
* Creates EntityManager instances used in the connection.
*/
readonly entityManager?: EntityManagerFactory;
};
}

View File

@ -10,26 +10,6 @@ import {LazyRelationsWrapper} from "../lazy-loading/LazyRelationsWrapper";
*/
export interface Driver {
/**
* Driver options contains connectivity options used to connection to the database.
*/
readonly options: DriverOptions;
/**
* Creates repository instance of this driver.
*/
// createRepository(connection: Connection, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): Repository<any>;
/**
* Creates tree repository instance of this driver.
*/
// createTreeRepository(connection: Connection, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): TreeRepository<any>;
/**
* Creates specific repository instance of this driver.
*/
// createSpecificRepository(connection: Connection, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): SpecificRepository<any>;
/**
* Performs connection to the database.
* Based on pooling options, it can either create connection immediately,

View File

@ -3,16 +3,13 @@ import {ConnectionIsNotSetError} from "../error/ConnectionIsNotSetError";
import {DriverOptions} from "../DriverOptions";
import {DatabaseConnection} from "../DatabaseConnection";
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
import {Logger} from "../../logger/Logger";
import {QueryRunner} from "../../query-runner/QueryRunner";
import {MongoQueryRunner} from "./MongoQueryRunner";
import {ObjectLiteral} from "../../common/ObjectLiteral";
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
import {PlatformTools} from "../../platform/PlatformTools";
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategyInterface";
import {EntityMetadata} from "../../metadata/EntityMetadata";
import {LazyRelationsWrapper} from "../../lazy-loading/LazyRelationsWrapper";
import {Connection} from "../../connection/Connection";
/**
@ -30,11 +27,6 @@ export class MongoDriver implements Driver {
*/
queryRunner: MongoQueryRunner;
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -49,23 +41,16 @@ export class MongoDriver implements Driver {
*/
protected pool: any;
/**
* Logger used to log queries and errors.
*/
protected logger: Logger;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
// validate options to make sure everything is correct and driver will be able to establish connection
this.validateOptions(connection.options);
// load mongodb package
this.options = connection.options;
this.logger = connection.logger;
this.mongodb = this.loadDependencies();
}
@ -78,7 +63,7 @@ export class MongoDriver implements Driver {
*/
connect(): Promise<void> {
return new Promise<void>((ok, fail) => {
this.mongodb.MongoClient.connect(this.buildConnectionUrl(), this.options.extra, (err: any, database: any) => {
this.mongodb.MongoClient.connect(this.buildConnectionUrl(), this.connection.options!.extra, (err: any, database: any) => {
if (err) return fail(err);
this.pool = database;
@ -87,7 +72,7 @@ export class MongoDriver implements Driver {
connection: this.pool,
isTransactionActive: false
};
this.queryRunner = new MongoQueryRunner(databaseConnection, this, this.logger);
this.queryRunner = new MongoQueryRunner(this.connection, databaseConnection);
ok();
});
});
@ -254,10 +239,10 @@ export class MongoDriver implements Driver {
* Builds connection url that is passed to underlying driver to perform connection to the mongodb database.
*/
protected buildConnectionUrl(): string {
if (this.options.url)
return this.options.url;
if (this.connection.options.url)
return this.connection.options.url;
return `mongodb://${this.options.host || "127.0.0.1"}:${this.options.port || "27017"}/${this.options.database}`;
return `mongodb://${this.connection.options.host || "127.0.0.1"}:${this.connection.options.port || "27017"}/${this.connection.options.database}`;
}
}

View File

@ -1,8 +1,6 @@
import {QueryRunner} from "../../query-runner/QueryRunner";
import {DatabaseConnection} from "../DatabaseConnection";
import {ObjectLiteral} from "../../common/ObjectLiteral";
import {Logger} from "../../logger/Logger";
import {MongoDriver} from "./MongoDriver";
import {ColumnSchema} from "../../schema-builder/schema/ColumnSchema";
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
import {TableSchema} from "../../schema-builder/schema/TableSchema";
@ -40,6 +38,7 @@ import {
UpdateWriteOpResult,
CollStats
} from "./typings";
import {Connection} from "../../connection/Connection";
/**
* Runs queries on a single MongoDB connection.
@ -50,9 +49,8 @@ export class MongoQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: MongoDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
@ -678,7 +676,7 @@ export class MongoQueryRunner implements QueryRunner {
* Database name shortcut.
*/
protected get dbName(): string {
return this.driver.options.database as string;
return this.connection.options.database as string;
}
/**

View File

@ -1,5 +1,5 @@
import { EventEmitter } from "events";
import { Readable, Writable } from "stream";
import {EventEmitter} from "events";
import {Readable, Writable} from "stream";
/**
* Creates a new MongoClient instance.

View File

@ -22,15 +22,6 @@ import {Connection} from "../../connection/Connection";
*/
export class MysqlDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -55,26 +46,20 @@ export class MysqlDriver implements Driver {
*/
protected databaseConnectionPool: DatabaseConnection[] = [];
/**
* Logger used to log queries and errors.
*/
protected logger: Logger;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
this.options = DriverUtils.buildDriverOptions(connection.options);
this.logger = connection.logger;
Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
// validate options to make sure everything is set
if (!(this.options.host || (this.options.extra && this.options.extra.socketPath)))
if (!(connection.options.host || (connection.options.extra && connection.options.extra.socketPath)))
throw new DriverOptionNotSetError("socketPath and host");
if (!this.options.username)
if (!connection.options.username)
throw new DriverOptionNotSetError("username");
if (!this.options.database)
if (!connection.options.database)
throw new DriverOptionNotSetError("database");
// load mysql package
@ -94,16 +79,16 @@ export class MysqlDriver implements Driver {
// build connection options for the driver
const options = Object.assign({}, {
host: this.options.host,
user: this.options.username,
password: this.options.password,
database: this.options.database,
port: this.options.port
}, this.options.extra || {});
host: this.connection.options.host,
user: this.connection.options.username,
password: this.connection.options.password,
database: this.connection.options.database,
port: this.connection.options.port
}, this.connection.options.extra || {});
// pooling is enabled either when its set explicitly to true,
// either when its not defined at all (e.g. enabled by default)
if (this.options.usePool === undefined || this.options.usePool === true) {
if (this.connection.options.usePool === undefined || this.connection.options.usePool === true) {
this.pool = this.mysql.createPool(options);
return Promise.resolve();
@ -153,7 +138,7 @@ export class MysqlDriver implements Driver {
return Promise.reject(new ConnectionIsNotSetError("mysql"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new MysqlQueryRunner(databaseConnection, this, this.logger);
return new MysqlQueryRunner(this.connection, databaseConnection);
}
/**

View File

@ -14,6 +14,7 @@ import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
import {IndexSchema} from "../../schema-builder/schema/IndexSchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {Connection} from "../../connection/Connection";
/**
* Runs queries on a single mysql database connection.
@ -34,9 +35,8 @@ export class MysqlQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: MysqlDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
@ -145,11 +145,11 @@ export class MysqlQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
return new Promise((ok, fail) => {
this.logger.logQuery(query, parameters);
this.connection.logger.logQuery(query, parameters);
this.databaseConnection.connection.query(query, parameters, (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
return fail(err);
}
@ -166,10 +166,10 @@ export class MysqlQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map(key => "?").join(",");
const parameters = keys.map(key => keyValues[key]);
const sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`;
const sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`;
const result = await this.query(sql, parameters);
return generatedColumn ? result.insertId : undefined;
}
@ -183,7 +183,7 @@ export class MysqlQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions).join(" AND ");
const sql = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const sql = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const conditionParams = Object.keys(conditions).map(key => conditions[key]);
const updateParams = Object.keys(valuesMap).map(key => valuesMap[key]);
const allParameters = updateParams.concat(conditionParams);
@ -210,7 +210,7 @@ export class MysqlQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -223,16 +223,16 @@ export class MysqlQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
return results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1;
}
@ -765,7 +765,7 @@ export class MysqlQueryRunner implements QueryRunner {
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`TRUNCATE TABLE ${this.driver.escapeTableName(tableName)}`);
await this.query(`TRUNCATE TABLE ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -776,14 +776,14 @@ export class MysqlQueryRunner implements QueryRunner {
* Database name shortcut.
*/
protected get dbName(): string {
return this.driver.options.database as string;
return this.connection.options.database as string;
}
/**
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral): string[] {
return Object.keys(objectLiteral).map(key => this.driver.escapeColumnName(key) + "=?");
return Object.keys(objectLiteral).map(key => this.connection.driver.escapeColumnName(key) + "=?");
}
/**

View File

@ -24,15 +24,6 @@ import {Connection} from "../../connection/Connection";
*/
export class OracleDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -57,26 +48,20 @@ export class OracleDriver implements Driver {
*/
protected databaseConnectionPool: DatabaseConnection[] = [];
/**
* Logger used to log queries and errors.
*/
protected logger: Logger;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
this.options = connection.options;
this.logger = connection.logger;
// Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
// validate options to make sure everything is set
if (!this.options.host)
if (!connection.options.host)
throw new DriverOptionNotSetError("host");
if (!this.options.username)
if (!connection.options.username)
throw new DriverOptionNotSetError("username");
if (!this.options.sid)
if (!connection.options.sid)
throw new DriverOptionNotSetError("sid");
// load oracle package
@ -97,14 +82,14 @@ export class OracleDriver implements Driver {
// build connection options for the driver
const options = Object.assign({}, {
user: this.options.username,
password: this.options.password,
connectString: this.options.host + ":" + this.options.port + "/" + this.options.sid,
}, this.options.extra || {});
user: this.connection.options.username,
password: this.connection.options.password,
connectString: this.connection.options.host + ":" + this.connection.options.port + "/" + this.connection.options.sid,
}, this.connection.options.extra || {});
// pooling is enabled either when its set explicitly to true,
// either when its not defined at all (e.g. enabled by default)
if (this.options.usePool === undefined || this.options.usePool === true) {
if (this.connection.options.usePool === undefined || this.connection.options.usePool === true) {
return new Promise<void>((ok, fail) => {
this.oracle.createPool(options, (err: any, pool: any) => {
if (err)
@ -165,7 +150,7 @@ export class OracleDriver implements Driver {
return Promise.reject(new ConnectionIsNotSetError("oracle"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new OracleQueryRunner(databaseConnection, this, this.logger);
return new OracleQueryRunner(this.connection, databaseConnection);
}
/**

View File

@ -3,8 +3,6 @@ import {DatabaseConnection} from "../DatabaseConnection";
import {ObjectLiteral} from "../../common/ObjectLiteral";
import {TransactionAlreadyStartedError} from "../error/TransactionAlreadyStartedError";
import {TransactionNotStartedError} from "../error/TransactionNotStartedError";
import {Logger} from "../../logger/Logger";
import {OracleDriver} from "./OracleDriver";
import {DataTypeNotSupportedByDriverError} from "../error/DataTypeNotSupportedByDriverError";
import {ColumnSchema} from "../../schema-builder/schema/ColumnSchema";
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
@ -14,6 +12,8 @@ import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
import {IndexSchema} from "../../schema-builder/schema/IndexSchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {Connection} from "../../connection/Connection";
import {OracleDriver} from "./OracleDriver";
/**
* Runs queries on a single mysql database connection.
@ -36,9 +36,8 @@ export class OracleQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: OracleDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
@ -146,11 +145,11 @@ export class OracleQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
return new Promise((ok, fail) => {
this.logger.logQuery(query, parameters);
this.connection.logger.logQuery(query, parameters);
const handler = (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
return fail(err);
}
@ -171,18 +170,19 @@ export class OracleQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map(key => ":" + key).join(", ");
const parameters = keys.map(key => keyValues[key]);
const insertSql = columns.length > 0
? `INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`
: `INSERT INTO ${this.driver.escapeTableName(tableName)} DEFAULT VALUES`;
? `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`
: `INSERT INTO ${this.connection.driver.escapeTableName(tableName)} DEFAULT VALUES`;
if (generatedColumn) {
const sql2 = `declare lastId number; begin ${insertSql} returning "id" into lastId; dbms_output.enable; dbms_output.put_line(lastId); dbms_output.get_line(:ln, :st); end;`;
const oracle = (this.connection.driver as OracleDriver).oracle;
const saveResult = await this.query(sql2, parameters.concat([
{ dir: this.driver.oracle.BIND_OUT, type: this.driver.oracle.STRING, maxSize: 32767 },
{ dir: this.driver.oracle.BIND_OUT, type: this.driver.oracle.NUMBER }
{ dir: oracle.BIND_OUT, type: oracle.STRING, maxSize: 32767 },
{ dir: oracle.BIND_OUT, type: oracle.NUMBER }
]));
return parseInt(saveResult[0]);
} else {
@ -199,7 +199,7 @@ export class OracleQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions).join(" AND ");
const sql = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const sql = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const conditionParams = Object.keys(conditions).map(key => conditions[key]);
const updateParams = Object.keys(valuesMap).map(key => valuesMap[key]);
const allParameters = updateParams.concat(conditionParams);
@ -226,7 +226,7 @@ export class OracleQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -239,16 +239,16 @@ export class OracleQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
return results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1;
}
@ -836,7 +836,7 @@ AND cons.constraint_name = cols.constraint_name AND cons.owner = cols.owner ORDE
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`TRUNCATE TABLE ${this.driver.escapeTableName(tableName)}`);
await this.query(`TRUNCATE TABLE ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -847,14 +847,14 @@ AND cons.constraint_name = cols.constraint_name AND cons.owner = cols.owner ORDE
* Database name shortcut.
*/
protected get dbName(): string {
return this.driver.options.schemaName as string;
return this.connection.options.schemaName as string;
}
/**
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral): string[] {
return Object.keys(objectLiteral).map(key => this.driver.escapeColumnName(key) + "=:" + key);
return Object.keys(objectLiteral).map(key => this.connection.driver.escapeColumnName(key) + "=:" + key);
}
/**

View File

@ -27,15 +27,6 @@ import {Connection} from "../../connection/Connection";
*/
export class PostgresDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -70,24 +61,22 @@ export class PostgresDriver implements Driver {
* default: "public"
*/
public schemaName?: string;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
this.options = DriverUtils.buildDriverOptions(connection.options);
this.logger = connection.logger;
Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
this.schemaName = connection.options.schemaName || "public";
// validate options to make sure everything is set
if (!this.options.host)
if (!connection.options.host)
throw new DriverOptionNotSetError("host");
if (!this.options.username)
if (!connection.options.username)
throw new DriverOptionNotSetError("username");
if (!this.options.database)
if (!connection.options.database)
throw new DriverOptionNotSetError("database");
// load postgres package
@ -107,16 +96,16 @@ export class PostgresDriver implements Driver {
// build connection options for the driver
const options = Object.assign({}, {
host: this.options.host,
user: this.options.username,
password: this.options.password,
database: this.options.database,
port: this.options.port
}, this.options.extra || {});
host: this.connection.options.host,
user: this.connection.options.username,
password: this.connection.options.password,
database: this.connection.options.database,
port: this.connection.options.port
}, this.connection.options.extra || {});
// pooling is enabled either when its set explicitly to true,
// either when its not defined at all (e.g. enabled by default)
if (this.options.usePool === undefined || this.options.usePool === true) {
if (this.connection.options.usePool === undefined || this.connection.options.usePool === true) {
this.pool = new this.postgres.Pool(options);
return Promise.resolve();
@ -133,8 +122,8 @@ export class PostgresDriver implements Driver {
} else {
this.databaseConnection!.connection.query(`SET search_path TO '${this.schemaName}', 'public';`, (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(`SET search_path TO '${this.schemaName}', 'public';`);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(`SET search_path TO '${this.schemaName}', 'public';`);
this.connection.logger.logQueryError(err);
fail(err);
} else {
ok();
@ -184,7 +173,7 @@ export class PostgresDriver implements Driver {
return Promise.reject(new ConnectionIsNotSetError("postgres"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new PostgresQueryRunner(databaseConnection, this, this.logger);
return new PostgresQueryRunner(this.connection, databaseConnection);
}
/**
@ -345,8 +334,8 @@ export class PostgresDriver implements Driver {
};
dbConnection.connection.query(`SET search_path TO '${this.schemaName}', 'public';`, (err: any) => {
if (err) {
this.logger.logFailedQuery(`SET search_path TO '${this.schemaName}', 'public';`);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(`SET search_path TO '${this.schemaName}', 'public';`);
this.connection.logger.logQueryError(err);
fail(err);
} else {
ok(dbConnection);

View File

@ -14,6 +14,7 @@ import {ForeignKeySchema} from "../../schema-builder/schema/ForeignKeySchema";
import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {Connection} from "../../connection/Connection";
/**
* Runs queries on a single postgres database connection.
@ -36,10 +37,9 @@ export class PostgresQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: PostgresDriver,
protected logger: Logger) {
this.schemaName = driver.schemaName || "public";
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
this.schemaName = connection.options.schemaName || "public";
}
// -------------------------------------------------------------------------
@ -139,11 +139,11 @@ export class PostgresQueryRunner implements QueryRunner {
// console.log("query: ", query);
// console.log("parameters: ", parameters);
return new Promise<any[]>((ok, fail) => {
this.logger.logQuery(query, parameters);
this.connection.logger.logQuery(query, parameters);
this.databaseConnection.connection.query(query, parameters, (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
fail(err);
} else {
ok(result.rows);
@ -160,11 +160,11 @@ export class PostgresQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map((key, index) => "$" + (index + 1)).join(",");
const sql = columns.length > 0
? `INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) VALUES (${values}) ${ generatedColumn ? " RETURNING " + this.driver.escapeColumnName(generatedColumn.databaseName) : "" }`
: `INSERT INTO ${this.driver.escapeTableName(tableName)} DEFAULT VALUES ${ generatedColumn ? " RETURNING " + this.driver.escapeColumnName(generatedColumn.databaseName) : "" }`;
? `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) VALUES (${values}) ${ generatedColumn ? " RETURNING " + this.connection.driver.escapeColumnName(generatedColumn.databaseName) : "" }`
: `INSERT INTO ${this.connection.driver.escapeTableName(tableName)} DEFAULT VALUES ${ generatedColumn ? " RETURNING " + this.connection.driver.escapeColumnName(generatedColumn.databaseName) : "" }`;
const parameters = keys.map(key => keyValues[key]);
const result: ObjectLiteral[] = await this.query(sql, parameters);
if (generatedColumn)
@ -182,7 +182,7 @@ export class PostgresQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions, Object.keys(valuesMap).length).join(" AND ");
const query = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const query = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const updateParams = Object.keys(valuesMap).map(key => valuesMap[key]);
const conditionParams = Object.keys(conditions).map(key => conditions[key]);
const allParameters = updateParams.concat(conditionParams);
@ -209,7 +209,7 @@ export class PostgresQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -222,12 +222,12 @@ export class PostgresQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
@ -837,7 +837,7 @@ where constraint_type = 'PRIMARY KEY' AND c.table_schema = '${this.schemaName}'
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`TRUNCATE TABLE ${this.driver.escapeTableName(tableName)}`);
await this.query(`TRUNCATE TABLE ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -848,14 +848,14 @@ where constraint_type = 'PRIMARY KEY' AND c.table_schema = '${this.schemaName}'
* Database name shortcut.
*/
protected get dbName(): string {
return this.driver.options.database as string;
return this.connection.options.database as string;
}
/**
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral, startIndex: number = 0): string[] {
return Object.keys(objectLiteral).map((key, index) => this.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
return Object.keys(objectLiteral).map((key, index) => this.connection.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
}
/**

View File

@ -21,15 +21,6 @@ import {Connection} from "../../connection/Connection";
*/
export class SqliteDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -44,22 +35,14 @@ export class SqliteDriver implements Driver {
*/
protected databaseConnection: DatabaseConnection|undefined;
/**
* Logger used to log queries and errors.
*/
protected logger: Logger;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
this.options = connection.options;
this.logger = connection.logger;
constructor(protected connection: Connection) {
// validate options to make sure everything is set
if (!this.options.storage)
if (!connection.options.storage)
throw new DriverOptionNotSetError("storage");
// load sqlite package
@ -75,7 +58,7 @@ export class SqliteDriver implements Driver {
*/
connect(): Promise<void> {
return new Promise<void>((ok, fail) => {
const connection = new this.sqlite.Database(this.options.storage, (err: any) => {
const connection = new this.sqlite.Database(this.connection.options.storage, (err: any) => {
if (err)
return fail(err);
@ -115,7 +98,7 @@ export class SqliteDriver implements Driver {
return Promise.reject(new ConnectionIsNotSetError("sqlite"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new SqliteQueryRunner(databaseConnection, this, this.logger);
return new SqliteQueryRunner(this.connection, databaseConnection);
}
/**

View File

@ -15,6 +15,7 @@ import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {RandomGenerator} from "../../util/RandomGenerator";
import {Connection} from "../../connection/Connection";
/**
* Runs queries on a single sqlite database connection.
@ -38,9 +39,8 @@ export class SqliteQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: SqliteDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
@ -139,11 +139,11 @@ export class SqliteQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
return new Promise<any[]>((ok, fail) => {
this.logger.logQuery(query, parameters);
this.connection.logger.logQuery(query, parameters);
this.databaseConnection.connection.all(query, parameters, (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
fail(err);
} else {
ok(result);
@ -160,18 +160,18 @@ export class SqliteQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map((key, index) => "$" + (index + 1)).join(",");
const sql = columns.length > 0 ? (`INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`) : `INSERT INTO ${this.driver.escapeTableName(tableName)} DEFAULT VALUES`;
const sql = columns.length > 0 ? (`INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`) : `INSERT INTO ${this.connection.driver.escapeTableName(tableName)} DEFAULT VALUES`;
const parameters = keys.map(key => keyValues[key]);
return new Promise<any[]>((ok, fail) => {
this.logger.logQuery(sql, parameters);
this.connection.logger.logQuery(sql, parameters);
const __this = this;
this.databaseConnection.connection.run(sql, parameters, function (err: any): void {
if (err) {
__this.logger.logFailedQuery(sql, parameters);
__this.logger.logQueryError(err);
__this.connection.logger.logFailedQuery(sql, parameters);
__this.connection.logger.logQueryError(err);
fail(err);
} else {
if (generatedColumn)
@ -192,7 +192,7 @@ export class SqliteQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions, Object.keys(valuesMap).length).join(" AND ");
const query = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const query = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const updateParams = Object.keys(valuesMap).map(key => valuesMap[key]);
const conditionParams = Object.keys(conditions).map(key => conditions[key]);
const allParameters = updateParams.concat(conditionParams);
@ -219,7 +219,7 @@ export class SqliteQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -232,12 +232,12 @@ export class SqliteQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
@ -317,7 +317,7 @@ export class SqliteQueryRunner implements QueryRunner {
const columnForeignKeys = dbForeignKeys
.filter(foreignKey => foreignKey["from"] === dbColumn["name"])
.map(foreignKey => {
// const keyName = this.driver.namingStrategy.foreignKeyName(dbTable["name"], [foreignKey["from"]], foreignKey["table"], [foreignKey["to"]]);
// const keyName = this.connection.driver.namingStrategy.foreignKeyName(dbTable["name"], [foreignKey["from"]], foreignKey["table"], [foreignKey["to"]]);
// todo: figure out solution here, name should be same as naming strategy generates!
const key = `${dbTable["name"]}_${[foreignKey["from"]].join("_")}_${foreignKey["table"]}_${[foreignKey["to"]].join("_")}`;
const keyName = "fk_" + RandomGenerator.sha1(key).substr(0, 27);
@ -815,7 +815,7 @@ export class SqliteQueryRunner implements QueryRunner {
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`DELETE FROM ${this.driver.escapeTableName(tableName)}`);
await this.query(`DELETE FROM ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -826,7 +826,7 @@ export class SqliteQueryRunner implements QueryRunner {
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral, startIndex: number = 0): string[] {
return Object.keys(objectLiteral).map((key, index) => this.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
return Object.keys(objectLiteral).map((key, index) => this.connection.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
}
/**

View File

@ -26,11 +26,6 @@ export class SqlServerDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
/**
* SQL Server library.
*/
@ -48,7 +43,7 @@ export class SqlServerDriver implements Driver {
/**
* SQL Server pool.
*/
protected connection: any;
protected connectionPool: any;
/**
* Pool of database connections.
@ -64,17 +59,16 @@ export class SqlServerDriver implements Driver {
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
this.options = DriverUtils.buildDriverOptions(connection.options);
this.logger = connection.logger;
Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
// validate options to make sure everything is set
if (!this.options.host)
if (!connection.options.host)
throw new DriverOptionNotSetError("host");
if (!this.options.username)
if (!connection.options.username)
throw new DriverOptionNotSetError("username");
if (!this.options.database)
if (!connection.options.database)
throw new DriverOptionNotSetError("database");
// load mssql package
@ -94,12 +88,12 @@ export class SqlServerDriver implements Driver {
// build connection options for the driver
const options = Object.assign({}, {
server: this.options.host,
user: this.options.username,
password: this.options.password,
database: this.options.database,
port: this.options.port
}, this.options.extra || {});
server: this.connection.options.host,
user: this.connection.options.username,
password: this.connection.options.password,
database: this.connection.options.database,
port: this.connection.options.port
}, this.connection.options.extra || {});
// set default useUTC option if it hasn't been set
if (!options.options) options.options = { useUTC: false };
@ -110,8 +104,8 @@ export class SqlServerDriver implements Driver {
return new Promise<void>((ok, fail) => {
const connection = new this.mssql.Connection(options).connect((err: any) => {
if (err) return fail(err);
this.connection = connection;
if (this.options.usePool === false) {
this.connectionPool = connection;
if (this.connection.options.usePool === false) {
this.databaseConnection = {
id: 1,
connection: new this.mssql.Request(connection),
@ -127,11 +121,11 @@ export class SqlServerDriver implements Driver {
* Closes connection with the database.
*/
async disconnect(): Promise<void> {
if (!this.connection)
if (!this.connectionPool)
throw new ConnectionIsNotSetError("mssql");
this.connection.close();
this.connection = undefined;
this.connectionPool.close();
this.connectionPool = undefined;
this.databaseConnection = undefined;
this.databaseConnectionPool = [];
}
@ -140,11 +134,11 @@ export class SqlServerDriver implements Driver {
* Creates a query runner used for common queries.
*/
async createQueryRunner(): Promise<QueryRunner> {
if (!this.connection)
if (!this.connectionPool)
return Promise.reject(new ConnectionIsNotSetError("mssql"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new SqlServerQueryRunner(databaseConnection, this, this.logger);
return new SqlServerQueryRunner(this.connection, databaseConnection);
}
/**
@ -154,7 +148,7 @@ export class SqlServerDriver implements Driver {
return {
driver: this.mssql,
connection: this.databaseConnection ? this.databaseConnection.connection : undefined,
pool: this.connection
pool: this.connectionPool
};
}
@ -275,7 +269,7 @@ export class SqlServerDriver implements Driver {
*/
protected retrieveDatabaseConnection(): Promise<DatabaseConnection> {
if (!this.connection)
if (!this.connectionPool)
throw new ConnectionIsNotSetError("mssql");
return new Promise((ok, fail) => {
@ -298,7 +292,7 @@ export class SqlServerDriver implements Driver {
// if (!dbConnection) {
let dbConnection: DatabaseConnection = {
id: this.databaseConnectionPool.length,
connection: this.connection,
connection: this.connectionPool,
isTransactionActive: false
};
dbConnection.releaseCallback = () => {

View File

@ -14,6 +14,8 @@ import {PrimaryKeySchema} from "../../schema-builder/schema/PrimaryKeySchema";
import {IndexSchema} from "../../schema-builder/schema/IndexSchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {Connection} from "../../connection/Connection";
import {MysqlDriver} from "../mysql/MysqlDriver";
/**
* Runs queries on a single mysql database connection.
@ -34,11 +36,9 @@ export class SqlServerQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: SqlServerDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -98,12 +98,12 @@ export class SqlServerQueryRunner implements QueryRunner {
//
// return new Promise<void>((ok, fail) => {
//
// const request = new this.driver.mssql.Request(this.isTransactionActive() ? this.databaseConnection.transaction : this.databaseConnection.connection);
// const request = new this.connection.driver.mssql.Request(this.isTransactionActive() ? this.databaseConnection.transaction : this.databaseConnection.connection);
// request.multiple = true;
// request.query(allQueries, (err: any, result: any) => {
// if (err) {
// this.logger.logFailedQuery(allQueries);
// this.logger.logQueryError(err);
// this.connection.logger.logFailedQuery(allQueries);
// this.connection.logger.logQueryError(err);
// return fail(err);
// }
//
@ -195,8 +195,8 @@ export class SqlServerQueryRunner implements QueryRunner {
return new Promise((ok, fail) => {
this.logger.logQuery(query, parameters);
const request = new this.driver.mssql.Request(this.isTransactionActive() ? this.databaseConnection.transaction : this.databaseConnection.connection);
this.connection.logger.logQuery(query, parameters);
const request = new (this.connection.driver as SqlServerDriver).mssql.Request(this.isTransactionActive() ? this.databaseConnection.transaction : this.databaseConnection.connection);
if (parameters && parameters.length) {
parameters.forEach((parameter, index) => {
request.input(index, parameters![index]);
@ -204,8 +204,8 @@ export class SqlServerQueryRunner implements QueryRunner {
}
request.query(query, (err: any, result: any) => {
if (err) {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
return fail(err);
}
@ -222,13 +222,13 @@ export class SqlServerQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map((key, index) => "@" + index).join(",");
const parameters = keys.map(key => keyValues[key]);
const sql = columns.length > 0
? `INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) ${ generatedColumn ? "OUTPUT INSERTED." + generatedColumn.databaseName + " " : "" }VALUES (${values})`
: `INSERT INTO ${this.driver.escapeTableName(tableName)} ${ generatedColumn ? "OUTPUT INSERTED." + generatedColumn.databaseName + " " : "" }DEFAULT VALUES `;
? `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) ${ generatedColumn ? "OUTPUT INSERTED." + generatedColumn.databaseName + " " : "" }VALUES (${values})`
: `INSERT INTO ${this.connection.driver.escapeTableName(tableName)} ${ generatedColumn ? "OUTPUT INSERTED." + generatedColumn.databaseName + " " : "" }DEFAULT VALUES `;
const result = await this.query(sql, parameters);
return generatedColumn ? result instanceof Array ? result[0][generatedColumn.databaseName] : result[generatedColumn.databaseName] : undefined;
@ -247,7 +247,7 @@ export class SqlServerQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions, updateParams.length).join(" AND ");
const sql = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const sql = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
await this.query(sql, allParameters);
}
@ -272,7 +272,7 @@ export class SqlServerQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -285,16 +285,16 @@ export class SqlServerQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
const results: ObjectLiteral[] = await this.query(`SELECT MAX(level) as level FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId}`);
return results && results[0] && results[0]["level"] ? parseInt(results[0]["level"]) + 1 : 1;
}
@ -870,7 +870,7 @@ WHERE columnUsages.TABLE_CATALOG = '${this.dbName}' AND tableConstraints.TABLE_C
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`TRUNCATE TABLE ${this.driver.escapeTableName(tableName)}`);
await this.query(`TRUNCATE TABLE ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -881,7 +881,7 @@ WHERE columnUsages.TABLE_CATALOG = '${this.dbName}' AND tableConstraints.TABLE_C
* Database name shortcut.
*/
protected get dbName(): string {
return this.driver.options.database as string;
return this.connection.options.database as string;
}
/**
@ -889,7 +889,7 @@ WHERE columnUsages.TABLE_CATALOG = '${this.dbName}' AND tableConstraints.TABLE_C
*/
protected parametrize(objectLiteral: ObjectLiteral, startFrom: number = 0): string[] {
return Object.keys(objectLiteral).map((key, index) => {
return this.driver.escapeColumnName(key) + "=@" + (startFrom + index);
return this.connection.driver.escapeColumnName(key) + "=@" + (startFrom + index);
});
}

View File

@ -11,8 +11,6 @@ import {ColumnMetadata} from "../../metadata/ColumnMetadata";
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
import {WebsqlQueryRunner} from "./WebsqlQueryRunner";
import {NamingStrategyInterface} from "../../naming-strategy/NamingStrategyInterface";
import {LazyRelationsWrapper} from "../../lazy-loading/LazyRelationsWrapper";
import {Connection} from "../../connection/Connection";
/**
@ -25,15 +23,6 @@ declare function openDatabase(...params: any[]): any;
*/
export class WebsqlDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Driver connection options.
*/
readonly options: DriverOptions;
// -------------------------------------------------------------------------
// Protected Properties
// -------------------------------------------------------------------------
@ -43,26 +32,20 @@ export class WebsqlDriver implements Driver {
*/
protected databaseConnection: DatabaseConnection|undefined;
/**
* Logger used to log queries and errors.
*/
protected logger: Logger;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
constructor(protected connection: Connection) {
this.options = DriverUtils.buildDriverOptions(connection.options);
this.logger = connection.logger;
Object.assign(connection.options, DriverUtils.buildDriverOptions(connection.options)); // todo: do it better way
// validate options to make sure everything is set
// if (!this.options.host)
// throw new DriverOptionNotSetError("host");
// if (!this.options.username)
// throw new DriverOptionNotSetError("username");
if (!this.options.database)
if (!connection.options.database)
throw new DriverOptionNotSetError("database");
// todo: what about extra options: version, description, size
}
@ -80,8 +63,8 @@ export class WebsqlDriver implements Driver {
// build connection options for the driver
const options = Object.assign({}, {
database: this.options.database,
}, this.options.extra || {});
database: this.connection.options.database,
}, this.connection.options.extra || {});
return new Promise<void>((ok, fail) => {
const connection = openDatabase(
@ -121,7 +104,7 @@ export class WebsqlDriver implements Driver {
return Promise.reject(new ConnectionIsNotSetError("websql"));
const databaseConnection = await this.retrieveDatabaseConnection();
return new WebsqlQueryRunner(databaseConnection, this, this.logger);
return new WebsqlQueryRunner(this.connection, databaseConnection);
}
/**

View File

@ -13,6 +13,7 @@ import {IndexSchema} from "../../schema-builder/schema/IndexSchema";
import {QueryRunnerAlreadyReleasedError} from "../../query-runner/error/QueryRunnerAlreadyReleasedError";
import {WebsqlDriver} from "./WebsqlDriver";
import {ColumnType} from "../../metadata/types/ColumnTypes";
import {Connection} from "../../connection/Connection";
/**
* Runs queries on a single websql database connection.
@ -33,9 +34,8 @@ export class WebsqlQueryRunner implements QueryRunner {
// Constructor
// -------------------------------------------------------------------------
constructor(protected databaseConnection: DatabaseConnection,
protected driver: WebsqlDriver,
protected logger: Logger) {
constructor(protected connection: Connection,
protected databaseConnection: DatabaseConnection) {
}
// -------------------------------------------------------------------------
@ -139,7 +139,7 @@ export class WebsqlQueryRunner implements QueryRunner {
return new Promise((ok, fail) => {
this.logger.logQuery(query, parameters);
this.connection.logger.logQuery(query, parameters);
const db = this.databaseConnection.connection;
// todo: check if transaction is not active
db.transaction((tx: any) => {
@ -151,8 +151,8 @@ export class WebsqlQueryRunner implements QueryRunner {
ok(rows);
}, (tx: any, err: any) => {
this.logger.logFailedQuery(query, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(query, parameters);
this.connection.logger.logQueryError(err);
return fail(err);
});
});
@ -167,13 +167,13 @@ export class WebsqlQueryRunner implements QueryRunner {
throw new QueryRunnerAlreadyReleasedError();
const keys = Object.keys(keyValues);
const columns = keys.map(key => this.driver.escapeColumnName(key)).join(", ");
const columns = keys.map(key => this.connection.driver.escapeColumnName(key)).join(", ");
const values = keys.map((key, index) => "$" + (index + 1)).join(",");
const sql = columns.length > 0 ? (`INSERT INTO ${this.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`) : `INSERT INTO ${this.driver.escapeTableName(tableName)} DEFAULT VALUES`;
const sql = columns.length > 0 ? (`INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(${columns}) VALUES (${values})`) : `INSERT INTO ${this.connection.driver.escapeTableName(tableName)} DEFAULT VALUES`;
const parameters = keys.map(key => keyValues[key]);
return new Promise<any[]>((ok, fail) => {
this.logger.logQuery(sql, parameters);
this.connection.logger.logQuery(sql, parameters);
const db = this.databaseConnection.connection;
// todo: check if transaction is not active
@ -184,8 +184,8 @@ export class WebsqlQueryRunner implements QueryRunner {
ok();
}, (tx: any, err: any) => {
this.logger.logFailedQuery(sql, parameters);
this.logger.logQueryError(err);
this.connection.logger.logFailedQuery(sql, parameters);
this.connection.logger.logQueryError(err);
return fail(err);
});
});
@ -201,7 +201,7 @@ export class WebsqlQueryRunner implements QueryRunner {
const updateValues = this.parametrize(valuesMap).join(", ");
const conditionString = this.parametrize(conditions, Object.keys(valuesMap).length).join(" AND ");
const query = `UPDATE ${this.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const query = `UPDATE ${this.connection.driver.escapeTableName(tableName)} SET ${updateValues} ${conditionString ? (" WHERE " + conditionString) : ""}`;
const updateParams = Object.keys(valuesMap).map(key => valuesMap[key]);
const conditionParams = Object.keys(conditions).map(key => conditions[key]);
const allParameters = updateParams.concat(conditionParams);
@ -228,7 +228,7 @@ export class WebsqlQueryRunner implements QueryRunner {
const conditionString = typeof conditions === "string" ? conditions : this.parametrize(conditions).join(" AND ");
const parameters = conditions instanceof Object ? Object.keys(conditions).map(key => (conditions as ObjectLiteral)[key]) : maybeParameters;
const sql = `DELETE FROM ${this.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
const sql = `DELETE FROM ${this.connection.driver.escapeTableName(tableName)} WHERE ${conditionString}`;
await this.query(sql, parameters);
}
@ -241,12 +241,12 @@ export class WebsqlQueryRunner implements QueryRunner {
let sql = "";
if (hasLevel) {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant, level) ` +
`SELECT ancestor, ${newEntityId}, level + 1 FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}, 1`;
} else {
sql = `INSERT INTO ${this.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
sql = `INSERT INTO ${this.connection.driver.escapeTableName(tableName)}(ancestor, descendant) ` +
`SELECT ancestor, ${newEntityId} FROM ${this.connection.driver.escapeTableName(tableName)} WHERE descendant = ${parentId} ` +
`UNION ALL SELECT ${newEntityId}, ${newEntityId}`;
}
await this.query(sql);
@ -821,7 +821,7 @@ export class WebsqlQueryRunner implements QueryRunner {
* Truncates table.
*/
async truncate(tableName: string): Promise<void> {
await this.query(`DELETE FROM ${this.driver.escapeTableName(tableName)}`);
await this.query(`DELETE FROM ${this.connection.driver.escapeTableName(tableName)}`);
}
// -------------------------------------------------------------------------
@ -832,7 +832,7 @@ export class WebsqlQueryRunner implements QueryRunner {
* Parametrizes given object of values. Used to create column=value queries.
*/
protected parametrize(objectLiteral: ObjectLiteral, startIndex: number = 0): string[] {
return Object.keys(objectLiteral).map((key, index) => this.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
return Object.keys(objectLiteral).map((key, index) => this.connection.driver.escapeColumnName(key) + "=$" + (startIndex + index + 1));
}
/**

View File

@ -8,13 +8,11 @@ import {FindOneOptions} from "../find-options/FindOneOptions";
import {DeepPartial} from "../common/DeepPartial";
import {RemoveOptions} from "../repository/RemoveOptions";
import {SaveOptions} from "../repository/SaveOptions";
import {RepositoryAggregator} from "../repository/RepositoryAggregator";
import {NoNeedToReleaseEntityManagerError} from "./error/NoNeedToReleaseEntityManagerError";
import {SpecificRepository} from "../repository/SpecificRepository";
import {MongoRepository} from "../repository/MongoRepository";
import {TreeRepository} from "../repository/TreeRepository";
import {Repository} from "../repository/Repository";
import {RepositoryNotTreeError} from "../connection/error/RepositoryNotTreeError";
import {QueryBuilder} from "../query-builder/QueryBuilder";
import {FindOptionsUtils} from "../find-options/FindOptionsUtils";
import {SubjectBuilder} from "../persistence/SubjectBuilder";
@ -42,11 +40,6 @@ export class EntityManager {
*/
private data: ObjectLiteral = {};
/**
* Stores all registered repositories.
*/
private repositoryAggregators: RepositoryAggregator[] = [];
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
@ -582,8 +575,12 @@ export class EntityManager {
getRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): Repository<Entity> {
// if single db connection is used then create its own repository with reused query runner
if (this.queryRunnerProvider)
return this.obtainRepositoryAggregator(entityClassOrName as any).repository;
if (this.queryRunnerProvider) {
if (this.queryRunnerProvider.isReleased)
throw new QueryRunnerProviderAlreadyReleasedError();
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunnerProvider);
}
return this.connection.getRepository<Entity>(entityClassOrName as any);
}
@ -598,11 +595,10 @@ export class EntityManager {
// if single db connection is used then create its own repository with reused query runner
if (this.queryRunnerProvider) {
const treeRepository = this.obtainRepositoryAggregator(entityClassOrName).treeRepository;
if (!treeRepository)
throw new RepositoryNotTreeError(entityClassOrName);
if (this.queryRunnerProvider.isReleased)
throw new QueryRunnerProviderAlreadyReleasedError();
return treeRepository;
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunnerProvider) as TreeRepository<Entity>;
}
return this.connection.getTreeRepository<Entity>(entityClassOrName as any);
@ -624,8 +620,12 @@ export class EntityManager {
getMongoRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): MongoRepository<Entity> {
// if single db connection is used then create its own repository with reused query runner
if (this.queryRunnerProvider)
return this.obtainRepositoryAggregator(entityClassOrName as any).repository as MongoRepository<Entity>;
if (this.queryRunnerProvider) {
if (this.queryRunnerProvider.isReleased)
throw new QueryRunnerProviderAlreadyReleasedError();
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunnerProvider) as MongoRepository<Entity>;
}
return this.connection.getMongoRepository<Entity>(entityClassOrName as any);
}
@ -661,8 +661,12 @@ export class EntityManager {
getSpecificRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): SpecificRepository<Entity> {
// if single db connection is used then create its own repository with reused query runner
if (this.queryRunnerProvider)
return this.obtainRepositoryAggregator(entityClassOrName).specificRepository;
if (this.queryRunnerProvider) {
if (this.queryRunnerProvider.isReleased)
throw new QueryRunnerProviderAlreadyReleasedError();
return this.connection.createIsolatedSpecificRepository(entityClassOrName, this.queryRunnerProvider);
}
return this.connection.getSpecificRepository<Entity>(entityClassOrName as any);
}
@ -757,25 +761,4 @@ export class EntityManager {
}
}
/**
* Gets, or if does not exist yet, creates and returns a repository aggregator for a particular entity target.
*/
protected obtainRepositoryAggregator<Entity>(entityClassOrName: ObjectType<Entity>|string): RepositoryAggregator {
if (this.queryRunnerProvider && this.queryRunnerProvider.isReleased)
throw new QueryRunnerProviderAlreadyReleasedError();
const metadata = this.connection.getMetadata(entityClassOrName);
let repositoryAggregator = this.repositoryAggregators.find(repositoryAggregate => repositoryAggregate.metadata === metadata);
if (!repositoryAggregator) {
repositoryAggregator = new RepositoryAggregator(
this.connection,
this.connection.getMetadata(entityClassOrName as any),
this.queryRunnerProvider
);
this.repositoryAggregators.push(repositoryAggregator); // todo: check isnt memory leak here?
}
return repositoryAggregator;
}
}

View File

@ -2,6 +2,7 @@ import {Connection} from "../connection/Connection";
import {EntityManager} from "./EntityManager";
import {MongoEntityManager} from "./MongoEntityManager";
import {MongoDriver} from "../driver/mongodb/MongoDriver";
import {QueryRunnerProvider} from "../query-runner/QueryRunnerProvider";
/**
* Helps to create entity managers.
@ -11,11 +12,11 @@ export class EntityManagerFactory {
/**
* Creates a new entity manager depend on a given connection's driver.
*/
create(connection: Connection): EntityManager {
create(connection: Connection, queryRunnerProvider?: QueryRunnerProvider): EntityManager {
if (connection.driver instanceof MongoDriver)
return new MongoEntityManager(connection);
return new MongoEntityManager(connection, queryRunnerProvider);
return new EntityManager(connection);
return new EntityManager(connection, queryRunnerProvider);
}
}

View File

@ -0,0 +1,16 @@
import {LoggerOptions} from "./LoggerOptions";
import {Logger} from "./Logger";
/**
* Helps to create logger instances.
*/
export class LoggerFactory {
/**
* Creates a new logger depend on a given connection's driver.
*/
create(options: LoggerOptions): Logger {
return new Logger(options);
}
}

View File

@ -14,6 +14,8 @@ import {TableMetadataArgs} from "../metadata-args/TableMetadataArgs";
import {Connection} from "../connection/Connection";
import {EntityListenerMetadata} from "./EntityListenerMetadata";
import {PropertyTypeFactory} from "./types/PropertyTypeInFunction";
import {Repository} from "../repository/Repository";
import {SpecificRepository} from "../repository/SpecificRepository";
/**
* Contains all entity metadata.
@ -24,6 +26,16 @@ export class EntityMetadata {
// Properties
// -------------------------------------------------------------------------
/**
* Repository used for this entity metadata.
*/
repository: Repository<any>;
/**
* Specific repository used for this entity metadata.
*/
specificRepository: SpecificRepository<any>;
/**
* Used to wrap lazy relations.
*/

View File

@ -1,57 +0,0 @@
import {Repository} from "./Repository";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {SpecificRepository} from "./SpecificRepository";
import {Connection} from "../connection/Connection";
import {TreeRepository} from "./TreeRepository";
import {QueryRunnerProvider} from "../query-runner/QueryRunnerProvider";
import {RepositoryFactory} from "./RepositoryFactory";
import {getFromContainer} from "../container";
/**
* Aggregates all repositories of the specific metadata.
*/
export class RepositoryAggregator {
// -------------------------------------------------------------------------
// Public Readonly properties
// -------------------------------------------------------------------------
/**
* Entity metadata which owns repositories.
*/
public readonly metadata: EntityMetadata;
/**
* Ordinary repository.
*/
public readonly repository: Repository<any>;
/**
* Tree repository.
*/
public readonly treeRepository?: TreeRepository<any>;
/**
* Repository with specific functions.
*/
public readonly specificRepository: SpecificRepository<any>;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider) {
this.metadata = metadata;
const factory = getFromContainer(RepositoryFactory);
if (metadata.isClosure) {
this.repository = this.treeRepository = factory.createTreeRepository(connection.manager, metadata, queryRunnerProvider);
} else {
this.repository = factory.createRepository(connection.manager, metadata, queryRunnerProvider);
}
this.specificRepository = factory.createSpecificRepository(connection, metadata, queryRunnerProvider);
}
}

View File

@ -20,34 +20,32 @@ export class RepositoryFactory {
/**
* Creates a regular repository.
*/
createRepository(manager: EntityManager, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): Repository<any> {
createRepository(connection: Connection, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): Repository<any> {
if (metadata.isClosure) {
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
const repository = new TreeRepository<any>();
(repository as any)["manager"] = connection.manager;
(repository as any)["metadata"] = metadata;
(repository as any)["queryRunnerProvider"] = queryRunnerProvider;
return repository;
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
let repository: Repository<any>;
if (manager.connection.driver instanceof MongoDriver) {
repository = new MongoRepository();
} else {
repository = new Repository<any>();
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
let repository: Repository<any>;
if (connection.driver instanceof MongoDriver) {
repository = new MongoRepository();
} else {
repository = new Repository<any>();
}
(repository as any)["manager"] = connection.manager;
(repository as any)["metadata"] = metadata;
(repository as any)["queryRunnerProvider"] = queryRunnerProvider;
return repository;
}
(repository as any)["manager"] = manager;
(repository as any)["metadata"] = metadata;
(repository as any)["queryRunnerProvider"] = queryRunnerProvider;
return repository;
}
/**
* Creates a tree repository.
*/
createTreeRepository(manager: EntityManager, metadata: EntityMetadata, queryRunnerProvider?: QueryRunnerProvider): TreeRepository<any> {
// NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed,
// however we need these properties for internal work of the class
const repository = new TreeRepository<any>();
(repository as any)["manager"] = manager;
(repository as any)["metadata"] = metadata;
(repository as any)["queryRunnerProvider"] = queryRunnerProvider;
return repository;
}
/**

View File

@ -2,10 +2,10 @@ import {ObjectLiteral} from "../common/ObjectLiteral";
export class OrmUtils {
static splitStringsAndClasses<T>(strAndClses: string[]|T[]): [string[], T[]] {
static splitClassesAndStrings<T>(clsesAndStrings: T[]|string[]): [T[], string[]] {
return [
(strAndClses as string[]).filter(str => typeof str === "string"),
(strAndClses as T[]).filter(cls => typeof cls !== "string"),
(clsesAndStrings as T[]).filter(cls => typeof cls !== "string"),
(clsesAndStrings as string[]).filter(str => typeof str === "string"),
];
}

View File

@ -4,19 +4,26 @@ import {expect} from "chai";
import {setupTestingConnections} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {getConnectionManager} from "../../../src/index";
import {ConnectionMetadataBuilder} from "../../../src/connection/ConnectionMetadataBuilder";
import {EntityMetadataValidator} from "../../../src/metadata-builder/EntityMetadataValidator";
const should = chai.should();
describe("entity-metadata-validator", () => {
let connections: Connection[];
before(() => {
connections = setupTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"] })
.map(options => getConnectionManager().create(options));
it("should throw error if relation count decorator used with ManyToOne or OneToOne relations", () => {
const connection = new Connection({ // dummy connection options, connection won't be established anyway
type: "mysql",
host: "localhost",
username: "test",
password: "test",
database: "test",
entities: [__dirname + "/entity/*{.js,.ts}"]
});
const connectionMetadataBuilder = new ConnectionMetadataBuilder(connection);
const entityMetadatas = connectionMetadataBuilder.buildEntityMetadatas([__dirname + "/entity/*{.js,.ts}"], []);
const entityMetadataValidator = new EntityMetadataValidator();
expect(() => entityMetadataValidator.validateMany(entityMetadatas)).to.throw(Error);
});
it("should throw error if relation count decorator used with ManyToOne or OneToOne relations", () => Promise.all(connections.map(async connection => {
expect(() => connection.buildMetadatas()).to.throw(Error);
})));
});

View File

@ -3,7 +3,10 @@ import {Post} from "./entity/Post";
import {Counters} from "./entity/Counters";
import {Connection} from "../../../src/connection/Connection";
import {expect} from "chai";
import {setupTestingConnections} from "../../utils/test-utils";
import {
closeTestingConnections, createTestingConnections, reloadTestingDatabases,
setupTestingConnections
} from "../../utils/test-utils";
import {Subcounters} from "./entity/Subcounters";
import {User} from "./entity/User";
import {getConnectionManager} from "../../../src/index";
@ -11,14 +14,13 @@ import {getConnectionManager} from "../../../src/index";
describe("entity-metadata > property-map", () => {
let connections: Connection[];
before(() => {
connections = setupTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"] })
.map(options => getConnectionManager().create(options))
.map(connection => {
connection.buildMetadatas();
return connection;
});
});
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchemaOnConnection: true,
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should create correct property map object", () => Promise.all(connections.map(async connection => {

View File

@ -1,7 +1,10 @@
import "reflect-metadata";
import * as chai from "chai";
import {expect} from "chai";
import {setupTestingConnections} from "../../../utils/test-utils";
import {
closeTestingConnections, createTestingConnections, reloadTestingDatabases,
setupTestingConnections
} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
import {Counters} from "./entity/Counters";
@ -11,16 +14,15 @@ import {getConnectionManager} from "../../../../src/index";
const should = chai.should();
describe("metadata-builder > ColumnMetadata", () => {
let connections: Connection[];
before(() => {
connections = setupTestingConnections({ entities: [__dirname + "/entity/*{.js,.ts}"] })
.map(options => getConnectionManager().create(options))
.map(connection => {
connection.buildMetadatas();
return connection;
});
});
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchemaOnConnection: true,
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("getValue", () => Promise.all(connections.map(async connection => {
const post = new Post();

View File

@ -1,23 +1,25 @@
import "reflect-metadata";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
import {Logger} from "../../../src/logger/Logger";
import {expect} from "chai";
import {Connection} from "../../../src/connection/Connection";
describe("github issues > #114 Can not be parsed correctly the URL of pg.", () => {
let driver: PostgresDriver;
before(() => driver = new PostgresDriver(new Connection({
type: "postgres",
url: "postgres://test:test@localhost:5432/test",
})));
let driver: PostgresDriver, connection: Connection;
before(() => {
connection = new Connection({
type: "postgres",
url: "postgres://test:test@localhost:5432/test",
});
driver = new PostgresDriver(connection);
});
it("should not fail in url parser", () => {
expect(driver.options.username).to.be.eq("test");
expect(driver.options.password).to.be.eq("test");
expect(driver.options.host).to.be.eq("localhost");
expect(driver.options.port).to.be.eq(5432);
expect(driver.options.database).to.be.eq("test");
expect(connection.options.username).to.be.eq("test");
expect(connection.options.password).to.be.eq("test");
expect(connection.options.host).to.be.eq("localhost");
expect(connection.options.port).to.be.eq(5432);
expect(connection.options.database).to.be.eq("test");
});
});