Skip to content

Commit

Permalink
feat: experimental read env data-source options and merge them with f…
Browse files Browse the repository at this point in the history
…ile based options
  • Loading branch information
tada5hi committed Apr 1, 2023
1 parent c3a401c commit e5c4e1b
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 46 deletions.
37 changes: 19 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"pascal-case": "^3.1.2",
"rapiq": "^0.8.0",
"reflect-metadata": "^0.1.13",
"smob": "^1.0.0",
"yargs": "^17.7.1"
},
"peerDependencies": {
Expand Down
21 changes: 19 additions & 2 deletions src/data-source/options/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import type { DataSourceOptions } from 'typeorm';
import { ConnectionOptionsReader } from 'typeorm';
import type { DataSourceOptionsBuildContext } from './type';
import { setDefaultSeederOptions } from '../../seeder';
import { adjustFilePathsForDataSourceOptions } from './utils';
import {
adjustFilePathsForDataSourceOptions,
mergeDataSourceOptionsWithEnv,
readDataSourceOptionsFromEnv,
} from './utils';
import { findDataSource } from '../find';

export async function extendDataSourceOptions(
Expand Down Expand Up @@ -57,10 +61,23 @@ export async function buildDataSourceOptions(
});

if (dataSource) {
return extendDataSourceOptions(
const options = await extendDataSourceOptions(
dataSource.options,
tsconfigDirectory,
);

if (context.experimental) {
return mergeDataSourceOptionsWithEnv(options);
}

return options;
}

if (context.experimental) {
const options = readDataSourceOptionsFromEnv();
if (options) {
return options;
}
}

return buildLegacyDataSourceOptions(context);
Expand Down
8 changes: 7 additions & 1 deletion src/data-source/options/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,11 @@ export type DataSourceOptionsBuildContext = {
* Directory path to the tsconfig.json file
* Default: process.cwd()
*/
tsconfigDirectory?: string
tsconfigDirectory?: string,

/**
* Use experimental features,
* like merging env and file data-source options.
*/
experimental?: boolean
};
129 changes: 129 additions & 0 deletions src/data-source/options/utils/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { merge } from 'smob';
import type { DataSourceOptions } from 'typeorm';
import type { BaseDataSourceOptions } from 'typeorm/data-source/BaseDataSourceOptions';
import type { BetterSqlite3ConnectionOptions } from 'typeorm/driver/better-sqlite3/BetterSqlite3ConnectionOptions';
import type { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
import type { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions';
import type { SqlServerConnectionOptions } from 'typeorm/driver/sqlserver/SqlServerConnectionOptions';
import type { DatabaseType } from 'typeorm/driver/types/DatabaseType';
import type { LoggerOptions } from 'typeorm/logger/LoggerOptions';
import { useEnv } from '../../../env';

export function hasEnvDataSourceOptions() : boolean {
return !!useEnv('type');
}

export function readDataSourceOptionsFromEnv() : DataSourceOptions | undefined {
if (!hasEnvDataSourceOptions()) {
return undefined;
}

// todo: include seeder options
const base : BaseDataSourceOptions = {
type: useEnv('type') as DatabaseType,
entities: useEnv('entities'),
subscribers: useEnv('subscribers'),
migrations: useEnv('migrations'),
migrationsTableName: useEnv('migrationsTableName'),
// migrationsTransactionMode: useEnv('migra')
metadataTableName: useEnv('metadataTableName'),
logging: useEnv('logging') as LoggerOptions,
logger: useEnv('logger') as BaseDataSourceOptions['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') as PostgresConnectionOptions['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'),
} as SqliteConnectionOptions;
}

if (base.type === 'better-sqlite3') {
return {
...base,
type: base.type,
database: useEnv('database'),
} as BetterSqlite3ConnectionOptions;
}

if (base.type === 'mssql') {
return {
...base,
...credentialOptions,
type: base.type,
schema: useEnv('schema'),
} as SqlServerConnectionOptions;
}

if (base.type === 'oracle') {
return {
...base,
...credentialOptions,
type: base.type,
sid: useEnv('sid'),
};
}

return {
...base,
...credentialOptions,
} as DataSourceOptions;
}

export function mergeDataSourceOptionsWithEnv(options: DataSourceOptions) {
const env = readDataSourceOptionsFromEnv();
if (!env) {
return options;
}

if (env.type !== options.type) {
return options;
}

return merge({}, env, options);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { DataSourceOptions } from 'typeorm';
import type { SeederOptions } from '../../seeder';
import type { SeederOptions } from '../../../seeder';
import {
CodeTransformation,
hasOwnProperty,
isCodeTransformation,
transformFilePath,
} from '../../utils';
import { readTsConfig } from '../../utils/tsconfig';
} from '../../../utils';
import { readTsConfig } from '../../../utils/tsconfig';

const keys = [
'entities',
Expand Down
2 changes: 2 additions & 0 deletions src/data-source/options/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './env';
export * from './file-path';
4 changes: 2 additions & 2 deletions src/env/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ export enum EnvironmentVariableName {
FACTORIES_ALT = 'TYPEORM_SEEDING_FACTORIES',

// Database
CONNECTION = 'DB_CONNECTION',
CONNECTION_ALT = 'TYPEORM_CONNECTION',
TYPE = 'DB_TYPE',
TYPE_ALT = 'TYPEORM_CONNECTION',

URL = 'DB_URL',
URL_ALT = 'TYPEORM_URL',
Expand Down
15 changes: 11 additions & 4 deletions src/env/module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { DatabaseType } from 'typeorm/driver/types/DatabaseType';
import { EnvironmentName, EnvironmentVariableName } from './constants';
import type { Environment } from './type';
import {
Expand Down Expand Up @@ -115,7 +116,7 @@ export function useEnv(key?: string) : any {
EnvironmentVariableName.ENTITY_PREFIX,
EnvironmentVariableName.ENTITY_PREFIX_ALT,
]),
maxQueryExecutionTime: readFromProcessEnv([
maxQueryExecutionTime: readIntFromProcessEnv([
EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME,
EnvironmentVariableName.MAX_QUERY_EXECUTION_TIME_ALT,
]),
Expand All @@ -139,8 +140,8 @@ export function useEnv(key?: string) : any {
}

let type : string | undefined;
if (hasProcessEnv([EnvironmentVariableName.CONNECTION, EnvironmentVariableName.CONNECTION_ALT])) {
type = readFromProcessEnv([EnvironmentVariableName.CONNECTION, EnvironmentVariableName.CONNECTION_ALT]);
if (hasProcessEnv([EnvironmentVariableName.TYPE, EnvironmentVariableName.TYPE_ALT])) {
type = readFromProcessEnv([EnvironmentVariableName.TYPE, EnvironmentVariableName.TYPE_ALT]);
} else if (hasProcessEnv([EnvironmentVariableName.URL, EnvironmentVariableName.URL_ALT])) {
const temp = readFromProcessEnv([EnvironmentVariableName.URL, EnvironmentVariableName.URL_ALT]);
if (temp) {
Expand All @@ -152,7 +153,7 @@ export function useEnv(key?: string) : any {
}
}
if (type) {
output.type = type;
output.type = type as DatabaseType; // todo: maybe validation here
}

instance = output;
Expand All @@ -163,3 +164,9 @@ export function useEnv(key?: string) : any {

return instance;
}

export function resetEnv() {
if (typeof instance !== 'undefined') {
instance = undefined;
}
}
5 changes: 3 additions & 2 deletions src/env/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { DatabaseType } from 'typeorm/driver/types/DatabaseType';
import type { DataSourceCacheOption } from '../data-source';
import type { EnvironmentName } from './constants';

Expand All @@ -9,7 +10,7 @@ export interface Environment {
factories: string[],

// DataSource
type?: string,
type?: DatabaseType,
url?: string,
host?: string,
port?: number,
Expand All @@ -33,7 +34,7 @@ export interface Environment {
subscribers: string[],
logging: string[] | boolean | string,
logger?: string,
maxQueryExecutionTime?: string,
maxQueryExecutionTime?: number,
debug?: string,
cache?: DataSourceCacheOption,
uuidExtension?: string
Expand Down
Loading

0 comments on commit e5c4e1b

Please sign in to comment.