ts-patch-mongoose 2.9.6 → 3.0.0
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/README.md +42 -27
- package/biome.json +1 -1
- package/dist/index.cjs +273 -53
- package/dist/index.d.cts +41 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +41 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +273 -53
- package/package.json +12 -18
- package/src/helpers.ts +118 -9
- package/src/hooks/delete-hooks.ts +1 -4
- package/src/hooks/update-hooks.ts +6 -15
- package/src/index.ts +4 -32
- package/src/ms.ts +66 -0
- package/src/omit-deep.ts +95 -0
- package/src/patch.ts +19 -21
- package/src/version.ts +5 -4
- package/tests/em.test.ts +2 -0
- package/tests/helpers.test.ts +229 -2
- package/tests/ms.test.ts +113 -0
- package/tests/omit-deep.test.ts +220 -0
- package/tests/plugin-all-features.test.ts +741 -0
- package/tests/plugin-complex-data.test.ts +1332 -0
- package/tsconfig.json +2 -3
- package/src/modules/omit-deep.d.ts +0 -3
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@ I need to track changes of mongoose models and save them as patch history (audit
|
|
|
23
23
|
|
|
24
24
|
```json
|
|
25
25
|
{
|
|
26
|
-
"node": "
|
|
27
|
-
"mongoose": ">=6.6.x || 7.x || 8.x",
|
|
26
|
+
"node": "20.x || 22.x || 24.x",
|
|
27
|
+
"mongoose": ">=6.6.x || 7.x || 8.x || 9.x",
|
|
28
28
|
}
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -40,37 +40,19 @@ I need to track changes of mongoose models and save them as patch history (audit
|
|
|
40
40
|
|
|
41
41
|
## Installation
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
`mongoose` is a peer dependency — install it alongside `ts-patch-mongoose`.
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install ts-patch-mongoose
|
|
47
|
-
pnpm add ts-patch-mongoose
|
|
48
|
-
yarn add ts-patch-mongoose
|
|
49
|
-
bun add ts-patch-mongoose
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
- This plugin requires mongoose `>=6.6.x || 7.x || 8.x` to be installed as a peer dependency
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# For latest mongoose 6
|
|
56
|
-
npm install mongoose@6
|
|
57
|
-
pnpm add mongoose@6
|
|
58
|
-
yarn add mongoose@6
|
|
59
|
-
bun add mongoose@6
|
|
60
|
-
# For latest mongoose 7
|
|
61
|
-
npm install mongoose@7
|
|
62
|
-
pnpm add mongoose@7
|
|
63
|
-
yarn add mongoose@7
|
|
64
|
-
bun add mongoose@7
|
|
65
|
-
# For latest mongoose 8
|
|
66
|
-
npm install mongoose@8
|
|
67
|
-
pnpm add mongoose@8
|
|
68
|
-
yarn add mongoose@8
|
|
69
|
-
bun add mongoose@8
|
|
46
|
+
npm install ts-patch-mongoose mongoose
|
|
47
|
+
pnpm add ts-patch-mongoose mongoose
|
|
48
|
+
yarn add ts-patch-mongoose mongoose
|
|
49
|
+
bun add ts-patch-mongoose mongoose
|
|
70
50
|
```
|
|
71
51
|
|
|
72
52
|
## Example
|
|
73
53
|
|
|
54
|
+
Works with any Node.js framework — Express, Fastify, Koa, Hono, Nest, etc.
|
|
55
|
+
\
|
|
74
56
|
How to use it with express [ts-express-tsx](https://github.com/ilovepixelart/ts-express-tsx)
|
|
75
57
|
|
|
76
58
|
Create your event constants `events.ts`
|
|
@@ -213,6 +195,39 @@ patchEventEmitter.on(BOOK_DELETED, ({ oldDoc }) => {
|
|
|
213
195
|
})
|
|
214
196
|
```
|
|
215
197
|
|
|
198
|
+
## NestJS
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
|
|
202
|
+
import { patchHistoryPlugin } from 'ts-patch-mongoose'
|
|
203
|
+
|
|
204
|
+
@Schema({ timestamps: true })
|
|
205
|
+
export class Book {
|
|
206
|
+
@Prop({ type: String, required: true })
|
|
207
|
+
title!: string
|
|
208
|
+
|
|
209
|
+
@Prop({ type: String })
|
|
210
|
+
description?: string
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const BookSchema = SchemaFactory.createForClass(Book)
|
|
214
|
+
|
|
215
|
+
BookSchema.plugin(patchHistoryPlugin, {
|
|
216
|
+
eventCreated: 'book-created',
|
|
217
|
+
eventUpdated: 'book-updated',
|
|
218
|
+
eventDeleted: 'book-deleted',
|
|
219
|
+
omit: ['__v', 'createdAt', 'updatedAt'],
|
|
220
|
+
})
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Contributing
|
|
224
|
+
|
|
225
|
+
Check [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
|
|
230
|
+
|
|
216
231
|
## Check my other projects
|
|
217
232
|
|
|
218
233
|
- [ts-migrate-mongoose](https://github.com/ilovepixelart/ts-migrate-mongoose) - Migration framework for mongoose
|
package/biome.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var isEmpty = require('lodash/isEmpty.js');
|
|
4
|
-
var ms = require('ms');
|
|
5
3
|
var mongoose = require('mongoose');
|
|
6
|
-
var isArray = require('lodash/isArray.js');
|
|
7
4
|
var jsonpatch = require('fast-json-patch');
|
|
8
|
-
var chunk = require('lodash/chunk.js');
|
|
9
|
-
var isFunction = require('lodash/isFunction.js');
|
|
10
|
-
var omit = require('omit-deep');
|
|
11
5
|
var EventEmitter = require('node:events');
|
|
12
|
-
var cloneDeep = require('lodash/cloneDeep.js');
|
|
13
|
-
var forEach = require('lodash/forEach.js');
|
|
14
|
-
var isObjectLike = require('lodash/isObjectLike.js');
|
|
15
|
-
var keys = require('lodash/keys.js');
|
|
16
6
|
var powerAssign = require('power-assign');
|
|
17
|
-
var semver = require('semver');
|
|
18
7
|
|
|
19
8
|
const HistorySchema = new mongoose.Schema(
|
|
20
9
|
{
|
|
@@ -61,6 +50,156 @@ HistorySchema.index({ collectionId: 1, version: -1 });
|
|
|
61
50
|
HistorySchema.index({ op: 1, modelName: 1, collectionName: 1, collectionId: 1, reason: 1, version: 1 });
|
|
62
51
|
const HistoryModel = mongoose.model("History", HistorySchema, "history");
|
|
63
52
|
|
|
53
|
+
const s = 1e3;
|
|
54
|
+
const m = s * 60;
|
|
55
|
+
const h = m * 60;
|
|
56
|
+
const d = h * 24;
|
|
57
|
+
const w = d * 7;
|
|
58
|
+
const y = d * 365.25;
|
|
59
|
+
const mo = y / 12;
|
|
60
|
+
const UNITS = {
|
|
61
|
+
milliseconds: 1,
|
|
62
|
+
millisecond: 1,
|
|
63
|
+
msecs: 1,
|
|
64
|
+
msec: 1,
|
|
65
|
+
ms: 1,
|
|
66
|
+
seconds: s,
|
|
67
|
+
second: s,
|
|
68
|
+
secs: s,
|
|
69
|
+
sec: s,
|
|
70
|
+
s,
|
|
71
|
+
minutes: m,
|
|
72
|
+
minute: m,
|
|
73
|
+
mins: m,
|
|
74
|
+
min: m,
|
|
75
|
+
m,
|
|
76
|
+
hours: h,
|
|
77
|
+
hour: h,
|
|
78
|
+
hrs: h,
|
|
79
|
+
hr: h,
|
|
80
|
+
h,
|
|
81
|
+
days: d,
|
|
82
|
+
day: d,
|
|
83
|
+
d,
|
|
84
|
+
weeks: w,
|
|
85
|
+
week: w,
|
|
86
|
+
w,
|
|
87
|
+
months: mo,
|
|
88
|
+
month: mo,
|
|
89
|
+
mo,
|
|
90
|
+
years: y,
|
|
91
|
+
year: y,
|
|
92
|
+
yrs: y,
|
|
93
|
+
yr: y,
|
|
94
|
+
y
|
|
95
|
+
};
|
|
96
|
+
const unitPattern = Object.keys(UNITS).sort((a, b) => b.length - a.length).join("|");
|
|
97
|
+
const RE = new RegExp(String.raw`^(-?(?:\d+)?\.?\d+)\s*(${unitPattern})?$`, "i");
|
|
98
|
+
const ms = (val) => {
|
|
99
|
+
const str = String(val);
|
|
100
|
+
if (str.length > 100) return Number.NaN;
|
|
101
|
+
const match = RE.exec(str);
|
|
102
|
+
if (!match) return Number.NaN;
|
|
103
|
+
const n = Number.parseFloat(match[1] ?? "");
|
|
104
|
+
const type = (match[2] ?? "ms").toLowerCase();
|
|
105
|
+
return n * (UNITS[type] ?? 0);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const isArray = Array.isArray;
|
|
109
|
+
const isEmpty = (value) => {
|
|
110
|
+
if (value == null) return true;
|
|
111
|
+
if (Array.isArray(value) || typeof value === "string") return value.length === 0;
|
|
112
|
+
if (value instanceof Map || value instanceof Set) return value.size === 0;
|
|
113
|
+
if (typeof value === "object") {
|
|
114
|
+
for (const key in value) {
|
|
115
|
+
if (Object.hasOwn(value, key)) return false;
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
121
|
+
const isFunction = (value) => {
|
|
122
|
+
return typeof value === "function";
|
|
123
|
+
};
|
|
124
|
+
const isObjectLike = (value) => {
|
|
125
|
+
return typeof value === "object" && value !== null;
|
|
126
|
+
};
|
|
127
|
+
const cloneArrayBuffer = (arrayBuffer) => {
|
|
128
|
+
const result = new ArrayBuffer(arrayBuffer.byteLength);
|
|
129
|
+
new Uint8Array(result).set(new Uint8Array(arrayBuffer));
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
const cloneImmutable = (value) => {
|
|
133
|
+
const tag = Object.prototype.toString.call(value);
|
|
134
|
+
switch (tag) {
|
|
135
|
+
case "[object Date]":
|
|
136
|
+
return /* @__PURE__ */ new Date(+value);
|
|
137
|
+
case "[object RegExp]": {
|
|
138
|
+
const re = value;
|
|
139
|
+
const cloned = new RegExp(re.source, re.flags);
|
|
140
|
+
cloned.lastIndex = re.lastIndex;
|
|
141
|
+
return cloned;
|
|
142
|
+
}
|
|
143
|
+
case "[object ArrayBuffer]":
|
|
144
|
+
return cloneArrayBuffer(value);
|
|
145
|
+
case "[object DataView]": {
|
|
146
|
+
const dv = value;
|
|
147
|
+
const buffer = cloneArrayBuffer(dv.buffer);
|
|
148
|
+
return new DataView(buffer, dv.byteOffset, dv.byteLength);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (ArrayBuffer.isView(value)) {
|
|
152
|
+
const ta = value;
|
|
153
|
+
const buffer = cloneArrayBuffer(ta.buffer);
|
|
154
|
+
return new value.constructor(buffer, ta.byteOffset, ta.length);
|
|
155
|
+
}
|
|
156
|
+
return void 0;
|
|
157
|
+
};
|
|
158
|
+
const cloneCollection = (value, seen) => {
|
|
159
|
+
if (value instanceof Map) {
|
|
160
|
+
const map = /* @__PURE__ */ new Map();
|
|
161
|
+
seen.set(value, map);
|
|
162
|
+
for (const [k, v] of value) map.set(k, cloneDeep(v, seen));
|
|
163
|
+
return map;
|
|
164
|
+
}
|
|
165
|
+
if (value instanceof Set) {
|
|
166
|
+
const set = /* @__PURE__ */ new Set();
|
|
167
|
+
seen.set(value, set);
|
|
168
|
+
for (const v of value) set.add(cloneDeep(v, seen));
|
|
169
|
+
return set;
|
|
170
|
+
}
|
|
171
|
+
if (Array.isArray(value)) {
|
|
172
|
+
const arr = new Array(value.length);
|
|
173
|
+
seen.set(value, arr);
|
|
174
|
+
for (let i = 0; i < value.length; i++) {
|
|
175
|
+
arr[i] = cloneDeep(value[i], seen);
|
|
176
|
+
}
|
|
177
|
+
return arr;
|
|
178
|
+
}
|
|
179
|
+
const result = typeof value.constructor === "function" ? Object.create(Object.getPrototypeOf(value)) : {};
|
|
180
|
+
seen.set(value, result);
|
|
181
|
+
for (const key of Object.keys(value)) {
|
|
182
|
+
result[key] = cloneDeep(value[key], seen);
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
};
|
|
186
|
+
const cloneDeep = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
187
|
+
if (value === null || typeof value !== "object") return value;
|
|
188
|
+
if (seen.has(value)) return seen.get(value);
|
|
189
|
+
const immutable = cloneImmutable(value);
|
|
190
|
+
if (immutable !== void 0) return immutable;
|
|
191
|
+
if ("toJSON" in value && typeof value.toJSON === "function") {
|
|
192
|
+
return JSON.parse(JSON.stringify(value));
|
|
193
|
+
}
|
|
194
|
+
return cloneCollection(value, seen);
|
|
195
|
+
};
|
|
196
|
+
const chunk = (array, size) => {
|
|
197
|
+
const result = [];
|
|
198
|
+
for (let i = 0; i < array.length; i += size) {
|
|
199
|
+
result.push(array.slice(i, i + size));
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
};
|
|
64
203
|
const isHookIgnored = (options) => {
|
|
65
204
|
return options.ignoreHook === true || options.ignoreEvent === true && options.ignorePatchHistory === true;
|
|
66
205
|
};
|
|
@@ -77,7 +216,7 @@ const setPatchHistoryTTL = async (ttl) => {
|
|
|
77
216
|
await HistoryModel.collection.dropIndex(name);
|
|
78
217
|
return;
|
|
79
218
|
}
|
|
80
|
-
const milliseconds =
|
|
219
|
+
const milliseconds = ms(ttl);
|
|
81
220
|
if (milliseconds < 1e3 && existingIndex) {
|
|
82
221
|
await HistoryModel.collection.dropIndex(name);
|
|
83
222
|
return;
|
|
@@ -99,63 +238,144 @@ class PatchEventEmitter extends EventEmitter {
|
|
|
99
238
|
}
|
|
100
239
|
const em = new PatchEventEmitter();
|
|
101
240
|
|
|
102
|
-
|
|
241
|
+
const isPlainObject = (val) => {
|
|
242
|
+
if (Object.prototype.toString.call(val) !== "[object Object]") return false;
|
|
243
|
+
const prot = Object.getPrototypeOf(val);
|
|
244
|
+
return prot === null || prot === Object.prototype;
|
|
245
|
+
};
|
|
246
|
+
const isUnsafeKey = (key) => {
|
|
247
|
+
return key === "__proto__" || key === "constructor" || key === "prototype";
|
|
248
|
+
};
|
|
249
|
+
const getValue$1 = (obj, path) => {
|
|
250
|
+
const segs = path.split(".");
|
|
251
|
+
let current = obj;
|
|
252
|
+
for (const seg of segs) {
|
|
253
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
254
|
+
current = current[seg];
|
|
255
|
+
}
|
|
256
|
+
return current;
|
|
257
|
+
};
|
|
258
|
+
const hasValue = (val) => {
|
|
259
|
+
if (val == null) return false;
|
|
260
|
+
if (typeof val === "boolean" || typeof val === "number" || typeof val === "function") return true;
|
|
261
|
+
if (typeof val === "string") return val.length !== 0;
|
|
262
|
+
if (Array.isArray(val)) return val.length !== 0;
|
|
263
|
+
if (val instanceof RegExp) return val.source !== "(?:)" && val.source !== "";
|
|
264
|
+
if (val instanceof Error) return val.message !== "";
|
|
265
|
+
if (val instanceof Map || val instanceof Set) return val.size !== 0;
|
|
266
|
+
if (typeof val === "object") {
|
|
267
|
+
for (const key of Object.keys(val)) {
|
|
268
|
+
if (hasValue(val[key])) return true;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
return true;
|
|
273
|
+
};
|
|
274
|
+
const has = (obj, path) => {
|
|
275
|
+
if (obj != null && typeof obj === "object" && typeof path === "string") {
|
|
276
|
+
return hasValue(getValue$1(obj, path));
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
};
|
|
280
|
+
const unset = (obj, prop) => {
|
|
281
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
282
|
+
if (Object.hasOwn(obj, prop)) {
|
|
283
|
+
delete obj[prop];
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
if (has(obj, prop)) {
|
|
287
|
+
const segs = prop.split(".");
|
|
288
|
+
let last = segs.pop();
|
|
289
|
+
while (segs.length && segs.at(-1)?.slice(-1) === "\\") {
|
|
290
|
+
last = `${segs.pop().slice(0, -1)}.${last}`;
|
|
291
|
+
}
|
|
292
|
+
let target = obj;
|
|
293
|
+
while (segs.length) {
|
|
294
|
+
const seg = segs.shift();
|
|
295
|
+
if (isUnsafeKey(seg)) return false;
|
|
296
|
+
target = target[seg];
|
|
297
|
+
}
|
|
298
|
+
return delete target[last ?? ""];
|
|
299
|
+
}
|
|
300
|
+
return true;
|
|
301
|
+
};
|
|
302
|
+
const omitDeep = (value, keys) => {
|
|
303
|
+
if (value === void 0) return {};
|
|
304
|
+
if (Array.isArray(value)) {
|
|
305
|
+
for (let i = 0; i < value.length; i++) {
|
|
306
|
+
value[i] = omitDeep(value[i], keys);
|
|
307
|
+
}
|
|
308
|
+
return value;
|
|
309
|
+
}
|
|
310
|
+
if (!isPlainObject(value)) return value;
|
|
311
|
+
const omitKeys = typeof keys === "string" ? [keys] : keys;
|
|
312
|
+
if (!Array.isArray(omitKeys)) return value;
|
|
313
|
+
for (const key of omitKeys) {
|
|
314
|
+
unset(value, key);
|
|
315
|
+
}
|
|
316
|
+
for (const key of Object.keys(value)) {
|
|
317
|
+
value[key] = omitDeep(value[key], omitKeys);
|
|
318
|
+
}
|
|
319
|
+
return value;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const isPatchHistoryEnabled = (opts, context) => {
|
|
103
323
|
return !opts.patchHistoryDisabled && !context.ignorePatchHistory;
|
|
104
|
-
}
|
|
105
|
-
|
|
324
|
+
};
|
|
325
|
+
const getJsonOmit = (opts, doc) => {
|
|
106
326
|
const object = JSON.parse(JSON.stringify(doc));
|
|
107
327
|
if (opts.omit) {
|
|
108
|
-
return
|
|
328
|
+
return omitDeep(object, opts.omit);
|
|
109
329
|
}
|
|
110
330
|
return object;
|
|
111
|
-
}
|
|
112
|
-
|
|
331
|
+
};
|
|
332
|
+
const getObjectOmit = (opts, doc) => {
|
|
113
333
|
if (opts.omit) {
|
|
114
|
-
return
|
|
334
|
+
return omitDeep(isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit);
|
|
115
335
|
}
|
|
116
336
|
return doc;
|
|
117
|
-
}
|
|
118
|
-
async
|
|
337
|
+
};
|
|
338
|
+
const getUser = async (opts, doc) => {
|
|
119
339
|
if (isFunction(opts.getUser)) {
|
|
120
340
|
return await opts.getUser(doc);
|
|
121
341
|
}
|
|
122
342
|
return void 0;
|
|
123
|
-
}
|
|
124
|
-
async
|
|
343
|
+
};
|
|
344
|
+
const getReason = async (opts, doc) => {
|
|
125
345
|
if (isFunction(opts.getReason)) {
|
|
126
346
|
return await opts.getReason(doc);
|
|
127
347
|
}
|
|
128
348
|
return void 0;
|
|
129
|
-
}
|
|
130
|
-
async
|
|
349
|
+
};
|
|
350
|
+
const getMetadata = async (opts, doc) => {
|
|
131
351
|
if (isFunction(opts.getMetadata)) {
|
|
132
352
|
return await opts.getMetadata(doc);
|
|
133
353
|
}
|
|
134
354
|
return void 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
355
|
+
};
|
|
356
|
+
const getValue = (item) => {
|
|
137
357
|
return item.status === "fulfilled" ? item.value : void 0;
|
|
138
|
-
}
|
|
139
|
-
async
|
|
358
|
+
};
|
|
359
|
+
const getData = async (opts, doc) => {
|
|
140
360
|
return Promise.allSettled([getUser(opts, doc), getReason(opts, doc), getMetadata(opts, doc)]).then(([user, reason, metadata]) => {
|
|
141
361
|
return [getValue(user), getValue(reason), getValue(metadata)];
|
|
142
362
|
});
|
|
143
|
-
}
|
|
144
|
-
|
|
363
|
+
};
|
|
364
|
+
const emitEvent = (context, event, data) => {
|
|
145
365
|
if (event && !context.ignoreEvent) {
|
|
146
366
|
em.emit(event, data);
|
|
147
367
|
}
|
|
148
|
-
}
|
|
149
|
-
async
|
|
368
|
+
};
|
|
369
|
+
const bulkPatch = async (opts, context, eventKey, docsKey) => {
|
|
150
370
|
const history = isPatchHistoryEnabled(opts, context);
|
|
151
371
|
const event = opts[eventKey];
|
|
152
372
|
const docs = context[docsKey];
|
|
153
373
|
const key = eventKey === "eventCreated" ? "doc" : "oldDoc";
|
|
154
|
-
if (isEmpty(docs) || !event && !history) return;
|
|
374
|
+
if (isEmpty(docs) || !docs || !event && !history) return;
|
|
155
375
|
const chunks = chunk(docs, 1e3);
|
|
156
|
-
for (const
|
|
376
|
+
for (const batch of chunks) {
|
|
157
377
|
const bulk = [];
|
|
158
|
-
for (const doc of
|
|
378
|
+
for (const doc of batch) {
|
|
159
379
|
emitEvent(context, event, { [key]: doc });
|
|
160
380
|
if (history) {
|
|
161
381
|
const [user, reason, metadata] = await getData(opts, doc);
|
|
@@ -182,11 +402,11 @@ async function bulkPatch(opts, context, eventKey, docsKey) {
|
|
|
182
402
|
});
|
|
183
403
|
}
|
|
184
404
|
}
|
|
185
|
-
}
|
|
186
|
-
async
|
|
405
|
+
};
|
|
406
|
+
const createPatch = async (opts, context) => {
|
|
187
407
|
await bulkPatch(opts, context, "eventCreated", "createdDocs");
|
|
188
|
-
}
|
|
189
|
-
async
|
|
408
|
+
};
|
|
409
|
+
const updatePatch = async (opts, context, current, original) => {
|
|
190
410
|
const history = isPatchHistoryEnabled(opts, context);
|
|
191
411
|
const currentObject = getJsonOmit(opts, current);
|
|
192
412
|
const originalObject = getJsonOmit(opts, original);
|
|
@@ -213,10 +433,10 @@ async function updatePatch(opts, context, current, original) {
|
|
|
213
433
|
...metadata !== void 0 && { metadata }
|
|
214
434
|
});
|
|
215
435
|
}
|
|
216
|
-
}
|
|
217
|
-
async
|
|
436
|
+
};
|
|
437
|
+
const deletePatch = async (opts, context) => {
|
|
218
438
|
await bulkPatch(opts, context, "eventDeleted", "deletedDocs");
|
|
219
|
-
}
|
|
439
|
+
};
|
|
220
440
|
|
|
221
441
|
const deleteMethods = ["remove", "findOneAndDelete", "findOneAndRemove", "findByIdAndDelete", "findByIdAndRemove", "deleteOne", "deleteMany"];
|
|
222
442
|
const deleteHooksInitialize = (schema, opts) => {
|
|
@@ -279,12 +499,12 @@ const saveHooksInitialize = (schema, opts) => {
|
|
|
279
499
|
const updateMethods = ["update", "updateOne", "replaceOne", "updateMany", "findOneAndUpdate", "findOneAndReplace", "findByIdAndUpdate"];
|
|
280
500
|
const assignUpdate = (document, update, commands) => {
|
|
281
501
|
let updated = powerAssign.assign(document.toObject(toObjectOptions), update);
|
|
282
|
-
|
|
502
|
+
for (const command of commands) {
|
|
283
503
|
try {
|
|
284
504
|
updated = powerAssign.assign(updated, command);
|
|
285
505
|
} catch {
|
|
286
506
|
}
|
|
287
|
-
}
|
|
507
|
+
}
|
|
288
508
|
const doc = document.set(updated).toObject(toObjectOptions);
|
|
289
509
|
if (update.createdAt) doc.createdAt = update.createdAt;
|
|
290
510
|
return doc;
|
|
@@ -294,12 +514,12 @@ const splitUpdateAndCommands = (updateQuery) => {
|
|
|
294
514
|
const commands = [];
|
|
295
515
|
if (!isEmpty(updateQuery) && !isArray(updateQuery) && isObjectLike(updateQuery)) {
|
|
296
516
|
update = cloneDeep(updateQuery);
|
|
297
|
-
const keysWithDollarSign = keys(update).filter((key) => key.startsWith("$"));
|
|
517
|
+
const keysWithDollarSign = Object.keys(update).filter((key) => key.startsWith("$"));
|
|
298
518
|
if (!isEmpty(keysWithDollarSign)) {
|
|
299
|
-
|
|
519
|
+
for (const key of keysWithDollarSign) {
|
|
300
520
|
commands.push({ [key]: update[key] });
|
|
301
521
|
delete update[key];
|
|
302
|
-
}
|
|
522
|
+
}
|
|
303
523
|
}
|
|
304
524
|
}
|
|
305
525
|
return { update, commands };
|
|
@@ -344,7 +564,6 @@ const updateHooksInitialize = (schema, opts) => {
|
|
|
344
564
|
current = await model.findOne(combined).sort("desc").lean().exec();
|
|
345
565
|
}
|
|
346
566
|
if (!isEmpty(filter) && !current) {
|
|
347
|
-
console.log("filter", filter);
|
|
348
567
|
current = await model.findOne(filter).sort("desc").lean().exec();
|
|
349
568
|
}
|
|
350
569
|
if (current) {
|
|
@@ -354,15 +573,16 @@ const updateHooksInitialize = (schema, opts) => {
|
|
|
354
573
|
});
|
|
355
574
|
};
|
|
356
575
|
|
|
357
|
-
const
|
|
358
|
-
const
|
|
359
|
-
const
|
|
576
|
+
const major = Number.parseInt(mongoose.version, 10);
|
|
577
|
+
const isMongooseLessThan8 = major < 8;
|
|
578
|
+
const isMongooseLessThan7 = major < 7;
|
|
579
|
+
const isMongoose6 = major === 6;
|
|
360
580
|
if (isMongoose6) {
|
|
361
581
|
mongoose.set("strictQuery", false);
|
|
362
582
|
}
|
|
363
583
|
|
|
364
584
|
const remove = isMongooseLessThan7 ? "remove" : "deleteOne";
|
|
365
|
-
const patchHistoryPlugin =
|
|
585
|
+
const patchHistoryPlugin = (schema, opts) => {
|
|
366
586
|
saveHooksInitialize(schema, opts);
|
|
367
587
|
updateHooksInitialize(schema, opts);
|
|
368
588
|
deleteHooksInitialize(schema, opts);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Types, Query, HydratedDocument, Schema } from 'mongoose';
|
|
2
2
|
import { Operation } from 'fast-json-patch';
|
|
3
3
|
import EventEmitter from 'node:events';
|
|
4
|
-
import ms from 'ms';
|
|
5
4
|
|
|
6
5
|
interface History {
|
|
7
6
|
op: string;
|
|
@@ -54,10 +53,49 @@ declare class PatchEventEmitter extends EventEmitter {
|
|
|
54
53
|
}
|
|
55
54
|
declare const em: PatchEventEmitter;
|
|
56
55
|
|
|
57
|
-
declare const
|
|
56
|
+
declare const UNITS: {
|
|
57
|
+
readonly milliseconds: 1;
|
|
58
|
+
readonly millisecond: 1;
|
|
59
|
+
readonly msecs: 1;
|
|
60
|
+
readonly msec: 1;
|
|
61
|
+
readonly ms: 1;
|
|
62
|
+
readonly seconds: 1000;
|
|
63
|
+
readonly second: 1000;
|
|
64
|
+
readonly secs: 1000;
|
|
65
|
+
readonly sec: 1000;
|
|
66
|
+
readonly s: 1000;
|
|
67
|
+
readonly minutes: number;
|
|
68
|
+
readonly minute: number;
|
|
69
|
+
readonly mins: number;
|
|
70
|
+
readonly min: number;
|
|
71
|
+
readonly m: number;
|
|
72
|
+
readonly hours: number;
|
|
73
|
+
readonly hour: number;
|
|
74
|
+
readonly hrs: number;
|
|
75
|
+
readonly hr: number;
|
|
76
|
+
readonly h: number;
|
|
77
|
+
readonly days: number;
|
|
78
|
+
readonly day: number;
|
|
79
|
+
readonly d: number;
|
|
80
|
+
readonly weeks: number;
|
|
81
|
+
readonly week: number;
|
|
82
|
+
readonly w: number;
|
|
83
|
+
readonly months: number;
|
|
84
|
+
readonly month: number;
|
|
85
|
+
readonly mo: number;
|
|
86
|
+
readonly years: number;
|
|
87
|
+
readonly year: number;
|
|
88
|
+
readonly yrs: number;
|
|
89
|
+
readonly yr: number;
|
|
90
|
+
readonly y: number;
|
|
91
|
+
};
|
|
92
|
+
type Unit = keyof typeof UNITS;
|
|
93
|
+
type Duration = number | `${number}` | `${number}${Unit}` | `${number} ${Unit}`;
|
|
94
|
+
|
|
95
|
+
declare const setPatchHistoryTTL: (ttl: Duration) => Promise<void>;
|
|
58
96
|
|
|
59
97
|
declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: PluginOptions<T>) => void;
|
|
60
98
|
|
|
61
99
|
export { em as patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
|
|
62
|
-
export type { History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
|
|
100
|
+
export type { Duration, History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
|
|
63
101
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","sources":["../src/types.ts","../src/em.ts","../src/helpers.ts","../src/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.cts","sources":["../src/types.ts","../src/em.ts","../src/ms.ts","../src/helpers.ts","../src/index.ts"],"mappings":";;;;AAGM,UAAW,OAAO;;;;kBAIR,KAAK,CAAC,QAAQ;;;;;;YAMpB,SAAS;;AAGb,UAAW,UAAU;aAChB,gBAAgB;UACnB,gBAAgB;YACd,SAAS;;AAGb,UAAW,YAAY;;;;;kBAKb,gBAAgB;kBAChB,gBAAgB;;;;AAK1B,KAAM,WAAW,MAAM,KAAK;;cAAiC,YAAY;;AAEzE,KAAM,IAAI,GAAG,MAAM;AAEnB,KAAM,QAAQ,GAAG,MAAM;AAEvB,UAAW,aAAa;;;;;;oBAMZ,gBAAgB,QAAQ,OAAO,CAAC,IAAI,IAAI,IAAI;sBAC1C,gBAAgB,QAAQ,OAAO;wBAC7B,gBAAgB,QAAQ,OAAO,CAAC,QAAQ,IAAI,QAAQ;;;uBAGrD,gBAAgB,UAAU,OAAO;;;AChDtD,cAAM,iBAAkB,SAAQ,YAAY;;AAC5C,cAAM,EAAE,mBAA0B;;ACKlC,cAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCZ,KAAM,IAAI,gBAAgB,KAAK;AAE/B,KAAM,QAAQ,sCAAsC,IAAI,kBAAkB,IAAI;;ACiFpF,cAAa,kBAAkB,QAAe,QAAQ,KAAG,OAAO;;AC9GhE,cAAa,kBAAkB,cAAe,MAAM,WAAW,aAAa","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Types, Query, HydratedDocument, Schema } from 'mongoose';
|
|
2
2
|
import { Operation } from 'fast-json-patch';
|
|
3
3
|
import EventEmitter from 'node:events';
|
|
4
|
-
import ms from 'ms';
|
|
5
4
|
|
|
6
5
|
interface History {
|
|
7
6
|
op: string;
|
|
@@ -54,10 +53,49 @@ declare class PatchEventEmitter extends EventEmitter {
|
|
|
54
53
|
}
|
|
55
54
|
declare const em: PatchEventEmitter;
|
|
56
55
|
|
|
57
|
-
declare const
|
|
56
|
+
declare const UNITS: {
|
|
57
|
+
readonly milliseconds: 1;
|
|
58
|
+
readonly millisecond: 1;
|
|
59
|
+
readonly msecs: 1;
|
|
60
|
+
readonly msec: 1;
|
|
61
|
+
readonly ms: 1;
|
|
62
|
+
readonly seconds: 1000;
|
|
63
|
+
readonly second: 1000;
|
|
64
|
+
readonly secs: 1000;
|
|
65
|
+
readonly sec: 1000;
|
|
66
|
+
readonly s: 1000;
|
|
67
|
+
readonly minutes: number;
|
|
68
|
+
readonly minute: number;
|
|
69
|
+
readonly mins: number;
|
|
70
|
+
readonly min: number;
|
|
71
|
+
readonly m: number;
|
|
72
|
+
readonly hours: number;
|
|
73
|
+
readonly hour: number;
|
|
74
|
+
readonly hrs: number;
|
|
75
|
+
readonly hr: number;
|
|
76
|
+
readonly h: number;
|
|
77
|
+
readonly days: number;
|
|
78
|
+
readonly day: number;
|
|
79
|
+
readonly d: number;
|
|
80
|
+
readonly weeks: number;
|
|
81
|
+
readonly week: number;
|
|
82
|
+
readonly w: number;
|
|
83
|
+
readonly months: number;
|
|
84
|
+
readonly month: number;
|
|
85
|
+
readonly mo: number;
|
|
86
|
+
readonly years: number;
|
|
87
|
+
readonly year: number;
|
|
88
|
+
readonly yrs: number;
|
|
89
|
+
readonly yr: number;
|
|
90
|
+
readonly y: number;
|
|
91
|
+
};
|
|
92
|
+
type Unit = keyof typeof UNITS;
|
|
93
|
+
type Duration = number | `${number}` | `${number}${Unit}` | `${number} ${Unit}`;
|
|
94
|
+
|
|
95
|
+
declare const setPatchHistoryTTL: (ttl: Duration) => Promise<void>;
|
|
58
96
|
|
|
59
97
|
declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: PluginOptions<T>) => void;
|
|
60
98
|
|
|
61
99
|
export { em as patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
|
|
62
|
-
export type { History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
|
|
100
|
+
export type { Duration, History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
|
|
63
101
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sources":["../src/types.ts","../src/em.ts","../src/helpers.ts","../src/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","sources":["../src/types.ts","../src/em.ts","../src/ms.ts","../src/helpers.ts","../src/index.ts"],"mappings":";;;;AAGM,UAAW,OAAO;;;;kBAIR,KAAK,CAAC,QAAQ;;;;;;YAMpB,SAAS;;AAGb,UAAW,UAAU;aAChB,gBAAgB;UACnB,gBAAgB;YACd,SAAS;;AAGb,UAAW,YAAY;;;;;kBAKb,gBAAgB;kBAChB,gBAAgB;;;;AAK1B,KAAM,WAAW,MAAM,KAAK;;cAAiC,YAAY;;AAEzE,KAAM,IAAI,GAAG,MAAM;AAEnB,KAAM,QAAQ,GAAG,MAAM;AAEvB,UAAW,aAAa;;;;;;oBAMZ,gBAAgB,QAAQ,OAAO,CAAC,IAAI,IAAI,IAAI;sBAC1C,gBAAgB,QAAQ,OAAO;wBAC7B,gBAAgB,QAAQ,OAAO,CAAC,QAAQ,IAAI,QAAQ;;;uBAGrD,gBAAgB,UAAU,OAAO;;;AChDtD,cAAM,iBAAkB,SAAQ,YAAY;;AAC5C,cAAM,EAAE,mBAA0B;;ACKlC,cAAa,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCZ,KAAM,IAAI,gBAAgB,KAAK;AAE/B,KAAM,QAAQ,sCAAsC,IAAI,kBAAkB,IAAI;;ACiFpF,cAAa,kBAAkB,QAAe,QAAQ,KAAG,OAAO;;AC9GhE,cAAa,kBAAkB,cAAe,MAAM,WAAW,aAAa","names":[]}
|