diff --git a/lib/interfaces/ISequelizeConfig.ts b/lib/interfaces/ISequelizeConfig.ts
index 7fde370e..ca5e7637 100644
--- a/lib/interfaces/ISequelizeConfig.ts
+++ b/lib/interfaces/ISequelizeConfig.ts
@@ -5,7 +5,7 @@ export interface ISequelizeConfig extends Options {
/**
* Name of database
*/
- name: string;
+ database: string;
/**
* Username of database
diff --git a/lib/interfaces/ISequelizeDbNameConfig.ts b/lib/interfaces/ISequelizeDbNameConfig.ts
new file mode 100644
index 00000000..eee2a218
--- /dev/null
+++ b/lib/interfaces/ISequelizeDbNameConfig.ts
@@ -0,0 +1,36 @@
+import {Options} from 'sequelize';
+
+/**
+ * This class is dedicated for deprecated "name" property.
+ * For congruence to Sequelize config, use "database" instead.
+ */
+export interface ISequelizeDbNameConfig extends Options {
+
+ /**
+ * Name of database
+ * @deprecated: name is deprecated. Use database instead.
+ */
+ name: string;
+
+ /**
+ * Username of database
+ */
+ username: string;
+
+ /**
+ * Password for database user
+ */
+ password: string;
+
+ /**
+ * Path to models, which should be loaded
+ */
+ modelPaths?: string[];
+
+ /**
+ * Makes it possible to use sequelize for validation only
+ * if set to true. For this configuration it is always false.
+ * See ISequelizeValidationOnlyConfig interface
+ */
+ validateOnly?: false;
+}
diff --git a/lib/interfaces/ISequelizeUriConfig.ts b/lib/interfaces/ISequelizeUriConfig.ts
new file mode 100644
index 00000000..159f0dc3
--- /dev/null
+++ b/lib/interfaces/ISequelizeUriConfig.ts
@@ -0,0 +1,21 @@
+import {Options} from 'sequelize';
+
+export interface ISequelizeUriConfig extends Options {
+
+ /**
+ * Uri connection string to database
+ */
+ uri: string;
+
+ /**
+ * Path to models, which should be loaded
+ */
+ modelPaths?: string[];
+
+ /**
+ * Makes it possible to use sequelize for validation only
+ * if set to true. For this configuration it is always false.
+ * See ISequelizeValidationOnlyConfig interface
+ */
+ validateOnly?: false;
+}
diff --git a/lib/models/BaseSequelize.ts b/lib/models/BaseSequelize.ts
index 5e68fdbd..ee143df8 100644
--- a/lib/models/BaseSequelize.ts
+++ b/lib/models/BaseSequelize.ts
@@ -2,6 +2,9 @@ import {Model} from "./Model";
import {DEFAULT_DEFINE_OPTIONS, getModels} from "../services/models";
import {getAssociations, processAssociation} from "../services/association";
import {ISequelizeConfig} from "../interfaces/ISequelizeConfig";
+import {ISequelizeUriConfig} from "../interfaces/ISequelizeUriConfig";
+import {ISequelizeDbNameConfig} from "../interfaces/ISequelizeDbNameConfig";
+import {SequelizeConfig} from "../types/SequelizeConfig";
import {resolveScopes} from "../services/scopes";
import {ISequelizeValidationOnlyConfig} from "../interfaces/ISequelizeValidationOnlyConfig";
import {extend} from "../utils/object";
@@ -19,6 +22,14 @@ export abstract class BaseSequelize {
thoughMap: { [through: string]: any } = {};
_: { [modelName: string]: (typeof Model) } = {};
+ static isISequelizeDbNameConfig(obj: any): obj is ISequelizeDbNameConfig {
+ return obj.hasOwnProperty("name") && obj.hasOwnProperty("username");
+ }
+
+ static isISequelizeUriConfig(obj: any): obj is ISequelizeUriConfig {
+ return obj.hasOwnProperty("uri");
+ }
+
static extend(target: any): void {
extend(target, this);
@@ -27,7 +38,7 @@ export abstract class BaseSequelize {
/**
* Prepares sequelize config passed to original sequelize constructor
*/
- static prepareConfig(config: ISequelizeConfig | ISequelizeValidationOnlyConfig): ISequelizeConfig {
+ static prepareConfig(config: SequelizeConfig | ISequelizeValidationOnlyConfig): SequelizeConfig {
if (!config.define) {
config.define = {};
}
@@ -37,13 +48,19 @@ export abstract class BaseSequelize {
return this.getValidationOnlyConfig(config);
}
- return {...config as ISequelizeConfig};
+
+ if (BaseSequelize.isISequelizeDbNameConfig(config)) {
+ // @TODO: remove deprecated "name" property
+ return {...config, database: config.name} as ISequelizeConfig;
+ }
+
+ return {...config as SequelizeConfig};
}
- static getValidationOnlyConfig(config: ISequelizeConfig | ISequelizeValidationOnlyConfig): ISequelizeConfig {
+ static getValidationOnlyConfig(config: SequelizeConfig | ISequelizeValidationOnlyConfig): ISequelizeConfig {
return {
...config,
- name: '_name_',
+ database: '_name_',
username: '_username_',
password: '_password_',
dialect: 'sqlite',
@@ -64,7 +81,7 @@ export abstract class BaseSequelize {
models.forEach(model => this._[model.name] = model);
}
- init(config: ISequelizeConfig): void {
+ init(config: SequelizeConfig): void {
if (config.modelPaths) this.addModels(config.modelPaths);
}
diff --git a/lib/models/Sequelize.d.ts b/lib/models/Sequelize.d.ts
index ecd30318..285a7fad 100644
--- a/lib/models/Sequelize.d.ts
+++ b/lib/models/Sequelize.d.ts
@@ -1,15 +1,15 @@
-///
import 'reflect-metadata';
import * as SequelizeOrigin from 'sequelize';
import {Model} from "./Model";
-import {ISequelizeConfig} from "../interfaces/ISequelizeConfig";
+import {SequelizeConfig} from "../types/SequelizeConfig";
import {ISequelizeValidationOnlyConfig} from "../interfaces/ISequelizeValidationOnlyConfig";
export declare class Sequelize extends SequelizeOrigin {
_: {[modelName: string]: (typeof Model)};
- constructor(config: ISequelizeConfig | ISequelizeValidationOnlyConfig);
+ constructor(config: SequelizeConfig | ISequelizeValidationOnlyConfig);
+ constructor(uri: string);
addModels(models: Array): void;
addModels(modelPaths: string[]): void;
diff --git a/lib/models/v3/Sequelize.ts b/lib/models/v3/Sequelize.ts
index 331f58f2..837f3193 100644
--- a/lib/models/v3/Sequelize.ts
+++ b/lib/models/v3/Sequelize.ts
@@ -1,15 +1,13 @@
import 'reflect-metadata';
import * as SequelizeOrigin from 'sequelize';
import {Model} from "../Model";
-import {ISequelizeConfig} from "../../interfaces/ISequelizeConfig";
+import {SequelizeConfig} from "../../types/SequelizeConfig";
import {getModelName, getAttributes, getOptions} from "../../services/models";
import {PROPERTY_LINK_TO_ORIG} from "../../services/models";
import {BaseSequelize} from "../BaseSequelize";
import {Table} from "../../annotations/Table";
import {ISequelizeAssociation} from "../../interfaces/ISequelizeAssociation";
-let preparedConfig;
-
export class Sequelize extends SequelizeOrigin implements BaseSequelize {
// to fix "$1" called with something that's not an instance of Sequelize.Model
@@ -17,24 +15,27 @@ export class Sequelize extends SequelizeOrigin implements BaseSequelize {
thoughMap: { [through: string]: any } = {};
_: { [modelName: string]: typeof Model } = {};
- init: (config: ISequelizeConfig) => void;
+ init: (config: SequelizeConfig) => void;
addModels: (models: Array | string[]) => void;
associateModels: (models: Array) => void;
- constructor(config: ISequelizeConfig) {
- // a spread operator would be the more reasonable approach here,
- // but this is currently not possible due to a bug by ts
- // https://github.com/Microsoft/TypeScript/issues/4130
- // TODO@robin probably make the constructor private and
- // TODO use a static factory function instead
+ constructor(config: SequelizeConfig | string) {
+
super(
- (preparedConfig = BaseSequelize.prepareConfig(config), preparedConfig.name),
- preparedConfig.username,
- preparedConfig.password,
- preparedConfig
+ (typeof config === "string") ?
+ config : // URI string
+ BaseSequelize.isISequelizeUriConfig(config) ?
+ config.uri : // URI string from ISequelizeUriConfig
+ BaseSequelize.prepareConfig(config) // Config object (ISequelizeConfig)
);
- this.init(config);
+ if (BaseSequelize.isISequelizeUriConfig(config)) {
+ this.options = {...this.options, ...config};
+ }
+
+ if (typeof config !== "string") {
+ this.init(config);
+ }
}
getThroughModel(through: string): typeof Model {
diff --git a/lib/models/v4/Sequelize.ts b/lib/models/v4/Sequelize.ts
index f1cd89ad..cfa6f645 100644
--- a/lib/models/v4/Sequelize.ts
+++ b/lib/models/v4/Sequelize.ts
@@ -1,36 +1,37 @@
import 'reflect-metadata';
import * as OriginSequelize from 'sequelize';
import {Model} from "../Model";
-import {ISequelizeConfig} from "../../interfaces/ISequelizeConfig";
+import {SequelizeConfig} from "../../types/SequelizeConfig";
import {getModelName, getAttributes, getOptions} from "../../services/models";
import {BaseSequelize} from "../BaseSequelize";
import {Table} from "../../annotations/Table";
import {ISequelizeAssociation} from "../../interfaces/ISequelizeAssociation";
-let preparedConfig;
-
export class Sequelize extends OriginSequelize implements BaseSequelize {
thoughMap: {[through: string]: any} = {};
_: {[modelName: string]: typeof Model} = {};
- init: (config: ISequelizeConfig) => void;
- addModels: (models: Array|string[]) => void;
+ init: (config: SequelizeConfig) => void;
+ addModels: (models: Array | string[]) => void;
associateModels: (models: Array) => void;
- constructor(config: ISequelizeConfig) {
- // a spread operator would be the more reasonable approach here,
- // but this is currently not possible due to a bug by ts
- // https://github.com/Microsoft/TypeScript/issues/4130
- // TODO@robin probably make the constructor private and
- // TODO use a static factory function instead
+ constructor(config: SequelizeConfig | string) {
+
super(
- (preparedConfig = BaseSequelize.prepareConfig(config), preparedConfig.name),
- preparedConfig.username,
- preparedConfig.password,
- preparedConfig
+ (typeof config === "string") ?
+ config : // URI string
+ BaseSequelize.isISequelizeUriConfig(config) ?
+ config.uri : // URI string from ISequelizeUriConfig
+ BaseSequelize.prepareConfig(config) // Config object (ISequelizeConfig)
);
- this.init(config);
+ if (BaseSequelize.isISequelizeUriConfig(config)) {
+ this.options = {...this.options, ...config};
+ }
+
+ if (typeof config !== "string") {
+ this.init(config);
+ }
}
getThroughModel(through: string): typeof Model {
diff --git a/lib/types/SequelizeConfig.ts b/lib/types/SequelizeConfig.ts
new file mode 100644
index 00000000..182633e8
--- /dev/null
+++ b/lib/types/SequelizeConfig.ts
@@ -0,0 +1,5 @@
+import {ISequelizeConfig} from "../interfaces/ISequelizeConfig";
+import {ISequelizeUriConfig} from "../interfaces/ISequelizeUriConfig";
+import {ISequelizeDbNameConfig} from "../interfaces/ISequelizeDbNameConfig";
+
+export type SequelizeConfig = ISequelizeConfig | ISequelizeUriConfig | ISequelizeDbNameConfig;
diff --git a/package-lock.json b/package-lock.json
index 6017e5b1..d2f82403 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@types/bluebird": {
- "version": "3.5.5",
- "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.5.tgz",
- "integrity": "sha1-PH6M9mC51g6iXHh/3SWN22q7OE0="
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.4.tgz",
+ "integrity": "sha1-8SAWKwT9bVXhA0bX4ulu7UYrAs8="
},
"@types/chai": {
"version": "3.4.35",
@@ -68,13 +68,13 @@
"integrity": "sha1-tkd8qal+UmXyrGf56nBOrl4Or00="
},
"@types/sequelize": {
- "version": "4.0.68",
- "resolved": "https://registry.npmjs.org/@types/sequelize/-/sequelize-4.0.68.tgz",
- "integrity": "sha512-rarqeMu6s9wbdUxGG16erywZGKrrX4fzgvckpd+88s3EqPKPjTNCyEGzStA8q4mM7avHA/LMxnwBro1+oXKfYw==",
+ "version": "4.0.69",
+ "resolved": "https://registry.npmjs.org/@types/sequelize/-/sequelize-4.0.69.tgz",
+ "integrity": "sha512-uOfvMCj3n25GiYk7GQtxaTCD4NcY69EB5H+TwlHkcaJ1l2Wz8rjYnfJMLpen+Jv4rpMSX5dbmcrPRIiSdYeCMg==",
"requires": {
- "@types/bluebird": "3.5.5",
+ "@types/bluebird": "3.5.4",
"@types/lodash": "4.14.54",
- "@types/validator": "6.2.0"
+ "@types/validator": "6.2.2"
}
},
"@types/sinon": {
@@ -94,9 +94,9 @@
}
},
"@types/validator": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/@types/validator/-/validator-6.2.0.tgz",
- "integrity": "sha1-AgMi/hkp9piJ62daG9tamDlLcfA="
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-6.2.2.tgz",
+ "integrity": "sha512-ucoZO5gK7SJnMFrXLiMboPRnG9KwYN3PleaFc4uoEw/Ejrs8+osBs5XRDNjHfa5wFwc1jvFnn+rEe4DsRkwT8g=="
},
"ansi-align": {
"version": "1.1.0",
@@ -837,7 +837,7 @@
"iconv-lite": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
- "integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=",
+ "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==",
"dev": true
},
"imurmurhash": {
@@ -1135,7 +1135,7 @@
"lru-cache": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
- "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=",
+ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
"dev": true,
"requires": {
"pseudomap": "1.0.2",
@@ -1166,7 +1166,7 @@
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "1.1.7"
@@ -1269,7 +1269,7 @@
"readable-stream": {
"version": "2.2.11",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz",
- "integrity": "sha1-B5azH412iAB/8Lk6gIjTSqF8D3I=",
+ "integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==",
"dev": true,
"requires": {
"core-util-is": "1.0.2",
@@ -1292,7 +1292,7 @@
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"dev": true,
"requires": {
"safe-buffer": "5.1.0"
@@ -1338,7 +1338,7 @@
"nyc": {
"version": "11.0.2",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-11.0.2.tgz",
- "integrity": "sha1-nlkqaXGGAoJTtmhRbDjwecOcCPM=",
+ "integrity": "sha512-31rRd6ME9NM17w0oPKqi51a6fzJAqYarnzQXK+iL8XaX+3H6VH0BQut7qHIgrv2mBASRic4oNi2KRgcbFODrsQ==",
"dev": true,
"requires": {
"archy": "1.0.0",
@@ -4557,7 +4557,7 @@
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
- "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "1.0.0",
diff --git a/package.json b/package.json
index 046d72d7..5b7d01ee 100644
--- a/package.json
+++ b/package.json
@@ -30,9 +30,10 @@
"main": "index.js",
"types": "index.d.ts",
"dependencies": {
+ "@types/bluebird": "3.5.4",
"@types/node": "6.0.41",
"@types/reflect-metadata": "0.0.4",
- "@types/sequelize": "4.0.68",
+ "@types/sequelize": "4.0.69",
"es6-shim": "0.35.3"
},
"devDependencies": {
diff --git a/test/specs/models/sequelize.spec.ts b/test/specs/models/sequelize.spec.ts
index 67eaaa0a..45d611fa 100644
--- a/test/specs/models/sequelize.spec.ts
+++ b/test/specs/models/sequelize.spec.ts
@@ -11,6 +11,14 @@ import {Table} from '../../../lib/annotations/Table';
describe('sequelize', () => {
const sequelize = createSequelize(false);
+ const connectionUri = "sqlite://root@localhost/__";
+
+ function testOptionsProp(instance: Sequelize): void {
+ expect(instance).to.have.property('options').that.have.property('dialect').that.eqls('sqlite');
+ expect(instance).to.have.property('config').that.have.property('host').that.eqls('localhost');
+ expect(instance).to.have.property('config').that.have.property('database').that.eqls('__');
+ expect(instance).to.have.property('config').that.have.property('username').that.eqls('root');
+ }
describe('constructor', () => {
@@ -20,6 +28,72 @@ describe('sequelize', () => {
});
+ describe('constructor: using "name" property as a db name', () => {
+
+ const db = '__';
+ const sequelizeDbName = new Sequelize({
+ name: db,
+ dialect: 'sqlite',
+ username: 'root',
+ password: '',
+ storage: ':memory:',
+ logging: !('SEQ_SILENT' in process.env)
+ });
+
+ it('should equal Sequelize class', () => {
+ expect(sequelizeDbName.constructor).to.equal(Sequelize);
+ });
+
+ it('should contain database property, which equal to db.', () => {
+ expect(sequelizeDbName)
+ .to.have.property('config')
+ .that.have.property('database')
+ .that.eqls(db);
+ });
+
+ });
+
+ describe('constructor using uri in options object', () => {
+
+ const sequelizeUri = new Sequelize({
+ uri: connectionUri,
+ storage: ':memory:',
+ logging: !('SEQ_SILENT' in process.env),
+ pool: {max: 8, min: 0}
+ });
+
+ it('should equal Sequelize class', () => {
+ expect(sequelizeUri.constructor).to.equal(Sequelize);
+ });
+
+ it('should contain valid options extracted from connection string', () => {
+ testOptionsProp(sequelizeUri);
+ });
+
+ it('should contain additional Sequelize options', () => {
+ expect(sequelizeUri)
+ .to.have.property('options')
+ .that.have.property('pool')
+ .that.have.property('max')
+ .that.eqls(8);
+ });
+
+ });
+
+ describe('constructor using uri string', () => {
+
+ const sequelizeUri = new Sequelize(connectionUri);
+
+ it('should equal Sequelize class', () => {
+ expect(sequelizeUri.constructor).to.equal(Sequelize);
+ });
+
+ it('should contain valid options extracted from connection string', () => {
+ testOptionsProp(sequelizeUri);
+ });
+
+ });
+
describe('global define options', () => {
const DEFINE_OPTIONS = {timestamps: true, underscoredAll: true};
diff --git a/test/utils/sequelize.ts b/test/utils/sequelize.ts
index 5fc4dcfb..c740ad61 100644
--- a/test/utils/sequelize.ts
+++ b/test/utils/sequelize.ts
@@ -5,7 +5,7 @@ import {DefineOptions, Sequelize as SequelizeType} from "sequelize";
export function createSequelize(useModelsInPath: boolean = true, define: DefineOptions = {}): Sequelize {
return new Sequelize({
- name: '__',
+ database: '__',
dialect: 'sqlite',
username: 'root',
password: '',