@sera4/essentia 1.1.66-rc.1 → 3.0.8

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