mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
#62 and #61 - removed all third party dependencies that could be removed for browser platform; added platform tools classes and extracted all platform-specific code there; removed mysql2 driver type - mysql2 can be used if mysql is not installed by mysql2 is
This commit is contained in:
parent
9386825b17
commit
4a85607da1
@ -58,17 +58,10 @@
|
||||
"typescript": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash": "4.14.40",
|
||||
"@types/node": "^6.0.50",
|
||||
"app-root-path": "^2.0.1",
|
||||
"dependency-graph": "^0.5.0",
|
||||
"glob": "^7.1.1",
|
||||
"lodash": "^4.17.2",
|
||||
"path": "^0.12.7",
|
||||
"reflect-metadata": "^0.1.8",
|
||||
"require-all": "^2.0.0",
|
||||
"sha1": "^1.1.1",
|
||||
"url": "^0.11.0",
|
||||
"yargonaut": "^1.1.2",
|
||||
"yargs": "^6.4.0"
|
||||
},
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import * as _ from "lodash";
|
||||
import {NamingStrategyInterface} from "../../../src/naming-strategy/NamingStrategyInterface";
|
||||
import {NamingStrategy} from "../../../src/decorator/NamingStrategy";
|
||||
import {DefaultNamingStrategy} from "../../../src/naming-strategy/DefaultNamingStrategy";
|
||||
import {snakeCase} from "../../../src/util/StringUtils";
|
||||
|
||||
@NamingStrategy("custom_strategy")
|
||||
export class CustomNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
|
||||
tableName(className: string, customName: string): string {
|
||||
return customName ? customName : _.snakeCase(className);
|
||||
return customName ? customName : snakeCase(className);
|
||||
}
|
||||
|
||||
columnName(propertyName: string, customName: string): string {
|
||||
return customName ? customName : _.snakeCase(propertyName);
|
||||
return customName ? customName : snakeCase(propertyName);
|
||||
}
|
||||
|
||||
columnNameCustomized(customName: string): string {
|
||||
@ -19,7 +19,7 @@ export class CustomNamingStrategy extends DefaultNamingStrategy implements Namin
|
||||
}
|
||||
|
||||
relationName(propertyName: string): string {
|
||||
return _.snakeCase(propertyName);
|
||||
return snakeCase(propertyName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import * as fs from "fs";
|
||||
import {Connection} from "./Connection";
|
||||
import {ConnectionNotFoundError} from "./error/ConnectionNotFoundError";
|
||||
import {MysqlDriver} from "../driver/mysql/MysqlDriver";
|
||||
@ -14,6 +13,7 @@ import {OracleDriver} from "../driver/oracle/OracleDriver";
|
||||
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
|
||||
import {OrmUtils} from "../util/OrmUtils";
|
||||
import {CannotDetermineConnectionOptionsError} from "./error/CannotDetermineConnectionOptionsError";
|
||||
import {PlatformTools} from "../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* ConnectionManager is used to store and manage all these different connections.
|
||||
@ -118,7 +118,7 @@ export class ConnectionManager {
|
||||
* it will try to create connection from environment variables.
|
||||
* There are several environment variables you can set:
|
||||
*
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "mysql2", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_URL - database connection url. Should be a string.
|
||||
* - TYPEORM_HOST - database host. Should be a string.
|
||||
* - TYPEORM_PORT - database access port. Should be a number.
|
||||
@ -186,7 +186,7 @@ export class ConnectionManager {
|
||||
* it will try to create connection from environment variables.
|
||||
* There are several environment variables you can set:
|
||||
*
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "mysql2", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_URL - database connection url. Should be a string.
|
||||
* - TYPEORM_HOST - database host. Should be a string.
|
||||
* - TYPEORM_PORT - database access port. Should be a number.
|
||||
@ -254,18 +254,18 @@ export class ConnectionManager {
|
||||
* Checks if ormconfig.json exists.
|
||||
*/
|
||||
protected hasOrmConfigurationFile(): boolean {
|
||||
const path = require("app-root-path").path + "/ormconfig.json";
|
||||
if (!fs.existsSync(path))
|
||||
const path = PlatformTools.load("app-root-path").path + "/ormconfig.json";
|
||||
if (!PlatformTools.fileExist(path))
|
||||
return false;
|
||||
|
||||
const configuration: ConnectionOptions[]|ConnectionOptions = require(path);
|
||||
const configuration: ConnectionOptions[]|ConnectionOptions = PlatformTools.load(path);
|
||||
if (configuration instanceof Array) {
|
||||
return configuration
|
||||
.filter(options => !options.environment || options.environment === process.env.NODE_ENV)
|
||||
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV"))
|
||||
.length > 0;
|
||||
|
||||
} else if (configuration instanceof Object) {
|
||||
if (configuration.environment && configuration.environment !== process.env.NODE_ENV)
|
||||
if (configuration.environment && configuration.environment !== PlatformTools.getEnvVariable("NODE_ENV"))
|
||||
return false;
|
||||
|
||||
return Object.keys(configuration).length > 0;
|
||||
@ -278,14 +278,14 @@ export class ConnectionManager {
|
||||
* Checks if there is a default connection in the ormconfig.json file.
|
||||
*/
|
||||
protected hasDefaultConfigurationInConfigurationFile(): boolean {
|
||||
const path = require("app-root-path").path + "/ormconfig.json";
|
||||
if (!fs.existsSync(path))
|
||||
const path = PlatformTools.load("app-root-path").path + "/ormconfig.json";
|
||||
if (!PlatformTools.fileExist(path))
|
||||
return false;
|
||||
|
||||
const configuration: ConnectionOptions[]|ConnectionOptions = require(path);
|
||||
const configuration: ConnectionOptions[]|ConnectionOptions = PlatformTools.load(path);
|
||||
if (configuration instanceof Array) {
|
||||
return !!configuration
|
||||
.filter(options => !options.environment || options.environment === process.env.NODE_ENV)
|
||||
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV"))
|
||||
.find(config => !!config.name || config.name === "default");
|
||||
|
||||
} else if (configuration instanceof Object) {
|
||||
@ -293,7 +293,7 @@ export class ConnectionManager {
|
||||
configuration.name !== "default")
|
||||
return false;
|
||||
|
||||
if (configuration.environment && configuration.environment !== process.env.NODE_ENV)
|
||||
if (configuration.environment && configuration.environment !== PlatformTools.getEnvVariable("NODE_ENV"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -306,7 +306,7 @@ export class ConnectionManager {
|
||||
* Checks if environment variables contains connection options.
|
||||
*/
|
||||
protected hasDefaultConfigurationInEnvironmentVariables(): boolean {
|
||||
return !!process.env.TYPEORM_DRIVER_TYPE;
|
||||
return !!PlatformTools.getEnvVariable("TYPEORM_DRIVER_TYPE");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,28 +315,28 @@ export class ConnectionManager {
|
||||
protected async createFromEnvAndConnect(): Promise<Connection> {
|
||||
return this.createAndConnectByConnectionOptions({
|
||||
driver: {
|
||||
type: process.env.TYPEORM_DRIVER_TYPE,
|
||||
url: process.env.TYPEORM_URL,
|
||||
host: process.env.TYPEORM_HOST,
|
||||
port: process.env.TYPEORM_PORT,
|
||||
username: process.env.TYPEORM_USERNAME,
|
||||
password: process.env.TYPEORM_PASSWORD,
|
||||
database: process.env.TYPEORM_DATABASE,
|
||||
sid: process.env.TYPEORM_SID,
|
||||
storage: process.env.TYPEORM_STORAGE,
|
||||
usePool: process.env.TYPEORM_USE_POOL !== undefined ? OrmUtils.toBoolean(process.env.TYPEORM_USE_POOL) : undefined, // special check for defined is required here
|
||||
extra: process.env.TYPEORM_DRIVER_EXTRA ? JSON.parse(process.env.TYPEORM_DRIVER_EXTRA) : undefined
|
||||
type: PlatformTools.getEnvVariable("TYPEORM_DRIVER_TYPE"),
|
||||
url: PlatformTools.getEnvVariable("TYPEORM_URL"),
|
||||
host: PlatformTools.getEnvVariable("TYPEORM_HOST"),
|
||||
port: PlatformTools.getEnvVariable("TYPEORM_PORT"),
|
||||
username: PlatformTools.getEnvVariable("TYPEORM_USERNAME"),
|
||||
password: PlatformTools.getEnvVariable("TYPEORM_PASSWORD"),
|
||||
database: PlatformTools.getEnvVariable("TYPEORM_DATABASE"),
|
||||
sid: PlatformTools.getEnvVariable("TYPEORM_SID"),
|
||||
storage: PlatformTools.getEnvVariable("TYPEORM_STORAGE"),
|
||||
usePool: PlatformTools.getEnvVariable("TYPEORM_USE_POOL") !== undefined ? OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_USE_POOL")) : undefined, // special check for defined is required here
|
||||
extra: PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA") ? JSON.parse(PlatformTools.getEnvVariable("TYPEORM_DRIVER_EXTRA")) : undefined
|
||||
},
|
||||
autoSchemaSync: OrmUtils.toBoolean(process.env.TYPEORM_AUTO_SCHEMA_SYNC),
|
||||
entities: process.env.TYPEORM_ENTITIES ? process.env.TYPEORM_ENTITIES.split(",") : [],
|
||||
subscribers: process.env.TYPEORM_SUBSCRIBERS ? process.env.TYPEORM_SUBSCRIBERS.split(",") : [],
|
||||
entitySchemas: process.env.TYPEORM_ENTITY_SCHEMAS ? process.env.TYPEORM_ENTITY_SCHEMAS.split(",") : [],
|
||||
namingStrategies: process.env.TYPEORM_NAMING_STRATEGIES ? process.env.TYPEORM_NAMING_STRATEGIES.split(",") : [],
|
||||
usedNamingStrategy: process.env.TYPEORM_USED_NAMING_STRATEGY,
|
||||
autoSchemaSync: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_AUTO_SCHEMA_SYNC")),
|
||||
entities: PlatformTools.getEnvVariable("TYPEORM_ENTITIES") ? PlatformTools.getEnvVariable("TYPEORM_ENTITIES").split(",") : [],
|
||||
subscribers: PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS") ? PlatformTools.getEnvVariable("TYPEORM_SUBSCRIBERS").split(",") : [],
|
||||
entitySchemas: PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS") ? PlatformTools.getEnvVariable("TYPEORM_ENTITY_SCHEMAS").split(",") : [],
|
||||
namingStrategies: PlatformTools.getEnvVariable("TYPEORM_NAMING_STRATEGIES") ? PlatformTools.getEnvVariable("TYPEORM_NAMING_STRATEGIES").split(",") : [],
|
||||
usedNamingStrategy: PlatformTools.getEnvVariable("TYPEORM_USED_NAMING_STRATEGY"),
|
||||
logging: {
|
||||
logQueries: OrmUtils.toBoolean(process.env.TYPEORM_LOGGING_QUERIES),
|
||||
logFailedQueryError: OrmUtils.toBoolean(process.env.TYPEORM_LOGGING_FAILED_QUERIES),
|
||||
logOnlyFailedQueries: OrmUtils.toBoolean(process.env.TYPEORM_LOGGING_ONLY_FAILED_QUERIES),
|
||||
logQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_QUERIES")),
|
||||
logFailedQueryError: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_FAILED_QUERIES")),
|
||||
logOnlyFailedQueries: OrmUtils.toBoolean(PlatformTools.getEnvVariable("TYPEORM_LOGGING_ONLY_FAILED_QUERIES")),
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -349,12 +349,12 @@ export class ConnectionManager {
|
||||
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
|
||||
*/
|
||||
protected async createFromConfigAndConnectToAll(path?: string): Promise<Connection[]> {
|
||||
const optionsArray: ConnectionOptions[] = require(path || (require("app-root-path").path + "/ormconfig.json"));
|
||||
const optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
|
||||
if (!optionsArray)
|
||||
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);
|
||||
|
||||
const promises = optionsArray
|
||||
.filter(options => !options.environment || options.environment === process.env.NODE_ENV) // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
|
||||
.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV")) // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
|
||||
.map(options => this.createAndConnectByConnectionOptions(options));
|
||||
|
||||
return Promise.all(promises);
|
||||
@ -367,15 +367,15 @@ export class ConnectionManager {
|
||||
* If path is not given, then ormconfig.json file will be searched near node_modules directory.
|
||||
*/
|
||||
protected async createFromConfigAndConnect(connectionName: string, path?: string): Promise<Connection> {
|
||||
const optionsArray: ConnectionOptions[] = require(path || (require("app-root-path").path + "/ormconfig.json"));
|
||||
const optionsArray: ConnectionOptions[] = PlatformTools.load(path || (PlatformTools.load("app-root-path").path + "/ormconfig.json"));
|
||||
if (!optionsArray)
|
||||
throw new Error(`Configuration ${path || "ormconfig.json"} was not found. Add connection configuration inside ormconfig.json file.`);
|
||||
|
||||
const environmentLessOptions = optionsArray.filter(options => (options.name || "default") === connectionName);
|
||||
const options = environmentLessOptions.filter(options => !options.environment || options.environment === process.env.NODE_ENV); // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
|
||||
const options = environmentLessOptions.filter(options => !options.environment || options.environment === PlatformTools.getEnvVariable("NODE_ENV")); // skip connection creation if environment is set in the options, and its not equal to the value in the NODE_ENV variable
|
||||
|
||||
if (!options.length)
|
||||
throw new Error(`Connection "${connectionName}" ${process.env.NODE_ENV ? "for the environment " + process.env.NODE_ENV + " " : ""}was not found in the json configuration file.` +
|
||||
throw new Error(`Connection "${connectionName}" ${PlatformTools.getEnvVariable("NODE_ENV") ? "for the environment " + PlatformTools.getEnvVariable("NODE_ENV") + " " : ""}was not found in the json configuration file.` +
|
||||
(environmentLessOptions.length ? ` However there are such configurations for other environments: ${environmentLessOptions.map(options => options.environment).join(", ")}.` : ""));
|
||||
|
||||
return this.createAndConnectByConnectionOptions(options[0]);
|
||||
@ -391,11 +391,11 @@ export class ConnectionManager {
|
||||
await connection.connect();
|
||||
|
||||
// if option is set - drop schema once connection is done
|
||||
if (options.dropSchemaOnConnection && !process.env.SKIP_SCHEMA_CREATION)
|
||||
if (options.dropSchemaOnConnection && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
|
||||
await connection.dropDatabase();
|
||||
|
||||
// if option is set - automatically synchronize a schema
|
||||
if (options.autoSchemaSync && !process.env.SKIP_SCHEMA_CREATION)
|
||||
if (options.autoSchemaSync && !PlatformTools.getEnvVariable("SKIP_SCHEMA_CREATION"))
|
||||
await connection.syncSchema();
|
||||
|
||||
return connection;
|
||||
@ -417,9 +417,7 @@ export class ConnectionManager {
|
||||
protected createDriver(options: DriverOptions, logger: Logger): Driver {
|
||||
switch (options.type) {
|
||||
case "mysql":
|
||||
return new MysqlDriver(options, logger, undefined, "mysql");
|
||||
case "mysql2":
|
||||
return new MysqlDriver(options, logger, undefined, "mysql2");
|
||||
return new MysqlDriver(options, logger, undefined);
|
||||
case "postgres":
|
||||
return new PostgresDriver(options, logger);
|
||||
case "mariadb":
|
||||
|
||||
@ -6,7 +6,7 @@ export class MissingDriverError extends Error {
|
||||
|
||||
constructor(driverType: string) {
|
||||
super();
|
||||
this.message = `Wrong driver ${driverType} given. Supported drivers are: "mysql", "mysql2", "postgres", "mssql", "oracle", "mariadb", "sqlite".`;
|
||||
this.message = `Wrong driver ${driverType} given. Supported drivers are: "mysql", "postgres", "mssql", "oracle", "mariadb", "sqlite".`;
|
||||
this.stack = new Error().stack;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ export interface DriverOptions {
|
||||
/**
|
||||
* Database type. This value is required.
|
||||
*/
|
||||
readonly type: "mysql"|"mysql2"|"postgres"|"mariadb"|"sqlite"|"oracle"|"mssql";
|
||||
readonly type: "mysql"|"postgres"|"mariadb"|"sqlite"|"oracle"|"mssql";
|
||||
|
||||
/**
|
||||
* Connection url to where perform connection to.
|
||||
|
||||
@ -50,16 +50,21 @@ export class DriverUtils {
|
||||
* Extracts connection data from the connection url.
|
||||
*/
|
||||
private static parseConnectionUrl(url: string) {
|
||||
const urlParser = require("url");
|
||||
const params = urlParser.parse(url);
|
||||
const auth = params.auth.split(":");
|
||||
const firstSlashes = url.indexOf("//");
|
||||
const preBase = url.substr(firstSlashes + 2);
|
||||
const secondSlash = preBase.indexOf("/");
|
||||
const base = (secondSlash !== -1) ? preBase.substr(0, secondSlash) : preBase;
|
||||
const afterBase = (secondSlash !== -1) ? preBase.substr(secondSlash) + 1 : undefined;
|
||||
const [usernameAndPassword, hostAndPort] = base.split("@");
|
||||
const [username, password] = usernameAndPassword.split(":");
|
||||
const [host, port] = hostAndPort.split(":");
|
||||
|
||||
return {
|
||||
host: params.hostname,
|
||||
username: auth[0],
|
||||
password: auth[1],
|
||||
port: parseInt(params.port),
|
||||
database: params.pathname.split("/")[1]
|
||||
host: host,
|
||||
username: username,
|
||||
password: password,
|
||||
port: port ? parseInt(port) : undefined,
|
||||
database: afterBase ? afterBase.split("/")[0] : undefined
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ import {ConnectionIsNotSetError} from "../error/ConnectionIsNotSetError";
|
||||
import {DriverOptions} from "../DriverOptions";
|
||||
import {DatabaseConnection} from "../DatabaseConnection";
|
||||
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
|
||||
import {DriverPackageLoadError} from "../error/DriverPackageLoadError";
|
||||
import {DriverUtils} from "../DriverUtils";
|
||||
import {Logger} from "../../logger/Logger";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
@ -13,6 +12,7 @@ import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
|
||||
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
|
||||
import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Organizes communication with MySQL DBMS.
|
||||
@ -57,21 +57,15 @@ export class MysqlDriver implements Driver {
|
||||
*/
|
||||
protected logger: Logger;
|
||||
|
||||
/**
|
||||
* Driver type's version. node-mysql and mysql2 are supported.
|
||||
*/
|
||||
protected version: "mysql"|"mysql2" = "mysql";
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(options: DriverOptions, logger: Logger, mysql?: any, mysqlVersion: "mysql"|"mysql2" = "mysql") {
|
||||
constructor(options: DriverOptions, logger: Logger, mysql?: any) {
|
||||
|
||||
this.options = DriverUtils.buildDriverOptions(options);
|
||||
this.logger = logger;
|
||||
this.mysql = mysql;
|
||||
this.version = mysqlVersion;
|
||||
|
||||
// validate options to make sure everything is set
|
||||
if (!this.options.host)
|
||||
@ -130,7 +124,7 @@ export class MysqlDriver implements Driver {
|
||||
*/
|
||||
disconnect(): Promise<void> {
|
||||
if (!this.databaseConnection && !this.pool)
|
||||
throw new ConnectionIsNotSetError(this.version);
|
||||
throw new ConnectionIsNotSetError("mysql");
|
||||
|
||||
return new Promise<void>((ok, fail) => {
|
||||
const handler = (err: any) => err ? fail(err) : ok();
|
||||
@ -155,7 +149,7 @@ export class MysqlDriver implements Driver {
|
||||
*/
|
||||
async createQueryRunner(): Promise<QueryRunner> {
|
||||
if (!this.databaseConnection && !this.pool)
|
||||
return Promise.reject(new ConnectionIsNotSetError(this.version));
|
||||
return Promise.reject(new ConnectionIsNotSetError("mysql"));
|
||||
|
||||
const databaseConnection = await this.retrieveDatabaseConnection();
|
||||
return new MysqlQueryRunner(databaseConnection, this, this.logger);
|
||||
@ -312,20 +306,23 @@ export class MysqlDriver implements Driver {
|
||||
if (this.databaseConnection)
|
||||
return Promise.resolve(this.databaseConnection);
|
||||
|
||||
throw new ConnectionIsNotSetError(this.version);
|
||||
throw new ConnectionIsNotSetError("mysql");
|
||||
}
|
||||
|
||||
/**
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
protected loadDependencies(): void {
|
||||
if (!require)
|
||||
throw new DriverPackageLoadError();
|
||||
|
||||
try {
|
||||
this.mysql = require(this.version);
|
||||
this.mysql = PlatformTools.load("mysql"); // try to load first supported package
|
||||
|
||||
} catch (e) {
|
||||
throw new DriverPackageNotInstalledError("Mysql", this.version);
|
||||
try {
|
||||
this.mysql = PlatformTools.load("mysql2"); // try to load second supported package
|
||||
|
||||
} catch (e) {
|
||||
throw new DriverPackageNotInstalledError("Mysql", "mysql");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ import {ConnectionIsNotSetError} from "../error/ConnectionIsNotSetError";
|
||||
import {DriverOptions} from "../DriverOptions";
|
||||
import {DatabaseConnection} from "../DatabaseConnection";
|
||||
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
|
||||
import {DriverPackageLoadError} from "../error/DriverPackageLoadError";
|
||||
import {DriverUtils} from "../DriverUtils";
|
||||
import {Logger} from "../../logger/Logger";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
@ -13,6 +12,7 @@ import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
|
||||
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
|
||||
import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Organizes communication with Oracle DBMS.
|
||||
@ -330,12 +330,10 @@ export class OracleDriver implements Driver {
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
protected loadDependencies(): void {
|
||||
if (!require)
|
||||
throw new DriverPackageLoadError();
|
||||
|
||||
try {
|
||||
this.oracle = require("oracledb");
|
||||
} catch (e) {
|
||||
this.oracle = PlatformTools.load("oracledb");
|
||||
|
||||
} catch (e) { // todo: better error for browser env
|
||||
throw new DriverPackageNotInstalledError("Oracle", "oracledb");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import {DriverOptions} from "../DriverOptions";
|
||||
import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {DatabaseConnection} from "../DatabaseConnection";
|
||||
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
|
||||
import {DriverPackageLoadError} from "../error/DriverPackageLoadError";
|
||||
import {DriverUtils} from "../DriverUtils";
|
||||
import {ColumnTypes} from "../../metadata/types/ColumnTypes";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
@ -13,6 +12,7 @@ import {PostgresQueryRunner} from "./PostgresQueryRunner";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
|
||||
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
|
||||
import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
// todo(tests):
|
||||
// check connection with url
|
||||
@ -338,12 +338,10 @@ export class PostgresDriver implements Driver {
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
protected loadDependencies(): void {
|
||||
if (!require)
|
||||
throw new DriverPackageLoadError();
|
||||
|
||||
try {
|
||||
this.postgres = require("pg");
|
||||
} catch (e) {
|
||||
this.postgres = PlatformTools.load("pg");
|
||||
|
||||
} catch (e) { // todo: better error for browser env
|
||||
throw new DriverPackageNotInstalledError("Postgres", "pg");
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import {DriverOptions} from "../DriverOptions";
|
||||
import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {DatabaseConnection} from "../DatabaseConnection";
|
||||
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
|
||||
import {DriverPackageLoadError} from "../error/DriverPackageLoadError";
|
||||
import {ColumnTypes} from "../../metadata/types/ColumnTypes";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
import {Logger} from "../../logger/Logger";
|
||||
@ -12,6 +11,7 @@ import {SqliteQueryRunner} from "./SqliteQueryRunner";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
|
||||
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
|
||||
import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Organizes communication with sqlite DBMS.
|
||||
@ -255,12 +255,10 @@ export class SqliteDriver implements Driver {
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
protected loadDependencies(): void {
|
||||
if (!require)
|
||||
throw new DriverPackageLoadError();
|
||||
|
||||
try {
|
||||
this.sqlite = require("sqlite3").verbose();
|
||||
} catch (e) {
|
||||
this.sqlite = PlatformTools.load("sqlite3").verbose();
|
||||
|
||||
} catch (e) { // todo: better error for browser env
|
||||
throw new DriverPackageNotInstalledError("SQLite", "sqlite3");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import {ConnectionIsNotSetError} from "../error/ConnectionIsNotSetError";
|
||||
import {DriverOptions} from "../DriverOptions";
|
||||
import {DatabaseConnection} from "../DatabaseConnection";
|
||||
import {DriverPackageNotInstalledError} from "../error/DriverPackageNotInstalledError";
|
||||
import {DriverPackageLoadError} from "../error/DriverPackageLoadError";
|
||||
import {DriverUtils} from "../DriverUtils";
|
||||
import {Logger} from "../../logger/Logger";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
@ -13,6 +12,7 @@ import {ObjectLiteral} from "../../common/ObjectLiteral";
|
||||
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
|
||||
import {DriverOptionNotSetError} from "../error/DriverOptionNotSetError";
|
||||
import {DataTransformationUtils} from "../../util/DataTransformationUtils";
|
||||
import {PlatformTools} from "../../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Organizes communication with SQL Server DBMS.
|
||||
@ -315,12 +315,10 @@ export class SqlServerDriver implements Driver {
|
||||
* If driver dependency is not given explicitly, then try to load it via "require".
|
||||
*/
|
||||
protected loadDependencies(): void {
|
||||
if (!require)
|
||||
throw new DriverPackageLoadError();
|
||||
|
||||
try {
|
||||
this.mssql = require("mssql");
|
||||
} catch (e) {
|
||||
this.mssql = PlatformTools.load("mssql");
|
||||
|
||||
} catch (e) { // todo: better error for browser env
|
||||
throw new DriverPackageNotInstalledError("SQL Server", "mssql");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
/*!
|
||||
*/
|
||||
|
||||
import {DriverOptions} from "./driver/DriverOptions";
|
||||
import {ConnectionManager} from "./connection/ConnectionManager";
|
||||
import {Connection} from "./connection/Connection";
|
||||
@ -113,7 +112,7 @@ export function getConnectionManager(): ConnectionManager {
|
||||
* it will try to create connection from environment variables.
|
||||
* There are several environment variables you can set:
|
||||
*
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "mysql2", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_URL - database connection url. Should be a string.
|
||||
* - TYPEORM_HOST - database host. Should be a string.
|
||||
* - TYPEORM_PORT - database access port. Should be a number.
|
||||
@ -164,7 +163,7 @@ export function createConnection(optionsOrConnectionNameFromConfig?: ConnectionO
|
||||
* it will try to create connection from environment variables.
|
||||
* There are several environment variables you can set:
|
||||
*
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "mysql2", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_DRIVER_TYPE - driver type. Can be "mysql", "postgres", "mariadb", "sqlite", "oracle" or "mssql".
|
||||
* - TYPEORM_URL - database connection url. Should be a string.
|
||||
* - TYPEORM_HOST - database host. Should be a string.
|
||||
* - TYPEORM_PORT - database access port. Should be a number.
|
||||
|
||||
@ -7,6 +7,7 @@ import {MissingJoinTableError} from "./error/MissingJoinTableError";
|
||||
import {EntityMetadata} from "../metadata/EntityMetadata";
|
||||
import {MissingPrimaryColumnError} from "./error/MissingPrimaryColumnError";
|
||||
import {CircularRelationsError} from "./error/CircularRelationsError";
|
||||
import {DepGraph} from "../util/DepGraph";
|
||||
|
||||
/// todo: add check if there are multiple tables with the same name
|
||||
/// todo: add checks when generated column / table names are too long for the specific driver
|
||||
@ -112,7 +113,6 @@ export class EntityMetadataValidator {
|
||||
*/
|
||||
protected validateDependencies(entityMetadatas: EntityMetadata[]) {
|
||||
|
||||
const DepGraph = require("dependency-graph").DepGraph;
|
||||
const graph = new DepGraph();
|
||||
entityMetadatas.forEach(entityMetadata => {
|
||||
graph.addNode(entityMetadata.name);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {NamingStrategyInterface} from "./NamingStrategyInterface";
|
||||
import * as _ from "lodash";
|
||||
import {RandomGenerator} from "../util/RandomGenerator";
|
||||
import {snakeCase, camelCase} from "../util/StringUtils";
|
||||
|
||||
/**
|
||||
* Naming strategy that is used by default.
|
||||
@ -7,7 +8,7 @@ import * as _ from "lodash";
|
||||
export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
|
||||
tableName(className: string, customName: string): string {
|
||||
return customName ? customName : _.snakeCase(className);
|
||||
return customName ? customName : snakeCase(className);
|
||||
}
|
||||
|
||||
columnName(propertyName: string, customName: string): string {
|
||||
@ -15,7 +16,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
}
|
||||
|
||||
embeddedColumnName(embeddedPropertyName: string, columnPropertyName: string, columnCustomName?: string): string {
|
||||
return _.camelCase(embeddedPropertyName + "_" + (columnCustomName ? columnCustomName : columnPropertyName));
|
||||
return camelCase(embeddedPropertyName + "_" + (columnCustomName ? columnCustomName : columnPropertyName));
|
||||
}
|
||||
|
||||
relationName(propertyName: string): string {
|
||||
@ -27,7 +28,7 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
return customName;
|
||||
|
||||
const key = "ind_" + tableName + "_" + columns.join("_");
|
||||
return "ind_" + require("sha1")(key);
|
||||
return "ind_" + RandomGenerator.sha1(key).substr(0, 27);
|
||||
}
|
||||
|
||||
joinColumnInverseSideName(joinColumnName: string, propertyName: string): string {
|
||||
@ -43,18 +44,18 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
secondPropertyName: string,
|
||||
firstColumnName: string,
|
||||
secondColumnName: string): string {
|
||||
return _.snakeCase(firstTableName + "_" + firstPropertyName + "_" + secondTableName + "_" + secondColumnName);
|
||||
return snakeCase(firstTableName + "_" + firstPropertyName + "_" + secondTableName + "_" + secondColumnName);
|
||||
}
|
||||
|
||||
joinTableColumnName(tableName: string, columnName: string, secondTableName: string, secondColumnName: string): string {
|
||||
const column1 = _.camelCase(tableName + "_" + columnName);
|
||||
const column2 = _.camelCase(secondTableName + "_" + secondColumnName);
|
||||
const column1 = camelCase(tableName + "_" + columnName);
|
||||
const column2 = camelCase(secondTableName + "_" + secondColumnName);
|
||||
return column1 === column2 ? column1 + "_1" : column1; // todo: do we still need _1 prefix?!
|
||||
}
|
||||
|
||||
joinTableInverseColumnName(tableName: string, columnName: string, secondTableName: string, secondColumnName: string): string {
|
||||
const column1 = _.camelCase(tableName + "_" + columnName);
|
||||
const column2 = _.camelCase(secondTableName + "_" + secondColumnName);
|
||||
const column1 = camelCase(tableName + "_" + columnName);
|
||||
const column2 = camelCase(secondTableName + "_" + secondColumnName);
|
||||
return column1 === column2 ? column1 + "_2" : column1; // todo: do we still need _2 prefix?!
|
||||
}
|
||||
|
||||
@ -64,11 +65,11 @@ export class DefaultNamingStrategy implements NamingStrategyInterface {
|
||||
|
||||
foreignKeyName(tableName: string, columnNames: string[], referencedTableName: string, referencedColumnNames: string[]): string {
|
||||
const key = `${tableName}_${columnNames.join("_")}_${referencedTableName}_${referencedColumnNames.join("_")}`;
|
||||
return "fk_" + require("sha1")(key).substr(0, 27); // todo: use crypto instead?
|
||||
return "fk_" + RandomGenerator.sha1(key).substr(0, 27); // todo: use crypto instead?
|
||||
}
|
||||
|
||||
classTableInheritanceParentColumnName(parentTableName: any, parentTableIdPropertyName: any): string {
|
||||
return _.camelCase(parentTableName + "_" + parentTableIdPropertyName);
|
||||
return camelCase(parentTableName + "_" + parentTableIdPropertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
23
src/platform/BrowserPlatformTools.ts
Normal file
23
src/platform/BrowserPlatformTools.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Browser's implementation of the platform-specific tools.
|
||||
*
|
||||
* This file gonna replace PlatformTools for browser environment.
|
||||
* For node.js environment this class is not getting packaged.
|
||||
* Don't use methods of this class in the code, use PlatformTools methods instead.
|
||||
*/
|
||||
export class BrowserPlatformTools {
|
||||
|
||||
/**
|
||||
* Type of the currently running platform.
|
||||
*/
|
||||
static type: "browser"|"node" = "browser";
|
||||
|
||||
/**
|
||||
* Loads ("require"-s) given file or package.
|
||||
* This operation only supports on node platform
|
||||
*/
|
||||
static load(name: string) {
|
||||
throw new Error(`This option/function is not supported in the browser environment. Failed operation: require("${name}").`);
|
||||
}
|
||||
|
||||
}
|
||||
57
src/platform/PlatformTools.ts
Normal file
57
src/platform/PlatformTools.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
|
||||
/**
|
||||
* Platform-specific tools.
|
||||
*/
|
||||
export class PlatformTools {
|
||||
|
||||
/**
|
||||
* Type of the currently running platform.
|
||||
*/
|
||||
static type: "browser"|"node" = "node";
|
||||
|
||||
/**
|
||||
* Loads ("require"-s) given file or package.
|
||||
* This operation only supports on node platform
|
||||
*/
|
||||
static load(name: string): any {
|
||||
return require(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes given path. Does "path.normalize".
|
||||
*/
|
||||
static pathNormilize(pathStr: string): string {
|
||||
return path.normalize(pathStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets file extension. Does "path.extname".
|
||||
*/
|
||||
static pathExtname(pathStr: string): string {
|
||||
return path.extname(pathStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved given path. Does "path.resolve".
|
||||
*/
|
||||
static pathResolve(pathStr: string): string {
|
||||
return path.resolve(pathStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously checks if file exist. Does "fs.existsSync".
|
||||
*/
|
||||
static fileExist(pathStr: string): boolean {
|
||||
return fs.existsSync(pathStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets environment variable.
|
||||
*/
|
||||
static getEnvVariable(name: string): any {
|
||||
return process.env[name];
|
||||
}
|
||||
|
||||
}
|
||||
232
src/util/DepGraph.ts
Normal file
232
src/util/DepGraph.ts
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* This source code is from https://github.com/jriecken/dependency-graph
|
||||
* Just added "any" types here, wrapper everything into exported class.
|
||||
* We cant use a package itself because we want to package "everything-in-it" for the frontend users of TypeORM.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simple dependency graph
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper for creating a Depth-First-Search on
|
||||
* a set of edges.
|
||||
*
|
||||
* Detects cycles and throws an Error if one is detected.
|
||||
*
|
||||
* @param edges The set of edges to DFS through
|
||||
* @param leavesOnly Whether to only return "leaf" nodes (ones who have no edges)
|
||||
* @param result An array in which the results will be populated
|
||||
*/
|
||||
function createDFS(edges: any, leavesOnly: any, result: any) {
|
||||
let currentPath: any[] = [];
|
||||
let visited: any = {};
|
||||
return function DFS(currentNode: any) {
|
||||
visited[currentNode] = true;
|
||||
currentPath.push(currentNode);
|
||||
edges[currentNode].forEach(function (node: any) {
|
||||
if (!visited[node]) {
|
||||
DFS(node);
|
||||
} else if (currentPath.indexOf(node) >= 0) {
|
||||
currentPath.push(node);
|
||||
throw new Error(`Dependency Cycle Found: ${currentPath.join(" -> ")}`);
|
||||
}
|
||||
});
|
||||
currentPath.pop();
|
||||
if ((!leavesOnly || edges[currentNode].length === 0) && result.indexOf(currentNode) === -1) {
|
||||
result.push(currentNode);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export class DepGraph {
|
||||
nodes: any = {};
|
||||
outgoingEdges: any = {}; // Node -> [Dependency Node]
|
||||
incomingEdges: any = {}; // Node -> [Dependant Node]
|
||||
|
||||
/**
|
||||
* Add a node to the dependency graph. If a node already exists, this method will do nothing.
|
||||
*/
|
||||
addNode(node: any, data?: any) {
|
||||
if (!this.hasNode(node)) {
|
||||
// Checking the arguments length allows the user to add a node with undefined data
|
||||
if (arguments.length === 2) {
|
||||
this.nodes[node] = data;
|
||||
} else {
|
||||
this.nodes[node] = node;
|
||||
}
|
||||
this.outgoingEdges[node] = [];
|
||||
this.incomingEdges[node] = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a node from the dependency graph. If a node does not exist, this method will do nothing.
|
||||
*/
|
||||
removeNode(node: any) {
|
||||
if (this.hasNode(node)) {
|
||||
delete this.nodes[node];
|
||||
delete this.outgoingEdges[node];
|
||||
delete this.incomingEdges[node];
|
||||
[this.incomingEdges, this.outgoingEdges].forEach(function(edgeList) {
|
||||
Object.keys(edgeList).forEach(function(key: any) {
|
||||
let idx = edgeList[key].indexOf(node);
|
||||
if (idx >= 0) {
|
||||
edgeList[key].splice(idx, 1);
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a node exists in the graph
|
||||
*/
|
||||
hasNode(node: any) {
|
||||
return this.nodes.hasOwnProperty(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data associated with a node name
|
||||
*/
|
||||
getNodeData(node: any) {
|
||||
if (this.hasNode(node)) {
|
||||
return this.nodes[node];
|
||||
} else {
|
||||
throw new Error(`Node does not exist: ${node}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the associated data for a given node name. If the node does not exist, this method will throw an error
|
||||
*/
|
||||
setNodeData(node: any, data: any) {
|
||||
if (this.hasNode(node)) {
|
||||
this.nodes[node] = data;
|
||||
} else {
|
||||
throw new Error(`Node does not exist: ${node}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a dependency between two nodes. If either of the nodes does not exist,
|
||||
* an Error will be thrown.
|
||||
*/
|
||||
addDependency(from: any, to: any) {
|
||||
if (!this.hasNode(from)) {
|
||||
throw new Error(`Node does not exist: ${from}`);
|
||||
}
|
||||
if (!this.hasNode(to)) {
|
||||
throw new Error(`Node does not exist: ${to}`);
|
||||
}
|
||||
if (this.outgoingEdges[from].indexOf(to) === -1) {
|
||||
this.outgoingEdges[from].push(to);
|
||||
}
|
||||
if (this.incomingEdges[to].indexOf(from) === -1) {
|
||||
this.incomingEdges[to].push(from);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a dependency between two nodes.
|
||||
*/
|
||||
removeDependency(from: any, to: any) {
|
||||
let idx: any;
|
||||
if (this.hasNode(from)) {
|
||||
idx = this.outgoingEdges[from].indexOf(to);
|
||||
if (idx >= 0) {
|
||||
this.outgoingEdges[from].splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hasNode(to)) {
|
||||
idx = this.incomingEdges[to].indexOf(from);
|
||||
if (idx >= 0) {
|
||||
this.incomingEdges[to].splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing the nodes that the specified node depends on (transitively).
|
||||
*
|
||||
* Throws an Error if the graph has a cycle, or the specified node does not exist.
|
||||
*
|
||||
* If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned
|
||||
* in the array.
|
||||
*/
|
||||
dependenciesOf(node: any, leavesOnly: any) {
|
||||
if (this.hasNode(node)) {
|
||||
let result: any[] = [];
|
||||
let DFS = createDFS(this.outgoingEdges, leavesOnly, result);
|
||||
DFS(node);
|
||||
let idx = result.indexOf(node);
|
||||
if (idx >= 0) {
|
||||
result.splice(idx, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
throw new Error(`Node does not exist: ${node}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get an array containing the nodes that depend on the specified node (transitively).
|
||||
*
|
||||
* Throws an Error if the graph has a cycle, or the specified node does not exist.
|
||||
*
|
||||
* If `leavesOnly` is true, only nodes that do not have any dependants will be returned in the array.
|
||||
*/
|
||||
dependantsOf(node: any, leavesOnly: any) {
|
||||
if (this.hasNode(node)) {
|
||||
let result: any[] = [];
|
||||
let DFS = createDFS(this.incomingEdges, leavesOnly, result);
|
||||
DFS(node);
|
||||
let idx = result.indexOf(node);
|
||||
if (idx >= 0) {
|
||||
result.splice(idx, 1);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
throw new Error(`Node does not exist: ${node}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the overall processing order for the dependency graph.
|
||||
*
|
||||
* Throws an Error if the graph has a cycle.
|
||||
*
|
||||
* If `leavesOnly` is true, only nodes that do not depend on any other nodes will be returned.
|
||||
*/
|
||||
overallOrder(leavesOnly?: any) {
|
||||
let self = this;
|
||||
let result: any[] = [];
|
||||
let keys = Object.keys(this.nodes);
|
||||
if (keys.length === 0) {
|
||||
return result; // Empty graph
|
||||
} else {
|
||||
// Look for cycles - we run the DFS starting at all the nodes in case there
|
||||
// are several disconnected subgraphs inside this dependency graph.
|
||||
let CycleDFS = createDFS(this.outgoingEdges, false, []);
|
||||
keys.forEach(function(n: any) {
|
||||
CycleDFS(n);
|
||||
});
|
||||
|
||||
let DFS = createDFS(this.outgoingEdges, leavesOnly, result);
|
||||
// Find all potential starting points (nodes with nothing depending on them) an
|
||||
// run a DFS starting at these points to get the order
|
||||
keys.filter(function (node) {
|
||||
return self.incomingEdges[node].length === 0;
|
||||
}).forEach(function (n) {
|
||||
DFS(n);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import * as path from "path";
|
||||
import {PlatformTools} from "../platform/PlatformTools";
|
||||
|
||||
/**
|
||||
* Loads all exported classes from the given directory.
|
||||
@ -20,26 +20,29 @@ export function importClassesFromDirectories(directories: string[], formats = ["
|
||||
}
|
||||
|
||||
const allFiles = directories.reduce((allDirs, dir) => {
|
||||
return allDirs.concat(require("glob").sync(path.normalize(dir)));
|
||||
return allDirs.concat(PlatformTools.load("glob").sync(PlatformTools.pathNormilize(dir)));
|
||||
}, [] as string[]);
|
||||
|
||||
const dirs = allFiles
|
||||
.filter(file => {
|
||||
const dtsExtension = file.substring(file.length - 5, file.length);
|
||||
return formats.indexOf(path.extname(file)) !== -1 && dtsExtension !== ".d.ts";
|
||||
return formats.indexOf(PlatformTools.pathExtname(file)) !== -1 && dtsExtension !== ".d.ts";
|
||||
})
|
||||
.map(file => require(path.resolve(file)));
|
||||
.map(file => PlatformTools.load(PlatformTools.pathResolve(file)));
|
||||
|
||||
return loadFileClasses(dirs, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all json files from the given directory.
|
||||
*/
|
||||
export function importJsonsFromDirectories(directories: string[], format = ".json"): any[] {
|
||||
|
||||
const allFiles = directories.reduce((allDirs, dir) => {
|
||||
return allDirs.concat(require("glob").sync(path.normalize(dir)));
|
||||
return allDirs.concat(PlatformTools.load("glob").sync(PlatformTools.pathNormilize(dir)));
|
||||
}, [] as string[]);
|
||||
|
||||
return allFiles
|
||||
.filter(file => path.extname(file) === format)
|
||||
.map(file => require(path.resolve(file)));
|
||||
.filter(file => PlatformTools.pathExtname(file) === format)
|
||||
.map(file => PlatformTools.load(PlatformTools.pathResolve(file)));
|
||||
}
|
||||
146
src/util/RandomGenerator.ts
Normal file
146
src/util/RandomGenerator.ts
Normal file
@ -0,0 +1,146 @@
|
||||
export class RandomGenerator {
|
||||
|
||||
/**
|
||||
* discuss at: http://locutus.io/php/sha1/
|
||||
* original by: Webtoolkit.info (http://www.webtoolkit.info/)
|
||||
* improved by: Michael White (http://getsprink.com)
|
||||
* improved by: Kevin van Zonneveld (http://kvz.io)
|
||||
* input by: Brett Zamir (http://brett-zamir.me)
|
||||
* note 1: Keep in mind that in accordance with PHP, the whole string is buffered and then
|
||||
* note 1: hashed. If available, we'd recommend using Node's native crypto modules directly
|
||||
* note 1: in a steaming fashion for faster and more efficient hashing
|
||||
* example 1: sha1('Kevin van Zonneveld')
|
||||
* returns 1: '54916d2e62f65b3afa6e192e6a601cdbe5cb5897'
|
||||
*/
|
||||
static sha1(str: string) {
|
||||
|
||||
let _rotLeft = function(n: any, s: any) {
|
||||
let t4 = (n << s) | (n >>> (32 - s));
|
||||
return t4;
|
||||
};
|
||||
|
||||
let _cvtHex = function(val: any) {
|
||||
let str = "";
|
||||
let i;
|
||||
let v;
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
v = (val >>> (i * 4)) & 0x0f;
|
||||
str += v.toString(16);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
let blockstart;
|
||||
let i, j;
|
||||
let W = new Array(80);
|
||||
let H0 = 0x67452301;
|
||||
let H1 = 0xEFCDAB89;
|
||||
let H2 = 0x98BADCFE;
|
||||
let H3 = 0x10325476;
|
||||
let H4 = 0xC3D2E1F0;
|
||||
let A, B, C, D, E;
|
||||
let temp;
|
||||
|
||||
// utf8_encode
|
||||
str = /*unescape*/(encodeURIComponent(str));
|
||||
let strLen = str.length;
|
||||
|
||||
let wordArray = [];
|
||||
for (i = 0; i < strLen - 3; i += 4) {
|
||||
j = str.charCodeAt(i) << 24 |
|
||||
str.charCodeAt(i + 1) << 16 |
|
||||
str.charCodeAt(i + 2) << 8 |
|
||||
str.charCodeAt(i + 3);
|
||||
wordArray.push(j);
|
||||
}
|
||||
|
||||
switch (strLen % 4) {
|
||||
case 0:
|
||||
i = 0x080000000;
|
||||
break;
|
||||
case 1:
|
||||
i = str.charCodeAt(strLen - 1) << 24 | 0x0800000;
|
||||
break;
|
||||
case 2:
|
||||
i = str.charCodeAt(strLen - 2) << 24 | str.charCodeAt(strLen - 1) << 16 | 0x08000;
|
||||
break;
|
||||
case 3:
|
||||
i = str.charCodeAt(strLen - 3) << 24 |
|
||||
str.charCodeAt(strLen - 2) << 16 |
|
||||
str.charCodeAt(strLen - 1) <<
|
||||
8 | 0x80;
|
||||
break;
|
||||
}
|
||||
|
||||
wordArray.push(i);
|
||||
|
||||
while ((wordArray.length % 16) !== 14) {
|
||||
wordArray.push(0);
|
||||
}
|
||||
|
||||
wordArray.push(strLen >>> 29);
|
||||
wordArray.push((strLen << 3) & 0x0ffffffff);
|
||||
|
||||
for (blockstart = 0; blockstart < wordArray.length; blockstart += 16) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
W[i] = wordArray[blockstart + i];
|
||||
}
|
||||
for (i = 16; i <= 79; i++) {
|
||||
W[i] = _rotLeft(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
|
||||
}
|
||||
|
||||
A = H0;
|
||||
B = H1;
|
||||
C = H2;
|
||||
D = H3;
|
||||
E = H4;
|
||||
|
||||
for (i = 0; i <= 19; i++) {
|
||||
temp = (_rotLeft(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
|
||||
E = D;
|
||||
D = C;
|
||||
C = _rotLeft(B, 30);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (i = 20; i <= 39; i++) {
|
||||
temp = (_rotLeft(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
|
||||
E = D;
|
||||
D = C;
|
||||
C = _rotLeft(B, 30);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (i = 40; i <= 59; i++) {
|
||||
temp = (_rotLeft(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
|
||||
E = D;
|
||||
D = C;
|
||||
C = _rotLeft(B, 30);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for (i = 60; i <= 79; i++) {
|
||||
temp = (_rotLeft(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
|
||||
E = D;
|
||||
D = C;
|
||||
C = _rotLeft(B, 30);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
H0 = (H0 + A) & 0x0ffffffff;
|
||||
H1 = (H1 + B) & 0x0ffffffff;
|
||||
H2 = (H2 + C) & 0x0ffffffff;
|
||||
H3 = (H3 + D) & 0x0ffffffff;
|
||||
H4 = (H4 + E) & 0x0ffffffff;
|
||||
}
|
||||
|
||||
temp = _cvtHex(H0) + _cvtHex(H1) + _cvtHex(H2) + _cvtHex(H3) + _cvtHex(H4);
|
||||
return temp.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
19
src/util/StringUtils.ts
Normal file
19
src/util/StringUtils.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Converts string into camelCase.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/2970525/converting-any-string-into-camel-case
|
||||
*/
|
||||
export function camelCase(str: string) {
|
||||
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) {
|
||||
return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
|
||||
}).replace(/\s+/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string into snake-case.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/30521224/javascript-convert-pascalcase-to-underscore-case
|
||||
*/
|
||||
export function snakeCase(str: string) {
|
||||
return str.replace(/(?:^|\.?)([A-Z])/g, (x, y) => "_" + y.toLowerCase()).replace(/^_/, "");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user