mythix 1.0.1
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.
- package/.vscode/settings.json +7 -0
- package/LICENSE +21 -0
- package/README.md +716 -0
- package/package.json +34 -0
- package/spec/controller-utils-spec.js +141 -0
- package/spec/support/jasmine.json +13 -0
- package/spec/utils-spec.js +10 -0
- package/src/application.js +934 -0
- package/src/cli/cli-utils.js +388 -0
- package/src/cli/index.js +3 -0
- package/src/cli/migrations/makemigrations-command.js +94 -0
- package/src/cli/migrations/migrate-command.js +105 -0
- package/src/cli/migrations/migration-utils.js +952 -0
- package/src/cli/serve-command.js +32 -0
- package/src/cli/shell-command.js +82 -0
- package/src/controllers/controller-base.js +83 -0
- package/src/controllers/controller-utils.js +415 -0
- package/src/controllers/index.js +20 -0
- package/src/http-server/http-errors.js +68 -0
- package/src/http-server/http-server.js +359 -0
- package/src/http-server/http-utils.js +23 -0
- package/src/http-server/index.js +17 -0
- package/src/http-server/middleware/default-middleware.js +106 -0
- package/src/http-server/middleware/index.js +5 -0
- package/src/index.js +32 -0
- package/src/logger.js +211 -0
- package/src/models/index.js +14 -0
- package/src/models/model-utils.js +259 -0
- package/src/models/model.js +85 -0
- package/src/tasks/index.js +7 -0
- package/src/tasks/task-base.js +120 -0
- package/src/tasks/task-utils.js +127 -0
- package/src/utils/config-utils.js +35 -0
- package/src/utils/crypto-utils.js +36 -0
- package/src/utils/file-utils.js +43 -0
- package/src/utils/http-utils.js +191 -0
- package/src/utils/index.js +17 -0
package/src/logger.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
const Path = require('path');
|
|
2
|
+
const FileSystem = require('fs');
|
|
3
|
+
|
|
4
|
+
const LEVEL_ERROR = 1;
|
|
5
|
+
const LEVEL_WARN = 2;
|
|
6
|
+
const LEVEL_INFO = 3;
|
|
7
|
+
const LEVEL_DEBUG = 4;
|
|
8
|
+
|
|
9
|
+
function errorStackToString(rootPath, error) {
|
|
10
|
+
return ('\n -> ' + error.stack.split(/\n+/).slice(1).map((part) => `${part.replace(/^\s+at\s+/, '')}\n`).join(' -> ')).trimEnd();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function writeToWriterObject(writer, type, _output) {
|
|
14
|
+
var method = writer[type],
|
|
15
|
+
output = _output;
|
|
16
|
+
|
|
17
|
+
if (this._customWriter || typeof method !== 'function') {
|
|
18
|
+
method = writer.write;
|
|
19
|
+
output = `${output}\n`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (typeof method === 'function')
|
|
23
|
+
method.call(writer, output);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function logToWriter(type, ..._args) {
|
|
27
|
+
var args = (_args.map((_arg) => {
|
|
28
|
+
var arg = _arg;
|
|
29
|
+
|
|
30
|
+
if (arg instanceof Error) {
|
|
31
|
+
var formattedStack = (typeof this._errorStackFormatter === 'function')
|
|
32
|
+
? this._errorStackFormatter.call(this, this._rootPath, arg)
|
|
33
|
+
: errorStackToString.call(this, this._rootPath, arg);
|
|
34
|
+
|
|
35
|
+
arg = `${arg.name}: ${arg.message}: ${formattedStack}`;
|
|
36
|
+
} else if (arg && typeof arg.valueOf() === 'function') {
|
|
37
|
+
arg = arg.valueOf();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (arg === true)
|
|
41
|
+
return 'true';
|
|
42
|
+
else if (arg === false)
|
|
43
|
+
return 'false';
|
|
44
|
+
else if (typeof arg === 'number')
|
|
45
|
+
return ('' + arg);
|
|
46
|
+
else if (typeof arg === 'string')
|
|
47
|
+
return arg;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
arg = JSON.stringify(arg);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return '<LOGGER_ERROR>';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return arg;
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
var formatter = this._formatter;
|
|
59
|
+
var writer = this._writer;
|
|
60
|
+
var content = args.join(' ');
|
|
61
|
+
var output = `${type.charAt(0).toUpperCase()}, [${(new Date()).toISOString()} #${this._pid}] -- : ${(typeof formatter === 'function') ? formatter(content) : content}`;
|
|
62
|
+
|
|
63
|
+
writeToWriterObject.call(this, (!writer) ? console : writer, type, output);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class Logger {
|
|
67
|
+
constructor(_opts) {
|
|
68
|
+
var opts = Object.assign({
|
|
69
|
+
level: LEVEL_INFO,
|
|
70
|
+
writer: null,
|
|
71
|
+
rootPath: process.cwd(),
|
|
72
|
+
errorStackFormatter: null,
|
|
73
|
+
}, _opts || {}, {
|
|
74
|
+
pid: process.pid,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// If string, assume file path
|
|
78
|
+
var customWriter = false;
|
|
79
|
+
if (typeof opts.writer === 'string') {
|
|
80
|
+
opts.writer = FileSystem.createWriteStream(opts.writer, {
|
|
81
|
+
flags: 'a',
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
emitClose: true,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
customWriter = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
Object.defineProperties(this, {
|
|
90
|
+
'_level': {
|
|
91
|
+
writable: false,
|
|
92
|
+
enumerable: false,
|
|
93
|
+
configurable: false,
|
|
94
|
+
value: opts.level,
|
|
95
|
+
},
|
|
96
|
+
'_writer': {
|
|
97
|
+
writable: false,
|
|
98
|
+
enumerable: false,
|
|
99
|
+
configurable: false,
|
|
100
|
+
value: opts.writer,
|
|
101
|
+
},
|
|
102
|
+
'_customWriter': {
|
|
103
|
+
writable: false,
|
|
104
|
+
enumerable: false,
|
|
105
|
+
configurable: false,
|
|
106
|
+
value: customWriter,
|
|
107
|
+
},
|
|
108
|
+
'_pid': {
|
|
109
|
+
writable: false,
|
|
110
|
+
enumerable: false,
|
|
111
|
+
configurable: false,
|
|
112
|
+
value: opts.pid,
|
|
113
|
+
},
|
|
114
|
+
'_formatter': {
|
|
115
|
+
writable: false,
|
|
116
|
+
enumerable: false,
|
|
117
|
+
configurable: false,
|
|
118
|
+
value: opts.formatter,
|
|
119
|
+
},
|
|
120
|
+
'_rootPath': {
|
|
121
|
+
writable: false,
|
|
122
|
+
enumerable: false,
|
|
123
|
+
configurable: false,
|
|
124
|
+
value: opts.rootPath,
|
|
125
|
+
},
|
|
126
|
+
'_errorStackFormatter': {
|
|
127
|
+
writable: false,
|
|
128
|
+
enumerable: false,
|
|
129
|
+
configurable: false,
|
|
130
|
+
value: opts.errorStackFormatter,
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
clone(extraOpts) {
|
|
136
|
+
return new this.constructor(Object.assign({
|
|
137
|
+
level: this._level,
|
|
138
|
+
writer: this._writer,
|
|
139
|
+
pid: this._pid,
|
|
140
|
+
formatter: this._formatter,
|
|
141
|
+
rootPath: this._rootPath,
|
|
142
|
+
}, extraOpts || {}));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
isErrorLevel() {
|
|
146
|
+
return (this._level >= LEVEL_ERROR);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
isWarningLevel() {
|
|
150
|
+
return (this._level >= LEVEL_WARN);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
isInfoLevel() {
|
|
154
|
+
return (this._level >= LEVEL_INFO);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
isDebugLevel() {
|
|
158
|
+
return (this._level >= LEVEL_DEBUG);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
error(...args) {
|
|
162
|
+
if (this.isErrorLevel())
|
|
163
|
+
logToWriter.call(this, 'error', ...args);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
warn(...args) {
|
|
167
|
+
if (this.isWarningLevel())
|
|
168
|
+
logToWriter.call(this, 'warn', ...args);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
info(...args) {
|
|
172
|
+
if (this.isInfoLevel())
|
|
173
|
+
logToWriter.call(this, 'info', ...args);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
debug(...args) {
|
|
177
|
+
if (this.isDebugLevel())
|
|
178
|
+
logToWriter.call(this, 'debug', ...args);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
log(...args) {
|
|
182
|
+
if (this.isErrorLevel())
|
|
183
|
+
logToWriter.call(this, 'log', ...args);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
stop() {
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
if (this._customWriter) {
|
|
189
|
+
this._writer.end((err) => {
|
|
190
|
+
if (err)
|
|
191
|
+
return reject(err);
|
|
192
|
+
|
|
193
|
+
resolve();
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
resolve();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
Object.assign(Logger, {
|
|
203
|
+
ERROR: LEVEL_ERROR,
|
|
204
|
+
WARN: LEVEL_WARN,
|
|
205
|
+
INFO: LEVEL_INFO,
|
|
206
|
+
DEBUG: LEVEL_DEBUG,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
Logger,
|
|
211
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { Model } = require('./model');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
defineModel,
|
|
5
|
+
getModelPrimaryKeyField,
|
|
6
|
+
buildModelRelations,
|
|
7
|
+
} = require('./model-utils');
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
Model,
|
|
11
|
+
defineModel,
|
|
12
|
+
getModelPrimaryKeyField,
|
|
13
|
+
buildModelRelations,
|
|
14
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
const Nife = require('nife');
|
|
2
|
+
const Inflection = require('inflection');
|
|
3
|
+
const { Model } = require('./model');
|
|
4
|
+
|
|
5
|
+
function relationHelper(type) {
|
|
6
|
+
return function(target, _options) {
|
|
7
|
+
const getName = () => {
|
|
8
|
+
if (options.name)
|
|
9
|
+
return options.name;
|
|
10
|
+
|
|
11
|
+
if (type.match(/many/i))
|
|
12
|
+
return Inflection.pluralize(target);
|
|
13
|
+
else
|
|
14
|
+
return target.toLowerCase();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
var options = _options || {};
|
|
18
|
+
var defaultOnDeleteAction = 'RESTRICT';
|
|
19
|
+
if (options.allowNull)
|
|
20
|
+
defaultOnDeleteAction = 'SET NULL';
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
type,
|
|
24
|
+
target,
|
|
25
|
+
onDelete: options.onDelete || defaultOnDeleteAction,
|
|
26
|
+
onUpdate: options.onUpdate || options.onDelete || defaultOnDeleteAction,
|
|
27
|
+
field: options.field,
|
|
28
|
+
name: getName(),
|
|
29
|
+
allowNull: (options.hasOwnProperty('allowNull')) ? options.allowNull : false,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const RELATION_HELPERS = {
|
|
35
|
+
hasOne: relationHelper('hasOne'),
|
|
36
|
+
belongsTo: relationHelper('belongsTo'),
|
|
37
|
+
hasMany: relationHelper('belongsToMany'),
|
|
38
|
+
belongsToMany: relationHelper('belongsToMany'),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function defineModel(modelName, definer, _parent) {
|
|
42
|
+
function compileModelFields(Klass, DataTypes) {
|
|
43
|
+
var fields = Klass.fields;
|
|
44
|
+
var fieldNames = Object.keys(fields);
|
|
45
|
+
|
|
46
|
+
for (var i = 0, il = fieldNames.length; i < il; i++) {
|
|
47
|
+
var fieldName = fieldNames[i];
|
|
48
|
+
var field = fields[fieldName];
|
|
49
|
+
|
|
50
|
+
if (!field.field) {
|
|
51
|
+
var columnName = Nife.camelCaseToSnakeCase(fieldName);
|
|
52
|
+
field.field = columnName;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (field.type === DataTypes.BIGINT) {
|
|
56
|
+
if (!field.get) {
|
|
57
|
+
field.get = function(name) {
|
|
58
|
+
var value = this.getDataValue(name);
|
|
59
|
+
if (value == null)
|
|
60
|
+
return null;
|
|
61
|
+
|
|
62
|
+
return BigInt(value);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!field.set) {
|
|
67
|
+
field.set = function(_value, name) {
|
|
68
|
+
var value = _value;
|
|
69
|
+
if (value == null)
|
|
70
|
+
value = null;
|
|
71
|
+
else
|
|
72
|
+
value = BigInt(value);
|
|
73
|
+
|
|
74
|
+
return this.setDataValue(name, value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return fields;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function cleanModelFields(Klass) {
|
|
84
|
+
var finalFields = {};
|
|
85
|
+
var fields = Klass.fields;
|
|
86
|
+
var fieldNames = Object.keys(fields);
|
|
87
|
+
|
|
88
|
+
for (var i = 0, il = fieldNames.length; i < il; i++) {
|
|
89
|
+
var fieldName = fieldNames[i];
|
|
90
|
+
var field = fields[fieldName];
|
|
91
|
+
var newField = Nife.extend(Nife.extend.FILTER, (key) => !key.match(/^(index)$/), {}, field);
|
|
92
|
+
|
|
93
|
+
finalFields[fieldName] = newField;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return finalFields;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function generateIndexes(Klass) {
|
|
100
|
+
var finalIndexes = [];
|
|
101
|
+
var fields = Klass.fields;
|
|
102
|
+
var fieldNames = Object.keys(fields);
|
|
103
|
+
|
|
104
|
+
for (var i = 0, il = fieldNames.length; i < il; i++) {
|
|
105
|
+
var fieldName = fieldNames[i];
|
|
106
|
+
var field = fields[fieldName];
|
|
107
|
+
|
|
108
|
+
if (field.index) {
|
|
109
|
+
if (field.index === 'unique') {
|
|
110
|
+
finalIndexes.push({
|
|
111
|
+
unique: true,
|
|
112
|
+
fields: [ field.field ],
|
|
113
|
+
});
|
|
114
|
+
} else {
|
|
115
|
+
finalIndexes.push({
|
|
116
|
+
unique: false,
|
|
117
|
+
fields: [ field.field ],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
finalIndexes = finalIndexes.concat(Klass.indexes || [], [
|
|
124
|
+
{
|
|
125
|
+
unique: false,
|
|
126
|
+
fields: [ 'created_at' ],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
unique: false,
|
|
130
|
+
fields: [ 'updated_at' ],
|
|
131
|
+
}
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
return finalIndexes;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return function({ application, Sequelize, connection }) {
|
|
138
|
+
var Klass = definer({
|
|
139
|
+
Parent: (_parent) ? _parent : Model,
|
|
140
|
+
Type: Sequelize.DataTypes,
|
|
141
|
+
Relation: RELATION_HELPERS,
|
|
142
|
+
Sequelize,
|
|
143
|
+
connection,
|
|
144
|
+
modelName,
|
|
145
|
+
application,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
Klass.name = modelName;
|
|
149
|
+
|
|
150
|
+
var pluralName = (Klass.pluralName) ? Klass.pluralName : Inflection.pluralize(modelName);
|
|
151
|
+
if (Klass.pluralName !== pluralName)
|
|
152
|
+
Klass.pluralName = pluralName;
|
|
153
|
+
|
|
154
|
+
Klass.fields = compileModelFields(Klass, Sequelize.DataTypes);
|
|
155
|
+
|
|
156
|
+
var indexes = generateIndexes(Klass);
|
|
157
|
+
|
|
158
|
+
Klass.fields = cleanModelFields(Klass);
|
|
159
|
+
|
|
160
|
+
var applicationOptions = application.getOptions();
|
|
161
|
+
var tableName;
|
|
162
|
+
|
|
163
|
+
tableName = (`${Nife.get(applicationOptions, 'database.tablePrefix', '')}${Nife.camelCaseToSnakeCase(pluralName)}`).toLowerCase();
|
|
164
|
+
|
|
165
|
+
Klass.init(Klass.fields, {
|
|
166
|
+
underscored: true,
|
|
167
|
+
freezeTableName: true,
|
|
168
|
+
sequelize: connection,
|
|
169
|
+
tableName,
|
|
170
|
+
modelName,
|
|
171
|
+
indexes,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
Klass.getApplication = () => application;
|
|
175
|
+
Klass.getLogger = () => application.getLogger();
|
|
176
|
+
|
|
177
|
+
Klass.getPrimaryKeyField = getModelPrimaryKeyField.bind(this, Klass);
|
|
178
|
+
Klass.getPrimaryKeyFieldName = () => (getModelPrimaryKeyField(Klass).field);
|
|
179
|
+
|
|
180
|
+
if (typeof Klass.onModelClassCreate === 'function')
|
|
181
|
+
Klass = Klass.onModelClassCreate(Klass);
|
|
182
|
+
|
|
183
|
+
return { [modelName]: Klass };
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function getModelPrimaryKeyField(Klass) {
|
|
188
|
+
var fields = Klass.fields;
|
|
189
|
+
var fieldNames = Object.keys(fields);
|
|
190
|
+
|
|
191
|
+
for (var i = 0, il = fieldNames.length; i < il; i++) {
|
|
192
|
+
var fieldName = fieldNames[i];
|
|
193
|
+
var field = fields[fieldName];
|
|
194
|
+
|
|
195
|
+
if (field.primaryKey)
|
|
196
|
+
return field;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function buildModelRelations(models) {
|
|
201
|
+
var modelNames = Object.keys(models);
|
|
202
|
+
for (var i = 0, il = modelNames.length; i < il; i++) {
|
|
203
|
+
var modelName = modelNames[i];
|
|
204
|
+
var model = models[modelName];
|
|
205
|
+
var relations = model.relations;
|
|
206
|
+
|
|
207
|
+
if (!relations)
|
|
208
|
+
continue;
|
|
209
|
+
|
|
210
|
+
for (var j = 0, jl = relations.length; j < jl; j++) {
|
|
211
|
+
var relation = relations[j];
|
|
212
|
+
var type = relation.type;
|
|
213
|
+
var fieldName = Nife.camelCaseToSnakeCase(relation.field);
|
|
214
|
+
var targetModelName = relation.target;
|
|
215
|
+
var targetModel = models[targetModelName];
|
|
216
|
+
|
|
217
|
+
if (!targetModel)
|
|
218
|
+
throw new Error(`${modelName} relation error: target model ${targetModelName} not found`);
|
|
219
|
+
|
|
220
|
+
var primaryKeyField;
|
|
221
|
+
|
|
222
|
+
if (type.match(/^belongs/)) {
|
|
223
|
+
primaryKeyField = getModelPrimaryKeyField(targetModel);
|
|
224
|
+
|
|
225
|
+
if (!primaryKeyField)
|
|
226
|
+
throw new Error(`${modelName} relation error: primary key for model ${targetModelName} not found`);
|
|
227
|
+
|
|
228
|
+
if (!fieldName)
|
|
229
|
+
fieldName = `${Nife.camelCaseToSnakeCase(targetModelName)}_${primaryKeyField.field}`;
|
|
230
|
+
} else {
|
|
231
|
+
primaryKeyField = getModelPrimaryKeyField(model);
|
|
232
|
+
|
|
233
|
+
if (!primaryKeyField)
|
|
234
|
+
throw new Error(`${modelName} relation error: primary key for model ${modelName} not found`);
|
|
235
|
+
|
|
236
|
+
if (!fieldName)
|
|
237
|
+
fieldName = `${Nife.camelCaseToSnakeCase(modelName)}_${primaryKeyField.field}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
var pkFieldCopy = Nife.extend(Nife.extend.FILTER, (key) => !key.match(/^(field|primaryKey)$/), {}, primaryKeyField);
|
|
241
|
+
|
|
242
|
+
// Build relation options for sequelize
|
|
243
|
+
var options = {
|
|
244
|
+
onDelete: relation.onDelete,
|
|
245
|
+
onUpdate: relation.onUpdate,
|
|
246
|
+
foreignKey: Object.assign(pkFieldCopy, { name: relation.name, field: fieldName }),
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Set relation on model
|
|
250
|
+
model[type](targetModel, options);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
module.exports = {
|
|
256
|
+
defineModel,
|
|
257
|
+
getModelPrimaryKeyField,
|
|
258
|
+
buildModelRelations,
|
|
259
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const Nife = require('nife');
|
|
2
|
+
const { Sequelize } = require('sequelize');
|
|
3
|
+
|
|
4
|
+
class Model extends Sequelize.Model {
|
|
5
|
+
getApplication() {
|
|
6
|
+
return this.constructor.getApplication();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getLogger() {
|
|
10
|
+
var application = this.getApplication();
|
|
11
|
+
return application.getLogger();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getPrimaryKeyField() {
|
|
15
|
+
return this.constructor.getPrimaryKeyField();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getPrimaryKeyFieldName() {
|
|
19
|
+
return this.constructor.getPrimaryKeyFieldName();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static prepareWhereStatement(conditions) {
|
|
23
|
+
if (Nife.isEmpty(conditions))
|
|
24
|
+
return undefined;
|
|
25
|
+
|
|
26
|
+
const Ops = Sequelize.Op;
|
|
27
|
+
var finalQuery = {};
|
|
28
|
+
var keys = Object.keys(conditions);
|
|
29
|
+
|
|
30
|
+
for (var i = 0, il = keys.length; i < il; i++) {
|
|
31
|
+
var key = keys[i];
|
|
32
|
+
var value = conditions[key];
|
|
33
|
+
|
|
34
|
+
if (value === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
|
|
37
|
+
if (value === null) {
|
|
38
|
+
finalQuery[key] = { [Ops.is]: value };
|
|
39
|
+
} else if (Nife.instanceOf(value, 'number', 'string', 'boolean', 'bigint')) {
|
|
40
|
+
finalQuery[key] = { [Ops.eq]: value };
|
|
41
|
+
} else if (Nife.instanceOf(value, 'array') && Nife.isNotEmpty(value)) {
|
|
42
|
+
finalQuery[key] = { [Ops.in]: value };
|
|
43
|
+
} else if (Nife.isNotEmpty(value)) {
|
|
44
|
+
finalQuery[key] = value;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return finalQuery;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static onModelClassCreate(Klass) {
|
|
52
|
+
Klass.first = Klass.first.bind(this, Klass);
|
|
53
|
+
Klass.last = Klass.last.bind(this, Klass);
|
|
54
|
+
|
|
55
|
+
return Klass;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static async first(Model, conditions, _order) {
|
|
59
|
+
var options = {};
|
|
60
|
+
var query = Model.prepareWhereStatement(conditions);
|
|
61
|
+
|
|
62
|
+
if (Nife.isNotEmpty(query))
|
|
63
|
+
options.where = query;
|
|
64
|
+
|
|
65
|
+
var order = _order;
|
|
66
|
+
if (!order)
|
|
67
|
+
order = [ Model.getPrimaryKeyFieldName() ];
|
|
68
|
+
|
|
69
|
+
options.order = order;
|
|
70
|
+
|
|
71
|
+
return await Model.findOne(options);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static async last(Model, conditions, _order) {
|
|
75
|
+
var order = _order;
|
|
76
|
+
if (!order)
|
|
77
|
+
order = [ Model.getPrimaryKeyFieldName(), 'DESC' ];
|
|
78
|
+
|
|
79
|
+
return await Model.first(conditions, order);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
Model,
|
|
85
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
class TaskBase {
|
|
2
|
+
constructor(application, logger, runID) {
|
|
3
|
+
Object.defineProperties(this, {
|
|
4
|
+
'application': {
|
|
5
|
+
writable: false,
|
|
6
|
+
enumberable: false,
|
|
7
|
+
configurable: true,
|
|
8
|
+
value: application,
|
|
9
|
+
},
|
|
10
|
+
'logger': {
|
|
11
|
+
writable: true,
|
|
12
|
+
enumberable: false,
|
|
13
|
+
configurable: true,
|
|
14
|
+
value: logger,
|
|
15
|
+
},
|
|
16
|
+
'runID': {
|
|
17
|
+
writable: false,
|
|
18
|
+
enumberable: false,
|
|
19
|
+
configurable: true,
|
|
20
|
+
value: runID,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async start() {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async stop() {
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getApplication() {
|
|
33
|
+
return this.application;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getLogger() {
|
|
37
|
+
var logger = this.logger;
|
|
38
|
+
if (!logger) {
|
|
39
|
+
var application = this.getApplication();
|
|
40
|
+
logger = application.getLogger();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return logger;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getRunID() {
|
|
47
|
+
return this.runID;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getNumberOfWorkers() {
|
|
51
|
+
var workers = this.constructor.workers || 1;
|
|
52
|
+
return workers;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getModel(name) {
|
|
56
|
+
var application = this.application;
|
|
57
|
+
return application.getModel(name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getModels() {
|
|
61
|
+
var application = this.application;
|
|
62
|
+
return application.getModels();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getDBConnection() {
|
|
66
|
+
var application = this.application;
|
|
67
|
+
return application.getDBConnection();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getFrequency() {
|
|
71
|
+
return this.constructor.getFrequency();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getStartDelay() {
|
|
75
|
+
return this.constructor.getStartDelay();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static onTaskClassCreate(Klass) {
|
|
79
|
+
Klass.getFrequency = Klass.getFrequency.bind(this, Klass);
|
|
80
|
+
Klass.getStartDelay = Klass.getStartDelay.bind(this, Klass);
|
|
81
|
+
Klass.shouldRun = Klass.shouldRun.bind(this, Klass);
|
|
82
|
+
|
|
83
|
+
return Klass;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static getFrequency(Task, taskIndex) {
|
|
87
|
+
return Task._frequency || 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static getStartDelay(Task, taskIndex) {
|
|
91
|
+
var workers = Task.workers || 1;
|
|
92
|
+
var frequency = Task.getFrequency(taskIndex);
|
|
93
|
+
var startDelay = Task._startDelay || 0;
|
|
94
|
+
|
|
95
|
+
if (workers > 1) {
|
|
96
|
+
var shift = (frequency / workers);
|
|
97
|
+
startDelay = Math.round(startDelay + (shift * taskIndex));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return startDelay;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static shouldRun(Task, taskIndex, lastTime, currentTime, diff) {
|
|
104
|
+
if (!lastTime) {
|
|
105
|
+
if (diff >= Task.getStartDelay(taskIndex))
|
|
106
|
+
return true;
|
|
107
|
+
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (diff >= Task.getFrequency(taskIndex))
|
|
112
|
+
return true;
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = {
|
|
119
|
+
TaskBase,
|
|
120
|
+
};
|