UNPKG

@nestjs/typeorm

Version:

TypeORM for NestJS: connections and repositories through dependency injection, entities, transactions and multiple databases.

130 lines (129 loc) • 5.75 kB
import { Logger } from '@nestjs/common'; import { delay, retryWhen, scan } from 'rxjs/operators'; import { DataSource, EntityManager, EntitySchema, Repository } from 'typeorm'; import { CircularDependencyException } from '../exceptions/circular-dependency.exception.js'; import { DEFAULT_DATA_SOURCE_NAME } from '../typeorm.constants.js'; import { AbstractRepository } from './typeorm-compat.js'; const logger = new Logger('TypeOrmModule'); /** * This function returns the DataSource name for the given DataSource, DataSourceOptions * or dataSource name. TypeORM v1 removed `name` from `DataSource` and `DataSourceOptions`, * so it is read defensively while remaining backward compatible with 0.3.x * (where the user-supplied options still carry it). * @param {DataSource | DataSourceOptions | string} [dataSource='default'] This optional * parameter is either a DataSource, or a DataSourceOptions or a string. * @returns {string} The DataSource name, or 'default' when no name is set. * * @publicApi */ export function getDataSourceName(dataSource = DEFAULT_DATA_SOURCE_NAME) { if (typeof dataSource === 'string') { return dataSource; } return (dataSource?.name || DEFAULT_DATA_SOURCE_NAME); } /** * This function generates an injection token for an Entity or Repository * @param {EntityClassOrSchema} entity parameter can either be an Entity or Repository * @param {DataSource | DataSourceOptions | string} [dataSource='default'] This optional parameter is either * a DataSource, or a DataSourceOptions or a string. * @returns {string} The Entity | Repository injection token * * @publicApi */ export function getRepositoryToken(entity, dataSource = DEFAULT_DATA_SOURCE_NAME) { if (entity === null || entity === undefined) { throw new CircularDependencyException('@InjectRepository()'); } const dataSourcePrefix = getDataSourcePrefix(dataSource); if (entity instanceof Function && (entity.prototype instanceof Repository || (AbstractRepository && entity.prototype instanceof AbstractRepository))) { if (!dataSourcePrefix) { return entity; } return `${dataSourcePrefix}${getCustomRepositoryToken(entity)}`; } if (entity instanceof EntitySchema) { const schemaName = entity.options.target ? entity.options.target.name : entity.options.name; if (!schemaName) { throw new Error('EntitySchema must have either "target" or "name" defined'); } return `${dataSourcePrefix}${schemaName}Repository`; } return `${dataSourcePrefix}${entity.name}Repository`; } /** * This function generates an injection token for an Entity or Repository * @param {Function} This parameter can either be an Entity or Repository * @returns {string} The Repository injection token * * @publicApi */ export function getCustomRepositoryToken(repository) { if (repository === null || repository === undefined) { throw new CircularDependencyException('@InjectRepository()'); } return repository.name; } /** * 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. * * @publicApi */ export function getDataSourceToken(dataSource = DEFAULT_DATA_SOURCE_NAME) { const name = getDataSourceName(dataSource); return name === DEFAULT_DATA_SOURCE_NAME ? DataSource : `${name}DataSource`; } /** * @deprecated * * @publicApi */ export const getConnectionToken = getDataSourceToken; /** * 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 getDataSourcePrefix(dataSource = DEFAULT_DATA_SOURCE_NAME) { const name = getDataSourceName(dataSource); return name === DEFAULT_DATA_SOURCE_NAME ? '' : `${name}_`; } /** * 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(dataSource = DEFAULT_DATA_SOURCE_NAME) { const name = getDataSourceName(dataSource); return name === DEFAULT_DATA_SOURCE_NAME ? EntityManager : `${name}EntityManager`; } export function handleRetry(retryAttempts = 10, retryDelay = 3000, dataSourceName = DEFAULT_DATA_SOURCE_NAME, verboseRetryLog = false, toRetry) { return (source) => source.pipe(retryWhen((e) => e.pipe(scan((errorCount, error) => { if (toRetry && !toRetry(error)) { throw error; } const dataSourceInfo = dataSourceName === DEFAULT_DATA_SOURCE_NAME ? '' : ` (${dataSourceName})`; const verboseMessage = verboseRetryLog ? ` Message: ${error.message}.` : ''; logger.error(`Unable to connect to the database${dataSourceInfo}.${verboseMessage} Retrying (${errorCount + 1})...`, error.stack); if (errorCount + 1 >= retryAttempts) { throw error; } return errorCount + 1; }, 0), delay(retryDelay)))); } export const generateString = () => crypto.randomUUID();