removed naming strategy stuff, refactoring connection

This commit is contained in:
Umed Khudoiberdiev 2017-06-07 18:09:05 +05:00
parent c5a35d04a4
commit 365055c6ff
29 changed files with 219 additions and 397 deletions

View File

@ -26,6 +26,9 @@ each for its own `findOne*` or `find*` methods
* custom repositories do not support container anymore
* added ActiveRecord support (by extending EntityModel) class
* controller / subscriber / migrations from options tsconfig now appended with a project root directory
* removed naming strategy decorator, naming strategy by name functionality.
Now naming strategy should be registered by passing naming strategy instance directly
* driver options now deprecated in connection options
### NEW FEATURES

View File

@ -75,10 +75,13 @@
},
"dependencies": {
"app-root-path": "^2.0.1",
"dotenv": "^4.0.0",
"glob": "^7.1.1",
"js-yaml": "^3.8.4",
"reflect-metadata": "^0.1.10",
"yargonaut": "^1.1.2",
"yargs": "^8.0.1"
"yargs": "^8.0.1",
"xml2js": "^0.4.17"
},
"scripts": {
"test": "node_modules/.bin/gulp tests"

View File

@ -13,9 +13,8 @@ const options: ConnectionOptions = {
database: "test"
},
autoSchemaSync: true,
usedNamingStrategy: "custom_strategy",
entities: [Post],
namingStrategies: [CustomNamingStrategy]
namingStrategy: new CustomNamingStrategy(),
entities: [Post]
};
createConnection(options).then(connection => {

View File

@ -1,9 +1,7 @@
import {NamingStrategyInterface} from "../../../src/naming-strategy/NamingStrategyInterface";
import {NamingStrategy} from "../../../src/decorator/NamingStrategy";
import {DefaultNamingStrategy} from "../../../src/naming-strategy/DefaultNamingStrategy";
import {snakeCase} from "../../../src/util/StringUtils";
@NamingStrategy("custom_strategy")
export class CustomNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface {
tableName(targetName: string, userSpecifiedName: string): string {

View File

@ -13,7 +13,6 @@ import {CannotCloseNotConnectedError} from "./error/CannotCloseNotConnectedError
import {CannotConnectAlreadyConnectedError} from "./error/CannotConnectAlreadyConnectedError";
import {TreeRepository} from "../repository/TreeRepository";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {NamingStrategyNotFoundError} from "./error/NamingStrategyNotFoundError";
import {RepositoryNotTreeError} from "./error/RepositoryNotTreeError";
import {EntitySchema} from "../entity-schema/EntitySchema";
import {CannotSyncNotConnectedError} from "./error/CannotSyncNotConnectedError";
@ -31,10 +30,6 @@ import {MigrationInterface} from "../migration/MigrationInterface";
import {MigrationExecutor} from "../migration/MigrationExecutor";
import {CannotRunMigrationNotConnectedError} from "./error/CannotRunMigrationNotConnectedError";
import {PlatformTools} from "../platform/PlatformTools";
import {AbstractRepository} from "../repository/AbstractRepository";
import {CustomRepositoryNotFoundError} from "../repository/error/CustomRepositoryNotFoundError";
import {CustomRepositoryReusedError} from "../repository/error/CustomRepositoryReusedError";
import {CustomRepositoryCannotInheritRepositoryError} from "../repository/error/CustomRepositoryCannotInheritRepositoryError";
import {MongoRepository} from "../repository/MongoRepository";
import {MongoDriver} from "../driver/mongodb/MongoDriver";
import {MongoEntityManager} from "../entity-manager/MongoEntityManager";
@ -42,7 +37,8 @@ import {EntitySchemaTransformer} from "../entity-schema/EntitySchemaTransformer"
import {EntityMetadataValidator} from "../metadata-builder/EntityMetadataValidator";
/**
* Connection is a single database connection to a specific database of a database management system.
* Connection is a single database ORM connection to a specific DBMS database.
* Its not required to be a database connection, depend on database type it can create connection pool.
* You can have multiple connections to multiple databases in your application.
*/
export class Connection {
@ -54,31 +50,17 @@ export class Connection {
/**
* Connection name.
*/
public readonly name: string;
readonly name: string;
/**
* Indicates if connection is initialized or not.
*/
readonly isConnected = false;
/**
* Database driver used by this connection.
*/
public readonly driver: Driver;
/**
* Logger used to log orm events.
*/
public readonly logger: Logger;
/**
* All entity metadatas that are registered for this connection.
*/
public readonly entityMetadatas: EntityMetadata[] = [];
/**
* Used to broadcast connection events.
*/
public readonly broadcaster: Broadcaster;
// -------------------------------------------------------------------------
// Private Properties
// -------------------------------------------------------------------------
readonly driver: Driver;
/**
* Gets EntityManager of this connection.
@ -86,54 +68,63 @@ export class Connection {
readonly manager: EntityManager;
/**
* Stores all registered repositories.
* Logger used to log orm events.
*/
private readonly repositoryAggregators: RepositoryAggregator[] = [];
readonly logger: Logger;
/**
* Stores all entity repository instances.
* Naming strategy used in the connection.
*/
private readonly entityRepositories: Object[] = [];
readonly namingStrategy = new DefaultNamingStrategy();
/**
* All entity metadatas that are registered for this connection.
*/
readonly entityMetadatas: EntityMetadata[] = [];
/**
* Used to broadcast connection events.
*/
readonly broadcaster: Broadcaster;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
readonly lazyRelationsWrapper = new LazyRelationsWrapper(this);
// -------------------------------------------------------------------------
// Private Properties
// -------------------------------------------------------------------------
/**
* Stores all registered repositories.
*/
private repositoryAggregators: RepositoryAggregator[] = [];
/**
* Entity subscribers that are registered for this connection.
*/
private readonly entitySubscribers: EntitySubscriberInterface<any>[] = [];
private entitySubscribers: EntitySubscriberInterface<any>[] = [];
/**
* Registered entity classes to be used for this connection.
*/
private readonly entityClasses: Function[] = [];
private entityClasses: Function[] = [];
/**
* Registered entity schemas to be used for this connection.
*/
private readonly entitySchemas: EntitySchema[] = [];
private entitySchemas: EntitySchema[] = [];
/**
* Registered subscriber classes to be used for this connection.
*/
private readonly subscriberClasses: Function[] = [];
/**
* Registered naming strategy classes to be used for this connection.
*/
private readonly namingStrategyClasses: Function[] = [];
private subscriberClasses: Function[] = [];
/**
* Registered migration classes to be used for this connection.
*/
private readonly migrationClasses: Function[] = [];
/**
* Naming strategy to be used in this connection.
*/
private usedNamingStrategy: Function|string;
/**
* Indicates if connection has been done or not.
*/
private _isConnected = false;
private migrationClasses: Function[] = [];
// -------------------------------------------------------------------------
// Constructor
@ -143,33 +134,19 @@ export class Connection {
this.name = name;
this.driver = driver;
this.logger = logger;
this.broadcaster = new Broadcaster(this, this.entitySubscribers);
this.manager = this.createEntityManager();
this.broadcaster = this.createBroadcaster();
}
// -------------------------------------------------------------------------
// Accessors
// -------------------------------------------------------------------------
/**
* Indicates if connection to the database already established for this connection.
*/
get isConnected(): boolean {
return this._isConnected;
}
/**
* Gets entity manager that allows to perform repository operations with any entity in this connection.
*
* @deprecated use manager instead.
*/
get entityManager(): EntityManager {
return this.manager;
}
/**
* Gets the mongodb entity manager that allows to perform mongodb-specific repository operations
* with any entity in this connection.
*
* Available only in mongodb connections.
*/
get mongoEntityManager(): MongoEntityManager {
if (!(this.manager instanceof MongoEntityManager))
@ -184,6 +161,9 @@ export class Connection {
/**
* Performs connection to the database.
* This method should be called once on application bootstrap.
* This method not necessarily creates database connection (depend on database type),
* but it also can setup a connection pool with database to use.
*/
async connect(): Promise<this> {
if (this.isConnected)
@ -193,7 +173,7 @@ export class Connection {
await this.driver.connect();
// set connected status for the current connection
this._isConnected = true;
Object.assign(this, { isConnected: true });
// build all metadatas registered in the current connection
try {
@ -212,23 +192,14 @@ export class Connection {
/**
* Closes connection with the database.
* Once connection is closed, you cannot use repositories and perform any operations except
* opening connection again.
* Once connection is closed, you cannot use repositories or perform any operations except opening connection again.
*/
async close(): Promise<void> {
if (!this.isConnected)
throw new CannotCloseNotConnectedError(this.name);
await this.driver.disconnect();
this._isConnected = false;
}
/**
* Drops the database and all its data.
*/
async dropDatabase(): Promise<void> {
const queryRunner = await this.driver.createQueryRunner();
await queryRunner.clearDatabase();
Object.assign(this, { isConnected: false });
}
/**
@ -248,10 +219,20 @@ export class Connection {
await this.driver.syncSchema(this.entityMetadatas);
} else {
await this.createSchemaBuilder().build();
const schemaBuilder = new SchemaBuilder(this.driver, this.logger, this.entityMetadatas);
await schemaBuilder.build();
}
}
/**
* Drops the database and all its data.
* Be careful with this method on production since this method will erase all your database tables and data inside them.
*/
async dropDatabase(): Promise<void> {
const queryRunner = await this.driver.createQueryRunner();
await queryRunner.clearDatabase();
}
/**
* Runs all pending migrations.
*/
@ -300,14 +281,6 @@ export class Connection {
return this;
}
/**
* Imports naming strategies from the given paths (directories) and registers them in the current connection.
*/
importNamingStrategiesFromDirectories(paths: string[]): this {
this.importNamingStrategies(importClassesFromDirectories(paths));
return this;
}
/**
* Imports migrations from the given paths (directories) and registers them in the current connection.
*/
@ -349,17 +322,6 @@ export class Connection {
return this;
}
/**
* Imports naming strategies and registers them in the current connection.
*/
importNamingStrategies(strategies: Function[]): this {
if (this.isConnected)
throw new CannotImportAlreadyConnectedError("naming strategies", this.name);
strategies.forEach(cls => this.namingStrategyClasses.push(cls));
return this;
}
/**
* Imports migrations and registers them in the current connection.
*/
@ -375,23 +337,11 @@ export class Connection {
* Sets given naming strategy to be used.
* Naming strategy must be set to be used before connection is established.
*/
useNamingStrategy(name: string): this;
/**
* Sets given naming strategy to be used.
* Naming strategy must be set to be used before connection is established.
*/
useNamingStrategy(strategy: Function): this;
/**
* Sets given naming strategy to be used.
* Naming strategy must be set to be used before connection is established.
*/
useNamingStrategy(strategyClassOrName: string|Function): this {
useNamingStrategy(namingStrategy: NamingStrategyInterface): this {
if (this.isConnected)
throw new CannotUseNamingStrategyNotConnectedError(this.name);
this.usedNamingStrategy = strategyClassOrName;
Object.assign(this, { namingStrategy: namingStrategy });
return this;
}
@ -570,6 +520,19 @@ export class Connection {
return this.manager.getCustomRepository(customRepository);
}
// -------------------------------------------------------------------------
// Deprecated
// -------------------------------------------------------------------------
/**
* Gets entity manager that allows to perform repository operations with any entity in this connection.
*
* @deprecated use manager instead.
*/
get entityManager(): EntityManager {
return this.manager;
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
@ -601,12 +564,12 @@ export class Connection {
this.repositoryAggregators.length = 0;
this.entityMetadatas.length = 0;
this.driver.namingStrategy = this.createNamingStrategy(); // todo: why they are in the driver
this.driver.lazyRelationsWrapper = this.createLazyRelationsWrapper(); // todo: why they are in the driver
const entityMetadataValidator = new EntityMetadataValidator();
// take imported event subscribers
if (this.subscriberClasses && this.subscriberClasses.length && !PlatformTools.getEnvVariable("SKIP_SUBSCRIBERS_LOADING")) {
if (this.subscriberClasses &&
this.subscriberClasses.length &&
!PlatformTools.getEnvVariable("SKIP_SUBSCRIBERS_LOADING")) {
getMetadataArgsStorage()
.filterSubscribers(this.subscriberClasses)
.map(metadata => getFromContainer(metadata.target))
@ -639,34 +602,6 @@ export class Connection {
entityMetadataValidator.validateMany(this.entityMetadatas);
}
/**
* Creates a naming strategy to be used for this connection.
*/
protected createNamingStrategy(): NamingStrategyInterface {
// if naming strategies are not loaded, or used naming strategy is not set then use default naming strategy
if (!this.namingStrategyClasses || !this.namingStrategyClasses.length || !this.usedNamingStrategy)
return getFromContainer(DefaultNamingStrategy);
// try to find used naming strategy in the list of loaded naming strategies
const namingMetadata = getMetadataArgsStorage()
.filterNamingStrategies(this.namingStrategyClasses)
.find(strategy => {
if (typeof this.usedNamingStrategy === "string") {
return strategy.name === this.usedNamingStrategy;
} else {
return strategy.target === this.usedNamingStrategy;
}
});
// throw an error if not found
if (!namingMetadata)
throw new NamingStrategyNotFoundError(this.usedNamingStrategy, this.name);
// initialize a naming strategy instance
return getFromContainer<NamingStrategyInterface>(namingMetadata.target);
}
/**
* Creates a new default entity manager without single connection setup.
*/
@ -677,25 +612,4 @@ export class Connection {
return new EntityManager(this);
}
/**
* Creates a new entity broadcaster using in this connection.
*/
protected createBroadcaster() {
return new Broadcaster(this, this.entitySubscribers);
}
/**
* Creates a schema builder used to build a database schema for the entities of the current connection.
*/
protected createSchemaBuilder() {
return new SchemaBuilder(this.driver, this.logger, this.entityMetadatas);
}
/**
* Creates a lazy relations wrapper.
*/
protected createLazyRelationsWrapper() {
return new LazyRelationsWrapper(this);
}
}

View File

@ -65,7 +65,7 @@ export class ConnectionManager {
create(options: ConnectionOptions): Connection {
const logger = new Logger(options.logging || {});
const driver = this.createDriver(options.driver, logger);
const driver = this.createDriver(options.driver || {} as DriverOptions, logger); // || {} is temporary
const connection = this.createConnection(options.name || "default", driver, logger);
// import entity schemas
@ -92,14 +92,6 @@ export class ConnectionManager {
.importSubscribersFromDirectories(directories);
}
// import naming strategies
if (options.namingStrategies) {
const [directories, classes] = this.splitStringsAndClasses(options.namingStrategies);
connection
.importNamingStrategies(classes)
.importNamingStrategiesFromDirectories(directories);
}
// import migrations
if (options.migrations) {
const [directories, classes] = this.splitStringsAndClasses(options.migrations);
@ -109,8 +101,8 @@ export class ConnectionManager {
}
// set naming strategy to be used for this connection
if (options.usedNamingStrategy)
connection.useNamingStrategy(options.usedNamingStrategy as any);
if (options.namingStrategy)
connection.useNamingStrategy(options.namingStrategy);
return connection;
}
@ -341,8 +333,6 @@ export class ConnectionManager {
entities: PlatformTools.getEnvVariable("TYPEORM_ENTITIES") ? PlatformTools.getEnvVariable("TYPEORM_ENTITIES").split(",") : [],
subscribers: PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS") ? PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS").split(",") : [],
entitySchemas: PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS") ? PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS").split(",") : [],
namingStrategies: PlatformTools.getEnvVariable("TYPEORM_NAMING_STRATEGIES") ? PlatformTools.getEnvVariable("TYPEORM_NAMING_STRATEGIES").split(",") : [],
usedNamingStrategy: PlatformTools.getEnvVariable("TYPEORM_USED_NAMING_STRATEGY"),
logging: {
logQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_QUERIES")),
logFailedQueryError: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_FAILED_QUERIES")),
@ -415,14 +405,6 @@ export class ConnectionManager {
return migration;
});
}
if (options.namingStrategies) {
options.namingStrategies = (options.namingStrategies as any[]).map(namingStrategy => {
if (typeof namingStrategy === "string" || namingStrategy.substr(0, 1) !== "/")
return PlatformTools.load("app-root-path").path + "/" + namingStrategy;
return namingStrategy;
});
}
return this.createAndConnectByConnectionOptions(options);
}

View File

@ -1,6 +1,8 @@
import {DriverOptions} from "../driver/DriverOptions";
import {EntitySchema} from "../entity-schema/EntitySchema";
import {LoggerOptions} from "../logger/LoggerOptions";
import {NamingStrategyInterface} from "../naming-strategy/NamingStrategyInterface";
import {DriverType} from "../driver/DriverType";
/**
* ConnectionOptions is an interface with settings and options for specific connection.
@ -9,11 +11,6 @@ import {LoggerOptions} from "../logger/LoggerOptions";
*/
export interface ConnectionOptions {
/**
* Database options of this connection.
*/
driver: DriverOptions;
/**
* Connection name. If connection name is not given then it will be called "default".
* Different connections must have different names.
@ -21,9 +18,87 @@ export interface ConnectionOptions {
name?: string;
/**
* Name of the naming strategy or target class of the naming strategy to be used for this connection.
* Database options of this connection.
*
* @deprecated Define options right in the connection options section.
*/
usedNamingStrategy?: string|Function;
driver?: DriverOptions;
/**
* Database type. This value is required.
*/
type?: DriverType;
/**
* Connection url to where perform connection to.
*/
url?: string;
/**
* Database host.
*/
host?: string;
/**
* Database host port.
*/
port?: number;
/**
* Database username.
*/
username?: string;
/**
* Database password.
*/
password?: string;
/**
* Database name to connect to.
*/
database?: string;
/**
* Schema name. By default is "public" (used only in Postgres databases).
*/
schemaName?: string;
/**
* Connection SID (used for Oracle databases).
*/
sid?: string;
/**
* Storage type or path to the storage (used for SQLite databases).
*/
storage?: string;
/**
* Indicates if connection pooling should be used or not.
* Be default it is enabled if its supported by a platform.
* Set to false to disable it.
*
* @todo: rename to disablePool? What about mongodb pool?
*/
usePool?: boolean;
/**
* Extra connection options to be passed to the underlying driver.
*/
extra?: any;
/**
* Prefix to use on all tables (collections) of this connection in the database.
*
* @todo: rename to entityPrefix
*/
tablesPrefix?: string;
/**
* Naming strategy to be used to name tables and columns in the database.
*/
namingStrategy?: NamingStrategyInterface;
/**
* Entities to be loaded for this connection.
@ -39,13 +114,6 @@ export interface ConnectionOptions {
*/
subscribers?: Function[]|string[];
/**
* Naming strategies to be loaded for this connection.
* Accepts both naming strategy classes and directories where from naming strategies need to be loaded.
* Directories support glob patterns.
*/
namingStrategies?: Function[]|string[];
/**
* Entity schemas to be loaded for this connection.
* Accepts both entity schema classes and directories where from entity schemas need to be loaded.

View File

@ -1,19 +0,0 @@
import {getMetadataArgsStorage} from "../index";
import {NamingStrategyMetadataArgs} from "../metadata-args/NamingStrategyMetadataArgs";
/**
* Decorator registers a new naming strategy to be used in naming things.
*
* todo: deprecate using naming strategies this way. use it without decorators
* todo: but add multiple default naming strategies for use
*/
export function NamingStrategy(name?: string): Function {
return function (target: Function) {
const strategyName = name ? name : (<any> target).name;
const args: NamingStrategyMetadataArgs = {
target: target,
name: strategyName
};
getMetadataArgsStorage().namingStrategies.push(args);
};
}

View File

@ -10,16 +10,6 @@ import {LazyRelationsWrapper} from "../lazy-loading/LazyRelationsWrapper";
*/
export interface Driver {
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver options contains connectivity options used to connection to the database.
*/

View File

@ -1,7 +1,4 @@
/**
* Driver type.
*/
export type DriverType = "mysql"|"postgres"|"mariadb"|"sqlite"|"oracle"|"mssql"|"websql"|"mongodb";
import {DriverType} from "./DriverType";
/**
* Connectivity options used to connect to the database, and other database-driver-specific options.
@ -11,52 +8,52 @@ export interface DriverOptions {
/**
* Database type. This value is required.
*/
readonly type: DriverType;
type: DriverType;
/**
* Connection url to where perform connection to.
*/
readonly url?: string;
url?: string;
/**
* Database host.
*/
readonly host?: string;
host?: string;
/**
* Database host port.
*/
readonly port?: number;
port?: number;
/**
* Database username.
*/
readonly username?: string;
username?: string;
/**
* Database password.
*/
readonly password?: string;
password?: string;
/**
* Database name to connect to.
*/
readonly database?: string;
database?: string;
/**
* Schema name. By default is "public" (used only in Postgres databases).
*/
readonly schemaName?: string;
schemaName?: string;
/**
* Connection SID (used for Oracle databases).
*/
readonly sid?: string;
sid?: string;
/**
* Storage type or path to the storage (used for SQLite databases).
*/
readonly storage?: string;
storage?: string;
/**
* Indicates if connection pooling should be used or not.
@ -65,18 +62,18 @@ export interface DriverOptions {
*
* @todo: rename to disablePool? What about mongodb pool?
*/
readonly usePool?: boolean;
usePool?: boolean;
/**
* Extra connection options to be passed to the underlying driver.
*/
readonly extra?: any;
extra?: any;
/**
* Prefix to use on all tables (collections) of this connection in the database.
*
* @todo: rename to entityPrefix
*/
readonly tablesPrefix?: string;
tablesPrefix?: string;
}

4
src/driver/DriverType.ts Normal file
View File

@ -0,0 +1,4 @@
/**
* Driver type.
*/
export type DriverType = "mysql"|"postgres"|"mariadb"|"sqlite"|"oracle"|"mssql"|"websql"|"mongodb";

View File

@ -23,16 +23,6 @@ export class MongoDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Mongodb does not require to dynamically create query runner each time,
* because it does not have a regular pool.

View File

@ -25,16 +25,6 @@ export class MysqlDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

View File

@ -27,16 +27,6 @@ export class OracleDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

View File

@ -30,16 +30,6 @@ export class PostgresDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

View File

@ -24,16 +24,6 @@ export class SqliteDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

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 {RandomGenerator} from "../../util/RandomGenerator";
/**
* Runs queries on a single sqlite database connection.
@ -316,7 +317,10 @@ 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.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);
return new ForeignKeySchema(keyName, [foreignKey["from"]], [foreignKey["to"]], foreignKey["table"], foreignKey["on_delete"]); // todo: how sqlite return from and to when they are arrays? (multiple column foreign keys)
});
tableSchema.addForeignKeys(columnForeignKeys);

View File

@ -25,16 +25,6 @@ export class SqlServerDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

View File

@ -28,16 +28,6 @@ export class WebsqlDriver implements Driver {
// Public Properties
// -------------------------------------------------------------------------
/**
* Naming strategy used in the connection where this driver is used.
*/
namingStrategy: NamingStrategyInterface;
/**
* Used to wrap lazy relations to be able to perform lazy loadings.
*/
lazyRelationsWrapper: LazyRelationsWrapper;
/**
* Driver connection options.
*/

View File

@ -65,7 +65,6 @@ export * from "./decorator/tree/TreeLevelColumn";
export * from "./decorator/tree/TreeParent";
export * from "./decorator/tree/TreeChildren";
export * from "./decorator/Index";
export * from "./decorator/NamingStrategy";
export * from "./decorator/Embedded";
export * from "./decorator/DiscriminatorValue";
export * from "./decorator/EntityRepository";

View File

@ -157,7 +157,7 @@ export class EntityMetadataBuilder {
// build all indices (need to do it after relations and their join columns are built)
entityMetadatas.forEach(entityMetadata => {
entityMetadata.indices.forEach(index => index.build(this.connection.driver.namingStrategy));
entityMetadata.indices.forEach(index => index.build(this.connection.namingStrategy));
});
entityMetadatas
@ -165,7 +165,7 @@ export class EntityMetadataBuilder {
.forEach(metadata => {
const parentPrimaryColumns = metadata.parentEntityMetadata.primaryColumns;
const parentRelationColumns = parentPrimaryColumns.map(parentPrimaryColumn => {
const columnName = this.connection.driver.namingStrategy.classTableInheritanceParentColumnName(metadata.parentEntityMetadata.tableName, parentPrimaryColumn.propertyPath);
const columnName = this.connection.namingStrategy.classTableInheritanceParentColumnName(metadata.parentEntityMetadata.tableName, parentPrimaryColumn.propertyPath);
const column = new ColumnMetadata({
entityMetadata: metadata,
referencedColumn: parentPrimaryColumn,
@ -183,7 +183,7 @@ export class EntityMetadataBuilder {
}
});
metadata.registerColumn(column);
column.build(this.connection.driver.namingStrategy);
column.build(this.connection.namingStrategy);
return column;
});
@ -191,7 +191,7 @@ export class EntityMetadataBuilder {
new ForeignKeyMetadata({
entityMetadata: metadata,
referencedEntityMetadata: metadata.parentEntityMetadata,
namingStrategy: this.connection.driver.namingStrategy,
namingStrategy: this.connection.namingStrategy,
columns: parentRelationColumns,
referencedColumns: parentPrimaryColumns,
onDelete: "CASCADE"
@ -206,7 +206,7 @@ export class EntityMetadataBuilder {
entityMetadata.relations
.filter(relation => relation.isLazy)
.forEach(relation => {
this.connection.driver.lazyRelationsWrapper.wrap((entityMetadata.target as Function).prototype, relation);
this.connection.lazyRelationsWrapper.wrap((entityMetadata.target as Function).prototype, relation);
});
});
@ -307,12 +307,12 @@ export class EntityMetadataBuilder {
* Computes all entity metadata's computed properties, and all its sub-metadatas (relations, columns, embeds, etc).
*/
protected computeEntityMetadata(entityMetadata: EntityMetadata) {
entityMetadata.embeddeds.forEach(embedded => embedded.build(this.connection.driver.namingStrategy));
entityMetadata.embeddeds.forEach(embedded => embedded.build(this.connection.namingStrategy));
entityMetadata.embeddeds.forEach(embedded => {
embedded.columnsFromTree.forEach(column => column.build(this.connection.driver.namingStrategy));
embedded.columnsFromTree.forEach(column => column.build(this.connection.namingStrategy));
embedded.relationsFromTree.forEach(relation => relation.build());
});
entityMetadata.ownColumns.forEach(column => column.build(this.connection.driver.namingStrategy));
entityMetadata.ownColumns.forEach(column => column.build(this.connection.namingStrategy));
entityMetadata.ownRelations.forEach(relation => relation.build());
entityMetadata.relations = entityMetadata.embeddeds.reduce((relations, embedded) => relations.concat(embedded.relationsFromTree), entityMetadata.ownRelations);
entityMetadata.oneToOneRelations = entityMetadata.relations.filter(relation => relation.isOneToOne);
@ -334,7 +334,7 @@ export class EntityMetadataBuilder {
entityMetadata.treeLevelColumn = entityMetadata.columns.find(column => column.isTreeLevel);
entityMetadata.parentIdColumns = entityMetadata.columns.filter(column => column.isParentId);
entityMetadata.objectIdColumn = entityMetadata.columns.find(column => column.isObjectId);
entityMetadata.foreignKeys.forEach(foreignKey => foreignKey.build(this.connection.driver.namingStrategy));
entityMetadata.foreignKeys.forEach(foreignKey => foreignKey.build(this.connection.namingStrategy));
entityMetadata.propertiesMap = entityMetadata.createPropertiesMap();
entityMetadata.relationIds.forEach(relationId => relationId.build());
entityMetadata.relationCounts.forEach(relationCount => relationCount.build());

View File

@ -30,7 +30,7 @@ export class JunctionEntityMetadataBuilder {
const referencedColumns = this.collectReferencedColumns(relation, joinTable);
const inverseReferencedColumns = this.collectInverseReferencedColumns(relation, joinTable);
const joinTableName = joinTable.name || this.connection.driver.namingStrategy.joinTableName(
const joinTableName = joinTable.name || this.connection.namingStrategy.joinTableName(
relation.entityMetadata.tableNameWithoutPrefix,
relation.inverseEntityMetadata.tableNameWithoutPrefix,
relation.propertyPath,
@ -52,7 +52,7 @@ export class JunctionEntityMetadataBuilder {
return (!joinColumnArgs.referencedColumnName || joinColumnArgs.referencedColumnName === referencedColumn.propertyName) &&
!!joinColumnArgs.name;
}) : undefined;
const columnName = joinColumn && joinColumn.name ? joinColumn.name : this.connection.driver.namingStrategy.joinTableColumnName(relation.entityMetadata.tableNameWithoutPrefix, referencedColumn.propertyName, referencedColumn.databaseName);
const columnName = joinColumn && joinColumn.name ? joinColumn.name : this.connection.namingStrategy.joinTableColumnName(relation.entityMetadata.tableNameWithoutPrefix, referencedColumn.propertyName, referencedColumn.databaseName);
return new ColumnMetadata({
entityMetadata: entityMetadata,
@ -78,7 +78,7 @@ export class JunctionEntityMetadataBuilder {
return (!joinColumnArgs.referencedColumnName || joinColumnArgs.referencedColumnName === inverseReferencedColumn.propertyName) &&
!!joinColumnArgs.name;
}) : undefined;
const columnName = joinColumn && joinColumn.name ? joinColumn.name : this.connection.driver.namingStrategy.joinTableColumnName(relation.inverseEntityMetadata.tableNameWithoutPrefix, inverseReferencedColumn.propertyName, inverseReferencedColumn.databaseName);
const columnName = joinColumn && joinColumn.name ? joinColumn.name : this.connection.namingStrategy.joinTableColumnName(relation.inverseEntityMetadata.tableNameWithoutPrefix, inverseReferencedColumn.propertyName, inverseReferencedColumn.databaseName);
return new ColumnMetadata({
entityMetadata: entityMetadata,

View File

@ -59,7 +59,7 @@ export class RelationJoinColumnBuilder {
return new ForeignKeyMetadata({
entityMetadata: relation.entityMetadata,
referencedEntityMetadata: relation.inverseEntityMetadata,
namingStrategy: this.connection.driver.namingStrategy,
namingStrategy: this.connection.namingStrategy,
columns: columns,
referencedColumns: referencedColumns,
onDelete: relation.onDelete,
@ -102,7 +102,7 @@ export class RelationJoinColumnBuilder {
return (!joinColumn.referencedColumnName || joinColumn.referencedColumnName === referencedColumn.propertyName) &&
!!joinColumn.name;
});
const joinColumnName = joinColumnMetadataArg ? joinColumnMetadataArg.name : this.connection.driver.namingStrategy.joinColumnName(relation.propertyName, referencedColumn.propertyName);
const joinColumnName = joinColumnMetadataArg ? joinColumnMetadataArg.name : this.connection.namingStrategy.joinColumnName(relation.propertyName, referencedColumn.propertyName);
let relationalColumn = relation.entityMetadata.ownColumns.find(column => column.databaseName === joinColumnName);
if (!relationalColumn) {
@ -125,7 +125,7 @@ export class RelationJoinColumnBuilder {
relationalColumn.referencedColumn = referencedColumn; // its important to set it here because we need to set referenced column for user defined join column
relationalColumn.type = referencedColumn.type; // also since types of relational column and join column must be equal we override user defined column type
relationalColumn.relationMetadata = relation;
relationalColumn.build(this.connection.driver.namingStrategy);
relationalColumn.build(this.connection.namingStrategy);
return relationalColumn;
});
}

View File

@ -342,9 +342,9 @@ export class EntityMetadata {
parentClosureEntityMetadata?: EntityMetadata,
args: TableMetadataArgs
}) {
const namingStrategy = options.connection.driver.namingStrategy;
const namingStrategy = options.connection.namingStrategy;
const tablesPrefix = options.connection.driver.options.tablesPrefix;
this.lazyRelationsWrapper = options.connection.driver.lazyRelationsWrapper;
this.lazyRelationsWrapper = options.connection.lazyRelationsWrapper;
this.parentClosureEntityMetadata = options.parentClosureEntityMetadata!;
this.target = options.args.target;
this.tableType = options.args.type;

View File

@ -13,7 +13,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
* @param targetName Name of the target entity that can be used to generate a table name.
* @param userSpecifiedName For example if user specified a table name in a decorator, e.g. @Entity("name")
*/
tableName(targetName: string, userSpecifiedName: string): string {
tableName(targetName: string, userSpecifiedName: string|undefined): string {
return userSpecifiedName ? userSpecifiedName : snakeCase(targetName);
}

View File

@ -22,6 +22,7 @@ import {Blog} from "./modules/blog/entity/Blog";
import {Question} from "./modules/question/entity/Question";
import {Video} from "./modules/video/entity/Video";
import {ConnectionOptions} from "../../../src/connection/ConnectionOptions";
import {DefaultNamingStrategy} from "../../../src/naming-strategy/DefaultNamingStrategy";
describe("Connection", () => {
const resourceDir = __dirname + "/../../../../../test/functional/connection/";
@ -127,11 +128,9 @@ describe("Connection", () => {
expect(() => connection.importEntities([Post])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importEntitySchemas([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importSubscribers([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importNamingStrategies([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importEntitiesFromDirectories([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importEntitySchemaFromDirectories([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importSubscribersFromDirectories([])).to.throw(Error); // CannotImportAlreadyConnectedError
expect(() => connection.importNamingStrategiesFromDirectories([])).to.throw(Error); // CannotImportAlreadyConnectedError
}));
it("should not be able to connect again", () => connections.forEach(connection => {
@ -139,7 +138,7 @@ describe("Connection", () => {
}));
it("should not be able to change used naming strategy", () => connections.forEach(connection => {
expect(() => connection.useNamingStrategy("something")).to.throw(Error); // CannotUseNamingStrategyNotConnectedError
expect(() => connection.useNamingStrategy(new DefaultNamingStrategy())).to.throw(Error); // CannotUseNamingStrategyNotConnectedError
}));
it("should be able to close a connection", async () => Promise.all(connections.map(connection => {
@ -295,7 +294,6 @@ describe("Connection", () => {
it("should successfully load entities / entity schemas / subscribers / naming strategies from directories", async () => {
connection.importEntitiesFromDirectories([__dirname + "/entity/*"]);
connection.importEntitySchemaFromDirectories([resourceDir + "/schema/*"]);
connection.importNamingStrategiesFromDirectories([__dirname + "/naming-strategy/*"]);
connection.importSubscribersFromDirectories([__dirname + "/subscriber/*"]);
await connection.connect();
connection.getRepository(Post).should.be.instanceOf(Repository);
@ -311,7 +309,6 @@ describe("Connection", () => {
it("should successfully load entities / entity schemas / subscribers / naming strategies from glob-patterned directories", async () => {
connection.importEntitiesFromDirectories([__dirname + "/modules/**/entity/*"]);
connection.importEntitySchemaFromDirectories([resourceDir + "/modules/**/schema/*"]);
connection.importNamingStrategiesFromDirectories([__dirname + "/modules/**/naming-strategy/*"]);
connection.importSubscribersFromDirectories([__dirname + "/modules/**/subscriber/*"]);
await connection.connect();
connection.getRepository(Blog).should.be.instanceOf(Repository);
@ -329,49 +326,6 @@ describe("Connection", () => {
});
});
describe("using naming strategy", function() {
let connection: Connection;
beforeEach(async () => {
connection = getConnectionManager().create(setupSingleTestingConnection("mysql", {
name: "default",
entities: []
}));
});
afterEach(() => connection.isConnected ? connection.close() : {});
it("should use naming strategy when its class passed to useNamingStrategy method", async () => {
connection.importEntities([Post]);
connection.importNamingStrategies([FirstCustomNamingStrategy]);
connection.useNamingStrategy(FirstCustomNamingStrategy);
await connection.connect();
connection.getMetadata(Post).tableName.should.be.equal("POST");
});
it("should use naming strategy when its name passed to useNamingStrategy method", async () => {
connection.importEntities([Category]);
connection.importNamingStrategies([SecondCustomNamingStrategy]);
connection.useNamingStrategy("secondCustomNamingStrategy");
await connection.connect();
connection.getMetadata(Category).tableName.should.be.equal("category");
});
it("should throw an error if not registered naming strategy was used (assert by name)", () => {
connection.importEntities([Category]);
connection.importNamingStrategies([FirstCustomNamingStrategy]);
connection.useNamingStrategy("secondCustomNamingStrategy");
return connection.connect().should.be.rejected; // NamingStrategyNotFoundError
});
it("should throw an error if not registered naming strategy was used (assert by Function)", () => {
connection.importEntities([Category]);
connection.importNamingStrategies([SecondCustomNamingStrategy]);
connection.useNamingStrategy(FirstCustomNamingStrategy);
return connection.connect().should.be.rejected; // NamingStrategyNotFoundError
});
});
describe("skip schema generation when skipSchemaSync option is used", function() {
let connections: Connection[];

View File

@ -1,8 +1,6 @@
import {DefaultNamingStrategy} from "../../../../src/naming-strategy/DefaultNamingStrategy";
import {NamingStrategy} from "../../../../src/decorator/NamingStrategy";
import {NamingStrategyInterface} from "../../../../src/naming-strategy/NamingStrategyInterface";
@NamingStrategy("firstCustomNamingStrategy")
export class FirstCustomNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface {
tableName(className: string, customName: string): string {

View File

@ -1,8 +1,6 @@
import {DefaultNamingStrategy} from "../../../../src/naming-strategy/DefaultNamingStrategy";
import {NamingStrategy} from "../../../../src/decorator/NamingStrategy";
import {NamingStrategyInterface} from "../../../../src/naming-strategy/NamingStrategyInterface";
@NamingStrategy("secondCustomNamingStrategy")
export class SecondCustomNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface {
tableName(className: string, customName: string): string {

View File

@ -1,8 +1,8 @@
import {ConnectionOptions} from "../../src/connection/ConnectionOptions";
import {createConnection, createConnections} from "../../src/index";
import {Connection} from "../../src/connection/Connection";
import {DriverType} from "../../src/driver/DriverOptions";
import {EntitySchema} from "../../src/entity-schema/EntitySchema";
import {DriverType} from "../../src/driver/DriverType";
/**
* Interface in which data is stored in ormconfig.json of the project.
@ -128,7 +128,7 @@ export function setupTestingConnections(options?: TestingOptions) {
return false;
if (options && options.enabledDrivers && options.enabledDrivers.length)
return options.enabledDrivers.indexOf(connectionOptions.driver.type) !== -1;
return options.enabledDrivers.indexOf(connectionOptions.driver!.type) !== -1; // ! is temporary
if (connectionOptions.disabledIfNotEnabledImplicitly === true)
return false;