@nestjs/typeorm
Version:
Nest - modern, fast, powerful node.js web framework (@typeorm)
135 lines (134 loc) • 5.69 kB
JavaScript
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();