UNPKG

@nestjs/typeorm

Version:

Nest - modern, fast, powerful node.js web framework (@typeorm)

135 lines (134 loc) 5.69 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'); /** * Reads the NestJS-level data source `name`. TypeORM v1 removed `name` from * `DataSource` and `DataSourceOptions`, so it is accessed defensively while * remaining backward compatible with 0.3.x (where the user-supplied options * still carry it at runtime). */ function getName(dataSource) { return dataSource.name; } /** * This function generates an injection token for an Entity or Repository * @param {EntityClassOrSchema} entity parameter can either be an Entity or Repository * @param {string} [dataSource='default'] DataSource name * @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) { return `${dataSourcePrefix}${entity.options.target ? entity.options.target.name : entity.options.name}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) { return DEFAULT_DATA_SOURCE_NAME === dataSource ? DataSource : 'string' === typeof dataSource ? `${dataSource}DataSource` : DEFAULT_DATA_SOURCE_NAME === getName(dataSource) || !getName(dataSource) ? DataSource : `${getName(dataSource)}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) { if (dataSource === DEFAULT_DATA_SOURCE_NAME) { return ''; } if (typeof dataSource === 'string') { return dataSource + '_'; } const name = getName(dataSource); if (name === DEFAULT_DATA_SOURCE_NAME || !name) { return ''; } return 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) { return DEFAULT_DATA_SOURCE_NAME === dataSource ? EntityManager : 'string' === typeof dataSource ? `${dataSource}EntityManager` : DEFAULT_DATA_SOURCE_NAME === getName(dataSource) || !getName(dataSource) ? EntityManager : `${getName(dataSource)}EntityManager`; } export function handleRetry(retryAttempts = 9, 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 function getDataSourceName(options) { return options && options.name ? options.name : DEFAULT_DATA_SOURCE_NAME; } export const generateString = () => crypto.randomUUID();