diff --git a/lib/common/typeorm.decorators.ts b/lib/common/typeorm.decorators.ts index 6650d8920..87523e64a 100644 --- a/lib/common/typeorm.decorators.ts +++ b/lib/common/typeorm.decorators.ts @@ -1,26 +1,29 @@ import { Inject } from '@nestjs/common'; -import { Connection, ConnectionOptions } from 'typeorm'; +import { DataSource, DataSourceOptions } from 'typeorm'; import { EntityClassOrSchema } from '../interfaces/entity-class-or-schema.type'; -import { DEFAULT_CONNECTION_NAME } from '../typeorm.constants'; +import { DEFAULT_DATA_SOURCE_NAME } from '../typeorm.constants'; import { - getConnectionToken, + getDataSourceToken, getEntityManagerToken, getRepositoryToken, } from './typeorm.utils'; export const InjectRepository = ( entity: EntityClassOrSchema, - connection: string = DEFAULT_CONNECTION_NAME, -): ReturnType => Inject(getRepositoryToken(entity, connection)); + dataSource: string = DEFAULT_DATA_SOURCE_NAME, +): ReturnType => Inject(getRepositoryToken(entity, dataSource)); -export const InjectConnection: ( - connection?: Connection | ConnectionOptions | string, +export const InjectDataSource: ( + dataSource?: DataSource | DataSourceOptions | string, ) => ReturnType = ( - connection?: Connection | ConnectionOptions | string, -) => Inject(getConnectionToken(connection)); + dataSource?: DataSource | DataSourceOptions | string, +) => Inject(getDataSourceToken(dataSource)); + +/** @deprecated */ +export const InjectConnection = InjectDataSource; export const InjectEntityManager: ( - connection?: Connection | ConnectionOptions | string, + dataSource?: DataSource | DataSourceOptions | string, ) => ReturnType = ( - connection?: Connection | ConnectionOptions | string, -) => Inject(getEntityManagerToken(connection)); + dataSource?: DataSource | DataSourceOptions | string, +) => Inject(getEntityManagerToken(dataSource)); diff --git a/lib/common/typeorm.utils.ts b/lib/common/typeorm.utils.ts index c9d4f3e68..4bb2c7b22 100644 --- a/lib/common/typeorm.utils.ts +++ b/lib/common/typeorm.utils.ts @@ -3,50 +3,53 @@ import { Observable } from 'rxjs'; import { delay, retryWhen, scan } from 'rxjs/operators'; import { AbstractRepository, - Connection, - ConnectionOptions, + DataSource, + DataSourceOptions, EntityManager, EntitySchema, - Repository + Repository, } from 'typeorm'; import { v4 as uuid } from 'uuid'; import { CircularDependencyException } from '../exceptions/circular-dependency.exception'; import { EntityClassOrSchema } from '../interfaces/entity-class-or-schema.type'; -import { DEFAULT_CONNECTION_NAME } from '../typeorm.constants'; +import { DEFAULT_DATA_SOURCE_NAME } from '../typeorm.constants'; const logger = new Logger('TypeOrmModule'); /** * This function generates an injection token for an Entity or Repository * @param {EntityClassOrSchema} entity parameter can either be an Entity or Repository - * @param {string} [connection='default'] Connection name + * @param {string} [dataSource='default'] DataSource name * @returns {string} The Entity | Repository injection token */ export function getRepositoryToken( entity: EntityClassOrSchema, - connection: Connection | ConnectionOptions | string = DEFAULT_CONNECTION_NAME, + dataSource: + | DataSource + | DataSourceOptions + | string = DEFAULT_DATA_SOURCE_NAME, ): Function | string { if (entity === null || entity === undefined) { throw new CircularDependencyException('@InjectRepository()'); } - const connectionPrefix = getConnectionPrefix(connection); + const dataSourcePrefix = getDataSourcePrefix(dataSource); if ( entity instanceof Function && (entity.prototype instanceof Repository || entity.prototype instanceof AbstractRepository) ) { - if (!connectionPrefix) { + if (!dataSourcePrefix) { return entity; } - return `${connectionPrefix}${getCustomRepositoryToken(entity)}`; + return `${dataSourcePrefix}${getCustomRepositoryToken(entity)}`; } if (entity instanceof EntitySchema) { - return `${connectionPrefix}${ + return `${dataSourcePrefix}${ entity.options.target ? entity.options.target.name : entity.options.name }Repository`; } - return `${connectionPrefix}${entity.name}Repository`; + return `${dataSourcePrefix}${entity.name}Repository`; } /** @@ -62,66 +65,78 @@ export function getCustomRepositoryToken(repository: Function): string { } /** - * This function returns a Connection injection token for the given Connection, ConnectionOptions or connection name. - * @param {Connection | ConnectionOptions | string} [connection='default'] This optional parameter is either - * a Connection, or a ConnectionOptions or a string. - * @returns {string | Function} The Connection injection token. + * This function returns a DataSource injection token for the given DataSource, DataSourceOptions or dataSource name. + * @param {DataSource | DataSourceOptions | string} [dataSource='default'] This optional parameter is either + * a DataSource, or a DataSourceOptions or a string. + * @returns {string | Function} The DataSource injection token. */ -export function getConnectionToken( - connection: Connection | ConnectionOptions | string = DEFAULT_CONNECTION_NAME, -): string | Function | Type { - return DEFAULT_CONNECTION_NAME === connection - ? Connection - : 'string' === typeof connection - ? `${connection}Connection` - : DEFAULT_CONNECTION_NAME === connection.name || !connection.name - ? Connection - : `${connection.name}Connection`; +export function getDataSourceToken( + dataSource: + | DataSource + | DataSourceOptions + | string = DEFAULT_DATA_SOURCE_NAME, +): string | Function | Type { + return DEFAULT_DATA_SOURCE_NAME === dataSource + ? DataSource + : 'string' === typeof dataSource + ? `${dataSource}DataSource` + : DEFAULT_DATA_SOURCE_NAME === dataSource.name || !dataSource.name + ? DataSource + : `${dataSource.name}DataSource`; } +/** @deprecated */ +export const getConnectionToken = getDataSourceToken; + /** - * This function returns a Connection prefix based on the connection name - * @param {Connection | ConnectionOptions | string} [connection='default'] This optional parameter is either - * a Connection, or a ConnectionOptions or a string. - * @returns {string | Function} The Connection injection token. + * This function returns a DataSource prefix based on the dataSource name + * @param {DataSource | DataSourceOptions | string} [dataSource='default'] This optional parameter is either + * a DataSource, or a DataSourceOptions or a string. + * @returns {string | Function} The DataSource injection token. */ -export function getConnectionPrefix( - connection: Connection | ConnectionOptions | string = DEFAULT_CONNECTION_NAME, +export function getDataSourcePrefix( + dataSource: + | DataSource + | DataSourceOptions + | string = DEFAULT_DATA_SOURCE_NAME, ): string { - if (connection === DEFAULT_CONNECTION_NAME) { + if (dataSource === DEFAULT_DATA_SOURCE_NAME) { return ''; } - if (typeof connection === 'string') { - return connection + '_'; + if (typeof dataSource === 'string') { + return dataSource + '_'; } - if (connection.name === DEFAULT_CONNECTION_NAME || !connection.name) { + if (dataSource.name === DEFAULT_DATA_SOURCE_NAME || !dataSource.name) { return ''; } - return connection.name + '_'; + return dataSource.name + '_'; } /** - * This function returns an EntityManager injection token for the given Connection, ConnectionOptions or connection name. - * @param {Connection | ConnectionOptions | string} [connection='default'] This optional parameter is either - * a Connection, or a ConnectionOptions or a string. + * This function returns an EntityManager injection token for the given DataSource, DataSourceOptions or dataSource name. + * @param {DataSource | DataSourceOptions | string} [dataSource='default'] This optional parameter is either + * a DataSource, or a DataSourceOptions or a string. * @returns {string | Function} The EntityManager injection token. */ export function getEntityManagerToken( - connection: Connection | ConnectionOptions | string = DEFAULT_CONNECTION_NAME, + dataSource: + | DataSource + | DataSourceOptions + | string = DEFAULT_DATA_SOURCE_NAME, ): string | Function { - return DEFAULT_CONNECTION_NAME === connection + return DEFAULT_DATA_SOURCE_NAME === dataSource ? EntityManager - : 'string' === typeof connection - ? `${connection}EntityManager` - : DEFAULT_CONNECTION_NAME === connection.name || !connection.name + : 'string' === typeof dataSource + ? `${dataSource}EntityManager` + : DEFAULT_DATA_SOURCE_NAME === dataSource.name || !dataSource.name ? EntityManager - : `${connection.name}EntityManager`; + : `${dataSource.name}EntityManager`; } export function handleRetry( retryAttempts = 9, retryDelay = 3000, - connectionName = DEFAULT_CONNECTION_NAME, + dataSourceName = DEFAULT_DATA_SOURCE_NAME, verboseRetryLog = false, toRetry?: (err: any) => boolean, ): (source: Observable) => Observable { @@ -133,17 +148,18 @@ export function handleRetry( if (toRetry && !toRetry(error)) { throw error; } - const connectionInfo = - connectionName === DEFAULT_CONNECTION_NAME + const dataSourceInfo = + dataSourceName === DEFAULT_DATA_SOURCE_NAME ? '' - : ` (${connectionName})`; + : ` (${dataSourceName})`; const verboseMessage = verboseRetryLog ? ` Message: ${error.message}.` : ''; logger.error( - `Unable to connect to the database${connectionInfo}.${verboseMessage} Retrying (${errorCount + - 1})...`, + `Unable to connect to the database${dataSourceInfo}.${verboseMessage} Retrying (${ + errorCount + 1 + })...`, error.stack, ); if (errorCount + 1 >= retryAttempts) { @@ -157,8 +173,8 @@ export function handleRetry( ); } -export function getConnectionName(options: ConnectionOptions): string { - return options && options.name ? options.name : DEFAULT_CONNECTION_NAME; +export function getDataSourceName(options: DataSourceOptions): string { + return options && options.name ? options.name : DEFAULT_DATA_SOURCE_NAME; } export const generateString = (): string => uuid(); diff --git a/lib/entities-metadata.storage.ts b/lib/entities-metadata.storage.ts index 54bdbb5c7..135ff6da1 100644 --- a/lib/entities-metadata.storage.ts +++ b/lib/entities-metadata.storage.ts @@ -1,25 +1,25 @@ -import { Connection, ConnectionOptions } from 'typeorm'; +import { DataSource, DataSourceOptions } from 'typeorm'; import { EntityClassOrSchema } from './interfaces/entity-class-or-schema.type'; -type ConnectionToken = Connection | ConnectionOptions | string; +type DataSourceToken = DataSource | DataSourceOptions | string; export class EntitiesMetadataStorage { private static readonly storage = new Map(); - static addEntitiesByConnection( - connection: ConnectionToken, + static addEntitiesByDataSource( + dataSource: DataSourceToken, entities: EntityClassOrSchema[], ): void { - const connectionToken = - typeof connection === 'string' ? connection : connection.name; - if (!connectionToken) { + const dataSourceToken = + typeof dataSource === 'string' ? dataSource : dataSource.name; + if (!dataSourceToken) { return; } - let collection = this.storage.get(connectionToken); + let collection = this.storage.get(dataSourceToken); if (!collection) { collection = []; - this.storage.set(connectionToken, collection); + this.storage.set(dataSourceToken, collection); } entities.forEach((entity) => { if (collection!.includes(entity)) { @@ -29,15 +29,15 @@ export class EntitiesMetadataStorage { }); } - static getEntitiesByConnection( - connection: ConnectionToken, + static getEntitiesByDataSource( + dataSource: DataSourceToken, ): EntityClassOrSchema[] { - const connectionToken = - typeof connection === 'string' ? connection : connection.name; + const dataSourceToken = + typeof dataSource === 'string' ? dataSource : dataSource.name; - if (!connectionToken) { + if (!dataSourceToken) { return []; } - return this.storage.get(connectionToken) || []; + return this.storage.get(dataSourceToken) || []; } } diff --git a/lib/helpers/get-custom-repository-entity.ts b/lib/helpers/get-custom-repository-entity.ts deleted file mode 100644 index 974280bf4..000000000 --- a/lib/helpers/get-custom-repository-entity.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - AbstractRepository, - getMetadataArgsStorage, - Repository, -} from 'typeorm'; -import { EntityClassOrSchema } from '../interfaces/entity-class-or-schema.type'; - -export function getCustomRepositoryEntity( - entities: EntityClassOrSchema[], -): Array { - const customRepositoryEntities = new Array(); - const typeormEntityRepositories = getMetadataArgsStorage().entityRepositories; - - for (const entity of entities) { - const isCustomRepository = - entity instanceof Function && - (entity.prototype instanceof Repository || - entity.prototype instanceof AbstractRepository); - if (isCustomRepository) { - const entityRepositoryMetadataArgs = typeormEntityRepositories.find( - (repository) => { - return ( - repository.target === - (entity instanceof Function ? entity : (entity as any)?.constructor) - ); - }, - ); - if (entityRepositoryMetadataArgs) { - const targetEntity = entityRepositoryMetadataArgs.entity as EntityClassOrSchema; - const isEntityRegisteredAlready = entities.indexOf(targetEntity) !== -1; - - if (!isEntityRegisteredAlready) { - customRepositoryEntities.push(targetEntity); - } - } - } - } - return customRepositoryEntities; -} diff --git a/lib/helpers/index.ts b/lib/helpers/index.ts deleted file mode 100644 index 00dce66cf..000000000 --- a/lib/helpers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './get-custom-repository-entity'; diff --git a/lib/interfaces/typeorm-options.interface.ts b/lib/interfaces/typeorm-options.interface.ts index c9b96b47d..d9b0ea59b 100644 --- a/lib/interfaces/typeorm-options.interface.ts +++ b/lib/interfaces/typeorm-options.interface.ts @@ -1,5 +1,5 @@ -import {ModuleMetadata, Provider, Type} from '@nestjs/common'; -import { Connection, ConnectionOptions } from 'typeorm'; +import { ModuleMetadata, Provider, Type } from '@nestjs/common'; +import { DataSource, DataSourceOptions } from 'typeorm'; export type TypeOrmModuleOptions = { /** @@ -24,15 +24,11 @@ export type TypeOrmModuleOptions = { * If `true`, entities will be loaded automatically. */ autoLoadEntities?: boolean; - /** - * If `true`, connection will not be closed on application shutdown. - */ - keepConnectionAlive?: boolean; /** * If `true`, will show verbose error messages on each connection retry. */ verboseRetryLog?: boolean; -} & Partial; +} & Partial; export interface TypeOrmOptionsFactory { createTypeOrmOptions( @@ -40,9 +36,9 @@ export interface TypeOrmOptionsFactory { ): Promise | TypeOrmModuleOptions; } -export type TypeOrmConnectionFactory = ( - options?: ConnectionOptions, -) => Promise; +export type TypeOrmDataSourceFactory = ( + options?: DataSourceOptions, +) => Promise; export interface TypeOrmModuleAsyncOptions extends Pick { @@ -52,7 +48,7 @@ export interface TypeOrmModuleAsyncOptions useFactory?: ( ...args: any[] ) => Promise | TypeOrmModuleOptions; - connectionFactory?: TypeOrmConnectionFactory; + dataSourceFactory?: TypeOrmDataSourceFactory; inject?: any[]; extraProviders?: Provider[]; } diff --git a/lib/typeorm-core.module.ts b/lib/typeorm-core.module.ts index 26c14f823..a7312a246 100644 --- a/lib/typeorm-core.module.ts +++ b/lib/typeorm-core.module.ts @@ -6,29 +6,24 @@ import { Module, OnApplicationShutdown, Provider, - Type, + Type } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; -import { defer, lastValueFrom, of } from 'rxjs'; -import { - Connection, - ConnectionOptions, - createConnection, - getConnectionManager, -} from 'typeorm'; +import { defer, lastValueFrom } from 'rxjs'; +import { Connection, DataSource, DataSourceOptions } from 'typeorm'; import { generateString, - getConnectionName, - getConnectionToken, + getDataSourceName, + getDataSourceToken, getEntityManagerToken, - handleRetry, + handleRetry } from './common/typeorm.utils'; import { EntitiesMetadataStorage } from './entities-metadata.storage'; import { - TypeOrmConnectionFactory, + TypeOrmDataSourceFactory, TypeOrmModuleAsyncOptions, TypeOrmModuleOptions, - TypeOrmOptionsFactory, + TypeOrmOptionsFactory } from './interfaces/typeorm-options.interface'; import { TYPEORM_MODULE_ID, TYPEORM_MODULE_OPTIONS } from './typeorm.constants'; @@ -48,77 +43,104 @@ export class TypeOrmCoreModule implements OnApplicationShutdown { provide: TYPEORM_MODULE_OPTIONS, useValue: options, }; - const connectionProvider = { - provide: getConnectionToken(options as ConnectionOptions) as string, - useFactory: async () => await this.createConnectionFactory(options), + const dataSourceProvider = { + provide: getDataSourceToken(options as DataSourceOptions), + useFactory: async () => await this.createDataSourceFactory(options), }; const entityManagerProvider = this.createEntityManagerProvider( - options as ConnectionOptions, + options as DataSourceOptions, ); + + const providers = [ + entityManagerProvider, + dataSourceProvider, + typeOrmModuleOptions, + ]; + const exports = [entityManagerProvider, dataSourceProvider]; + + // TODO: "Connection" class is going to be removed in the next version of "typeorm" + if (dataSourceProvider.provide === DataSource) { + providers.push({ + provide: Connection, + useExisting: DataSource, + }); + exports.push(Connection); + } + return { module: TypeOrmCoreModule, - providers: [ - entityManagerProvider, - connectionProvider, - typeOrmModuleOptions, - ], - exports: [entityManagerProvider, connectionProvider], + providers, + exports, }; } static forRootAsync(options: TypeOrmModuleAsyncOptions): DynamicModule { - const connectionProvider = { - provide: getConnectionToken(options as ConnectionOptions) as string, + const dataSourceProvider = { + provide: getDataSourceToken(options as DataSourceOptions), useFactory: async (typeOrmOptions: TypeOrmModuleOptions) => { if (options.name) { - return await this.createConnectionFactory( + return await this.createDataSourceFactory( { ...typeOrmOptions, name: options.name, }, - options.connectionFactory, + options.dataSourceFactory, ); } - return await this.createConnectionFactory( + return await this.createDataSourceFactory( typeOrmOptions, - options.connectionFactory, + options.dataSourceFactory, ); }, inject: [TYPEORM_MODULE_OPTIONS], }; const entityManagerProvider = { - provide: getEntityManagerToken(options as ConnectionOptions) as string, - useFactory: (connection: Connection) => connection.manager, - inject: [getConnectionToken(options as ConnectionOptions)], + provide: getEntityManagerToken(options as DataSourceOptions) as string, + useFactory: (dataSource: DataSource) => dataSource.manager, + inject: [getDataSourceToken(options as DataSourceOptions)], }; const asyncProviders = this.createAsyncProviders(options); + const providers = [ + ...asyncProviders, + entityManagerProvider, + dataSourceProvider, + { + provide: TYPEORM_MODULE_ID, + useValue: generateString(), + }, + ...(options.extraProviders || []), + ]; + const exports: Array = [ + entityManagerProvider, + dataSourceProvider, + ]; + + // TODO: "Connection" class is going to be removed in the next version of "typeorm" + if (dataSourceProvider.provide === DataSource) { + providers.push({ + provide: Connection, + useExisting: DataSource, + }); + exports.push(Connection); + } + return { module: TypeOrmCoreModule, imports: options.imports, - providers: [ - ...asyncProviders, - entityManagerProvider, - connectionProvider, - { - provide: TYPEORM_MODULE_ID, - useValue: generateString(), - }, - ...(options.extraProviders || []), - ], - exports: [entityManagerProvider, connectionProvider], + providers, + exports, }; } async onApplicationShutdown(): Promise { - if (this.options.keepConnectionAlive) { - return; - } - const connection = this.moduleRef.get( - getConnectionToken(this.options as ConnectionOptions) as Type, + const dataSource = this.moduleRef.get( + getDataSourceToken(this.options as DataSourceOptions) as Type, ); try { - connection && (await connection.close()); + if (dataSource && dataSource.isInitialized) { + await dataSource.destroy(); + } } catch (e) { this.logger.error(e?.message); } @@ -163,63 +185,51 @@ export class TypeOrmCoreModule implements OnApplicationShutdown { } private static createEntityManagerProvider( - options: ConnectionOptions, + options: DataSourceOptions, ): Provider { return { provide: getEntityManagerToken(options) as string, - useFactory: (connection: Connection) => connection.manager, - inject: [getConnectionToken(options)], + useFactory: (dataSource: DataSource) => dataSource.manager, + inject: [getDataSourceToken(options)], }; } - private static async createConnectionFactory( + private static async createDataSourceFactory( options: TypeOrmModuleOptions, - connectionFactory?: TypeOrmConnectionFactory, - ): Promise { - const connectionToken = getConnectionName(options as ConnectionOptions); - const createTypeormConnection = connectionFactory ?? createConnection; + dataSourceFactory?: TypeOrmDataSourceFactory, + ): Promise { + const dataSourceToken = getDataSourceName(options as DataSourceOptions); + const createTypeormDataSource = + dataSourceFactory ?? + ((options: DataSourceOptions) => new DataSource(options)); return await lastValueFrom( - defer(() => { - try { - if (options.keepConnectionAlive) { - const connectionName = getConnectionName( - options as ConnectionOptions, - ); - const manager = getConnectionManager(); - if (manager.has(connectionName)) { - const connection = manager.get(connectionName); - if (connection.isConnected) { - return of(connection); - } - } - } - } catch {} - - if (!options.type) { - return createTypeormConnection(); - } + defer(async () => { if (!options.autoLoadEntities) { - return createTypeormConnection(options as ConnectionOptions); + const dataSource = await createTypeormDataSource( + options as DataSourceOptions, + ); + return dataSource.initialize(); } let entities = options.entities; - if (entities) { + if (Array.isArray(entities)) { entities = entities.concat( - EntitiesMetadataStorage.getEntitiesByConnection(connectionToken), + EntitiesMetadataStorage.getEntitiesByDataSource(dataSourceToken), ); } else { entities = - EntitiesMetadataStorage.getEntitiesByConnection(connectionToken); + EntitiesMetadataStorage.getEntitiesByDataSource(dataSourceToken); } - return createTypeormConnection({ + const dataSource = await createTypeormDataSource({ ...options, entities, - } as ConnectionOptions); + } as DataSourceOptions); + return dataSource.initialize(); }).pipe( handleRetry( options.retryAttempts, options.retryDelay, - connectionToken, + dataSourceToken, options.verboseRetryLog, options.toRetry, ), diff --git a/lib/typeorm.constants.ts b/lib/typeorm.constants.ts index 030fca9c9..e27d9844a 100644 --- a/lib/typeorm.constants.ts +++ b/lib/typeorm.constants.ts @@ -1,3 +1,3 @@ export const TYPEORM_MODULE_OPTIONS = 'TypeOrmModuleOptions'; export const TYPEORM_MODULE_ID = 'TypeOrmModuleId'; -export const DEFAULT_CONNECTION_NAME = 'default'; +export const DEFAULT_DATA_SOURCE_NAME = 'default'; diff --git a/lib/typeorm.module.ts b/lib/typeorm.module.ts index cf5024ceb..48b0f5a51 100644 --- a/lib/typeorm.module.ts +++ b/lib/typeorm.module.ts @@ -1,14 +1,13 @@ import { DynamicModule, Module } from '@nestjs/common'; -import { Connection, ConnectionOptions } from 'typeorm'; +import { DataSource, DataSourceOptions } from 'typeorm'; import { EntitiesMetadataStorage } from './entities-metadata.storage'; -import { getCustomRepositoryEntity } from './helpers/get-custom-repository-entity'; import { EntityClassOrSchema } from './interfaces/entity-class-or-schema.type'; import { TypeOrmModuleAsyncOptions, TypeOrmModuleOptions, } from './interfaces/typeorm-options.interface'; import { TypeOrmCoreModule } from './typeorm-core.module'; -import { DEFAULT_CONNECTION_NAME } from './typeorm.constants'; +import { DEFAULT_DATA_SOURCE_NAME } from './typeorm.constants'; import { createTypeOrmProviders } from './typeorm.providers'; @Module({}) @@ -22,17 +21,13 @@ export class TypeOrmModule { static forFeature( entities: EntityClassOrSchema[] = [], - connection: - | Connection - | ConnectionOptions - | string = DEFAULT_CONNECTION_NAME, + dataSource: + | DataSource + | DataSourceOptions + | string = DEFAULT_DATA_SOURCE_NAME, ): DynamicModule { - const providers = createTypeOrmProviders(entities, connection); - const customRepositoryEntities = getCustomRepositoryEntity(entities); - EntitiesMetadataStorage.addEntitiesByConnection(connection, [ - ...entities, - ...customRepositoryEntities, - ]); + const providers = createTypeOrmProviders(entities, dataSource); + EntitiesMetadataStorage.addEntitiesByDataSource(dataSource, [...entities]); return { module: TypeOrmModule, providers: providers, diff --git a/lib/typeorm.providers.ts b/lib/typeorm.providers.ts index 5b5ce0db7..f38ab2987 100644 --- a/lib/typeorm.providers.ts +++ b/lib/typeorm.providers.ts @@ -1,34 +1,20 @@ import { Provider } from '@nestjs/common'; -import { - AbstractRepository, - Connection, - ConnectionOptions, - getMetadataArgsStorage, - Repository, -} from 'typeorm'; -import { getConnectionToken, getRepositoryToken } from './common/typeorm.utils'; +import { DataSource, DataSourceOptions, getMetadataArgsStorage } from 'typeorm'; +import { getDataSourceToken, getRepositoryToken } from './common/typeorm.utils'; import { EntityClassOrSchema } from './interfaces/entity-class-or-schema.type'; export function createTypeOrmProviders( entities?: EntityClassOrSchema[], - connection?: Connection | ConnectionOptions | string, + dataSource?: DataSource | DataSourceOptions | string, ): Provider[] { return (entities || []).map((entity) => ({ - provide: getRepositoryToken(entity, connection), - useFactory: (connection: Connection) => { - if ( - entity instanceof Function && - (entity.prototype instanceof Repository || - entity.prototype instanceof AbstractRepository) - ) { - return connection.getCustomRepository(entity); - } - - return connection.options.type === 'mongodb' - ? connection.getMongoRepository(entity) - : connection.getRepository(entity); + provide: getRepositoryToken(entity, dataSource), + useFactory: (dataSource: DataSource) => { + return dataSource.options.type === 'mongodb' + ? dataSource.getMongoRepository(entity) + : dataSource.getRepository(entity); }, - inject: [getConnectionToken(connection)], + inject: [getDataSourceToken(dataSource)], /** * Extra property to workaround dynamic modules serialisation issue * that occurs when "TypeOrm#forFeature()" method is called with the same number diff --git a/package-lock.json b/package-lock.json index e9f26e10d..35f3ca8d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@nestjs/typeorm", - "version": "8.0.4", + "version": "9.0.0-next.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2542,12 +2542,6 @@ "integrity": "sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw==", "dev": true }, - "@types/zen-observable": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==", - "dev": true - }, "@typescript-eslint/eslint-plugin": { "version": "5.27.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.27.0.tgz", @@ -2898,7 +2892,7 @@ "append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=", "dev": true }, "arg": { @@ -2919,13 +2913,13 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", "dev": true }, "array-includes": { @@ -2974,7 +2968,7 @@ "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "asap": { @@ -3405,7 +3399,7 @@ "busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", "dev": true, "requires": { "dicer": "0.2.5", @@ -3886,7 +3880,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", "dev": true }, "cookiejar": { @@ -3969,6 +3963,12 @@ "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", "dev": true }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true + }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -3989,13 +3989,13 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "decamelize-keys": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", "dev": true, "requires": { "decamelize": "^1.1.0", @@ -4005,7 +4005,7 @@ "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true } } @@ -4142,7 +4142,7 @@ "dicer": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", "dev": true, "requires": { "readable-stream": "1.1.x", @@ -4197,9 +4197,9 @@ } }, "dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", "dev": true }, "duplexer3": { @@ -4217,7 +4217,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, "electron-to-chromium": { @@ -4241,7 +4241,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, "end-of-stream": { @@ -4360,7 +4360,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", "dev": true }, "escape-string-regexp": { @@ -4901,7 +4901,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, "execa": { @@ -5350,7 +5350,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", "dev": true }, "fs-extra": { @@ -5544,7 +5544,7 @@ "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "dev": true, "requires": { "ini": "^1.3.4" @@ -6129,7 +6129,7 @@ "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, "is-plain-object": { @@ -6199,7 +6199,7 @@ "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "requires": { "text-extensions": "^1.0.0" @@ -8375,7 +8375,7 @@ "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, "keyv": { @@ -8759,7 +8759,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, "meow": { @@ -8784,7 +8784,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, "merge-stream": { @@ -10546,7 +10546,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } @@ -11323,9 +11323,9 @@ } }, "typeorm": { - "version": "0.2.45", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.45.tgz", - "integrity": "sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.4.tgz", + "integrity": "sha512-6v3HH12viDhIQwQDod/B0Plt1o7IYIVDxP7zwatD6fzN+IDdqTTinW/sWNw84Edpbhh2t7XILTaQEqj0NXFP/Q==", "dev": true, "requires": { "@sqltools/formatter": "^1.2.2", @@ -11333,18 +11333,18 @@ "buffer": "^6.0.3", "chalk": "^4.1.0", "cli-highlight": "^2.1.11", - "debug": "^4.3.1", - "dotenv": "^8.2.0", - "glob": "^7.1.6", - "js-yaml": "^4.0.0", + "date-fns": "^2.28.0", + "debug": "^4.3.3", + "dotenv": "^16.0.0", + "glob": "^7.2.0", + "js-yaml": "^4.1.0", "mkdirp": "^1.0.4", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", - "tslib": "^2.1.0", + "tslib": "^2.3.1", "uuid": "^8.3.2", "xml2js": "^0.4.23", - "yargs": "^17.0.1", - "zen-observable-ts": "^1.0.0" + "yargs": "^17.3.1" }, "dependencies": { "ansi-styles": { @@ -11391,6 +11391,15 @@ "color-name": "~1.1.4" } }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -11426,6 +11435,12 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -11462,9 +11477,9 @@ "dev": true }, "yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.0.tgz", + "integrity": "sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -11966,22 +11981,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true - }, - "zen-observable": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", - "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", - "dev": true - }, - "zen-observable-ts": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", - "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", - "dev": true, - "requires": { - "@types/zen-observable": "0.8.3", - "zen-observable": "0.8.15" - } } } } diff --git a/package.json b/package.json index 56d923d50..6d67c1420 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nestjs/typeorm", - "version": "8.0.4", + "version": "9.0.0-next.2", "description": "Nest - modern, fast, powerful node.js web framework (@typeorm)", "author": "Kamil Mysliwiec", "license": "MIT", @@ -45,7 +45,7 @@ "rxjs": "7.5.5", "supertest": "6.2.3", "ts-jest": "28.0.3", - "typeorm": "0.2.45", + "typeorm": "0.3.4", "typescript": "4.7.2" }, "dependencies": { @@ -56,7 +56,7 @@ "@nestjs/core": "^8.0.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0", - "typeorm": "^0.2.34" + "typeorm": "^0.3.0" }, "lint-staged": { "*.ts": [ diff --git a/tests/ormconfig.json b/tests/ormconfig.json deleted file mode 100644 index 378b0e0be..000000000 --- a/tests/ormconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "mysql", - "host": "0.0.0.0", - "port": 3306, - "username": "root", - "password": "root", - "database": "test", - "entities": ["src/**/**.entity{.ts,.js}"], - "synchronize": true -} diff --git a/tests/src/async-connection-factory-options.module.ts b/tests/src/async-connection-factory-options.module.ts index 09eaa5064..c8cb1c44d 100644 --- a/tests/src/async-connection-factory-options.module.ts +++ b/tests/src/async-connection-factory-options.module.ts @@ -1,5 +1,5 @@ import { Module } from '@nestjs/common'; -import { createConnection } from 'typeorm'; +import { DataSource } from 'typeorm'; import { TypeOrmModule } from '../../lib'; import { Photo } from './photo/photo.entity'; import { PhotoModule } from './photo/photo.module'; @@ -19,13 +19,12 @@ import { PhotoModule } from './photo/photo.module'; retryAttempts: 2, retryDelay: 1000, }), - connectionFactory: async (options) => { + dataSourceFactory: async (options) => { // Realistically, this function would be used for more than simply creating a connection, // i.e. checking for an existing and active connection prior to creating a new one. // However, including that logic here causes runtime test errors about variables being used before assignment. // Therefore, given the simple nature of this test case, simply create and return a connection. - const connection = await createConnection(options!); - return connection; + return new DataSource(options!); }, }), TypeOrmModule.forRoot({