@dynamatix/cat-shared 0.0.17 → 0.0.18

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.
@@ -1,11 +1,32 @@
1
1
  import AuditConfigModel from '../models/audit-config.model.js';
2
2
  import AuditLog from '../models/audit.model.js';
3
+ import ValueReferenceMap from '../models/value-reference-map.model.js';
3
4
  import { getContext } from '../services/request-context.service.js';
5
+ import mongoose from 'mongoose';
4
6
 
5
7
  let onAuditLogCreated = null;
6
8
 
9
+ // Generic resolver: fetch display values using ValueReferenceMap
10
+ async function resolveAuditValues(field, oldValue, newValue) {
11
+ const map = await ValueReferenceMap.findOne({ field });
12
+ if (!map || (!oldValue && !newValue)) return { oldValue, newValue };
13
+
14
+ const Model = mongoose.models[map.model];
15
+ if (!Model) return { oldValue, newValue };
16
+
17
+ const [oldDoc, newDoc] = await Promise.all([
18
+ oldValue ? Model.findById(oldValue).lean() : null,
19
+ newValue ? Model.findById(newValue).lean() : null
20
+ ]);
21
+
22
+ return {
23
+ oldValue: oldDoc?.[map.displayField] || oldValue,
24
+ newValue: newDoc?.[map.displayField] || newValue
25
+ };
26
+ }
27
+
7
28
  function applyAuditMiddleware(schema, collectionName) {
8
- // Handle create (after save)
29
+ // Handle creation audit
9
30
  schema.post('save', async function (doc) {
10
31
  const auditConfig = await AuditConfigModel.findOne({ collectionName });
11
32
  if (!auditConfig?.trackCreation) return;
@@ -30,13 +51,13 @@ function applyAuditMiddleware(schema, collectionName) {
30
51
  }
31
52
  });
32
53
 
33
- // Capture original doc before update
54
+ // Capture the original doc before update
34
55
  schema.pre(['findOneAndUpdate', 'findByIdAndUpdate'], async function (next) {
35
56
  this._originalDoc = await this.model.findOne(this.getQuery()).lean();
36
57
  next();
37
58
  });
38
59
 
39
- // Handle updates (after successful update)
60
+ // Handle update audits
40
61
  schema.post(['findOneAndUpdate', 'findByIdAndUpdate'], async function (result) {
41
62
  if (!result || !this._originalDoc) return;
42
63
 
@@ -50,16 +71,23 @@ function applyAuditMiddleware(schema, collectionName) {
50
71
  const contextId = context?.contextId;
51
72
 
52
73
  for (const field of auditConfig.fields) {
53
- if (update?.$set?.hasOwnProperty(field) || update?.hasOwnProperty(field)) {
74
+ const hasChanged =
75
+ update?.$set?.hasOwnProperty(field) || update?.hasOwnProperty(field);
76
+
77
+ if (hasChanged) {
54
78
  const newValue = update?.$set?.[field] ?? update?.[field];
55
79
  const oldValue = this._originalDoc[field];
56
80
 
57
81
  if (oldValue !== newValue) {
82
+ // Resolve human-readable values
83
+ const { oldValue: resolvedOld, newValue: resolvedNew } =
84
+ await resolveAuditValues(field, oldValue, newValue);
85
+
58
86
  logs.push({
59
87
  name: `${collectionName}.${field}`,
60
88
  recordId: result._id,
61
- oldValue,
62
- newValue,
89
+ oldValue: resolvedOld,
90
+ newValue: resolvedNew,
63
91
  createdBy: userId,
64
92
  contextId
65
93
  });
package/models/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as AuditConfigModel } from './audit-config.model.js';
2
- export { default as AuditModel } from './audit.model.js';
2
+ export { default as AuditModel } from './audit.model.js';
3
+ export { default as ValueReferenceMapModel } from './value-reference-map.model.js';
@@ -0,0 +1,12 @@
1
+ import mongoose from 'mongoose';
2
+
3
+ const valueReferenceMapSchema = new mongoose.Schema({
4
+ field: String, // e.g. 'documentTypeId', 'createdBy', 'status'
5
+ model: String, // e.g. 'DocumentType', 'User', 'ApplicationStatus'
6
+ displayField: String, // e.g. 'name', 'fullName', 'label'
7
+ });
8
+
9
+ valueReferenceMapSchema.index({ field: 1 }, { unique: true });
10
+
11
+ const ValueReferenceMapModel = mongoose.model('ValueReferenceMap', valueReferenceMapSchema);
12
+ export default ValueReferenceMapModel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamatix/cat-shared",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -13,5 +13,9 @@
13
13
  "./models": "./models/index.js",
14
14
  "./middlewares": "./middlewares/index.js",
15
15
  "./services": "./services/index.js"
16
+ },
17
+ "dependencies": {
18
+ "dotenv": "^16.4.7",
19
+ "mongoose": "^8.13.1"
16
20
  }
17
21
  }
@@ -0,0 +1,57 @@
1
+ import mongoose from 'mongoose';
2
+ import dotenv from 'dotenv';
3
+ import ValueReferenceMapModel from '../models/value-reference-map.model.js';
4
+
5
+ dotenv.config();
6
+
7
+ const MONGO_URI = process.env.MONGO_URI;
8
+
9
+ // Grouped definition (DRY)
10
+ const groupedMappings = [
11
+ {
12
+ model: 'DocumentType',
13
+ displayField: 'name',
14
+ fields: ['documentTypeId']
15
+ },
16
+ {
17
+ model: 'User',
18
+ displayField: 'fullName',
19
+ fields: ['createdBy', 'updatedBy', 'ownerId']
20
+ }
21
+ ];
22
+
23
+ // Flatten the mappings
24
+ const referenceMappings = groupedMappings.flatMap(group =>
25
+ group.fields.map(field => ({
26
+ field,
27
+ model: group.model,
28
+ displayField: group.displayField
29
+ }))
30
+ );
31
+
32
+ async function seed() {
33
+ try {
34
+ console.log(MONGO_URI);
35
+ await mongoose.connect(MONGO_URI);
36
+ console.log('✅ Connected to MongoDB');
37
+
38
+ for (const mapping of referenceMappings) {
39
+ const existing = await ValueReferenceMapModel.findOne({ field: mapping.field });
40
+ if (!existing) {
41
+ await ValueReferenceMapModel.create(mapping);
42
+ console.log(`➕ Inserted mapping for '${mapping.field}'`);
43
+ } else {
44
+ console.log(`⚠️ Mapping for '${mapping.field}' already exists`);
45
+ }
46
+ }
47
+
48
+ console.log('\n🌱 Seeding complete ✅');
49
+ } catch (err) {
50
+ console.error('❌ Seeding failed', err);
51
+ } finally {
52
+ await mongoose.disconnect();
53
+ process.exit();
54
+ }
55
+ }
56
+
57
+ seed();