mythix 1.2.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/package.json +6 -13
  2. package/src/application.js +5 -2
  3. package/src/cli/migrations/makemigrations-command.js +1 -2
  4. package/src/cli/migrations/migrate-command.js +4 -4
  5. package/src/cli/shell-command.js +0 -2
  6. package/src/controllers/controller-module.js +0 -9
  7. package/src/http-server/http-server.js +0 -5
  8. package/src/models/index.js +0 -4
  9. package/src/models/migration-model.js +2 -2
  10. package/src/models/model-module.js +19 -32
  11. package/src/models/model-utils.js +24 -374
  12. package/src/models/model.js +29 -150
  13. package/src/modules/database-module.js +23 -18
  14. package/src/tasks/task-module.js +1 -11
  15. package/src/tasks/task-utils.js +1 -2
  16. package/src/utils/test-utils.js +38 -50
  17. package/.eslintrc.js +0 -94
  18. package/.vscode/settings.json +0 -7
  19. package/spec/controllers/controller-utils-spec.js +0 -145
  20. package/spec/controllers/generate-client-api-interface-spec.js +0 -156
  21. package/spec/controllers/generateClientAPIInterface01.snapshot +0 -552
  22. package/spec/controllers/generateClientAPIInterface02.snapshot +0 -465
  23. package/spec/controllers/generateClientAPIInterface03.snapshot +0 -418
  24. package/spec/controllers/generateClientAPIInterface04.snapshot +0 -552
  25. package/spec/controllers/generateClientAPIInterface05.snapshot +0 -552
  26. package/spec/support/application.js +0 -50
  27. package/spec/support/config/index.js +0 -3
  28. package/spec/support/jasmine.json +0 -13
  29. package/spec/support/snapshots.js +0 -63
  30. package/spec/utils/crypto-utils-spec.js +0 -28
  31. package/spec/utils/file-utils-spec.js +0 -14
  32. package/spec/utils/mime-utils-spec.js +0 -175
@@ -1,398 +1,48 @@
1
1
  'use strict';
2
2
 
3
- const Nife = require('nife');
4
- const Inflection = require('inflection');
5
- const { Model } = require('./model');
6
-
7
- const MILLISECONDS_PER_SECOND = 1000;
8
-
9
- function relationHelper(modelName, type) {
10
- return function(target, _options) {
11
- const getName = () => {
12
- if (options.name)
13
- return options.name;
14
-
15
- if (type.match(/many/i))
16
- return Inflection.pluralize(target.toLowerCase());
17
- else
18
- return target.toLowerCase();
19
- };
20
-
21
- // const getFieldName = () => {
22
- // if (options.field)
23
- // return options.field;
24
-
25
- // if (type.match(/many/i))
26
- // return Inflection.pluralize(target.toLowerCase());
27
- // else
28
- // return target.toLowerCase();
29
- // };
30
-
31
- let options = _options || {};
32
- let defaultOnDeleteAction = 'RESTRICT';
33
- if (options.allowNull)
34
- defaultOnDeleteAction = 'SET NULL';
35
-
36
- return Object.assign({}, options, {
37
- type,
38
- target,
39
- onDelete: options.onDelete || defaultOnDeleteAction,
40
- onUpdate: options.onUpdate || options.onDelete || defaultOnDeleteAction,
41
- field: options.field,
42
- name: getName(),
43
- allowNull: (Object.prototype.hasOwnProperty.call(options, 'allowNull')) ? options.allowNull : true,
44
- });
45
- };
46
- }
47
-
48
- const RELATION_HELPERS = [
49
- 'hasOne',
50
- 'belongsTo',
51
- 'hasMany',
52
- 'belongsToMany',
53
- ];
54
-
55
- function getRelationHelpers(modelName) {
56
- let obj = {};
57
-
58
- for (let i = 0, il = RELATION_HELPERS.length; i < il; i++) {
59
- let type = RELATION_HELPERS[i];
60
- obj[type] = relationHelper(modelName, type);
61
- }
62
-
63
- return obj;
64
- }
65
-
66
- function preciseNow() {
67
- let janFirst2022 = 1640995200000;
68
- let now = Date.now() - janFirst2022;
69
- let highResolutionNow = Nife.now();
70
- let diff = Math.floor(highResolutionNow);
71
-
72
- return Math.floor((now + (highResolutionNow - diff)) * MILLISECONDS_PER_SECOND);
73
- }
3
+ const Nife = require('nife');
4
+ const { Types } = require('mythix-orm');
5
+ const { Model: ModelBase } = require('./model');
74
6
 
75
7
  function defineModel(modelName, definer, _parent) {
76
- function compileModelFields(Klass, DataTypes, application, connection) {
77
- const createAutoIncrementor = () => {
78
- return () => preciseNow();
79
- };
80
-
81
- let fields = Klass.fields;
82
- let fieldNames = Object.keys(fields);
83
- let isSQLIte = !!('' + Nife.get(connection, 'options.dialect')).match(/sqlite/);
84
-
85
- for (let i = 0, il = fieldNames.length; i < il; i++) {
86
- let fieldName = fieldNames[i];
87
- let field = fields[fieldName];
88
-
89
- if (!field.field) {
90
- let columnName = Nife.camelCaseToSnakeCase(fieldName);
91
- field.field = columnName;
92
- }
93
-
94
- if (!Object.prototype.hasOwnProperty.call(field, 'allowNull'))
95
- field.allowNull = (field.primaryKey) ? false : true;
96
-
97
- // If using SQLite, which doesn't support autoincrement
98
- // on anything except the primary key, then create our
99
- // own auto-incrementor for this field
100
- if (field.autoIncrement && isSQLIte && !field.primaryKey) {
101
- application.getLogger().warn(`!Warning!: Using an auto-increment field in SQLite on a non-primary-key column "${field.field}"! Be aware that this functionality is now emulated using high resolution timestamps. This won't work unless the column is a BIGINT. You may run into serious problems with this emulation!`);
102
- field.defaultValue = createAutoIncrementor();
103
- }
104
-
105
- if (field.type === DataTypes.BIGINT) {
106
- if (!field.get) {
107
- field.get = function(name) {
108
- let value = this.getDataValue(name);
109
- if (value == null)
110
- return null;
111
-
112
- return BigInt(value);
113
- };
114
- }
115
-
116
- if (!field.set) {
117
- field.set = function(_value, name) {
118
- let value = _value;
119
- if (value == null)
120
- value = null;
121
- else
122
- value = BigInt(value);
123
-
124
- return this.setDataValue(name, value);
125
- };
126
- }
127
- }
128
- }
129
-
130
- return fields;
131
- }
132
-
133
- function cleanModelFields(Klass, connection) {
134
- let finalFields = {};
135
- let fields = Klass.fields;
136
- let fieldNames = Object.keys(fields);
137
- let isSQLIte = !!('' + Nife.get(connection, 'options.dialect')).match(/sqlite/);
138
-
139
- for (let i = 0, il = fieldNames.length; i < il; i++) {
140
- let fieldName = fieldNames[i];
141
- let field = fields[fieldName];
142
- let newField = Nife.extend(Nife.extend.FILTER, (key) => {
143
- if (key.match(/^(index)$/))
144
- return false;
145
-
146
- // Strip "autoIncrement" if this is not the primary key
147
- // and we are using sqlite for our dialect
148
- if (key === 'autoIncrement' && isSQLIte && !field.primaryKey)
149
- return false;
150
-
151
- return true;
152
- }, {}, field);
153
-
154
- finalFields[fieldName] = newField;
155
- }
156
-
157
- return finalFields;
158
- }
159
-
160
- function generateIndexes(Klass) {
161
- let finalIndexes = [];
162
- let fields = Klass.fields;
163
- let fieldNames = Object.keys(fields);
164
-
165
- for (let i = 0, il = fieldNames.length; i < il; i++) {
166
- let fieldName = fieldNames[i];
167
- let field = fields[fieldName];
168
-
169
- if (field.index) {
170
- if (field.index === 'unique') {
171
- finalIndexes.push({
172
- unique: true,
173
- fields: [ field.field ],
174
- });
175
- } else {
176
- finalIndexes.push({
177
- unique: false,
178
- fields: [ field.field ],
179
- });
180
- }
181
- }
182
- }
183
-
184
- finalIndexes = finalIndexes.concat(Klass.indexes || [], [
185
- {
186
- unique: false,
187
- fields: [ 'created_at' ],
188
- },
189
- {
190
- unique: false,
191
- fields: [ 'updated_at' ],
192
- },
193
- ]);
194
-
195
- return finalIndexes;
196
- }
197
-
198
- return function({ application, Sequelize, connection }) {
8
+ return function({ application, connection }) {
199
9
  let definerArgs = {
200
- Parent: (_parent) ? _parent : Model,
201
- Type: Sequelize.DataTypes,
202
- Relation: getRelationHelpers(modelName),
203
- Sequelize,
10
+ Parent: (_parent) ? _parent : ModelBase,
11
+ Types,
204
12
  connection,
205
13
  modelName,
206
14
  application,
207
15
  };
208
16
 
209
- let Klass = definer(definerArgs);
210
-
211
- Klass.customName = modelName;
212
-
213
- if (typeof Klass.onModelClassCreate === 'function')
214
- Klass = Klass.onModelClassCreate(Klass, definerArgs);
17
+ let Model = definer(definerArgs);
215
18
 
216
- let pluralName = (Klass.pluralName) ? Klass.pluralName : Inflection.pluralize(modelName);
217
- if (Klass.pluralName !== pluralName)
218
- Klass.pluralName = pluralName;
19
+ if (typeof Model.onModelClassCreate === 'function')
20
+ Model = Model.onModelClassCreate(Model, definerArgs);
219
21
 
220
- Klass.fields = compileModelFields(Klass, Sequelize.DataTypes, application, connection);
22
+ let tableName = Model.getTableName();
23
+ let tablePrefix = application.getDBTablePrefix();
221
24
 
222
- let indexes = generateIndexes(Klass);
25
+ if (tablePrefix)
26
+ tableName = (`${tablePrefix}${tableName}`);
223
27
 
224
- Klass.fields = cleanModelFields(Klass, connection);
28
+ Model.getTableName = () => tableName;
29
+ Model.getModelName = () => modelName;
30
+ Model.getApplication = () => application;
31
+ Model.getLogger = () => application.getLogger();
32
+ Model._getConnection = (_connection) => {
33
+ if (_connection)
34
+ return _connection;
225
35
 
226
- let applicationOptions = application.getOptions();
227
- let tableName = Klass.tableName;
228
-
229
- if (!tableName)
230
- tableName = (`${Nife.get(applicationOptions, 'database.tablePrefix', '')}${Nife.camelCaseToSnakeCase(pluralName)}`).toLowerCase();
231
-
232
- // Sequelize bullshit...
233
- // Sequelize has undocumented static hook methods
234
- // that don't align with their own hook system.
235
- // Who knows what they are for, as they aren't
236
- // documented, nor even called when statically
237
- // defined on a model class... but... there you
238
- // have it, stupid undocumented bullshit (again)
239
- // that is breaking the world.
240
- // So we must first check that each method isn't
241
- // Sequelize bullshit, otherwise we get errors.
242
- let staticHooks = {
243
- beforeBulkCreate: Klass.beforeBulkCreate,
244
- beforeBulkDestroy: Klass.beforeBulkDestroy,
245
- beforeBulkUpdate: Klass.beforeBulkUpdate,
246
- beforeValidate: Klass.beforeValidate,
247
- afterValidate: Klass.afterValidate,
248
- validationFailed: Klass.validationFailed,
249
- beforeCreate: Klass.beforeCreate,
250
- beforeDestroy: Klass.beforeDestroy,
251
- beforeUpdate: Klass.beforeUpdate,
252
- beforeSave: Klass.beforeSave,
253
- beforeUpsert: Klass.beforeUpsert,
254
- afterCreate: Klass.afterCreate,
255
- afterDestroy: Klass.afterDestroy,
256
- afterUpdate: Klass.afterUpdate,
257
- afterSave: Klass.afterSave,
258
- afterUpsert: Klass.afterUpsert,
259
- afterBulkCreate: Klass.afterBulkCreate,
260
- afterBulkDestroy: Klass.afterBulkDestroy,
261
- afterBulkUpdate: Klass.afterBulkUpdate,
36
+ return connection;
262
37
  };
263
- let hookNames = Object.keys(staticHooks);
264
- let hooks = {};
265
- for (let i = 0, il = hookNames.length; i < il; i++) {
266
- let hookName = hookNames[i];
267
- let hookFunc = staticHooks[hookName];
268
- if (typeof hookFunc !== 'function')
269
- continue;
270
-
271
- // Are you mysterious Sequelize stupidity?
272
- // If so, skip the bullshit please.
273
- if (hookFunc === Sequelize.Model[hookName])
274
- continue;
275
38
 
276
- hooks[hookName] = hookFunc;
277
- }
278
-
279
- Klass.init(Klass.fields, {
280
- underscored: true,
281
- freezeTableName: true,
282
- sequelize: connection,
283
- tableName,
284
- modelName,
285
- indexes,
286
- name: {
287
- singular: modelName.toLowerCase(),
288
- plural: Inflection.pluralize(modelName.toLowerCase()),
289
- },
290
- hooks,
291
- });
39
+ if (typeof Model.onModelClassFinalized === 'function')
40
+ Model = Model.onModelClassFinalized(Model, definerArgs);
292
41
 
293
- Klass.getApplication = () => application;
294
- Klass.getLogger = () => application.getLogger();
295
- Klass.getModelName = (function() {
296
- return modelName;
297
- }).bind(Klass);
298
-
299
- Klass.prototype.getModelName = function() {
300
- return modelName;
301
- };
302
-
303
- Klass.getPrimaryKeyField = getModelPrimaryKeyField.bind(this, Klass);
304
- Klass.getPrimaryKeyFieldName = () => (getModelPrimaryKeyField(Klass).field);
305
-
306
- if (typeof Klass.onModelClassFinalized === 'function')
307
- Klass = Klass.onModelClassFinalized(Klass, definerArgs);
308
-
309
- return { [modelName]: Klass };
42
+ return { [modelName]: Model };
310
43
  };
311
44
  }
312
45
 
313
- function getModelPrimaryKeyField(Klass) {
314
- let fields = Klass.fields;
315
- let fieldNames = Object.keys(fields);
316
-
317
- for (let i = 0, il = fieldNames.length; i < il; i++) {
318
- let fieldName = fieldNames[i];
319
- let field = fields[fieldName];
320
-
321
- if (field.primaryKey)
322
- return field;
323
- }
324
- }
325
-
326
- function buildModelRelations(models) {
327
- let modelNames = Object.keys(models);
328
- for (let i = 0, il = modelNames.length; i < il; i++) {
329
- let modelName = modelNames[i];
330
- let model = models[modelName];
331
- let relations = model.relations;
332
-
333
- if (!relations)
334
- continue;
335
-
336
- for (let j = 0, jl = relations.length; j < jl; j++) {
337
- let relation = relations[j];
338
- let type = relation.type;
339
- let fieldName = Nife.camelCaseToSnakeCase(relation.field);
340
- let targetModelName = relation.target;
341
- let targetModel = models[targetModelName];
342
- let belongsType = !!type.match(/^belongs/);
343
-
344
- if (!targetModel)
345
- throw new Error(`${modelName} relation error: target model ${targetModelName} not found`);
346
-
347
- let primaryKeyField;
348
-
349
- if (belongsType) {
350
- primaryKeyField = getModelPrimaryKeyField(targetModel);
351
-
352
- if (!primaryKeyField)
353
- throw new Error(`${modelName} relation error: primary key for model ${targetModelName} not found`);
354
-
355
- let pkFieldName = primaryKeyField.field;
356
- if (pkFieldName === 'id')
357
- pkFieldName = 'ID';
358
-
359
- if (!fieldName)
360
- fieldName = `${Nife.camelCaseToSnakeCase(targetModelName)}${Nife.snakeCaseToCamelCase(pkFieldName, true)}`;
361
- } else {
362
- primaryKeyField = getModelPrimaryKeyField(model);
363
-
364
- if (!primaryKeyField)
365
- throw new Error(`${modelName} relation error: primary key for model ${modelName} not found`);
366
-
367
- let pkFieldName = primaryKeyField.field;
368
- if (pkFieldName === 'id')
369
- pkFieldName = 'ID';
370
-
371
- if (!fieldName)
372
- fieldName = `${Nife.camelCaseToSnakeCase(modelName)}${Nife.snakeCaseToCamelCase(pkFieldName, true)}`;
373
- }
374
-
375
- let pkFieldCopy = Nife.extend(Nife.extend.FILTER, (key) => !key.match(/^(field|primaryKey)$/), {}, primaryKeyField);
376
-
377
- // Build relation options for sequelize
378
- let options = Object.assign({}, relation, {
379
- onDelete: relation.onDelete,
380
- onUpdate: relation.onUpdate,
381
- allowNull: (relation.allowNull == null) ? true : relation.allowNull,
382
- foreignKey: (relation.foreignKey) ? relation.foreignKey : Object.assign(pkFieldCopy, { name: fieldName, as: relation.name, field: Nife.camelCaseToSnakeCase(fieldName) }),
383
- });
384
-
385
- // Set relation on model
386
-
387
- // console.log(`Creating model relation (${modelName} -> ${targetModelName}): `, type, options);
388
-
389
- model[type](targetModel, options);
390
- }
391
- }
392
- }
393
-
394
46
  module.exports = {
395
47
  defineModel,
396
- getModelPrimaryKeyField,
397
- buildModelRelations,
398
48
  };
@@ -1,9 +1,21 @@
1
1
  'use strict';
2
2
 
3
- const Nife = require('nife');
4
- const { Sequelize } = require('sequelize');
3
+ const { Model: _Model } = require('mythix-orm');
4
+
5
+ class Model extends _Model {
6
+ static getModel(modelName) {
7
+ if (modelName) {
8
+ let connection = this.getConnection();
9
+ return connection.getModel(modelName);
10
+ }
11
+
12
+ return this;
13
+ }
14
+
15
+ getModel(modelName) {
16
+ return this.constructor.getModel(modelName);
17
+ }
5
18
 
6
- class Model extends Sequelize.Model {
7
19
  getApplication() {
8
20
  return this.constructor.getApplication();
9
21
  }
@@ -13,21 +25,25 @@ class Model extends Sequelize.Model {
13
25
  return application.getLogger();
14
26
  }
15
27
 
16
- getDBConnection() {
28
+ getDBConnection(connection) {
29
+ if (connection)
30
+ return connection;
31
+
17
32
  let application = this.getApplication();
18
- return application.getDBConnection();
19
- }
33
+ if (!application)
34
+ return null;
20
35
 
21
- getPrimaryKeyField() {
22
- return this.constructor.getPrimaryKeyField();
23
- }
36
+ if (typeof application.getDBConnection === 'function')
37
+ return application.getDBConnection();
24
38
 
25
- getPrimaryKeyFieldName() {
26
- return this.constructor.getPrimaryKeyFieldName();
39
+ return null;
27
40
  }
28
41
 
29
- getTableName() {
30
- return this.constructor.getTableName();
42
+ getConnection(connection) {
43
+ if (connection)
44
+ return connection;
45
+
46
+ return this.getDBConnection();
31
47
  }
32
48
 
33
49
  overrideMethod(name, newMethod) {
@@ -60,143 +76,6 @@ class Model extends Sequelize.Model {
60
76
  this.overrideMethod(name, method);
61
77
  }
62
78
  }
63
-
64
- static prepareWhereStatement(conditions) {
65
- if (Nife.isEmpty(conditions))
66
- return undefined;
67
-
68
- if (conditions._mythixQuery)
69
- return conditions;
70
-
71
- const Ops = Sequelize.Op;
72
- let finalQuery = {};
73
- let keys = Object.keys(conditions).concat(Object.getOwnPropertySymbols(conditions));
74
-
75
- for (let i = 0, il = keys.length; i < il; i++) {
76
- let key = keys[i];
77
- let value = conditions[key];
78
-
79
- if (value === undefined)
80
- continue;
81
-
82
- let name = key;
83
- let invert = false;
84
-
85
- if (typeof name === 'string' && name.charAt(0) === '!') {
86
- name = name.substring(1);
87
- invert = true;
88
- }
89
-
90
- if (typeof key === 'symbol') {
91
- finalQuery[key] = value;
92
- } else if (value === null) {
93
- finalQuery[name] = (invert) ? { [Ops.not]: value } : { [Ops.is]: value };
94
- } else if (Nife.instanceOf(value, 'number', 'string', 'boolean', 'bigint')) {
95
- finalQuery[name] = (invert) ? { [Ops.ne]: value } : { [Ops.eq]: value };
96
- } else if (Nife.instanceOf(value, 'array') && Nife.isNotEmpty(value)) {
97
- finalQuery[name] = (invert) ? { [Ops.not]: { [Ops.in]: value } } : { [Ops.in]: value };
98
- } else if (Nife.isNotEmpty(value)) {
99
- if (invert)
100
- throw new Error(`Model.prepareWhereStatement: Attempted to invert a custom matcher "${name}"`);
101
-
102
- finalQuery[name] = value;
103
- }
104
- }
105
-
106
- if (Nife.isEmpty(finalQuery))
107
- return;
108
-
109
- Object.defineProperties(finalQuery, {
110
- '_mythixQuery': {
111
- writable: false,
112
- enumberable: false,
113
- configurable: false,
114
- value: true,
115
- },
116
- });
117
-
118
- return finalQuery;
119
- }
120
-
121
- static getDefaultOrderBy() {
122
- return [ this.getPrimaryKeyFieldName() ];
123
- }
124
-
125
- static prepareQueryOptions(conditions, _order) {
126
- const Ops = Sequelize.Op;
127
- let options;
128
- let query;
129
-
130
- if (conditions && Nife.isNotEmpty(conditions.where)) {
131
- query = conditions.where;
132
- options = Object.assign({}, conditions);
133
- } else if (conditions && conditions.where !== null) {
134
- query = this.prepareWhereStatement(conditions);
135
- }
136
-
137
- let order = _order;
138
- if (!options && Nife.instanceOf(order, 'object')) {
139
- options = Object.assign({}, order);
140
- order = options.order;
141
- } else if (!options) {
142
- options = {};
143
- }
144
-
145
- if (Nife.isNotEmpty(query))
146
- options.where = query;
147
-
148
- if (!order && options.defaultOrder !== false) {
149
- if (options.order) {
150
- order = options.order;
151
- } else {
152
- if (typeof this.getDefaultOrderBy === 'function')
153
- order = this.getDefaultOrderBy();
154
- else
155
- order = [ this.getPrimaryKeyFieldName() ];
156
- }
157
- }
158
-
159
- options.order = order;
160
- if (!Object.prototype.hasOwnProperty.call(options, 'distinct'))
161
- options.distinct = true;
162
-
163
- // If no "where" clause was specified, then grab everything
164
- if (!options.where)
165
- options.where = { [ this.getPrimaryKeyFieldName() ]: { [Ops.not]: null } };
166
-
167
- if (options.debug)
168
- console.log('QUERY OPTIONS: ', options);
169
-
170
- return options;
171
- }
172
-
173
- static where(conditions) {
174
- return this.prepareWhereStatement(conditions);
175
- }
176
-
177
- static async rowCount(conditions, options) {
178
- return await this.count(this.prepareQueryOptions(conditions, options));
179
- }
180
-
181
- static async bulkUpdate(attrs, conditions) {
182
- return await this.update(attrs, this.prepareQueryOptions(conditions, { distinct: false }));
183
- }
184
-
185
- static async all(conditions, order) {
186
- return await this.findAll(this.prepareQueryOptions(conditions, order));
187
- }
188
-
189
- static async first(conditions, order) {
190
- return await this.findOne(this.prepareQueryOptions(conditions, order));
191
- }
192
-
193
- static async last(conditions, _order) {
194
- let order = _order;
195
- if (!order)
196
- order = [ [ 'createdAt', 'DESC' ] ];
197
-
198
- return await this.first(conditions, order);
199
- }
200
79
  }
201
80
 
202
81
  module.exports = {
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- const Nife = require('nife');
4
- const { Sequelize } = require('sequelize');
5
- const { BaseModule } = require('../modules/base-module');
3
+ const Nife = require('nife');
4
+ const { BaseModule } = require('../modules/base-module');
5
+ const { ConnectionBase } = require('mythix-orm');
6
6
 
7
7
  class DatabaseModule extends BaseModule {
8
8
  static getModuleName() {
@@ -97,31 +97,36 @@ class DatabaseModule extends BaseModule {
97
97
  }
98
98
 
99
99
  async connectToDatabase(databaseConfig) {
100
- if (!databaseConfig) {
101
- this.getLogger().error('Error: database connection options not defined');
102
- return;
103
- }
100
+ if (!databaseConfig)
101
+ throw new Error('DatabaseModule::connectToDatabase: Database connection options not defined.');
104
102
 
105
- let sequelize = new Sequelize(databaseConfig);
106
103
  let dbConnectionString;
107
-
108
104
  if (Nife.instanceOf(databaseConfig, 'string'))
109
105
  dbConnectionString = databaseConfig;
110
106
  else
111
107
  dbConnectionString = `${databaseConfig.dialect}://${databaseConfig.host}:${databaseConfig.port || '<default port>'}/${databaseConfig.database}`;
112
108
 
113
109
  try {
114
- await sequelize.authenticate();
110
+ let app = this.getApplication();
111
+ if (typeof app.createDatabaseConnection !== 'function')
112
+ throw new Error('DatabaseModule::connectToDatabase: You must define a "createDatabaseConnection" method on your Application class.');
115
113
 
116
- this.getLogger().info(`Connection to ${dbConnectionString} has been established successfully!`);
114
+ let connection = await app.createDatabaseConnection(databaseConfig);
115
+ if (!connection)
116
+ throw new Error('DatabaseModule::connectToDatabase: Application::createDatabaseConnection must return a connection.');
117
+
118
+ if (!(connection instanceof ConnectionBase) && typeof connection === 'function' && connection.prototype instanceof ConnectionBase) {
119
+ const ConnectionKlass = connection;
120
+ connection = new ConnectionKlass(databaseConfig);
117
121
 
118
- // SQLite needs foreign keys TURNED ON
119
- // when we first connect (they default to off)
120
- let dialect = sequelize.getDialect();
121
- if (dialect === 'sqlite')
122
- await sequelize.query('PRAGMA foreign_keys = ON');
122
+ await connection.start();
123
+ } else if (!connection.isStarted()) {
124
+ await connection.start();
125
+ }
126
+
127
+ this.getLogger().info(`Connection to ${dbConnectionString} has been established successfully!`);
123
128
 
124
- return sequelize;
129
+ return connection;
125
130
  } catch (error) {
126
131
  this.getLogger().error(`Unable to connect to database ${dbConnectionString}:`, error);
127
132
  throw error;
@@ -146,7 +151,7 @@ class DatabaseModule extends BaseModule {
146
151
  return;
147
152
 
148
153
  this.getLogger().info('Closing database connections...');
149
- await this.connection.close();
154
+ await this.connection.stop();
150
155
  this.getLogger().info('All database connections closed successfully!');
151
156
  }
152
157
  }