1 | 'use strict';
|
2 |
|
3 | const DataTypes = require('./data-types');
|
4 | const SqlString = require('./sql-string');
|
5 | const _ = require('lodash');
|
6 | const baseIsNative = require('lodash/_baseIsNative');
|
7 | const uuidv1 = require('uuid').v1;
|
8 | const uuidv4 = require('uuid').v4;
|
9 | const operators = require('./operators');
|
10 | const operatorsSet = new Set(Object.values(operators));
|
11 |
|
12 | let inflection = require('inflection');
|
13 |
|
14 | exports.classToInvokable = require('./utils/class-to-invokable').classToInvokable;
|
15 | exports.joinSQLFragments = require('./utils/join-sql-fragments').joinSQLFragments;
|
16 |
|
17 | function useInflection(_inflection) {
|
18 | inflection = _inflection;
|
19 | }
|
20 | exports.useInflection = useInflection;
|
21 |
|
22 | function camelizeIf(str, condition) {
|
23 | let result = str;
|
24 |
|
25 | if (condition) {
|
26 | result = camelize(str);
|
27 | }
|
28 |
|
29 | return result;
|
30 | }
|
31 | exports.camelizeIf = camelizeIf;
|
32 |
|
33 | function underscoredIf(str, condition) {
|
34 | let result = str;
|
35 |
|
36 | if (condition) {
|
37 | result = underscore(str);
|
38 | }
|
39 |
|
40 | return result;
|
41 | }
|
42 | exports.underscoredIf = underscoredIf;
|
43 |
|
44 | function isPrimitive(val) {
|
45 | const type = typeof val;
|
46 | return type === 'string' || type === 'number' || type === 'boolean';
|
47 | }
|
48 | exports.isPrimitive = isPrimitive;
|
49 |
|
50 |
|
51 | function mergeDefaults(a, b) {
|
52 | return _.mergeWith(a, b, (objectValue, sourceValue) => {
|
53 |
|
54 | if (!_.isPlainObject(objectValue) && objectValue !== undefined) {
|
55 |
|
56 |
|
57 | if (_.isFunction(objectValue) && baseIsNative(objectValue)) {
|
58 | return sourceValue || objectValue;
|
59 | }
|
60 | return objectValue;
|
61 | }
|
62 | });
|
63 | }
|
64 | exports.mergeDefaults = mergeDefaults;
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | function merge() {
|
70 | const result = {};
|
71 |
|
72 | for (const obj of arguments) {
|
73 | _.forOwn(obj, (value, key) => {
|
74 | if (value !== undefined) {
|
75 | if (!result[key]) {
|
76 | result[key] = value;
|
77 | } else if (_.isPlainObject(value) && _.isPlainObject(result[key])) {
|
78 | result[key] = merge(result[key], value);
|
79 | } else if (Array.isArray(value) && Array.isArray(result[key])) {
|
80 | result[key] = value.concat(result[key]);
|
81 | } else {
|
82 | result[key] = value;
|
83 | }
|
84 | }
|
85 | });
|
86 | }
|
87 |
|
88 | return result;
|
89 | }
|
90 | exports.merge = merge;
|
91 |
|
92 | function spliceStr(str, index, count, add) {
|
93 | return str.slice(0, index) + add + str.slice(index + count);
|
94 | }
|
95 | exports.spliceStr = spliceStr;
|
96 |
|
97 | function camelize(str) {
|
98 | return str.trim().replace(/[-_\s]+(.)?/g, (match, c) => c.toUpperCase());
|
99 | }
|
100 | exports.camelize = camelize;
|
101 |
|
102 | function underscore(str) {
|
103 | return inflection.underscore(str);
|
104 | }
|
105 | exports.underscore = underscore;
|
106 |
|
107 | function singularize(str) {
|
108 | return inflection.singularize(str);
|
109 | }
|
110 | exports.singularize = singularize;
|
111 |
|
112 | function pluralize(str) {
|
113 | return inflection.pluralize(str);
|
114 | }
|
115 | exports.pluralize = pluralize;
|
116 |
|
117 | function format(arr, dialect) {
|
118 | const timeZone = null;
|
119 |
|
120 | return SqlString.format(arr[0], arr.slice(1), timeZone, dialect);
|
121 | }
|
122 | exports.format = format;
|
123 |
|
124 | function formatNamedParameters(sql, parameters, dialect) {
|
125 | const timeZone = null;
|
126 | return SqlString.formatNamedParameters(sql, parameters, timeZone, dialect);
|
127 | }
|
128 | exports.formatNamedParameters = formatNamedParameters;
|
129 |
|
130 | function cloneDeep(obj, onlyPlain) {
|
131 | obj = obj || {};
|
132 | return _.cloneDeepWith(obj, elem => {
|
133 |
|
134 | if (Array.isArray(elem) || _.isPlainObject(elem)) {
|
135 | return undefined;
|
136 | }
|
137 |
|
138 |
|
139 |
|
140 | if (onlyPlain || typeof elem === 'object') {
|
141 | return elem;
|
142 | }
|
143 |
|
144 |
|
145 | if (elem && typeof elem.clone === 'function') {
|
146 | return elem.clone();
|
147 | }
|
148 | });
|
149 | }
|
150 | exports.cloneDeep = cloneDeep;
|
151 |
|
152 |
|
153 | function mapFinderOptions(options, Model) {
|
154 | if (options.attributes && Array.isArray(options.attributes)) {
|
155 | options.attributes = Model._injectDependentVirtualAttributes(options.attributes);
|
156 | options.attributes = options.attributes.filter(v => !Model._virtualAttributes.has(v));
|
157 | }
|
158 |
|
159 | mapOptionFieldNames(options, Model);
|
160 |
|
161 | return options;
|
162 | }
|
163 | exports.mapFinderOptions = mapFinderOptions;
|
164 |
|
165 |
|
166 | function mapOptionFieldNames(options, Model) {
|
167 | if (Array.isArray(options.attributes)) {
|
168 | options.attributes = options.attributes.map(attr => {
|
169 |
|
170 | if (typeof attr !== 'string') return attr;
|
171 |
|
172 | if (Model.rawAttributes[attr] && attr !== Model.rawAttributes[attr].field) {
|
173 | return [Model.rawAttributes[attr].field, attr];
|
174 | }
|
175 | return attr;
|
176 | });
|
177 | }
|
178 |
|
179 | if (options.where && _.isPlainObject(options.where)) {
|
180 | options.where = mapWhereFieldNames(options.where, Model);
|
181 | }
|
182 |
|
183 | return options;
|
184 | }
|
185 | exports.mapOptionFieldNames = mapOptionFieldNames;
|
186 |
|
187 | function mapWhereFieldNames(attributes, Model) {
|
188 | if (attributes) {
|
189 | getComplexKeys(attributes).forEach(attribute => {
|
190 | const rawAttribute = Model.rawAttributes[attribute];
|
191 |
|
192 | if (rawAttribute && rawAttribute.field !== rawAttribute.fieldName) {
|
193 | attributes[rawAttribute.field] = attributes[attribute];
|
194 | delete attributes[attribute];
|
195 | }
|
196 |
|
197 | if (_.isPlainObject(attributes[attribute])
|
198 | && !(rawAttribute && (
|
199 | rawAttribute.type instanceof DataTypes.HSTORE
|
200 | || rawAttribute.type instanceof DataTypes.JSON))) {
|
201 | attributes[attribute] = mapOptionFieldNames({
|
202 | where: attributes[attribute]
|
203 | }, Model).where;
|
204 | }
|
205 |
|
206 | if (Array.isArray(attributes[attribute])) {
|
207 | attributes[attribute].forEach((where, index) => {
|
208 | if (_.isPlainObject(where)) {
|
209 | attributes[attribute][index] = mapWhereFieldNames(where, Model);
|
210 | }
|
211 | });
|
212 | }
|
213 |
|
214 | });
|
215 | }
|
216 |
|
217 | return attributes;
|
218 | }
|
219 | exports.mapWhereFieldNames = mapWhereFieldNames;
|
220 |
|
221 |
|
222 | function mapValueFieldNames(dataValues, fields, Model) {
|
223 | const values = {};
|
224 |
|
225 | for (const attr of fields) {
|
226 | if (dataValues[attr] !== undefined && !Model._virtualAttributes.has(attr)) {
|
227 |
|
228 | if (Model.rawAttributes[attr] && Model.rawAttributes[attr].field && Model.rawAttributes[attr].field !== attr) {
|
229 | values[Model.rawAttributes[attr].field] = dataValues[attr];
|
230 | } else {
|
231 | values[attr] = dataValues[attr];
|
232 | }
|
233 | }
|
234 | }
|
235 |
|
236 | return values;
|
237 | }
|
238 | exports.mapValueFieldNames = mapValueFieldNames;
|
239 |
|
240 | function isColString(value) {
|
241 | return typeof value === 'string' && value[0] === '$' && value[value.length - 1] === '$';
|
242 | }
|
243 | exports.isColString = isColString;
|
244 |
|
245 | function canTreatArrayAsAnd(arr) {
|
246 | return arr.some(arg => _.isPlainObject(arg) || arg instanceof Where);
|
247 | }
|
248 | exports.canTreatArrayAsAnd = canTreatArrayAsAnd;
|
249 |
|
250 | function combineTableNames(tableName1, tableName2) {
|
251 | return tableName1.toLowerCase() < tableName2.toLowerCase() ? tableName1 + tableName2 : tableName2 + tableName1;
|
252 | }
|
253 | exports.combineTableNames = combineTableNames;
|
254 |
|
255 | function toDefaultValue(value, dialect) {
|
256 | if (typeof value === 'function') {
|
257 | const tmp = value();
|
258 | if (tmp instanceof DataTypes.ABSTRACT) {
|
259 | return tmp.toSql();
|
260 | }
|
261 | return tmp;
|
262 | }
|
263 | if (value instanceof DataTypes.UUIDV1) {
|
264 | return uuidv1();
|
265 | }
|
266 | if (value instanceof DataTypes.UUIDV4) {
|
267 | return uuidv4();
|
268 | }
|
269 | if (value instanceof DataTypes.NOW) {
|
270 | return now(dialect);
|
271 | }
|
272 | if (Array.isArray(value)) {
|
273 | return value.slice();
|
274 | }
|
275 | if (_.isPlainObject(value)) {
|
276 | return { ...value };
|
277 | }
|
278 | return value;
|
279 | }
|
280 | exports.toDefaultValue = toDefaultValue;
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 | function defaultValueSchemable(value) {
|
291 | if (value === undefined) { return false; }
|
292 |
|
293 |
|
294 |
|
295 | if (value instanceof DataTypes.NOW) { return false; }
|
296 |
|
297 | if (value instanceof DataTypes.UUIDV1 || value instanceof DataTypes.UUIDV4) { return false; }
|
298 |
|
299 | return typeof value !== 'function';
|
300 | }
|
301 | exports.defaultValueSchemable = defaultValueSchemable;
|
302 |
|
303 | function removeNullValuesFromHash(hash, omitNull, options) {
|
304 | let result = hash;
|
305 |
|
306 | options = options || {};
|
307 | options.allowNull = options.allowNull || [];
|
308 |
|
309 | if (omitNull) {
|
310 | const _hash = {};
|
311 |
|
312 | _.forIn(hash, (val, key) => {
|
313 | if (options.allowNull.includes(key) || key.endsWith('Id') || val !== null && val !== undefined) {
|
314 | _hash[key] = val;
|
315 | }
|
316 | });
|
317 |
|
318 | result = _hash;
|
319 | }
|
320 |
|
321 | return result;
|
322 | }
|
323 | exports.removeNullValuesFromHash = removeNullValuesFromHash;
|
324 |
|
325 | const dialects = new Set(['mariadb', 'mysql', 'postgres', 'sqlite', 'mssql']);
|
326 |
|
327 | function now(dialect) {
|
328 | const d = new Date();
|
329 | if (!dialects.has(dialect)) {
|
330 | d.setMilliseconds(0);
|
331 | }
|
332 | return d;
|
333 | }
|
334 | exports.now = now;
|
335 |
|
336 |
|
337 |
|
338 |
|
339 | const TICK_CHAR = '`';
|
340 | exports.TICK_CHAR = TICK_CHAR;
|
341 |
|
342 | function addTicks(s, tickChar) {
|
343 | tickChar = tickChar || TICK_CHAR;
|
344 | return tickChar + removeTicks(s, tickChar) + tickChar;
|
345 | }
|
346 | exports.addTicks = addTicks;
|
347 |
|
348 | function removeTicks(s, tickChar) {
|
349 | tickChar = tickChar || TICK_CHAR;
|
350 | return s.replace(new RegExp(tickChar, 'g'), '');
|
351 | }
|
352 | exports.removeTicks = removeTicks;
|
353 |
|
354 |
|
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 | function flattenObjectDeep(value) {
|
384 | if (!_.isPlainObject(value)) return value;
|
385 | const flattenedObj = {};
|
386 |
|
387 | function flattenObject(obj, subPath) {
|
388 | Object.keys(obj).forEach(key => {
|
389 | const pathToProperty = subPath ? `${subPath}.${key}` : key;
|
390 | if (typeof obj[key] === 'object' && obj[key] !== null) {
|
391 | flattenObject(obj[key], pathToProperty);
|
392 | } else {
|
393 | flattenedObj[pathToProperty] = _.get(obj, key);
|
394 | }
|
395 | });
|
396 | return flattenedObj;
|
397 | }
|
398 |
|
399 | return flattenObject(value, undefined);
|
400 | }
|
401 | exports.flattenObjectDeep = flattenObjectDeep;
|
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 | class SequelizeMethod {}
|
410 | exports.SequelizeMethod = SequelizeMethod;
|
411 |
|
412 | class Fn extends SequelizeMethod {
|
413 | constructor(fn, args) {
|
414 | super();
|
415 | this.fn = fn;
|
416 | this.args = args;
|
417 | }
|
418 | clone() {
|
419 | return new Fn(this.fn, this.args);
|
420 | }
|
421 | }
|
422 | exports.Fn = Fn;
|
423 |
|
424 | class Col extends SequelizeMethod {
|
425 | constructor(col, ...args) {
|
426 | super();
|
427 | if (args.length > 0) {
|
428 | col = args;
|
429 | }
|
430 | this.col = col;
|
431 | }
|
432 | }
|
433 | exports.Col = Col;
|
434 |
|
435 | class Cast extends SequelizeMethod {
|
436 | constructor(val, type, json) {
|
437 | super();
|
438 | this.val = val;
|
439 | this.type = (type || '').trim();
|
440 | this.json = json || false;
|
441 | }
|
442 | }
|
443 | exports.Cast = Cast;
|
444 |
|
445 | class Literal extends SequelizeMethod {
|
446 | constructor(val) {
|
447 | super();
|
448 | this.val = val;
|
449 | }
|
450 | }
|
451 | exports.Literal = Literal;
|
452 |
|
453 | class Json extends SequelizeMethod {
|
454 | constructor(conditionsOrPath, value) {
|
455 | super();
|
456 | if (_.isObject(conditionsOrPath)) {
|
457 | this.conditions = conditionsOrPath;
|
458 | } else {
|
459 | this.path = conditionsOrPath;
|
460 | if (value) {
|
461 | this.value = value;
|
462 | }
|
463 | }
|
464 | }
|
465 | }
|
466 | exports.Json = Json;
|
467 |
|
468 | class Where extends SequelizeMethod {
|
469 | constructor(attribute, comparator, logic) {
|
470 | super();
|
471 | if (logic === undefined) {
|
472 | logic = comparator;
|
473 | comparator = '=';
|
474 | }
|
475 |
|
476 | this.attribute = attribute;
|
477 | this.comparator = comparator;
|
478 | this.logic = logic;
|
479 | }
|
480 | }
|
481 | exports.Where = Where;
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 | function getOperators(obj) {
|
493 | return Object.getOwnPropertySymbols(obj).filter(s => operatorsSet.has(s));
|
494 | }
|
495 | exports.getOperators = getOperators;
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 | function getComplexKeys(obj) {
|
505 | return getOperators(obj).concat(Object.keys(obj));
|
506 | }
|
507 | exports.getComplexKeys = getComplexKeys;
|
508 |
|
509 |
|
510 |
|
511 |
|
512 |
|
513 |
|
514 |
|
515 |
|
516 | function getComplexSize(obj) {
|
517 | return Array.isArray(obj) ? obj.length : getComplexKeys(obj).length;
|
518 | }
|
519 | exports.getComplexSize = getComplexSize;
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 |
|
526 |
|
527 |
|
528 | function isWhereEmpty(obj) {
|
529 | return !!obj && _.isEmpty(obj) && getOperators(obj).length === 0;
|
530 | }
|
531 | exports.isWhereEmpty = isWhereEmpty;
|
532 |
|
533 |
|
534 |
|
535 |
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 | function generateEnumName(tableName, columnName) {
|
542 | return `enum_${tableName}_${columnName}`;
|
543 | }
|
544 | exports.generateEnumName = generateEnumName;
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 | function camelizeObjectKeys(obj) {
|
554 | const newObj = new Object();
|
555 | Object.keys(obj).forEach(key => {
|
556 | newObj[camelize(key)] = obj[key];
|
557 | });
|
558 | return newObj;
|
559 | }
|
560 | exports.camelizeObjectKeys = camelizeObjectKeys;
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 | function defaults(object, ...sources) {
|
576 | object = Object(object);
|
577 |
|
578 | sources.forEach(source => {
|
579 | if (source) {
|
580 | source = Object(source);
|
581 |
|
582 | getComplexKeys(source).forEach(key => {
|
583 | const value = object[key];
|
584 | if (
|
585 | value === undefined ||
|
586 | _.eq(value, Object.prototype[key]) &&
|
587 | !Object.prototype.hasOwnProperty.call(object, key)
|
588 |
|
589 | ) {
|
590 | object[key] = source[key];
|
591 | }
|
592 | });
|
593 | }
|
594 | });
|
595 |
|
596 | return object;
|
597 | }
|
598 | exports.defaults = defaults;
|
599 |
|
600 |
|
601 |
|
602 |
|
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 | function nameIndex(index, tableName) {
|
611 | if (tableName.tableName) tableName = tableName.tableName;
|
612 |
|
613 | if (!Object.prototype.hasOwnProperty.call(index, 'name')) {
|
614 | const fields = index.fields.map(
|
615 | field => typeof field === 'string' ? field : field.name || field.attribute
|
616 | );
|
617 | index.name = underscore(`${tableName}_${fields.join('_')}`);
|
618 | }
|
619 |
|
620 | return index;
|
621 | }
|
622 | exports.nameIndex = nameIndex;
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 |
|
631 | function intersects(arr1, arr2) {
|
632 | return arr1.some(v => arr2.includes(v));
|
633 | }
|
634 | exports.intersects = intersects;
|