ts-patch-mongoose 3.1.0 → 4.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 +39 -27
- package/dist/index.cjs +287 -32
- package/dist/index.d.cts +23 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +23 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +287 -32
- package/package.json +19 -24
- package/biome.json +0 -47
- package/src/em.ts +0 -6
- package/src/helpers.ts +0 -174
- package/src/hooks/delete-hooks.ts +0 -49
- package/src/hooks/save-hooks.ts +0 -30
- package/src/hooks/update-hooks.ts +0 -125
- package/src/index.ts +0 -65
- package/src/model.ts +0 -50
- package/src/modules/power-assign.d.ts +0 -3
- package/src/ms.ts +0 -66
- package/src/omit-deep.ts +0 -56
- package/src/patch.ts +0 -154
- package/src/types.ts +0 -53
- package/src/version.ts +0 -13
- package/tests/constants/events.ts +0 -7
- package/tests/em.test.ts +0 -70
- package/tests/helpers.test.ts +0 -373
- package/tests/mongo/.gitignore +0 -3
- package/tests/mongo/server.ts +0 -31
- package/tests/ms.test.ts +0 -113
- package/tests/omit-deep.test.ts +0 -235
- package/tests/patch.test.ts +0 -200
- package/tests/plugin-all-features.test.ts +0 -844
- package/tests/plugin-complex-data.test.ts +0 -2647
- package/tests/plugin-event-created.test.ts +0 -371
- package/tests/plugin-event-deleted.test.ts +0 -400
- package/tests/plugin-event-updated.test.ts +0 -503
- package/tests/plugin-global.test.ts +0 -545
- package/tests/plugin-omit-all.test.ts +0 -349
- package/tests/plugin-patch-history-disabled.test.ts +0 -162
- package/tests/plugin-pre-delete.test.ts +0 -160
- package/tests/plugin-pre-save.test.ts +0 -54
- package/tests/plugin.test.ts +0 -576
- package/tests/schemas/Description.ts +0 -15
- package/tests/schemas/Product.ts +0 -38
- package/tests/schemas/User.ts +0 -22
- package/tsconfig.json +0 -32
- package/vite.config.mts +0 -24
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import mongoose, { Schema, model } from 'mongoose';
|
|
2
|
-
import jsonpatch from 'fast-json-patch';
|
|
3
2
|
import EventEmitter from 'node:events';
|
|
4
|
-
import { assign } from 'power-assign';
|
|
5
3
|
|
|
6
4
|
const HistorySchema = new Schema(
|
|
7
5
|
{
|
|
@@ -98,9 +96,10 @@ const ms = (val) => {
|
|
|
98
96
|
if (str.length > 100) return Number.NaN;
|
|
99
97
|
const match = RE.exec(str);
|
|
100
98
|
if (!match) return Number.NaN;
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
99
|
+
const [, numStr, unitStr] = match;
|
|
100
|
+
const n = Number.parseFloat(String(numStr));
|
|
101
|
+
const type = (unitStr ?? "ms").toLowerCase();
|
|
102
|
+
return n * UNITS[type];
|
|
104
103
|
};
|
|
105
104
|
|
|
106
105
|
const isArray = Array.isArray;
|
|
@@ -247,6 +246,94 @@ class PatchEventEmitter extends EventEmitter {
|
|
|
247
246
|
}
|
|
248
247
|
const em = new PatchEventEmitter();
|
|
249
248
|
|
|
249
|
+
const escapeToken = (key) => {
|
|
250
|
+
if (!key.includes("/") && !key.includes("~")) return key;
|
|
251
|
+
return key.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
252
|
+
};
|
|
253
|
+
const joinPath = (base, key) => `${base}/${escapeToken(key)}`;
|
|
254
|
+
const cloneValue = (value) => {
|
|
255
|
+
if (value === void 0) return null;
|
|
256
|
+
if (value === null || typeof value !== "object") return value;
|
|
257
|
+
return JSON.parse(JSON.stringify(value));
|
|
258
|
+
};
|
|
259
|
+
const isContainer = (value) => {
|
|
260
|
+
return typeof value === "object" && value !== null;
|
|
261
|
+
};
|
|
262
|
+
const keysOf = (value) => {
|
|
263
|
+
if (Array.isArray(value)) {
|
|
264
|
+
const indices = [];
|
|
265
|
+
for (let i = 0; i < value.length; i++) indices.push(String(i));
|
|
266
|
+
return indices;
|
|
267
|
+
}
|
|
268
|
+
return Object.keys(value);
|
|
269
|
+
};
|
|
270
|
+
const normalizeTarget = (target) => {
|
|
271
|
+
if (!isContainer(target) || Array.isArray(target)) return target;
|
|
272
|
+
const withToJSON = target;
|
|
273
|
+
return typeof withToJSON.toJSON === "function" ? withToJSON.toJSON() : target;
|
|
274
|
+
};
|
|
275
|
+
const emitTest = (path, value, invertible, out) => {
|
|
276
|
+
if (invertible) out.push({ op: "test", path, value: cloneValue(value) });
|
|
277
|
+
};
|
|
278
|
+
const emitReplace = (path, source, target, invertible, out) => {
|
|
279
|
+
emitTest(path, source, invertible, out);
|
|
280
|
+
out.push({ op: "replace", path, value: cloneValue(target) });
|
|
281
|
+
};
|
|
282
|
+
const emitRemove = (path, source, invertible, out) => {
|
|
283
|
+
emitTest(path, source, invertible, out);
|
|
284
|
+
out.push({ op: "remove", path });
|
|
285
|
+
};
|
|
286
|
+
const shouldTreatAsRemoval = (sourceChild, targetChild, sourceIsArray) => {
|
|
287
|
+
return targetChild === void 0 && sourceChild !== void 0 && !sourceIsArray;
|
|
288
|
+
};
|
|
289
|
+
const diffSourceKey = (scope, key) => {
|
|
290
|
+
const { source, target, targetKeySet, basePath, sourceIsArray, invertible, out } = scope;
|
|
291
|
+
const childPath = joinPath(basePath, key);
|
|
292
|
+
const sourceChild = source[key];
|
|
293
|
+
if (!targetKeySet.has(key)) {
|
|
294
|
+
emitRemove(childPath, sourceChild, invertible, out);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const targetChild = target[key];
|
|
298
|
+
if (shouldTreatAsRemoval(sourceChild, targetChild, sourceIsArray)) {
|
|
299
|
+
emitRemove(childPath, sourceChild, invertible, out);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
diff(sourceChild, targetChild, childPath, invertible, out);
|
|
303
|
+
};
|
|
304
|
+
const diffAddedKeys = (target, sourceKeys, targetKeys, basePath, out) => {
|
|
305
|
+
const sourceKeySet = new Set(sourceKeys);
|
|
306
|
+
for (const key of targetKeys) {
|
|
307
|
+
if (sourceKeySet.has(key)) continue;
|
|
308
|
+
const targetChild = target[key];
|
|
309
|
+
if (targetChild === void 0) continue;
|
|
310
|
+
out.push({ op: "add", path: joinPath(basePath, key), value: cloneValue(targetChild) });
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const diff = (source, target, basePath, invertible, out) => {
|
|
314
|
+
if (source === target) return;
|
|
315
|
+
const resolvedTarget = normalizeTarget(target);
|
|
316
|
+
const sourceIsArray = Array.isArray(source);
|
|
317
|
+
const targetIsArray = Array.isArray(resolvedTarget);
|
|
318
|
+
if (!isContainer(source) || !isContainer(resolvedTarget) || sourceIsArray !== targetIsArray) {
|
|
319
|
+
emitReplace(basePath, source, resolvedTarget, invertible, out);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const sourceKeys = keysOf(source);
|
|
323
|
+
const targetKeys = keysOf(resolvedTarget);
|
|
324
|
+
const targetKeySet = new Set(targetKeys);
|
|
325
|
+
const scope = { source, target: resolvedTarget, targetKeySet, basePath, sourceIsArray, invertible, out };
|
|
326
|
+
for (const key of Array.from(sourceKeys).reverse()) {
|
|
327
|
+
diffSourceKey(scope, key);
|
|
328
|
+
}
|
|
329
|
+
diffAddedKeys(resolvedTarget, sourceKeys, targetKeys, basePath, out);
|
|
330
|
+
};
|
|
331
|
+
const compare = (source, target, invertible = false) => {
|
|
332
|
+
const out = [];
|
|
333
|
+
diff(source, target, "", invertible, out);
|
|
334
|
+
return out;
|
|
335
|
+
};
|
|
336
|
+
|
|
250
337
|
const isPlainObject = (val) => {
|
|
251
338
|
if (Object.prototype.toString.call(val) !== "[object Object]") return false;
|
|
252
339
|
const prot = Object.getPrototypeOf(val);
|
|
@@ -377,13 +464,13 @@ const updatePatch = async (opts, context, current, original) => {
|
|
|
377
464
|
const currentObject = getJsonOmit(opts, current);
|
|
378
465
|
const originalObject = getJsonOmit(opts, original);
|
|
379
466
|
if (isEmpty(originalObject) || isEmpty(currentObject)) return;
|
|
380
|
-
const patch =
|
|
467
|
+
const patch = compare(originalObject, currentObject, true);
|
|
381
468
|
if (isEmpty(patch)) return;
|
|
382
469
|
emitEvent(context, opts.eventUpdated, { oldDoc: original, doc: current, patch });
|
|
383
470
|
if (history) {
|
|
384
471
|
let version = 0;
|
|
385
472
|
const lastHistory = await HistoryModel.findOne({ collectionId: original._id }).sort("-version").exec();
|
|
386
|
-
if (lastHistory
|
|
473
|
+
if (lastHistory) {
|
|
387
474
|
version = lastHistory.version + 1;
|
|
388
475
|
}
|
|
389
476
|
const [user, reason, metadata] = await getData(opts, current);
|
|
@@ -466,38 +553,202 @@ const saveHooksInitialize = (schema, opts) => {
|
|
|
466
553
|
});
|
|
467
554
|
};
|
|
468
555
|
|
|
556
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
557
|
+
const parseSegment = (segment) => {
|
|
558
|
+
const asNumber2 = Number(segment);
|
|
559
|
+
return Number.isInteger(asNumber2) && String(asNumber2) === segment ? asNumber2 : segment;
|
|
560
|
+
};
|
|
561
|
+
const parsePath = (path) => {
|
|
562
|
+
const [first, ...rest] = path.split(".").map(parseSegment);
|
|
563
|
+
let leaf = first ?? path;
|
|
564
|
+
const crumbs = [];
|
|
565
|
+
for (const key of rest) {
|
|
566
|
+
crumbs.push({ key: leaf, nextNumeric: typeof key === "number" });
|
|
567
|
+
leaf = key;
|
|
568
|
+
}
|
|
569
|
+
return { leaf, crumbs };
|
|
570
|
+
};
|
|
571
|
+
const deepEqualJson = (a, b) => {
|
|
572
|
+
try {
|
|
573
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
574
|
+
} catch {
|
|
575
|
+
return a === b;
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const ensureContainer = (parent, key, hintNumeric) => {
|
|
579
|
+
const existing = parent[key];
|
|
580
|
+
if (existing !== null && typeof existing === "object") {
|
|
581
|
+
return existing;
|
|
582
|
+
}
|
|
583
|
+
const created = hintNumeric ? [] : {};
|
|
584
|
+
parent[key] = created;
|
|
585
|
+
return created;
|
|
586
|
+
};
|
|
587
|
+
const setAtPath = (doc, path, value) => {
|
|
588
|
+
const { leaf, crumbs } = parsePath(path);
|
|
589
|
+
let cursor = doc;
|
|
590
|
+
for (const crumb of crumbs) {
|
|
591
|
+
cursor = ensureContainer(cursor, crumb.key, crumb.nextNumeric);
|
|
592
|
+
}
|
|
593
|
+
cursor[leaf] = value;
|
|
594
|
+
};
|
|
595
|
+
const getAtPath = (doc, path) => {
|
|
596
|
+
const { leaf, crumbs } = parsePath(path);
|
|
597
|
+
let cursor = doc;
|
|
598
|
+
for (const crumb of crumbs) {
|
|
599
|
+
const next = cursor[crumb.key];
|
|
600
|
+
if (next === null || typeof next !== "object") return void 0;
|
|
601
|
+
cursor = next;
|
|
602
|
+
}
|
|
603
|
+
return { container: cursor, leaf, exists: hasOwn.call(cursor, leaf) };
|
|
604
|
+
};
|
|
605
|
+
const unsetAtPath = (doc, path) => {
|
|
606
|
+
const located = getAtPath(doc, path);
|
|
607
|
+
if (!located) return;
|
|
608
|
+
if (Array.isArray(located.container)) {
|
|
609
|
+
located.container[located.leaf] = void 0;
|
|
610
|
+
} else {
|
|
611
|
+
delete located.container[located.leaf];
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
const asNumber = (value) => typeof value === "number" ? value : 0;
|
|
615
|
+
const toArray = (value) => Array.isArray(value) ? value : void 0;
|
|
616
|
+
const shouldReplaceForMin = (current, candidate) => {
|
|
617
|
+
if (candidate === void 0) return false;
|
|
618
|
+
if (current === void 0) return true;
|
|
619
|
+
return candidate < current;
|
|
620
|
+
};
|
|
621
|
+
const shouldReplaceForMax = (current, candidate) => {
|
|
622
|
+
if (candidate === void 0) return false;
|
|
623
|
+
if (current === void 0) return true;
|
|
624
|
+
return candidate > current;
|
|
625
|
+
};
|
|
626
|
+
const operators = {
|
|
627
|
+
$set: (doc, path, value) => setAtPath(doc, path, value),
|
|
628
|
+
$unset: (doc, path) => unsetAtPath(doc, path),
|
|
629
|
+
$inc: (doc, path, delta) => {
|
|
630
|
+
const located = getAtPath(doc, path);
|
|
631
|
+
const current = located?.exists ? asNumber(located.container[located.leaf]) : 0;
|
|
632
|
+
setAtPath(doc, path, current + asNumber(delta));
|
|
633
|
+
},
|
|
634
|
+
$mul: (doc, path, factor) => {
|
|
635
|
+
const located = getAtPath(doc, path);
|
|
636
|
+
const current = located?.exists ? asNumber(located.container[located.leaf]) : 0;
|
|
637
|
+
setAtPath(doc, path, current * asNumber(factor));
|
|
638
|
+
},
|
|
639
|
+
$min: (doc, path, candidate) => {
|
|
640
|
+
const located = getAtPath(doc, path);
|
|
641
|
+
if (!located?.exists) {
|
|
642
|
+
setAtPath(doc, path, candidate);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (shouldReplaceForMin(located.container[located.leaf], candidate)) {
|
|
646
|
+
setAtPath(doc, path, candidate);
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
$max: (doc, path, candidate) => {
|
|
650
|
+
const located = getAtPath(doc, path);
|
|
651
|
+
if (!located?.exists) {
|
|
652
|
+
setAtPath(doc, path, candidate);
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (shouldReplaceForMax(located.container[located.leaf], candidate)) {
|
|
656
|
+
setAtPath(doc, path, candidate);
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
$rename: (doc, path, newPath) => {
|
|
660
|
+
if (typeof newPath !== "string") return;
|
|
661
|
+
const located = getAtPath(doc, path);
|
|
662
|
+
if (!located?.exists) return;
|
|
663
|
+
const value = located.container[located.leaf];
|
|
664
|
+
unsetAtPath(doc, path);
|
|
665
|
+
setAtPath(doc, newPath, value);
|
|
666
|
+
},
|
|
667
|
+
$currentDate: (doc, path, spec) => {
|
|
668
|
+
const wantTimestamp = typeof spec === "object" && spec !== null && spec.$type === "timestamp";
|
|
669
|
+
setAtPath(doc, path, wantTimestamp ? Date.now() : /* @__PURE__ */ new Date());
|
|
670
|
+
},
|
|
671
|
+
$push: (doc, path, pushSpec) => {
|
|
672
|
+
const located = getAtPath(doc, path);
|
|
673
|
+
const existing = located?.exists ? toArray(located.container[located.leaf]) ?? [] : [];
|
|
674
|
+
const next = [...existing];
|
|
675
|
+
if (typeof pushSpec === "object" && pushSpec !== null && "$each" in pushSpec && Array.isArray(pushSpec.$each)) {
|
|
676
|
+
next.push(...pushSpec.$each);
|
|
677
|
+
} else {
|
|
678
|
+
next.push(pushSpec);
|
|
679
|
+
}
|
|
680
|
+
setAtPath(doc, path, next);
|
|
681
|
+
},
|
|
682
|
+
$addToSet: (doc, path, item) => {
|
|
683
|
+
const located = getAtPath(doc, path);
|
|
684
|
+
const existing = located?.exists ? toArray(located.container[located.leaf]) ?? [] : [];
|
|
685
|
+
const next = [...existing];
|
|
686
|
+
const rawItems = typeof item === "object" && item !== null && "$each" in item ? item.$each : item;
|
|
687
|
+
const toAdd = Array.isArray(rawItems) ? rawItems : [rawItems];
|
|
688
|
+
for (const candidate of toAdd) {
|
|
689
|
+
if (!next.some((existingEntry) => deepEqualJson(existingEntry, candidate))) {
|
|
690
|
+
next.push(candidate);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
setAtPath(doc, path, next);
|
|
694
|
+
},
|
|
695
|
+
$pull: (doc, path, matcher) => {
|
|
696
|
+
const located = getAtPath(doc, path);
|
|
697
|
+
const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
|
|
698
|
+
if (!existing) return;
|
|
699
|
+
const filtered = existing.filter((entry) => !deepEqualJson(entry, matcher));
|
|
700
|
+
setAtPath(doc, path, filtered);
|
|
701
|
+
},
|
|
702
|
+
$pullAll: (doc, path, values) => {
|
|
703
|
+
const located = getAtPath(doc, path);
|
|
704
|
+
const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
|
|
705
|
+
if (!existing || !Array.isArray(values)) return;
|
|
706
|
+
const filtered = existing.filter((entry) => !values.some((target) => deepEqualJson(entry, target)));
|
|
707
|
+
setAtPath(doc, path, filtered);
|
|
708
|
+
},
|
|
709
|
+
$pop: (doc, path, direction) => {
|
|
710
|
+
const located = getAtPath(doc, path);
|
|
711
|
+
const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
|
|
712
|
+
if (!existing || existing.length === 0) return;
|
|
713
|
+
const next = direction === -1 ? existing.slice(1) : existing.slice(0, -1);
|
|
714
|
+
setAtPath(doc, path, next);
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
const applyOperator = (doc, operator, fields) => {
|
|
718
|
+
const fn = operators[operator];
|
|
719
|
+
if (!fn || fields === null || typeof fields !== "object") return;
|
|
720
|
+
for (const [path, argument] of Object.entries(fields)) {
|
|
721
|
+
fn(doc, path, argument);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
const applyUpdate = (doc, update) => {
|
|
725
|
+
const result = { ...doc };
|
|
726
|
+
for (const [key, value] of Object.entries(update)) {
|
|
727
|
+
if (key.startsWith("$")) {
|
|
728
|
+
applyOperator(result, key, value);
|
|
729
|
+
} else {
|
|
730
|
+
setAtPath(result, key, value);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return result;
|
|
734
|
+
};
|
|
735
|
+
|
|
469
736
|
const updateMethods = ["update", "updateOne", "replaceOne", "updateMany", "findOneAndUpdate", "findOneAndReplace", "findByIdAndUpdate"];
|
|
470
737
|
const trackChangedFields = (fields, updated, changed) => {
|
|
471
738
|
if (!fields) return;
|
|
472
739
|
for (const key of Object.keys(fields)) {
|
|
473
|
-
const root = key.split(".")
|
|
740
|
+
const [root = key] = key.split(".");
|
|
474
741
|
changed.set(root, updated[root]);
|
|
475
742
|
}
|
|
476
743
|
};
|
|
477
|
-
const applyPullAll = (updated, fields, changed) => {
|
|
478
|
-
for (const [field, values] of Object.entries(fields)) {
|
|
479
|
-
const arr = updated[field];
|
|
480
|
-
if (Array.isArray(arr)) {
|
|
481
|
-
const filtered = arr.filter((item) => !values.some((v) => JSON.stringify(v) === JSON.stringify(item)));
|
|
482
|
-
updated[field] = filtered;
|
|
483
|
-
changed.set(field, filtered);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
744
|
const assignUpdate = (document, update, commands) => {
|
|
488
|
-
let updated =
|
|
745
|
+
let updated = applyUpdate(document.toObject(toObjectOptions), update);
|
|
489
746
|
const changedByCommand = /* @__PURE__ */ new Map();
|
|
490
747
|
for (const command of commands) {
|
|
491
|
-
const op = Object.keys(command)
|
|
748
|
+
const [op = ""] = Object.keys(command);
|
|
492
749
|
const fields = command[op];
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
trackChangedFields(fields, updated, changedByCommand);
|
|
496
|
-
} catch {
|
|
497
|
-
if (op === "$pullAll" && fields) {
|
|
498
|
-
applyPullAll(updated, fields, changedByCommand);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
750
|
+
updated = applyUpdate(updated, command);
|
|
751
|
+
trackChangedFields(fields, updated, changedByCommand);
|
|
501
752
|
}
|
|
502
753
|
const doc = document.set(updated).toObject(toObjectOptions);
|
|
503
754
|
for (const [field, value] of changedByCommand) {
|
|
@@ -552,11 +803,14 @@ const updateHooksInitialize = (schema, opts) => {
|
|
|
552
803
|
const updateQuery = this.getUpdate();
|
|
553
804
|
const { update, commands } = splitUpdateAndCommands(updateQuery);
|
|
554
805
|
const filter = this.getFilter();
|
|
555
|
-
const
|
|
806
|
+
const simulated = assignUpdate(model.hydrate({}), update, commands);
|
|
807
|
+
const simulatedFilter = Object.fromEntries(Object.entries(simulated).filter(([, v]) => v !== void 0));
|
|
808
|
+
const candidates = [update, simulatedFilter, filter];
|
|
556
809
|
let current = null;
|
|
557
810
|
for (const query of candidates) {
|
|
558
811
|
if (current || isEmpty(query)) continue;
|
|
559
|
-
|
|
812
|
+
const found = await model.findOne(query).sort({ _id: -1 }).lean().exec();
|
|
813
|
+
current = found;
|
|
560
814
|
}
|
|
561
815
|
if (current) {
|
|
562
816
|
this._context.createdDocs = [current];
|
|
@@ -588,13 +842,14 @@ const patchHistoryPlugin = (schema, opts) => {
|
|
|
588
842
|
await createPatch(opts, context);
|
|
589
843
|
});
|
|
590
844
|
if (isMongooseLessThan8) {
|
|
591
|
-
|
|
845
|
+
const legacySchema = schema;
|
|
846
|
+
legacySchema.pre(remove, { document: true, query: false }, async function() {
|
|
592
847
|
const original = this.toObject(toObjectOptions);
|
|
593
848
|
if (opts.preDelete && !isEmpty(original)) {
|
|
594
849
|
await opts.preDelete([original]);
|
|
595
850
|
}
|
|
596
851
|
});
|
|
597
|
-
|
|
852
|
+
legacySchema.post(remove, { document: true, query: false }, async function() {
|
|
598
853
|
const original = this.toObject(toObjectOptions);
|
|
599
854
|
const model = this.constructor;
|
|
600
855
|
const context = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-patch-mongoose",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Patch history & events for mongoose models",
|
|
5
5
|
"author": "ilovepixelart",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
"url": "https://github.com/ilovepixelart/ts-patch-mongoose/issues"
|
|
13
13
|
},
|
|
14
14
|
"homepage": "https://github.com/ilovepixelart/ts-patch-mongoose#readme",
|
|
15
|
-
"directories": {
|
|
16
|
-
"examples": "examples"
|
|
17
|
-
},
|
|
18
15
|
"keywords": [
|
|
19
16
|
"backend",
|
|
20
17
|
"mongoose",
|
|
@@ -36,15 +33,10 @@
|
|
|
36
33
|
"log"
|
|
37
34
|
],
|
|
38
35
|
"engines": {
|
|
39
|
-
"node": ">=
|
|
36
|
+
"node": ">=20"
|
|
40
37
|
},
|
|
41
38
|
"files": [
|
|
42
|
-
"dist"
|
|
43
|
-
"src",
|
|
44
|
-
"tests",
|
|
45
|
-
"tsconfig.json",
|
|
46
|
-
"vite.config.mts",
|
|
47
|
-
"biome.json"
|
|
39
|
+
"dist"
|
|
48
40
|
],
|
|
49
41
|
"type": "module",
|
|
50
42
|
"exports": {
|
|
@@ -60,32 +52,33 @@
|
|
|
60
52
|
"main": "./dist/index.cjs",
|
|
61
53
|
"module": "./dist/index.mjs",
|
|
62
54
|
"types": "./dist/index.d.cts",
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public",
|
|
57
|
+
"provenance": true
|
|
58
|
+
},
|
|
63
59
|
"scripts": {
|
|
64
|
-
"prepare": "simple-git-hooks",
|
|
65
60
|
"biome": "npx @biomejs/biome check",
|
|
66
61
|
"biome:fix": "npx @biomejs/biome check --write .",
|
|
67
62
|
"test": "vitest run --coverage",
|
|
68
63
|
"test:open": "vitest run --coverage && open-cli coverage/lcov-report/index.html",
|
|
69
64
|
"type:check": "tsc --noEmit",
|
|
65
|
+
"type:check:tests": "tsc --noEmit -p tests/tsconfig.json",
|
|
70
66
|
"build": "pkgroll --clean-dist",
|
|
71
|
-
"release": "npm install && npm run biome && npm run type:check && npm run build && np --no-publish"
|
|
72
|
-
},
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"fast-json-patch": "3.1.1",
|
|
75
|
-
"power-assign": "0.2.10"
|
|
67
|
+
"release": "npm install && npm run biome && npm run type:check && npm run type:check:tests && npm run build && np --no-publish"
|
|
76
68
|
},
|
|
77
69
|
"devDependencies": {
|
|
78
|
-
"@biomejs/biome": "2.4.
|
|
79
|
-
"@types/node": "25.
|
|
80
|
-
"@vitest/coverage-v8": "4.1.
|
|
70
|
+
"@biomejs/biome": "2.4.11",
|
|
71
|
+
"@types/node": "25.6.0",
|
|
72
|
+
"@vitest/coverage-v8": "4.1.4",
|
|
73
|
+
"fast-check": "4.6.0",
|
|
81
74
|
"mongodb-memory-server": "11.0.1",
|
|
82
|
-
"mongoose": "9.
|
|
83
|
-
"np": "11.0.
|
|
75
|
+
"mongoose": "9.4.1",
|
|
76
|
+
"np": "11.0.3",
|
|
84
77
|
"open-cli": "9.0.0",
|
|
85
78
|
"pkgroll": "2.27.0",
|
|
86
79
|
"simple-git-hooks": "2.13.1",
|
|
87
80
|
"typescript": "5.9.3",
|
|
88
|
-
"vitest": "4.1.
|
|
81
|
+
"vitest": "4.1.4"
|
|
89
82
|
},
|
|
90
83
|
"peerDependencies": {
|
|
91
84
|
"mongoose": ">=6.6.0 < 10"
|
|
@@ -99,6 +92,8 @@
|
|
|
99
92
|
},
|
|
100
93
|
"overrides": {
|
|
101
94
|
"tmp": "0.2.5",
|
|
102
|
-
"file-type": "21.3.2"
|
|
95
|
+
"file-type": "21.3.2",
|
|
96
|
+
"lodash": "4.18.1",
|
|
97
|
+
"vite": "8.0.8"
|
|
103
98
|
}
|
|
104
99
|
}
|
package/biome.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
|
|
3
|
-
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
|
|
4
|
-
"files": {
|
|
5
|
-
"ignoreUnknown": false,
|
|
6
|
-
"includes": ["src/**/*.ts", "tests/**/*.ts"]
|
|
7
|
-
},
|
|
8
|
-
"formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 },
|
|
9
|
-
"assist": {
|
|
10
|
-
"actions": {
|
|
11
|
-
"source": {
|
|
12
|
-
"organizeImports": {
|
|
13
|
-
"level": "on",
|
|
14
|
-
"options": {
|
|
15
|
-
"groups": [
|
|
16
|
-
"vitest",
|
|
17
|
-
":BLANK_LINE:",
|
|
18
|
-
":NODE:",
|
|
19
|
-
{ "type": false },
|
|
20
|
-
":BLANK_LINE:"
|
|
21
|
-
]
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
|
-
"linter": {
|
|
28
|
-
"enabled": true,
|
|
29
|
-
"rules": {
|
|
30
|
-
"recommended": true
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"javascript": {
|
|
34
|
-
"formatter": {
|
|
35
|
-
"trailingCommas": "all",
|
|
36
|
-
"quoteStyle": "single",
|
|
37
|
-
"semicolons": "asNeeded",
|
|
38
|
-
"lineWidth": 320
|
|
39
|
-
},
|
|
40
|
-
"globals": ["Atomics", "SharedArrayBuffer"]
|
|
41
|
-
},
|
|
42
|
-
"json": {
|
|
43
|
-
"formatter": {
|
|
44
|
-
"trailingCommas": "none"
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|