@sera4/essentia 1.1.65 → 3.0.6

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 (112) hide show
  1. package/README.md +352 -8
  2. package/dist/ts/cache/index.d.ts +33 -0
  3. package/dist/ts/cache/index.js +171 -0
  4. package/dist/ts/cache/index.js.map +1 -0
  5. package/dist/ts/configurations/server-config.d.ts +4 -0
  6. package/dist/ts/configurations/server-config.js +2 -0
  7. package/dist/ts/configurations/server-config.js.map +1 -0
  8. package/dist/ts/constants/index.d.ts +7 -0
  9. package/{constants → dist/ts/constants}/index.js +5 -6
  10. package/dist/ts/constants/index.js.map +1 -0
  11. package/dist/ts/cycle/index.d.ts +53 -0
  12. package/dist/ts/cycle/index.js +169 -0
  13. package/dist/ts/cycle/index.js.map +1 -0
  14. package/dist/ts/dns/DnsCache.d.ts +50 -0
  15. package/dist/ts/dns/DnsCache.js +137 -0
  16. package/dist/ts/dns/DnsCache.js.map +1 -0
  17. package/dist/ts/dns/index.d.ts +4 -0
  18. package/dist/ts/dns/index.js +4 -0
  19. package/dist/ts/dns/index.js.map +1 -0
  20. package/dist/ts/formatter/index.d.ts +44 -0
  21. package/dist/ts/formatter/index.js +76 -0
  22. package/dist/ts/formatter/index.js.map +1 -0
  23. package/dist/ts/hal/index.d.ts +26 -0
  24. package/dist/ts/hal/index.js +70 -0
  25. package/dist/ts/hal/index.js.map +1 -0
  26. package/dist/ts/health/index.d.ts +53 -0
  27. package/dist/ts/health/index.js +165 -0
  28. package/dist/ts/health/index.js.map +1 -0
  29. package/dist/ts/helpers/index.d.ts +1 -0
  30. package/dist/ts/helpers/index.js +2 -0
  31. package/dist/ts/helpers/index.js.map +1 -0
  32. package/dist/ts/helpers/test-server-wrapper.d.ts +56 -0
  33. package/dist/ts/helpers/test-server-wrapper.js +144 -0
  34. package/dist/ts/helpers/test-server-wrapper.js.map +1 -0
  35. package/dist/ts/index.d.ts +21 -0
  36. package/dist/ts/index.js +25 -0
  37. package/dist/ts/index.js.map +1 -0
  38. package/dist/ts/last-commit/index.d.ts +12 -0
  39. package/dist/ts/last-commit/index.js +82 -0
  40. package/dist/ts/last-commit/index.js.map +1 -0
  41. package/dist/ts/logger/index.d.ts +3 -0
  42. package/dist/ts/logger/index.js +4 -0
  43. package/dist/ts/logger/index.js.map +1 -0
  44. package/dist/ts/logger/s4-logger.d.ts +23 -0
  45. package/dist/ts/logger/s4-logger.js +103 -0
  46. package/dist/ts/logger/s4-logger.js.map +1 -0
  47. package/dist/ts/paginator/index.d.ts +2 -0
  48. package/dist/ts/paginator/index.js +3 -0
  49. package/dist/ts/paginator/index.js.map +1 -0
  50. package/dist/ts/paginator/s4-pagination.d.ts +26 -0
  51. package/dist/ts/paginator/s4-pagination.js +49 -0
  52. package/dist/ts/paginator/s4-pagination.js.map +1 -0
  53. package/dist/ts/paginator/sql-pagination.d.ts +52 -0
  54. package/dist/ts/paginator/sql-pagination.js +157 -0
  55. package/dist/ts/paginator/sql-pagination.js.map +1 -0
  56. package/dist/ts/paper-trail/helpers.d.ts +14 -0
  57. package/dist/ts/paper-trail/helpers.js +74 -0
  58. package/dist/ts/paper-trail/helpers.js.map +1 -0
  59. package/dist/ts/paper-trail/index.d.ts +54 -0
  60. package/dist/ts/paper-trail/index.js +236 -0
  61. package/dist/ts/paper-trail/index.js.map +1 -0
  62. package/dist/ts/prompts/index.d.ts +21 -0
  63. package/dist/ts/prompts/index.js +68 -0
  64. package/dist/ts/prompts/index.js.map +1 -0
  65. package/dist/ts/queue/index.d.ts +196 -0
  66. package/dist/ts/queue/index.js +371 -0
  67. package/dist/ts/queue/index.js.map +1 -0
  68. package/dist/ts/queue/publisher.d.ts +41 -0
  69. package/dist/ts/queue/publisher.js +84 -0
  70. package/dist/ts/queue/publisher.js.map +1 -0
  71. package/dist/ts/queue/queue-logger.d.ts +10 -0
  72. package/dist/ts/queue/queue-logger.js +35 -0
  73. package/dist/ts/queue/queue-logger.js.map +1 -0
  74. package/dist/ts/queue/subscriber.d.ts +55 -0
  75. package/dist/ts/queue/subscriber.js +98 -0
  76. package/dist/ts/queue/subscriber.js.map +1 -0
  77. package/dist/ts/safe-proxy/index.d.ts +35 -0
  78. package/dist/ts/safe-proxy/index.js +54 -0
  79. package/dist/ts/safe-proxy/index.js.map +1 -0
  80. package/dist/ts/serializer/index.d.ts +52 -0
  81. package/dist/ts/serializer/index.js +83 -0
  82. package/dist/ts/serializer/index.js.map +1 -0
  83. package/dist/ts/utils/index.d.ts +49 -0
  84. package/dist/ts/utils/index.js +157 -0
  85. package/dist/ts/utils/index.js.map +1 -0
  86. package/package.json +52 -11
  87. package/package.tar.gz +0 -0
  88. package/cache/index.js +0 -188
  89. package/formatter/index.js +0 -81
  90. package/hal/README.md +0 -54
  91. package/hal/index.js +0 -75
  92. package/health/health-logger.js +0 -40
  93. package/health/index.js +0 -188
  94. package/helpers/index.js +0 -1
  95. package/helpers/test-server-wrapper.js +0 -196
  96. package/last-commit.js +0 -12
  97. package/last_commit/index.js +0 -82
  98. package/logger/s4-logger.js +0 -128
  99. package/paginator/README.md +0 -183
  100. package/paginator/s4-pagination.js +0 -51
  101. package/paginator/sql-pagination.js +0 -178
  102. package/paper-trail/README.md +0 -68
  103. package/paper-trail/helpers.js +0 -99
  104. package/paper-trail/index.js +0 -842
  105. package/prompts/index.js +0 -78
  106. package/queue/index.js +0 -414
  107. package/queue/publisher.js +0 -96
  108. package/queue/queue-logger.js +0 -40
  109. package/queue/subscriber.js +0 -107
  110. package/safe_proxy/index.js +0 -61
  111. package/serializer/index.js +0 -90
  112. package/utils/index.js +0 -74
@@ -1,842 +0,0 @@
1
- import * as jsdiff from 'diff';
2
- import _ from 'lodash';
3
- import helpers from './helpers.js';
4
- import paginator from "../paginator/sql-pagination.js";
5
- import { utils } from "../utils/index.js"
6
-
7
- const censorText = "**********"
8
-
9
- let failHard = false;
10
- let Sequelize = null;
11
-
12
- const paperTrail = {};
13
-
14
- paperTrail.init = (sequelize, sequelizePackage, optionsArg) => {
15
- Sequelize = sequelizePackage;
16
- // In case that options is being parsed as a readonly attribute.
17
- // Or it is not passed at all
18
- const optsArg = _.cloneDeep(optionsArg || {});
19
-
20
- const defaultOptions = {
21
- debug: false,
22
- log: null,
23
- exclude: [
24
- 'id',
25
- 'createdAt',
26
- 'updatedAt',
27
- 'deletedAt',
28
- 'created_at',
29
- 'updated_at',
30
- 'deleted_at',
31
- 'audit_source',
32
- 'revision',
33
- ],
34
- // additional fields to exclude on a global basis
35
- excludeExtras: [],
36
- excludeVirtualAttributes: true, // by default do not record these
37
- censor: ["password", "password_salt", "temp_secret", "mfa_totp_secret"],
38
- revisionAttribute: 'revision',
39
- revisionModel: 'Revision',
40
- revisionChangeModel: 'RevisionChange',
41
- enableRevisionChangeModel: false,
42
- UUID: false,
43
- // does this project use int's and UUIDs for some references (postgres)
44
- mixedDocumentReference: false,
45
- underscored: false,
46
- underscoredAttributes: false,
47
- // always store these keys in a reference value if seen
48
- includeReferences: [],
49
- defaultAttributes: {
50
- documentId: 'documentId',
51
- revisionId: 'revisionId',
52
- autoGenerated: 'autoGenerated'
53
- },
54
- als: null,
55
- userModel: false,
56
- userModelAttribute: 'userId',
57
- tenantModel: false,
58
- tenantModelAttribute: 'tenantId',
59
- enableCompression: false,
60
- enableMigration: false,
61
- enableStrictDiff: true,
62
- continuationNamespace: null,
63
- continuationKey: 'userId',
64
- continuationTenantKey: 'tenantId',
65
- metaDataFields: null,
66
- metaDataContinuationKey: 'metaData',
67
- mysql: false,
68
- };
69
-
70
- if (optsArg.mixedDocumentReference)
71
- defaultOptions.defaultAttributes.documentUuid = "documentUuid";
72
-
73
- if (optsArg.underscoredAttributes) {
74
- helpers.toUnderscored(defaultOptions.defaultAttributes);
75
- }
76
-
77
- // deals with not wanting to overwrite the initial ones, just add some
78
- if (optsArg.excludeExtras) {
79
- if (optsArg.exclude) {
80
- optsArg.exclude = [...optsArg.exclude, ...optsArg.excludeExtras ]
81
- } else {
82
- optsArg.exclude = [...defaultOptions.exclude, ...optsArg.excludeExtras ]
83
- }
84
- }
85
-
86
- const options = _.defaults(optsArg, defaultOptions);
87
-
88
- const log = options.log || console.log;
89
-
90
- function createBeforeHook(operation) {
91
- const beforeHook = function beforeHook(instance, opt) {
92
-
93
- if (options.debug) {
94
- log('beforeHook called');
95
- log('instance:', instance);
96
- log('opt:', opt);
97
- }
98
-
99
- if (opt.noPaperTrail) {
100
- if (options.debug) {
101
- log('noPaperTrail opt: is true, not logging');
102
- }
103
- return;
104
- }
105
-
106
- const destroyOperation = operation === 'destroy';
107
- const restoreOperation = operation === 'restore';
108
-
109
- let previousVersion = _.cloneDeep(instance._previousDataValues);
110
- let currentVersion = _.cloneDeep(instance.dataValues);
111
-
112
- if (!destroyOperation && options.enableCompression) {
113
- _.forEach(opt.fields, a => {
114
- previousVersion[a] = instance._previousDataValues[a];
115
- currentVersion[a] = instance.dataValues[a];
116
- });
117
- } else {
118
- previousVersion = instance._previousDataValues;
119
- currentVersion = instance.dataValues;
120
- }
121
-
122
- const excludes = options.exclude.concat([...this.extraRevisionAttributesExclude]);
123
-
124
- // Supported nested models, allowing JSONB objects.
125
- previousVersion = _.omitBy(
126
- previousVersion,
127
- i => i != null && typeof i === 'object' && !(i instanceof Date || _.isPlainObject(i)),
128
- );
129
-
130
- previousVersion = _.omit(previousVersion, excludes);
131
-
132
- currentVersion = _.omitBy(
133
- currentVersion,
134
- i => i != null && typeof i === 'object' && !(i instanceof Date || _.isPlainObject(i)),
135
- );
136
-
137
- currentVersion = _.omit(currentVersion, excludes);
138
-
139
- // Disallow change of revision
140
- instance.set(
141
- options.revisionAttribute,
142
- instance._previousDataValues[options.revisionAttribute],
143
- );
144
-
145
- // Get diffs
146
- const delta = helpers.calcDelta(
147
- previousVersion,
148
- currentVersion,
149
- options.exclude,
150
- options.enableStrictDiff,
151
- );
152
-
153
- const currentRevisionId = instance.get(options.revisionAttribute);
154
-
155
- if (failHard && !currentRevisionId && opt.type === 'UPDATE') {
156
- throw new Error('Revision Id was undefined');
157
- }
158
-
159
- if (options.debug) {
160
- log('delta:', delta);
161
- log('revisionId', currentRevisionId);
162
- }
163
- // Check if all required fields have been provided to the opts / ALS
164
- if (options.metaDataFields) {
165
- // get all required field keys as an array
166
- const requiredFields = _.keys(
167
- _.pickBy(
168
- options.metaDataFields,
169
- function isMetaDataFieldRequired(required) {
170
- return required;
171
- },
172
- ),
173
- );
174
- if (requiredFields && requiredFields.length) {
175
- const store = options.als && options.als.getStore();
176
- const metaData = (store && store.get(metaDataContinuationKey)) || opt.metaData
177
- const requiredFieldsProvided = _.filter(
178
- requiredFields,
179
- function isMetaDataFieldNonUndefined(field) {
180
- return metaData[field] !== undefined;
181
- },
182
- );
183
- if (
184
- requiredFieldsProvided.length !== requiredFields.length
185
- ) {
186
- log(
187
- 'Required fields: ',
188
- options.metaDataFields,
189
- requiredFields,
190
- );
191
- log(
192
- 'Required fields provided: ',
193
- metaData,
194
- requiredFieldsProvided,
195
- );
196
- throw new Error(
197
- 'Not all required fields are provided to paper trail!',
198
- );
199
- }
200
- }
201
- }
202
-
203
- if (destroyOperation || restoreOperation || (delta && delta.length > 0)) {
204
- const revisionId = (currentRevisionId || 0) + 1;
205
- instance.set(options.revisionAttribute, revisionId);
206
-
207
- if (!instance.context) {
208
- instance.context = {};
209
- }
210
- instance.context.delta = delta;
211
- }
212
-
213
- if (options.debug) {
214
- log('end of beforeHook');
215
- }
216
- };
217
- return beforeHook;
218
- }
219
-
220
- function createAfterHook(operation) {
221
- const afterHook = function afterHook(instance, opt) {
222
- const store = options.als && options.als.getStore()
223
- if (options.debug) {
224
- log('afterHook called');
225
- log('instance:', instance);
226
- log('opt:', opt);
227
-
228
- if (store) {
229
- log(
230
- `ALS ${options.continuationKey}:`,
231
- store.get(options.continuationKey),
232
- );
233
- }
234
- }
235
-
236
- const destroyOperation = operation === 'destroy';
237
- const createOperation = operation === 'create';
238
- const restoreOperation = operation === 'restore';
239
-
240
- if (
241
- instance.context &&
242
- ((instance.context.delta &&
243
- instance.context.delta.length > 0) ||
244
- destroyOperation || restoreOperation)
245
- ) {
246
- const Revision = sequelize.model(options.revisionModel);
247
- let RevisionChange;
248
-
249
- if (options.enableRevisionChangeModel) {
250
- RevisionChange = sequelize.model(
251
- options.revisionChangeModel,
252
- );
253
- }
254
-
255
- const { delta } = instance.context;
256
-
257
- let previousVersion = {};
258
- let currentVersion = {};
259
- if (!destroyOperation && options.enableCompression) {
260
- opt.fields = opt.fields || instance._options.attributes
261
- _.forEach(opt.fields, a => {
262
- previousVersion[a] = instance._previousDataValues[a];
263
- currentVersion[a] = instance.dataValues[a];
264
- });
265
- } else {
266
- previousVersion = instance._previousDataValues;
267
- currentVersion = instance.dataValues;
268
- }
269
-
270
- // we need to support nested Objects in a different way
271
- // if the type of change is a nested object, we need to lookat the deltas and join the path with periods
272
- // to get and show the differences.
273
-
274
- // Supported nested models.
275
- previousVersion = _.omitBy(previousVersion, value => {
276
- if (value == null) return false; // keep null/undefined
277
- if (value instanceof Date) return false; // keep Dates
278
- if (_.isPlainObject(value)) return false; // keep plain objects (including nested objects)
279
- return typeof value === 'object'; // omit if it's an object that's not plain or a Date
280
- });
281
- previousVersion = _.omit(previousVersion, options.exclude);
282
-
283
- currentVersion = _.omitBy(currentVersion, value => {
284
- if (value == null) return false;
285
- if (value instanceof Date) return false;
286
- if (_.isPlainObject(value)) return false;
287
- return typeof value === 'object';
288
- });
289
-
290
- currentVersion = _.omit(currentVersion, options.exclude);
291
-
292
- const store = options.als && options.als.getStore()
293
- if (store && !store.has(options.continuationKey)) {
294
- if (failHard)
295
- throw new Error(
296
- `The ALS continuationKey ${options.continuationKey} was not defined.`,
297
- );
298
- }
299
-
300
- // For create/restore, keep full currentVersion (including JSONB/plain objects) so
301
- // the revision document has complete newValues. For update, blank object values
302
- // and repopulate only from delta so we store minimal nested changes.
303
- const blankObjectsAndApplyDelta = !createOperation && !restoreOperation;
304
-
305
- if (blankObjectsAndApplyDelta) {
306
- let objectsChanged = new Set();
307
- // if the previous version or new version contain objects; push them onto this list
308
- _.forEach(previousVersion, (value, key) => {
309
- if (typeof(value) === 'object' ) {
310
- objectsChanged.add(key);
311
- // blank it so we can set it equal to ONLY the values changed in the next segment
312
- previousVersion[key] = {};
313
- }
314
- });
315
- _.forEach(currentVersion, (value, key) => {
316
- if (typeof(value) === 'object' ) {
317
- objectsChanged.add(key);
318
- currentVersion[key] = {};
319
- }
320
- });
321
-
322
-
323
- // we don't want to see a full object; we want to see only
324
- // x.y.z -> value
325
- if (delta && objectsChanged.size > 0 ) {
326
- // the format of these are A,E,D,N (added, edited, deleted, new) for the kind
327
- // the array is either the key or key + subkeys ['options','subkey','subkey2'] etc.
328
- // {kind: 'E', path: Array(2), lhs: false, rhs: true}
329
- for (const difference of delta) {
330
- // blank the currentVersion[difference.path[0]]
331
- // and previousVersion[difference.path[0]]
332
- _.set(currentVersion, difference.path, difference.rhs);
333
- _.set(previousVersion, difference.path, difference.lhs);
334
- };
335
- }
336
- }
337
-
338
- let document;
339
- if (destroyOperation) {
340
- document = { oldValues: currentVersion };
341
- } else if (createOperation || restoreOperation) {
342
- // we want to print out the entire object as values MAY have changed when restoring
343
- // and for NEW objects, we want the initial state
344
- document = { newValues: currentVersion };
345
- } else {
346
- document = { oldValues: previousVersion, newValues: currentVersion };
347
- }
348
-
349
- const references = _.pick(instance.dataValues, options.includeReferences);
350
-
351
- if (Object.keys(references).length) {
352
- document['references'] = references;
353
- }
354
-
355
- if (options.mysql) {
356
- document = JSON.stringify(document);
357
- }
358
-
359
- // Build revision
360
- const query = {
361
- model: this.name,
362
- document,
363
- operation,
364
- };
365
-
366
- // Add all extra data fields to the query object
367
- if (options.metaDataFields) {
368
- const metaData =
369
- (store && store.get(options.metaDataContinuationKey)) ||
370
- opt.metaData;
371
- if (metaData) {
372
- _.forEach(
373
- options.metaDataFields,
374
- function getMetaDataValues(required, field) {
375
- const value = metaData[field];
376
- if (options.debug) {
377
- log(
378
- `Adding metaData field to Revision - ${field} => ${value}`,
379
- );
380
- }
381
- if (!(field in query)) {
382
- query[field] = value;
383
- } else if (options.debug) {
384
- log(
385
- `Revision object already has a value at ${field} => ${query[field]}`,
386
- );
387
- log('Not overwriting the original value');
388
- }
389
- },
390
- );
391
- }
392
- }
393
-
394
- query[options.defaultAttributes.autoGenerated] = opt.autoGenerated;
395
-
396
- // in case of custom user models that are not 'userId'
397
- query[options.userModelAttribute] =
398
- (store && store.get(options.continuationKey)) || opt.userId;
399
-
400
- query[options.tenantModelAttribute] =
401
- (store && store.get(options.continuationTenantKey)) || opt.tenantId;
402
-
403
- if (options.mixedDocumentReference && utils.isValidUuidV4(instance.id)) {
404
- query[options.defaultAttributes.documentUuid] = instance.id;
405
- } else {
406
- query[options.defaultAttributes.documentId] = instance.id;
407
- }
408
-
409
- const revision = Revision.build(query);
410
-
411
- revision[options.revisionAttribute] = instance.get(
412
- options.revisionAttribute,
413
- );
414
-
415
- return revision
416
- .save({ transaction: opt.transaction })
417
- .then(objectRevision => {
418
- // Loop diffs and create a revision-diff for each
419
- if (options.enableRevisionChangeModel) {
420
- _.forEach(delta, difference => {
421
- const o = helpers.diffToString(
422
- difference.item
423
- ? difference.item.lhs
424
- : difference.lhs,
425
- );
426
- const n = helpers.diffToString(
427
- difference.item
428
- ? difference.item.rhs
429
- : difference.rhs,
430
- );
431
-
432
- // let document = difference;
433
- document = difference;
434
- let diff = o || n ? jsdiff.diffChars(o, n) : [];
435
-
436
- if (options.mysql) {
437
- document = JSON.stringify(document);
438
- diff = JSON.stringify(diff);
439
- }
440
-
441
- const d = RevisionChange.build({
442
- path: difference.path[0],
443
- document,
444
- diff,
445
- revisionId: objectRevision.id,
446
- });
447
-
448
- d.save({ transaction: opt.transaction })
449
- .then(savedD => {
450
- // Add diff to revision
451
- objectRevision[
452
- `add${helpers.capitalizeFirstLetter(
453
- options.revisionChangeModel,
454
- )}`
455
- ](savedD);
456
-
457
- return null;
458
- })
459
- .catch(err => {
460
- log('RevisionChange save error', err);
461
- throw err;
462
- });
463
- });
464
- }
465
- return null;
466
- })
467
- .catch(err => {
468
- log('Revision save error', err);
469
- throw err;
470
- });
471
- }
472
-
473
- if (options.debug) {
474
- log('end of afterHook');
475
- }
476
-
477
- return null;
478
- };
479
- return afterHook;
480
- }
481
-
482
- // order in which sequelize processes the hooks
483
- // (1)
484
- // beforeBulkCreate(instances, options, fn)
485
- // beforeBulkDestroy(instances, options, fn)
486
- // beforeBulkUpdate(instances, options, fn)
487
- // (2)
488
- // beforeValidate(instance, options, fn)
489
- // (-)
490
- // validate
491
- // (3)
492
- // afterValidate(instance, options, fn)
493
- // - or -
494
- // validationFailed(instance, options, error, fn)
495
- // (4)
496
- // beforeCreate(instance, options, fn)
497
- // beforeDestroy(instance, options, fn)
498
- // beforeUpdate(instance, options, fn)
499
- // beforeRestore(instance, options, fn)
500
- // (-)
501
- // create
502
- // destroy
503
- // update
504
- // (5)
505
- // afterCreate(instance, options, fn)
506
- // afterDestroy(instance, options, fn)
507
- // afterUpdate(instance, options, fn)
508
- // afterRestore(instance, options, fn)
509
- // (6)
510
- // afterBulkCreate(instances, options, fn)
511
- // afterBulkDestroy(instances, options, fn)
512
- // afterBulkUpdate(instances, options, fn)
513
-
514
- // Extend model prototype with "hasPaperTrail" function
515
- // Call model.hasPaperTrail() to enable revisions for model
516
- _.assignIn(Sequelize.Model, {
517
- hasPaperTrail: function hasPaperTrail() {
518
- if (options.debug) {
519
- log('Enabling paper trail on', this.name);
520
- }
521
-
522
- this.rawAttributes[options.revisionAttribute] = {
523
- type: Sequelize.INTEGER,
524
- defaultValue: 0,
525
- };
526
- this.revisionable = true;
527
-
528
- // not sure if we need this
529
- this.refreshAttributes();
530
-
531
- this.extraRevisionAttributesExclude = new Set();
532
- if (options.excludeVirtualAttributes) {
533
- for (const attribute in this.rawAttributes) {
534
- if (this.rawAttributes[attribute].type == "VIRTUAL") {
535
- this.extraRevisionAttributesExclude.add(attribute);
536
- }
537
- }
538
- }
539
-
540
- if (options.enableMigration) {
541
- const tableName = this.getTableName();
542
-
543
- const queryInterface = sequelize.getQueryInterface();
544
-
545
- queryInterface.describeTable(tableName).then(attributes => {
546
- if (!attributes[options.revisionAttribute]) {
547
- if (options.debug) {
548
- log('adding revision attribute to the database');
549
- }
550
-
551
- queryInterface
552
- .addColumn(tableName, options.revisionAttribute, {
553
- type: Sequelize.INTEGER,
554
- defaultValue: 0,
555
- })
556
- .then(() => null)
557
- .catch(err => {
558
- log('something went really wrong..', err);
559
- return null;
560
- });
561
- }
562
- return null;
563
- });
564
- }
565
-
566
- this.addHook('beforeCreate', createBeforeHook('create'));
567
- this.addHook('beforeDestroy', createBeforeHook('destroy'));
568
- this.addHook('beforeUpdate', createBeforeHook('update'));
569
- this.addHook('beforeRestore', createBeforeHook('restore'));
570
- this.addHook('afterCreate', createAfterHook('create'));
571
- this.addHook('afterDestroy', createAfterHook('destroy'));
572
- this.addHook('afterUpdate', createAfterHook('update'));
573
- this.addHook('afterRestore', createAfterHook('restore'));
574
-
575
- // create association
576
- if (options.mixedDocumentReference) {
577
- this.hasMany(sequelize.models[options.revisionModel], {
578
- constraints: false,
579
- foreignKey: options.defaultAttributes.documentUuid,
580
- });
581
- this.hasMany(sequelize.models[options.revisionModel], {
582
- foreignKey: options.defaultAttributes.documentId,
583
- constraints: false,
584
- scope: {
585
- model: this.name,
586
- },
587
- });
588
- } else {
589
- return this.hasMany(sequelize.models[options.revisionModel], {
590
- foreignKey: options.defaultAttributes.documentId,
591
- constraints: false,
592
- scope: {
593
- model: this.name,
594
- },
595
- });
596
- }
597
-
598
-
599
- },
600
- });
601
-
602
- return {
603
- // TWS-1032 since ALS must be set after a .run()
604
- // invocation this CANNOT be set on init(). If you would
605
- // like to use ALS, set it after the first invocation of run()
606
- setupALS: function(asyncLocalStorage) {
607
- options.als = asyncLocalStorage;
608
- },
609
- alsEnabled: function() {
610
- return (options.als === true)
611
- },
612
- defineModels: function defineModels(db) {
613
- // Attributes for RevisionModel
614
- let attributes = {
615
- model: {
616
- type: Sequelize.TEXT,
617
- allowNull: false,
618
- },
619
- document: {
620
- type: Sequelize.JSONB,
621
- allowNull: false,
622
- },
623
- operation: Sequelize.STRING(7),
624
- };
625
-
626
- if (options.mysql) {
627
- attributes.document.type = Sequelize.TEXT('MEDIUMTEXT');
628
- }
629
-
630
- attributes[options.defaultAttributes.documentId] = {
631
- type: Sequelize.INTEGER,
632
- allowNull: false,
633
- };
634
-
635
- attributes[options.defaultAttributes.autoGenerated] = {
636
- type: Sequelize.BOOLEAN,
637
- defaultValue: false,
638
- allowNull: false,
639
- };
640
-
641
- attributes[options.revisionAttribute] = {
642
- type: Sequelize.INTEGER,
643
- allowNull: false,
644
- };
645
-
646
- attributes[options.userModelAttribute] = {
647
- type: options.UUID ? Sequelize.UUID : Sequelize.INTEGER,
648
- allowNull: true
649
- };
650
-
651
- attributes[options.tenantModelAttribute] = {
652
- type: options.UUID ? Sequelize.UUID : Sequelize.INTEGER,
653
- allowNull: true
654
- };
655
-
656
-
657
- if (options.UUID) {
658
- attributes.id = {
659
- primaryKey: true,
660
- type: Sequelize.UUID,
661
- defaultValue: Sequelize.UUIDV4,
662
- };
663
-
664
- if (!options.mixedDocumentReference)
665
- attributes[options.defaultAttributes.documentId].type = Sequelize.UUID;
666
-
667
- attributes[options.userModelAttribute].type = Sequelize.UUID;
668
- }
669
-
670
- if (options.mixedDocumentReference) {
671
- attributes[options.defaultAttributes.documentId].allowNull = true;
672
- attributes[options.defaultAttributes.documentUuid] = {
673
- type: Sequelize.UUID,
674
- allowNull: true
675
- }
676
- }
677
-
678
- if (options.debug) {
679
- log('attributes', attributes);
680
- }
681
-
682
- let indexes = [{
683
- name: "document_reference_id",
684
- fields: [options.defaultAttributes.documentId]
685
- }];
686
-
687
- if (options.userModel)
688
- indexes.push({ fields: [options.userModelAttribute]});
689
-
690
- if (options.tenantModel)
691
- indexes.push({ fields: [options.tenantModelAttribute]});
692
-
693
- if (options.mixedDocumentReference) {
694
- indexes.push({
695
- name: "document_reference_uuid",
696
- fields: [options.defaultAttributes.documentUuid]
697
- })
698
- }
699
-
700
- // Revision model
701
- const Revision = sequelize.define(
702
- options.revisionModel,
703
- attributes,
704
- {
705
- underscored: options.underscored,
706
- tableName: options.tableName,
707
- timestamps: true,
708
- createdAt: options.underscored ? "created_at" : "createdAt",
709
- updatedAt: options.underscored ? "updated_at" : "updatedAt",
710
- indexes
711
- },
712
- );
713
-
714
- // safely prune down values
715
- Revision.prototype.toJSON = function() {
716
- let values = this.get();
717
- const excludedFields = ["updated_at"];
718
-
719
- // ensure that we always reference the id as document_id
720
- values.document_id = values.document_id || values.document_uuid;
721
- delete values.document_uuid;
722
-
723
- _.forEach(defaultOptions.censor, a => {
724
- if (!utils.isBlank(values.document.newValues) && !utils.isBlank(values.document.newValues[a])){
725
- values.document.newValues[a] = censorText;
726
- }
727
- if (!utils.isBlank(values.document.oldValues) && !utils.isBlank(values.document.oldValues[a])){
728
- values.document.oldValues[a] = censorText;
729
- }
730
- })
731
-
732
- return _.omitBy(values, function(value, key) {
733
- return (excludedFields.includes(key) || (value === null));
734
- });
735
- };
736
-
737
- Revision.associate = function associate(models) {
738
- if (options.debug) {
739
- log('models', models);
740
- }
741
-
742
- if (options.userModel) {
743
- Revision.belongsTo(
744
- sequelize.model(options.userModel),
745
- options.belongsToUserOptions,
746
- );
747
- }
748
-
749
- if (options.tenantModel) {
750
- Revision.belongsTo(
751
- sequelize.model(options.tenantModel),
752
- options.belongsToTenantOptions,
753
- );
754
- }
755
- };
756
-
757
- if (options.enableRevisionChangeModel) {
758
- // Attributes for RevisionChangeModel
759
- attributes = {
760
- path: {
761
- type: Sequelize.TEXT,
762
- allowNull: false,
763
- },
764
- document: {
765
- type: Sequelize.JSONB,
766
- allowNull: false,
767
- },
768
- diff: {
769
- type: Sequelize.JSONB,
770
- allowNull: false,
771
- },
772
- };
773
-
774
- if (options.mysql) {
775
- attributes.document.type = Sequelize.TEXT('MEDIUMTEXT');
776
- attributes.diff.type = Sequelize.TEXT('MEDIUMTEXT');
777
- }
778
-
779
- if (options.UUID) {
780
- attributes.id = {
781
- primaryKey: true,
782
- type: Sequelize.UUID,
783
- defaultValue: Sequelize.UUIDV4,
784
- };
785
- }
786
- // RevisionChange model
787
- const RevisionChange = sequelize.define(
788
- options.revisionChangeModel,
789
- attributes,
790
- {
791
- underscored: options.underscored,
792
- },
793
- );
794
-
795
- // Set associations
796
- Revision.hasMany(RevisionChange, {
797
- foreignKey: options.defaultAttributes.revisionId,
798
- constraints: false,
799
- });
800
-
801
- RevisionChange.belongsTo(Revision);
802
-
803
- if (db)
804
- db[RevisionChange.name] = RevisionChange;
805
- }
806
-
807
- paginator.paginate(Revision);
808
-
809
- if (db)
810
- db[Revision.name] = Revision;
811
-
812
- /*
813
- * We could extract this to a separate function so that having a
814
- * user model doesn't require different loading
815
- *
816
- * or perhaps we could omit this because we are creating the
817
- * association through the associate call above.
818
- */
819
- if (options.userModel) {
820
- Revision.belongsTo(sequelize.model(options.userModel), {
821
- as: "account",
822
- foreignKey: {
823
- fieldName: options.userModelAttribute
824
- },
825
- onDelete: "CASCADE"
826
- });
827
- }
828
-
829
- return Revision;
830
- },
831
- };
832
- };
833
-
834
- /**
835
- * Throw exceptions when the user identifier from ALS is not set or if the
836
- * revisionAttribute was not loaded on the model.
837
- */
838
- paperTrail.enableFailHard = () => {
839
- failHard = true;
840
- };
841
-
842
- export default paperTrail;