typeorm-extension
Version:
A library to create/drop database, simple seeding data sets, ...
1,481 lines (1,444 loc) • 116 kB
JavaScript
'use strict';
var rapiq = require('rapiq');
var process$1 = require('node:process');
var typeorm = require('typeorm');
var locter = require('locter');
var path = require('node:path');
var fs = require('node:fs');
var consola = require('consola');
var envix = require('envix');
var smob = require('smob');
var DriverUtils = require('typeorm/driver/DriverUtils');
var DriverFactory = require('typeorm/driver/DriverFactory');
var pascalCase = require('pascal-case');
var MigrationGenerateCommand = require('typeorm/commands/MigrationGenerateCommand');
var faker = require('@faker-js/faker');
class TypeormExtensionError extends Error {
}
class DriverError extends TypeormExtensionError {
static undeterminable() {
return new DriverError('The driver could not be determined.');
}
static notSupported(driverName) {
return new DriverError(`The driver ${driverName} is not supported yet.`);
}
constructor(message){
super(message || 'A database driver related error has occurred.');
}
}
class OptionsError extends TypeormExtensionError {
static undeterminable() {
return new OptionsError('The database options could not be determined.');
}
static notFound() {
return new OptionsError('The database options could not be located/loaded.');
}
static databaseNotDefined() {
return new OptionsError('The database name to connect to is not defined.');
}
constructor(message){
super(message || 'A database options related error has occurred');
}
}
function getAliasForPath(items, path) {
if (typeof path === 'undefined' || typeof items === 'undefined') {
return undefined;
}
for(let i = 0; i < items.length; i++){
if (items[i].key === path) {
return items[i].value;
}
}
return undefined;
}
function buildKeyWithPrefix(name, prefix) {
if (prefix) {
return `${prefix}.${name}`;
}
return name;
}
var CodeTransformation = /*#__PURE__*/ function(CodeTransformation) {
CodeTransformation["JUST_IN_TIME"] = "jit";
CodeTransformation["NONE"] = "none";
return CodeTransformation;
}({});
function detectCodeTransformation() {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (process$1[Symbol.for('ts-node.register.instance')]) {
return CodeTransformation.JUST_IN_TIME;
}
return CodeTransformation.NONE;
}
function isCodeTransformation(input) {
return detectCodeTransformation() === input;
}
function getEntityName(entity) {
if (typeof entity === 'function') {
return entity.name;
}
if (typeorm.InstanceChecker.isEntitySchema(entity)) {
return entity.options.name;
}
return new entity().constructor.name;
}
function canReplaceWindowsSeparator(input) {
// https://superuser.com/questions/176388/why-does-windows-use-backslashes-for-paths-and-unix-forward-slashes/176395#176395
if (input.startsWith('\\\\?\\')) {
return false;
}
let characterIndex;
const specialCharacters = [
'[',
'{',
'(',
'^',
'$',
'.',
'|',
'?',
'*',
'+'
];
for(let i = 0; i < specialCharacters.length; i++){
characterIndex = input.indexOf(specialCharacters[i]);
if (characterIndex !== -1) {
// special character is prefixed with \, no transformation allowed
if (characterIndex !== 0 && input[characterIndex - 1] === '\\') {
return false;
}
}
}
return true;
}
function replaceWindowSeparator(input) {
return input.replace(/\\/g, '/');
}
function safeReplaceWindowsSeparator(input) {
if (input.indexOf('\\') === -1 || !canReplaceWindowsSeparator(input)) {
return input;
}
return replaceWindowSeparator(input);
}
const TRAILING_SLASH_RE = /\/$|\/\?/;
function hasTrailingSlash(input = '', queryParams = false) {
if (!queryParams) {
return input.endsWith('/');
}
return TRAILING_SLASH_RE.test(input);
}
function withoutTrailingSlash(input = '', queryParams = false) {
if (!queryParams) {
return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';
}
if (!hasTrailingSlash(input, true)) {
return input || '/';
}
const [s0, ...s] = input.split('?');
return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
}
async function readTSConfig(input) {
input = input || process.cwd();
input = path.isAbsolute(input) ? input : path.resolve(process.cwd(), input);
const filePath = input.indexOf('.json') === -1 ? path.join(input, 'tsconfig.json') : input;
try {
const tsConfig = await locter.load(filePath);
if (locter.isObject(tsConfig)) {
return tsConfig;
}
} catch (e) {
// don't do anything ;)
}
return {};
}
const stripLeadingModifier = (text)=>{
if (text.startsWith('./')) {
text = text.substring(2);
}
return text;
};
function transformFilePath(input, dist, src) {
let separator = path.sep;
const windowsSeparatorReplaceable = canReplaceWindowsSeparator(input);
if (windowsSeparatorReplaceable) {
separator = '/';
input = replaceWindowSeparator(input);
}
let base = input;
let baseIndex = input.lastIndexOf(separator);
if (baseIndex !== -1) {
base = base.substring(baseIndex + 1);
}
if (src) {
if (windowsSeparatorReplaceable) {
src = replaceWindowSeparator(src);
}
src = withoutTrailingSlash(stripLeadingModifier(src));
}
src = src || 'src';
if (dist) {
if (windowsSeparatorReplaceable) {
dist = replaceWindowSeparator(dist);
}
dist = withoutTrailingSlash(stripLeadingModifier(dist));
}
dist = dist || 'dist';
if (input.indexOf(src) !== -1 && input.indexOf(dist) === -1) {
const lastIndex = input.lastIndexOf(src);
const prevCharacter = input.substring(lastIndex - 1, lastIndex);
if (!prevCharacter || prevCharacter === separator) {
input = input.substring(0, lastIndex) + dist + input.substring(lastIndex + src.length);
baseIndex = input.lastIndexOf(separator);
}
}
// if the path already contains a js file extension, we are done
const jsExtensions = [
'js',
'cjs',
'mjs'
];
for(let i = 0; i < jsExtensions.length; i++){
if (base.indexOf(jsExtensions[i]) !== -1) {
return input;
}
}
const tsExtensions = [
'ts',
'cts',
'mts'
];
for(let i = 0; i < tsExtensions.length; i++){
const regex = new RegExp(`(\\.${tsExtensions[i]}|${tsExtensions[i]})`, 'g');
let matchesSum;
const matches = base.match(regex);
if (Array.isArray(matches)) {
matchesSum = matches.length;
}
let matchesCounter = 0;
const bracketIndex = base.lastIndexOf('{');
base = base.replace(regex, (...args)=>{
matchesCounter++;
// if the file extension name comes after the last bracket index,
// we can be pretty sure that the extension name is not part of a filename
if (args[2] >= bracketIndex && bracketIndex !== -1 || bracketIndex === -1 && matchesCounter === matchesSum) {
return args[0].startsWith('.') ? `.${jsExtensions[i]}` : jsExtensions[i];
}
return args[0];
});
}
if (baseIndex !== -1) {
base = input.substring(0, baseIndex + 1) + base;
}
return stripLeadingModifier(base);
}
async function adjustFilePath(input, tsconfig) {
if (isCodeTransformation(CodeTransformation.JUST_IN_TIME)) {
return input;
}
if (!locter.isObject(tsconfig)) {
tsconfig = await readTSConfig(tsconfig);
}
const { compilerOptions } = tsconfig;
if (typeof input === 'string') {
return transformFilePath(input, compilerOptions?.outDir);
}
if (Array.isArray(input)) {
for(let i = 0; i < input.length; i++){
if (typeof input[i] === 'string') {
input[i] = transformFilePath(input[i], compilerOptions?.outDir);
}
}
}
return input;
}
async function adjustFilePaths(input, keys, tsconfig) {
if (isCodeTransformation(CodeTransformation.JUST_IN_TIME)) {
return input;
}
if (!locter.isObject(tsconfig)) {
tsconfig = await readTSConfig(tsconfig);
}
keys = keys || Object.keys(input);
for(let i = 0; i < keys.length; i++){
input[keys[i]] = await adjustFilePath(input[keys[i]], tsconfig);
}
return input;
}
function resolveFilePath(filePath, root) {
if (path.isAbsolute(filePath)) {
return filePath;
}
return filePath.startsWith('/') ? filePath : path.resolve(root || process.cwd(), filePath);
}
function parseFilePath(filePath, root) {
const fullPath = resolveFilePath(filePath, root);
const directory = path.dirname(fullPath);
const name = path.basename(fullPath);
return {
directory,
name
};
}
async function isDirectory(input) {
try {
const stat = await fs.promises.stat(input);
return stat.isDirectory();
} catch (e) {
return false;
}
}
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
function hasStringProperty(obj, prop) {
return hasOwnProperty(obj, prop) && typeof obj[prop] === 'string';
}
function pickRecord(data, keys) {
const output = {};
for(let i = 0; i < keys.length; i++){
output[keys[i]] = data[keys[i]];
}
return output;
}
function isPromise(p) {
return locter.isObject(p) && (p instanceof Promise || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
typeof p.then === 'function');
}
function isQueryOptionDefined(input, option) {
if (typeof input === 'boolean') {
return false;
}
const options = Array.isArray(option) ? option : [
option
];
for(let i = 0; i < options.length; i++){
if (hasOwnProperty(input, options[i])) {
return true;
}
}
return false;
}
/**
* Apply parsed fields parameter data on the db query.
*
* @param query
* @param data
*/ /* istanbul ignore next */ function applyQueryFieldsParseOutput(query, data, options = {}) {
if (data.length === 0) {
return data;
}
query.select(data.map((field)=>{
const alias = getAliasForPath(options.relations, field.path) || options.defaultAlias || options.defaultPath;
return buildKeyWithPrefix(field.key, alias);
}));
return data;
}
/**
* Apply raw fields parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryFields(query, data, options) {
options = options || {};
if (options.defaultAlias) {
options.defaultPath = options.defaultAlias;
}
return applyQueryFieldsParseOutput(query, rapiq.parseQueryFields(data, options), options);
}
/**
* Apply raw fields parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyFields(query, data, options) {
return applyQueryFields(query, data, options);
}
// --------------------------------------------------
function transformParsedFilters(data, options = {}) {
const items = [];
for(let i = 0; i < data.length; i++){
const alias = getAliasForPath(options.relations, data[i].path) || options.defaultAlias || options.defaultPath;
const fullKey = buildKeyWithPrefix(data[i].key, alias);
const filter = data[i];
const statement = [
fullKey
];
let bindingKey;
if (options.bindingKey) {
bindingKey = options.bindingKey(fullKey).replace('.', '_');
} else {
bindingKey = `filter_${fullKey.replace('.', '_')}`;
}
if (filter.value === null || typeof filter.value === 'undefined') {
statement.push('IS');
if (filter.operator === rapiq.FilterComparisonOperator.NOT_EQUAL) {
statement.push('NOT');
}
statement.push('NULL');
items.push({
statement: statement.join(' '),
binding: {}
});
continue;
}
switch(filter.operator){
case rapiq.FilterComparisonOperator.EQUAL:
case rapiq.FilterComparisonOperator.NOT_EQUAL:
{
if (filter.operator === rapiq.FilterComparisonOperator.EQUAL) {
statement.push('=');
} else {
statement.push('!=');
}
statement.push(`:${bindingKey}`);
break;
}
case rapiq.FilterComparisonOperator.LIKE:
case rapiq.FilterComparisonOperator.NOT_LIKE:
{
if (filter.operator === rapiq.FilterComparisonOperator.NOT_LIKE) {
statement.push('NOT');
}
statement.push('LIKE');
statement.push(`:${bindingKey}`);
filter.value += '%';
break;
}
case rapiq.FilterComparisonOperator.IN:
case rapiq.FilterComparisonOperator.NOT_IN:
{
if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
statement.push('NOT');
}
statement.push('IN');
statement.push(`(:...${bindingKey})`);
if (Array.isArray(filter.value)) {
const nullIndex = filter.value.indexOf(null);
if (nullIndex !== -1) {
filter.value.splice(nullIndex, 1);
statement.unshift('(');
if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
statement.push('AND');
} else {
statement.push('OR');
}
statement.push(fullKey);
statement.push('IS');
if (filter.operator === rapiq.FilterComparisonOperator.NOT_IN) {
statement.push('NOT');
}
statement.push('NULL');
statement.push(')');
}
}
break;
}
case rapiq.FilterComparisonOperator.LESS_THAN:
case rapiq.FilterComparisonOperator.LESS_THAN_EQUAL:
case rapiq.FilterComparisonOperator.GREATER_THAN:
case rapiq.FilterComparisonOperator.GREATER_THAN_EQUAL:
{
if (filter.operator === rapiq.FilterComparisonOperator.LESS_THAN) {
statement.push('<');
} else if (filter.operator === rapiq.FilterComparisonOperator.LESS_THAN_EQUAL) {
statement.push('<=');
} else if (filter.operator === rapiq.FilterComparisonOperator.GREATER_THAN) {
statement.push('>');
} else {
statement.push('>=');
}
statement.push(`:${bindingKey}`);
break;
}
}
items.push({
statement: statement.join(' '),
binding: {
[bindingKey]: filter.value
}
});
}
return items;
}
/**
* Apply transformed filter[s] parameter data on the db query.
*
* @param query
* @param data
*/ function applyFiltersTransformed(query, data) {
if (data.length === 0) {
return data;
}
/* istanbul ignore next */ query.andWhere(new typeorm.Brackets((qb)=>{
for(let i = 0; i < data.length; i++){
if (i === 0) {
qb.where(data[i].statement, data[i].binding);
} else {
qb.andWhere(data[i].statement, data[i].binding);
}
}
}));
return data;
}
/**
* Apply parsed filter[s] parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryFiltersParseOutput(query, data, options) {
applyFiltersTransformed(query, transformParsedFilters(data, options));
return data;
}
// --------------------------------------------------
/**
* Apply raw filter[s] parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryFilters(query, data, options) {
options = options || {};
if (options.defaultAlias) {
options.defaultPath = options.defaultAlias;
}
return applyQueryFiltersParseOutput(query, rapiq.parseQueryFilters(data, options), options);
}
/**
* Apply raw filter[s] parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyFilters(query, data, options) {
return applyQueryFilters(query, data, options);
}
/**
* Apply parsed page/pagination parameter data on the db query.
*
* @param query
* @param data
*/ function applyQueryPaginationParseOutput(query, data) {
/* istanbul ignore next */ if (typeof data.limit !== 'undefined') {
query.take(data.limit);
if (typeof data.offset === 'undefined') {
query.skip(0);
}
}
/* istanbul ignore next */ if (typeof data.offset !== 'undefined') {
query.skip(data.offset);
}
return data;
}
/**
* Apply raw page/pagination parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryPagination(query, data, options) {
return applyQueryPaginationParseOutput(query, rapiq.parseQueryPagination(data, options));
}
/**
* Apply raw page/pagination parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyPagination(query, data, options) {
return applyQueryPagination(query, data, options);
}
/**
* Apply parsed include/relation parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryRelationsParseOutput(query, data, options) {
options = options || {};
for(let i = 0; i < data.length; i++){
const parts = data[i].key.split('.');
let key;
if (parts.length > 1) {
key = parts.slice(-2).join('.');
} else {
key = buildKeyWithPrefix(data[i].key, options.defaultAlias);
}
data[i].key = key;
/* istanbul ignore next */ query.leftJoinAndSelect(key, data[i].value);
}
return data;
}
/**
* Apply raw include/relations parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQueryRelations(query, data, options) {
return applyQueryRelationsParseOutput(query, rapiq.parseQueryRelations(data, options), options);
}
/**
* Apply raw include/relations parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyRelations(query, data, options) {
return applyQueryRelations(query, data, options);
}
// --------------------------------------------------
/**
* Apply parsed sort parameter data on the db query.
*
* @param query
* @param data
*/ function applyQuerySortParseOutput(query, data) {
if (data.length === 0) {
return data;
}
const sort = {};
for(let i = 0; i < data.length; i++){
const key = buildKeyWithPrefix(data[i].key, data[i].path);
sort[key] = data[i].value;
}
query.orderBy(sort);
return data;
}
/**
* Apply raw sort parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applyQuerySort(query, data, options) {
options = options || {};
if (options.defaultAlias) {
options.defaultPath = options.defaultAlias;
}
return applyQuerySortParseOutput(query, rapiq.parseQuerySort(data, options));
}
/**
* Apply raw sort parameter data on the db query.
*
* @param query
* @param data
* @param options
*/ function applySort(query, data, options) {
return applyQuerySort(query, data, options);
}
function applyQueryParseOutput(query, context) {
if (context.fields) {
applyQueryFieldsParseOutput(query, context.fields, {
defaultAlias: context.defaultPath,
relations: context.relations
});
}
if (context.filters) {
applyQueryFiltersParseOutput(query, context.filters, {
defaultAlias: context.defaultPath,
relations: context.relations
});
}
if (context.pagination) {
applyQueryPaginationParseOutput(query, context.pagination);
}
if (context.relations) {
applyQueryRelationsParseOutput(query, context.relations, {
defaultAlias: context.defaultPath
});
}
if (context.sort) {
applyQuerySortParseOutput(query, context.sort);
}
return context;
}
function applyQuery(query, input, options) {
options = options || {};
if (options.defaultAlias) {
options.defaultPath = options.defaultAlias;
}
if (typeof options.fields === 'undefined' || !isQueryOptionDefined(options.fields, [
'allowed',
'default'
])) {
options.fields = false;
}
if (typeof options.filters === 'undefined' || !isQueryOptionDefined(options.filters, [
'allowed',
'default'
])) {
options.filters = false;
}
if (typeof options.pagination === 'undefined') {
options.pagination = false;
}
if (typeof options.relations === 'undefined' || !isQueryOptionDefined(options.relations, [
'allowed'
])) {
options.relations = false;
}
if (typeof options.sort === 'undefined' || !isQueryOptionDefined(options.sort, [
'allowed',
'default'
])) {
options.sort = false;
}
const output = applyQueryParseOutput(query, rapiq.parseQuery(input, options));
return {
...output,
...options.defaultAlias ? {
defaultAlias: options.defaultAlias
} : {}
};
}
async function findDataSource(context = {}) {
let tsconfig;
if (!context.preserveFilePaths) {
if (locter.isObject(context.tsconfig)) {
tsconfig = context.tsconfig;
} else {
tsconfig = await readTSConfig(context.tsconfig);
}
}
const files = [
'data-source'
];
if (context.fileName) {
context.fileName = locter.removeFileNameExtension(context.fileName, [
'.ts',
'.mts',
'.cts',
'.js',
'.mjs',
'.cjs'
]);
if (context.fileName !== 'data-source') {
files.unshift(context.fileName);
}
}
let { directory } = context;
let directoryIsPattern = false;
if (context.directory) {
if (path.isAbsolute(context.directory)) {
directory = context.directory;
} else {
directoryIsPattern = true;
directory = safeReplaceWindowsSeparator(context.directory);
}
if (!context.preserveFilePaths) {
directory = await adjustFilePath(directory, tsconfig);
}
}
const lookupPaths = [];
for(let j = 0; j < files.length; j++){
if (directory && directoryIsPattern) {
lookupPaths.push(path.posix.join(directory, files[j]));
}
lookupPaths.push(...[
path.posix.join('src', files[j]),
path.posix.join('src/{db,database}', files[j])
]);
}
files.push(...lookupPaths);
if (!context.preserveFilePaths) {
for(let j = 0; j < files.length; j++){
files[j] = await adjustFilePath(files[j], tsconfig);
}
}
for(let i = 0; i < files.length; i++){
const info = await locter.locate(`${files[i]}.{js,cjs,mjs,ts,cts,mts}`, {
path: [
process.cwd(),
...directory && !directoryIsPattern ? [
directory
] : []
],
ignore: [
'**/*.d.ts'
]
});
if (info) {
let moduleRecord = await locter.load(info);
if (isPromise(moduleRecord)) {
moduleRecord = await moduleRecord;
}
if (typeorm.InstanceChecker.isDataSource(moduleRecord)) {
return moduleRecord;
}
if (!locter.isObject(moduleRecord)) {
continue;
}
const keys = Object.keys(moduleRecord);
for(let j = 0; j < keys.length; j++){
let value = moduleRecord[keys[j]];
if (isPromise(value)) {
value = await value;
}
if (typeorm.InstanceChecker.isDataSource(value)) {
return value;
}
}
}
}
return undefined;
}
/*
* Copyright (c) 2023-2023.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/ var EnvironmentName = /*#__PURE__*/ function(EnvironmentName) {
EnvironmentName["DEVELOPMENT"] = "development";
EnvironmentName["PRODUCTION"] = "production";
EnvironmentName["TEST"] = "test";
return EnvironmentName;
}({});
var EnvironmentVariableName = /*#__PURE__*/ function(EnvironmentVariableName) {
EnvironmentVariableName["ENV"] = "NODE_ENV";
// Seeder
EnvironmentVariableName["SEEDS"] = "DB_SEEDS";
EnvironmentVariableName["SEEDS_ALT"] = "TYPEORM_SEEDING_SEEDS";
EnvironmentVariableName["FACTORIES"] = "DB_FACTORIES";
EnvironmentVariableName["FACTORIES_ALT"] = "TYPEORM_SEEDING_FACTORIES";
// Database
EnvironmentVariableName["TYPE"] = "DB_TYPE";
EnvironmentVariableName["TYPE_ALT"] = "TYPEORM_CONNECTION";
EnvironmentVariableName["URL"] = "DB_URL";
EnvironmentVariableName["URL_ALT"] = "TYPEORM_URL";
EnvironmentVariableName["HOST"] = "DB_HOST";
EnvironmentVariableName["HOST_ALT"] = "TYPEORM_HOST";
EnvironmentVariableName["PORT"] = "DB_PORT";
EnvironmentVariableName["PORT_ALT"] = "TYPEORM_PORT";
EnvironmentVariableName["USERNAME"] = "DB_USERNAME";
EnvironmentVariableName["USERNAME_ALT"] = "TYPEORM_USERNAME";
EnvironmentVariableName["PASSWORD"] = "DB_PASSWORD";
EnvironmentVariableName["PASSWORD_ALT"] = "TYPEORM_PASSWORD";
EnvironmentVariableName["DATABASE"] = "DB_DATABASE";
EnvironmentVariableName["DATABASE_ALT"] = "TYPEORM_DATABASE";
EnvironmentVariableName["SID"] = "DB_SID";
EnvironmentVariableName["SID_ALT"] = "TYPEORM_SID";
EnvironmentVariableName["SCHEMA"] = "DB_SCHEMA";
EnvironmentVariableName["SCHEMA_ALT"] = "TYPEORM_SCHEMA";
EnvironmentVariableName["SCHEMA_DROP"] = "DB_DROP_SCHEMA";
EnvironmentVariableName["SCHEMA_DROP_ALT"] = "TYPEORM_DROP_SCHEMA";
EnvironmentVariableName["DRIVER_EXTRA"] = "DB_DRIVER_EXTRA";
EnvironmentVariableName["DRIVER_EXTRA_ALT"] = "TYPEORM_DRIVER_EXTRA";
EnvironmentVariableName["SYNCHRONIZE"] = "DB_SYNCHRONIZE";
EnvironmentVariableName["SYNCHRONIZE_ALT"] = "TYPEORM_SYNCHRONIZE";
EnvironmentVariableName["MIGRATIONS"] = "DB_MIGRATIONS";
EnvironmentVariableName["MIGRATIONS_ALT"] = "TYPEORM_MIGRATIONS";
EnvironmentVariableName["MIGRATIONS_RUN"] = "DB_MIGRATIONS_RUN";
EnvironmentVariableName["MIGRATIONS_RUN_ALT"] = "TYPEORM_MIGRATIONS_RUN";
EnvironmentVariableName["MIGRATIONS_TABLE_NAME"] = "DB_MIGRATIONS_TABLE_NAME";
EnvironmentVariableName["MIGRATIONS_TABLE_NAME_ALT"] = "TYPEORM_MIGRATIONS_TABLE_NAME";
EnvironmentVariableName["ENTITIES"] = "DB_ENTITIES";
EnvironmentVariableName["ENTITIES_ALT"] = "TYPEORM_ENTITIES";
EnvironmentVariableName["ENTITY_PREFIX"] = "DB_ENTITY_PREFIX";
EnvironmentVariableName["ENTITY_PREFIX_ALT"] = "TYPEORM_ENTITY_PREFIX";
EnvironmentVariableName["METADATA_TABLE_NAME"] = "DB_METADATA_TABLE_NAME";
EnvironmentVariableName["METADATA_TABLE_NAME_ALT"] = "TYPEORM_METADATA_TABLE_NAME";
EnvironmentVariableName["SUBSCRIBERS"] = "DB_SUBSCRIBERS";
EnvironmentVariableName["SUBSCRIBERS_ALT"] = "TYPEORM_SUBSCRIBERS";
EnvironmentVariableName["LOGGING"] = "DB_LOGGING";
EnvironmentVariableName["LOGGING_ALT"] = "TYPEORM_LOGGING";
EnvironmentVariableName["LOGGER"] = "DB_LOGGER";
EnvironmentVariableName["LOGGER_ALT"] = "TYPEORM_LOGGER";
EnvironmentVariableName["MAX_QUERY_EXECUTION_TIME"] = "DB_MAX_QUERY_EXECUTION_TIME";
EnvironmentVariableName["MAX_QUERY_EXECUTION_TIME_ALT"] = "TYPEORM_MAX_QUERY_EXECUTION_TIME";
EnvironmentVariableName["DEBUG"] = "DB_DEBUG";
EnvironmentVariableName["DEBUG_ALT"] = "TYPEORM_DEBUG";
EnvironmentVariableName["UUID_EXTENSION"] = "DB_UUID_EXTENSION";
EnvironmentVariableName["UUID_EXTENSION_ALT"] = "TYPEORM_UUID_EXTENSION";
EnvironmentVariableName["CACHE"] = "DB_CACHE";
EnvironmentVariableName["CACHE_ALT"] = "TYPEORM_CACHE";
EnvironmentVariableName["CACHE_ALWAYS_ENABLED"] = "DB_CACHE_ALWAYS_ENABLED";
EnvironmentVariableName["CACHE_ALWAYS_ENABLED_ALT"] = "TYPEORM_CACHE_ALWAYS_ENABLED";
EnvironmentVariableName["CACHE_OPTIONS"] = "DB_CACHE_OPTIONS";
EnvironmentVariableName["CACHE_OPTIONS_ALT"] = "TYPEORM_CACHE_OPTIONS";
EnvironmentVariableName["CACHE_DURATION"] = "DB_CACHE_DURATION";
EnvironmentVariableName["CACHE_DURATION_ALT"] = "TYPEORM_CACHE_DURATION";
return EnvironmentVariableName;
}({});
function transformLogging(input) {
const value = envix.toBool(input);
if (typeof value === 'boolean') {
return value;
}
if (input === 'all') {
return 'all';
}
return envix.toArray(input) ?? [];
}
function transformCache(input) {
const value = envix.toBool(input);
if (typeof value === 'boolean') {
return value;
}
if (input === 'redis' || input === 'ioredis' || input === 'database' || input === 'ioredis/cluster') {
let options;
const envCacheOptions = envix.oneOf([
envix.read(EnvironmentVariableName.CACHE_OPTIONS),
envix.read(EnvironmentVariableName.CACHE_OPTIONS_ALT)
]);
if (envCacheOptions) {
options = JSON.parse(envCacheOptions);
}
return {
type: input,
options,
alwaysEnabled: envix.oneOf([
envix.readBool(EnvironmentVariableName.CACHE_ALWAYS_ENABLED),
envix.readBool(EnvironmentVariableName.CACHE_ALWAYS_ENABLED_ALT)
]),
duration: envix.oneOf([
envix.readInt(EnvironmentVariableName.CACHE_DURATION),
envix.readInt(EnvironmentVariableName.CACHE_DURATION_ALT)
])
};
}
return undefined;
}
let instance$1;
function useEnv(key) {
if (typeof instance$1 !== 'undefined') {
if (typeof key === 'string') {
return instance$1[key];
}
return instance$1;
}
const output = {
env: envix.read(EnvironmentVariableName.ENV, EnvironmentName.DEVELOPMENT),
// Seeder
seeds: envix.oneOf([
envix.readArray(EnvironmentVariableName.SEEDS),
envix.readArray(EnvironmentVariableName.SEEDS_ALT)
]) ?? [],
factories: envix.oneOf([
envix.readArray(EnvironmentVariableName.FACTORIES),
envix.readArray(EnvironmentVariableName.FACTORIES_ALT)
]) ?? [],
// Database
url: envix.oneOf([
envix.read(EnvironmentVariableName.URL),
envix.read(EnvironmentVariableName.URL_ALT)
]),
host: envix.oneOf([
envix.read(EnvironmentVariableName.HOST),
envix.read(EnvironmentVariableName.HOST_ALT)
]),
port: envix.oneOf([
envix.readInt(EnvironmentVariableName.PORT),
envix.readInt(EnvironmentVariableName.PORT_ALT)
]),
username: envix.oneOf([
envix.read(EnvironmentVariableName.USERNAME),
envix.read(EnvironmentVariableName.USERNAME_ALT)
]),
password: envix.oneOf([
envix.read(EnvironmentVariableName.PASSWORD),
envix.read(EnvironmentVariableName.PASSWORD_ALT)
]),
database: envix.oneOf([
envix.read(EnvironmentVariableName.DATABASE),
envix.read(EnvironmentVariableName.DATABASE_ALT)
]),
sid: envix.oneOf([
envix.read(EnvironmentVariableName.SID),
envix.read(EnvironmentVariableName.SID_ALT)
]),
schema: envix.oneOf([
envix.read(EnvironmentVariableName.SCHEMA),
envix.read(EnvironmentVariableName.SCHEMA_ALT)
]),
extra: envix.oneOf([
envix.read(EnvironmentVariableName.DRIVER_EXTRA),
envix.read(EnvironmentVariableName.DRIVER_EXTRA_ALT)
]),
synchronize: envix.oneOf([
envix.readBool(EnvironmentVariableName.SYNCHRONIZE),
envix.readBool(EnvironmentVariableName.SYNCHRONIZE_ALT)
]),
schemaDrop: envix.oneOf([
envix.readBool(EnvironmentVariableName.SCHEMA_DROP),
envix.readBool(EnvironmentVariableName.SCHEMA_DROP_ALT)
]),
migrationsRun: envix.oneOf([
envix.readBool(EnvironmentVariableName.MIGRATIONS_RUN),
envix.readBool(EnvironmentVariableName.MIGRATIONS_RUN_ALT)
]),
entities: envix.oneOf([
envix.readArray(EnvironmentVariableName.ENTITIES),
envix.readArray(EnvironmentVariableName.ENTITIES_ALT)
]) ?? [],
migrations: envix.oneOf([
envix.readArray(EnvironmentVariableName.MIGRATIONS),
envix.readArray(EnvironmentVariableName.MIGRATIONS_ALT)
]) ?? [],
migrationsTableName: envix.oneOf([
envix.read(EnvironmentVariableName.MIGRATIONS_TABLE_NAME),
envix.read(EnvironmentVariableName.MIGRATIONS_TABLE_NAME_ALT)
]),
metadataTableName: envix.oneOf([
envix.read(EnvironmentVariableName.METADATA_TABLE_NAME),
envix.read(EnvironmentVariableName.METADATA_TABLE_NAME_ALT)
]),
subscribers: envix.oneOf([
envix.readArray(EnvironmentVariableName.SUBSCRIBERS),
envix.readArray(EnvironmentVariableName.SUBSCRIBERS_ALT)
]) ?? [],
logging: transformLogging(envix.oneOf([
envix.read(EnvironmentVariableName.LOGGING),
envix.read(EnvironmentVariableName.LOGGING_ALT)
])),
logger: envix.oneOf([
envix.read(EnvironmentVariableName.LOGGER),
envix.read(EnvironmentVariableName.LOGGER_ALT)
]),
entityPrefix: envix.oneOf([
envix.read(EnvironmentVariableName.ENTITY_PREFIX),
envix.read(EnvironmentVariableName.ENTITY_PREFIX_ALT)
]),
maxQueryExecutionTime: envix.oneOf([
envix.readInt(EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME),
envix.readInt(EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME_ALT)
]),
debug: envix.oneOf([
envix.read(EnvironmentVariableName.DEBUG),
envix.read(EnvironmentVariableName.DEBUG_ALT)
]),
cache: transformCache(envix.oneOf([
envix.read(EnvironmentVariableName.CACHE),
envix.read(EnvironmentVariableName.CACHE_ALT)
])),
uuidExtension: envix.oneOf([
envix.read(EnvironmentVariableName.UUID_EXTENSION),
envix.read(EnvironmentVariableName.UUID_EXTENSION_ALT)
])
};
if (output.extra) {
output.extra = JSON.parse(output.extra); // todo: ensure record<string,any> ??
}
let type;
const envType = envix.oneOf([
envix.read(EnvironmentVariableName.TYPE),
envix.read(EnvironmentVariableName.TYPE_ALT)
]);
if (envType) {
type = envType;
} else {
const envURL = envix.oneOf([
envix.read(EnvironmentVariableName.URL),
envix.read(EnvironmentVariableName.URL_ALT)
]);
if (envURL) {
[type] = envURL.split('://');
}
}
if (type) {
output.type = type; // todo: maybe validation here
}
instance$1 = output;
if (typeof key === 'string') {
return output[key];
}
return instance$1;
}
function resetEnv() {
if (typeof instance$1 !== 'undefined') {
instance$1 = undefined;
}
}
const merge = smob.createMerger({
strategy: (target, key, value)=>{
if (typeof target[key] === 'undefined') {
target[key] = value;
return target;
}
return undefined;
}
});
function mergeDataSourceOptions(target, source) {
if (target.type !== source.type) {
return target;
}
return merge(target, source);
}
function hasEnvDataSourceOptions() {
return !!useEnv('type');
}
/* istanbul ignore next */ function readDataSourceOptionsFromEnv() {
if (!hasEnvDataSourceOptions()) {
return undefined;
}
// todo: include seeder options
const base = {
type: useEnv('type'),
entities: useEnv('entities'),
subscribers: useEnv('subscribers'),
migrations: useEnv('migrations'),
migrationsTableName: useEnv('migrationsTableName'),
// migrationsTransactionMode: useEnv('migra')
metadataTableName: useEnv('metadataTableName'),
logging: useEnv('logging'),
logger: useEnv('logger'),
maxQueryExecutionTime: useEnv('maxQueryExecutionTime'),
synchronize: useEnv('synchronize'),
migrationsRun: useEnv('migrationsRun'),
dropSchema: useEnv('schemaDrop'),
entityPrefix: useEnv('entityPrefix'),
extra: useEnv('extra'),
cache: useEnv('cache')
};
const credentialOptions = {
url: useEnv('url'),
host: useEnv('host'),
port: useEnv('port'),
username: useEnv('username'),
password: useEnv('password'),
database: useEnv('database')
};
if (base.type === 'mysql' || base.type === 'mariadb') {
return {
...base,
...credentialOptions,
type: base.type
};
}
if (base.type === 'postgres') {
return {
...base,
...credentialOptions,
type: base.type,
schema: useEnv('schema'),
uuidExtension: useEnv('uuidExtension')
};
}
if (base.type === 'cockroachdb') {
return {
...base,
...credentialOptions,
type: base.type,
schema: useEnv('schema'),
timeTravelQueries: true
};
}
if (base.type === 'sqlite') {
return {
...base,
type: base.type,
database: useEnv('database') || 'db.sqlite'
};
}
if (base.type === 'better-sqlite3') {
return {
...base,
type: base.type,
database: useEnv('database') || 'db.sqlite'
};
}
if (base.type === 'mssql') {
return {
...base,
...credentialOptions,
type: base.type,
schema: useEnv('schema')
};
}
if (base.type === 'oracle') {
return {
...base,
...credentialOptions,
type: base.type,
sid: useEnv('sid')
};
}
return {
...base,
...credentialOptions
};
}
function mergeDataSourceOptionsWithEnv(options) {
const env = readDataSourceOptionsFromEnv();
if (!env) {
return options;
}
return mergeDataSourceOptions(env, options);
}
/**
* Build DataSourceOptions from DataSource or from configuration.
*
* @param context
*/ async function buildDataSourceOptions(context = {}) {
const directory = context.directory || process.cwd();
let tsconfig;
if (!context.preserveFilePaths) {
if (locter.isObject(context.tsconfig)) {
tsconfig = context.tsconfig;
} else {
tsconfig = await readTSConfig(context.tsconfig);
}
}
const dataSource = await findDataSource({
directory,
fileName: context.dataSourceName,
tsconfig
});
if (dataSource) {
if (context.preserveFilePaths) {
return mergeDataSourceOptionsWithEnv(dataSource.options);
}
const options = await adjustFilePaths(dataSource.options, [
'entities',
'migrations',
'subscribers'
], tsconfig);
return mergeDataSourceOptionsWithEnv(options);
}
const options = readDataSourceOptionsFromEnv();
if (options) {
if (context.preserveFilePaths) {
return options;
}
return adjustFilePaths(options, [
'entities',
'migrations',
'subscribers'
], tsconfig);
}
throw OptionsError.notFound();
}
const instances$1 = {};
const instancePromises = {};
function setDataSourceOptions(options, alias) {
instances$1[alias || 'default'] = options;
}
function hasDataSourceOptions(alias) {
return Object.prototype.hasOwnProperty.call(instances$1, alias || 'default');
}
async function useDataSourceOptions(alias) {
alias = alias || 'default';
if (Object.prototype.hasOwnProperty.call(instances$1, alias)) {
return instances$1[alias];
}
/* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(instancePromises, alias)) {
instancePromises[alias] = buildDataSourceOptions().catch((e)=>{
if (alias) {
delete instancePromises[alias];
}
throw e;
});
}
instances$1[alias] = await instancePromises[alias];
return instances$1[alias];
}
const instances = {};
const initializePromises = {};
const optionsPromises = {};
function setDataSource(dataSource, alias) {
alias = alias || 'default';
instances[alias] = dataSource;
}
function hasDataSource(alias) {
alias = alias || 'default';
return Object.prototype.hasOwnProperty.call(instances, alias);
}
function unsetDataSource(alias) {
alias = alias || 'default';
if (Object.prototype.hasOwnProperty.call(instances, alias)) {
delete instances[alias];
}
/* istanbul ignore next */ if (Object.prototype.hasOwnProperty.call(optionsPromises, alias)) {
delete optionsPromises[alias];
}
/* istanbul ignore next */ if (Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
delete initializePromises[alias];
}
}
async function useDataSource(alias) {
alias = alias || 'default';
if (Object.prototype.hasOwnProperty.call(instances, alias)) {
if (!instances[alias].isInitialized) {
/* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
initializePromises[alias] = instances[alias].initialize().catch((e)=>{
if (alias) {
delete initializePromises[alias];
}
throw e;
});
}
await initializePromises[alias];
}
return instances[alias];
}
/* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(optionsPromises, alias)) {
optionsPromises[alias] = useDataSourceOptions(alias).catch((e)=>{
if (alias) {
delete optionsPromises[alias];
}
throw e;
});
}
const options = await optionsPromises[alias];
const dataSource = new typeorm.DataSource(options);
/* istanbul ignore next */ if (!Object.prototype.hasOwnProperty.call(initializePromises, alias)) {
initializePromises[alias] = dataSource.initialize().catch((e)=>{
if (alias) {
delete initializePromises[alias];
}
throw e;
});
}
await initializePromises[alias];
instances[alias] = dataSource;
return dataSource;
}
/**
* Check database setup progress.
*
* @param context
*/ async function checkDatabase(context = {}) {
const result = {
exists: true,
schema: false,
migrationsPending: []
};
let dataSource;
let dataSourceCleanup;
if (typeof context.dataSource === 'undefined' && typeof context.options === 'undefined' && hasDataSource(context.alias)) {
dataSource = await useDataSource(context.alias);
if (dataSource.options.synchronize || dataSource.options.migrationsRun) {
dataSource = new typeorm.DataSource({
...dataSource.options,
synchronize: false,
migrationsRun: false
});
dataSourceCleanup = true;
} else {
dataSourceCleanup = false;
}
} else {
let dataSourceOptions;
if (context.options) {
dataSourceOptions = context.options;
} else {
dataSourceOptions = await useDataSourceOptions(context.alias);
}
dataSource = new typeorm.DataSource({
...dataSourceOptions,
synchronize: false,
migrationsRun: false
});
dataSourceCleanup = context.dataSourceCleanup ?? true;
}
try {
if (!dataSource.isInitialized) {
await dataSource.initialize();
}
} catch (e) {
result.exists = false;
return result;
}
const queryRunner = dataSource.createQueryRunner();
if (dataSource.migrations && dataSource.migrations.length > 0) {
const migrationExecutor = new typeorm.MigrationExecutor(dataSource, queryRunner);
result.migrationsPending = await migrationExecutor.getPendingMigrations();
result.schema = result.migrationsPending.length === 0;
} else {
let schema;
if (hasStringProperty(dataSource.driver.options, 'schema')) {
schema = dataSource.driver.options.schema;
}
const migrationsTableName = dataSource.driver.buildTableName(dataSource.options.migrationsTableName || 'migrations', schema, dataSource.driver.database);
const migrationsTableExists = await queryRunner.hasTable(migrationsTableName);
if (migrationsTableExists) {
result.schema = dataSource.entityMetadatas.length === 0;
} else {
const tableNames = dataSource.entityMetadatas.map((entityMetadata)=>entityMetadata.tablePath);
const tables = await queryRunner.getTables(tableNames);
if (tables.length === dataSource.entityMetadatas.length) {
const { upQueries } = await dataSource.driver.createSchemaBuilder().log();
result.schema = upQueries.length === 0;
} else {
result.schema = false;
}
}
}
await queryRunner.release();
if (dataSourceCleanup) {
await dataSource.destroy();
}
return result;
}
function getCharsetFromDataSourceOptions(options) {
if (hasOwnProperty(options, 'charset') && typeof options.charset === 'string') {
return options.charset;
}
if (typeof options?.extra?.charset === 'string') {
return options.extra.charset;
}
return undefined;
}
function getCharacterSetFromDataSourceOptions(options) {
if (hasOwnProperty(options, 'characterSet') && typeof options.characterSet === 'string') {
return options.characterSet;
}
if (typeof options?.extra?.characterSet === 'string') {
return options.extra.characterSet;
}
return undefined;
}
function buildDriverOptions(options) {
let driverOptions;
switch(options.type){
case 'mysql':
case 'mariadb':
case 'postgres':
case 'cockroachdb':
case 'mssql':
case 'oracle':
driverOptions = DriverUtils.DriverUtils.buildDriverOptions(options.replication ? options.replication.master : options);
break;
case 'mongodb':
driverOptions = DriverUtils.DriverUtils.buildMongoDBDriverOptions(options);
break;
default:
driverOptions = DriverUtils.DriverUtils.buildDriverOptions(options);
}
const charset = getCharsetFromDataSourceOptions(options);
const characterSet = getCharacterSetFromDataSourceOptions(options);
return {
host: driverOptions.host,
user: driverOptions.user || driverOptions.username,
password: driverOptions.password,
database: driverOptions.database,
port: driverOptions.port,
...charset ? {
charset
} : {},
...characterSet ? {
characterSet
} : {},
...driverOptions.ssl ? {
ssl: driverOptions.ssl
} : {},
...driverOptions.url ? {
url: driverOptions.url
} : {},
...driverOptions.connectString ? {
connectString: driverOptions.connectString
} : {},
...driverOptions.sid ? {
sid: driverOptions.sid
} : {},
...driverOptions.serviceName ? {
serviceName: driverOptions.serviceName
} : {},
...driverOptions.template ? {
template: driverOptions.template
} : {},
...options.extra ? {
extra: options.extr