ts-patch-mongoose 2.6.7 → 2.6.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.
- package/README.md +7 -1
- package/dist/cjs/helpers.js +32 -1
- package/dist/cjs/helpers.js.map +1 -1
- package/dist/cjs/plugin.js +3 -1
- package/dist/cjs/plugin.js.map +1 -1
- package/dist/cjs/types/helpers.d.ts +1 -0
- package/dist/cjs/types/helpers.d.ts.map +1 -1
- package/dist/cjs/types/plugin.d.ts +1 -0
- package/dist/cjs/types/plugin.d.ts.map +1 -1
- package/dist/esm/helpers.js +29 -0
- package/dist/esm/helpers.js.map +1 -1
- package/dist/esm/plugin.js +1 -0
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/types/helpers.d.ts +1 -0
- package/dist/esm/types/helpers.d.ts.map +1 -1
- package/dist/esm/types/plugin.d.ts +1 -0
- package/dist/esm/types/plugin.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/helpers.ts +43 -0
- package/src/plugin.ts +2 -0
- package/tests/helpers.test.ts +86 -0
package/README.md
CHANGED
|
@@ -105,9 +105,15 @@ import { Schema, model } from 'mongoose'
|
|
|
105
105
|
import type { HydratedDocument, Types } from 'mongoose'
|
|
106
106
|
import type IBook from '../interfaces/IBook'
|
|
107
107
|
|
|
108
|
-
import { patchHistoryPlugin } from 'ts-patch-mongoose'
|
|
108
|
+
import { patchHistoryPlugin, setPatchHistoryTTL } from 'ts-patch-mongoose'
|
|
109
109
|
import { BOOK_CREATED, BOOK_UPDATED, BOOK_DELETED } from '../constants/events'
|
|
110
110
|
|
|
111
|
+
// You can set patch history TTL in plain english or in milliseconds as you wish.
|
|
112
|
+
// This will determine how long you want to keep patch history.
|
|
113
|
+
// You don't need to use this global config in case you want to keep patch history forever.
|
|
114
|
+
// Execute this method after you connected to you database somewhere in your application.
|
|
115
|
+
setPatchHistoryTTL('1 month')
|
|
116
|
+
|
|
111
117
|
const BookSchema = new Schema<IBook>({
|
|
112
118
|
name: {
|
|
113
119
|
title: String,
|
package/dist/cjs/helpers.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toObjectOptions = exports.isHookIgnored = void 0;
|
|
3
|
+
exports.setPatchHistoryTTL = exports.toObjectOptions = exports.isHookIgnored = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ms_1 = tslib_1.__importDefault(require("ms"));
|
|
6
|
+
const History_1 = tslib_1.__importDefault(require("./models/History"));
|
|
4
7
|
const isHookIgnored = (options) => {
|
|
5
8
|
return options.ignoreHook === true || (options.ignoreEvent === true && options.ignorePatchHistory === true);
|
|
6
9
|
};
|
|
@@ -9,4 +12,32 @@ exports.toObjectOptions = {
|
|
|
9
12
|
depopulate: true,
|
|
10
13
|
virtuals: false,
|
|
11
14
|
};
|
|
15
|
+
const setPatchHistoryTTL = async (ttl) => {
|
|
16
|
+
const name = 'createdAt_1_TTL';
|
|
17
|
+
try {
|
|
18
|
+
const indexes = await History_1.default.collection.indexes();
|
|
19
|
+
const existingIndex = indexes?.find((index) => index.name === name);
|
|
20
|
+
if (!ttl && existingIndex) {
|
|
21
|
+
await History_1.default.collection.dropIndex(name);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const milliseconds = (0, ms_1.default)(ttl);
|
|
25
|
+
if (milliseconds < 1000 && existingIndex) {
|
|
26
|
+
await History_1.default.collection.dropIndex(name);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const expireAfterSeconds = milliseconds / 1000;
|
|
30
|
+
if (existingIndex && existingIndex.expireAfterSeconds === expireAfterSeconds) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (existingIndex) {
|
|
34
|
+
await History_1.default.collection.dropIndex(name);
|
|
35
|
+
}
|
|
36
|
+
await History_1.default.collection.createIndex({ createdAt: 1 }, { expireAfterSeconds, name });
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error("Couldn't create or update index for history collection", err);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
exports.setPatchHistoryTTL = setPatchHistoryTTL;
|
|
12
43
|
//# sourceMappingURL=helpers.js.map
|
package/dist/cjs/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":";;;;AAAA,oDAAmB;AAEnB,uEAAsC;AAI/B,MAAM,aAAa,GAAG,CAAI,OAAwB,EAAW,EAAE;IACpE,OAAO,OAAO,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAA;AAC7G,CAAC,CAAA;AAFY,QAAA,aAAa,iBAEzB;AAEY,QAAA,eAAe,GAAoB;IAC9C,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,KAAK;CAChB,CAAA;AAEM,MAAM,kBAAkB,GAAG,KAAK,EAAE,GAAoB,EAAiB,EAAE;IAC9E,MAAM,IAAI,GAAG,iBAAiB,CAAA;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAA;QAClD,MAAM,aAAa,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QAGnE,IAAI,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC;YAC1B,MAAM,iBAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,YAAY,GAAG,IAAA,YAAE,EAAC,GAAa,CAAC,CAAA;QAGtC,IAAI,YAAY,GAAG,IAAI,IAAI,aAAa,EAAE,CAAC;YACzC,MAAM,iBAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,kBAAkB,GAAG,YAAY,GAAG,IAAI,CAAA;QAE9C,IAAI,aAAa,IAAI,aAAa,CAAC,kBAAkB,KAAK,kBAAkB,EAAE,CAAC;YAE7E,OAAM;QACR,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAElB,MAAM,iBAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAC1C,CAAC;QAGD,MAAM,iBAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAA;IACtF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wDAAwD,EAAE,GAAG,CAAC,CAAA;IAC9E,CAAC;AACH,CAAC,CAAA;AArCY,QAAA,kBAAkB,sBAqC9B"}
|
package/dist/cjs/plugin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.patchHistoryPlugin = exports.patchEventEmitter = void 0;
|
|
3
|
+
exports.patchHistoryPlugin = exports.setPatchHistoryTTL = exports.patchEventEmitter = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
|
6
6
|
const em_1 = tslib_1.__importDefault(require("./em"));
|
|
@@ -12,6 +12,8 @@ const save_hooks_1 = require("./hooks/save-hooks");
|
|
|
12
12
|
const update_hooks_1 = require("./hooks/update-hooks");
|
|
13
13
|
const remove = version_1.isMongooseLessThan7 ? 'remove' : 'deleteOne';
|
|
14
14
|
exports.patchEventEmitter = em_1.default;
|
|
15
|
+
var helpers_2 = require("./helpers");
|
|
16
|
+
Object.defineProperty(exports, "setPatchHistoryTTL", { enumerable: true, get: function () { return helpers_2.setPatchHistoryTTL; } });
|
|
15
17
|
const patchHistoryPlugin = function plugin(schema, opts) {
|
|
16
18
|
(0, save_hooks_1.saveHooksInitialize)(schema, opts);
|
|
17
19
|
(0, update_hooks_1.updateHooksInitialize)(schema, opts);
|
package/dist/cjs/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":";;;;AAAA,4DAAsB;AACtB,sDAAqB;AAErB,uCAA2C;AAC3C,mCAAkD;AAClD,uCAAoE;AAEpE,uDAA4D;AAC5D,mDAAwD;AACxD,uDAA4D;AAM5D,MAAM,MAAM,GAAG,6BAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;AAK9C,QAAA,iBAAiB,GAAG,YAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":";;;;AAAA,4DAAsB;AACtB,sDAAqB;AAErB,uCAA2C;AAC3C,mCAAkD;AAClD,uCAAoE;AAEpE,uDAA4D;AAC5D,mDAAwD;AACxD,uDAA4D;AAM5D,MAAM,MAAM,GAAG,6BAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;AAK9C,QAAA,iBAAiB,GAAG,YAAE,CAAA;AAEnC,qCAA8C;AAArC,6GAAA,kBAAkB,OAAA;AAQpB,MAAM,kBAAkB,GAAG,SAAS,MAAM,CAAI,MAAiB,EAAE,IAAuB;IAE7F,IAAA,gCAAmB,EAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACjC,IAAA,oCAAqB,EAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACnC,IAAA,oCAAqB,EAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAGnC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,WAAW,IAAI;QAC5C,MAAM,OAAO,GAAG;YACd,EAAE,EAAE,QAAQ;YACZ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS;YAC3C,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc;YACrE,WAAW,EAAE,IAAwC;SACtD,CAAA;QAED,MAAM,IAAA,mBAAW,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAIF,IAAI,6BAAmB,EAAE,CAAC;QAExB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK;YAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,yBAAe,CAAwB,CAAA;YAEtE,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAClC,CAAC;QACH,CAAC,CAAC,CAAA;QAGF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,yBAAe,CAAwB,CAAA;YACtE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAuB,CAAA;YAE1C,MAAM,OAAO,GAAgB;gBAC3B,EAAE,EAAE,QAAQ;gBACZ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS;gBAC5C,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,UAAU,CAAC,cAAc;gBACtE,WAAW,EAAE,CAAC,QAAQ,CAAC;aACxB,CAAA;YAED,MAAM,IAAA,mBAAW,EAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA;AA9CY,QAAA,kBAAkB,sBA8C9B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { QueryOptions, ToObjectOptions } from 'mongoose';
|
|
2
2
|
export declare const isHookIgnored: <T>(options: QueryOptions<T>) => boolean;
|
|
3
3
|
export declare const toObjectOptions: ToObjectOptions;
|
|
4
|
+
export declare const setPatchHistoryTTL: (ttl: number | string) => Promise<void>;
|
|
4
5
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE7D,eAAO,MAAM,aAAa,GAAI,CAAC,WAAW,YAAY,CAAC,CAAC,CAAC,KAAG,OAE3D,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,eAG7B,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAe,MAAM,GAAG,MAAM,KAAG,OAAO,CAAC,IAAI,CAqC3E,CAAA"}
|
|
@@ -18,5 +18,6 @@ export declare const patchEventEmitter: {
|
|
|
18
18
|
prependOnceListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
|
|
19
19
|
eventNames(): (string | symbol)[];
|
|
20
20
|
};
|
|
21
|
+
export { setPatchHistoryTTL } from './helpers';
|
|
21
22
|
export declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: IPluginOptions<T>) => void;
|
|
22
23
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA2B,MAAM,EAAE,MAAM,UAAU,CAAA;AAE/D,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAA;AAO7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;CAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA2B,MAAM,EAAE,MAAM,UAAU,CAAA;AAE/D,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAA;AAO7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;CAAK,CAAA;AAEnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAQ9C,eAAO,MAAM,kBAAkB,GAAmB,CAAC,UAAU,MAAM,CAAC,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAG,IA8CjG,CAAA"}
|
package/dist/esm/helpers.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import ms from 'ms';
|
|
2
|
+
import History from './models/History.js';
|
|
1
3
|
export const isHookIgnored = (options) => {
|
|
2
4
|
return options.ignoreHook === true || (options.ignoreEvent === true && options.ignorePatchHistory === true);
|
|
3
5
|
};
|
|
@@ -5,4 +7,31 @@ export const toObjectOptions = {
|
|
|
5
7
|
depopulate: true,
|
|
6
8
|
virtuals: false,
|
|
7
9
|
};
|
|
10
|
+
export const setPatchHistoryTTL = async (ttl) => {
|
|
11
|
+
const name = 'createdAt_1_TTL';
|
|
12
|
+
try {
|
|
13
|
+
const indexes = await History.collection.indexes();
|
|
14
|
+
const existingIndex = indexes?.find((index) => index.name === name);
|
|
15
|
+
if (!ttl && existingIndex) {
|
|
16
|
+
await History.collection.dropIndex(name);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const milliseconds = ms(ttl);
|
|
20
|
+
if (milliseconds < 1000 && existingIndex) {
|
|
21
|
+
await History.collection.dropIndex(name);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const expireAfterSeconds = milliseconds / 1000;
|
|
25
|
+
if (existingIndex && existingIndex.expireAfterSeconds === expireAfterSeconds) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (existingIndex) {
|
|
29
|
+
await History.collection.dropIndex(name);
|
|
30
|
+
}
|
|
31
|
+
await History.collection.createIndex({ createdAt: 1 }, { expireAfterSeconds, name });
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error("Couldn't create or update index for history collection", err);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
8
37
|
//# sourceMappingURL=helpers.js.map
|
package/dist/esm/helpers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,OAAO,MAAM,kBAAkB,CAAA;AAItC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAI,OAAwB,EAAW,EAAE;IACpE,OAAO,OAAO,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,kBAAkB,KAAK,IAAI,CAAC,CAAA;AAC7G,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,KAAK;CAChB,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAAE,GAAoB,EAAiB,EAAE;IAC9E,MAAM,IAAI,GAAG,iBAAiB,CAAA;IAC9B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAA;QAClD,MAAM,aAAa,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QAGnE,IAAI,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,YAAY,GAAG,EAAE,CAAC,GAAa,CAAC,CAAA;QAGtC,IAAI,YAAY,GAAG,IAAI,IAAI,aAAa,EAAE,CAAC;YACzC,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;YACxC,OAAM;QACR,CAAC;QAED,MAAM,kBAAkB,GAAG,YAAY,GAAG,IAAI,CAAA;QAE9C,IAAI,aAAa,IAAI,aAAa,CAAC,kBAAkB,KAAK,kBAAkB,EAAE,CAAC;YAE7E,OAAM;QACR,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAElB,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAC1C,CAAC;QAGD,MAAM,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAA;IACtF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wDAAwD,EAAE,GAAG,CAAC,CAAA;IAC9E,CAAC;AACH,CAAC,CAAA"}
|
package/dist/esm/plugin.js
CHANGED
|
@@ -8,6 +8,7 @@ import { saveHooksInitialize } from './hooks/save-hooks.js';
|
|
|
8
8
|
import { updateHooksInitialize } from './hooks/update-hooks.js';
|
|
9
9
|
const remove = isMongooseLessThan7 ? 'remove' : 'deleteOne';
|
|
10
10
|
export const patchEventEmitter = em;
|
|
11
|
+
export { setPatchHistoryTTL } from './helpers';
|
|
11
12
|
export const patchHistoryPlugin = function plugin(schema, opts) {
|
|
12
13
|
saveHooksInitialize(schema, opts);
|
|
13
14
|
updateHooksInitialize(schema, opts);
|
package/dist/esm/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAA;AACtB,OAAO,EAAE,MAAM,MAAM,CAAA;AAErB,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAM5D,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;AAK3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAA;AACtB,OAAO,EAAE,MAAM,MAAM,CAAA;AAErB,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAEpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAM5D,MAAM,MAAM,GAAG,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAA;AAK3D,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAA;AAEnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAQ9C,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,MAAM,CAAI,MAAiB,EAAE,IAAuB;IAE7F,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACjC,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IACnC,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAGnC,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,WAAW,IAAI;QAC5C,MAAM,OAAO,GAAG;YACd,EAAE,EAAE,QAAQ;YACZ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS;YAC3C,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,UAAU,CAAC,cAAc;YACrE,WAAW,EAAE,IAAwC;SACtD,CAAA;QAED,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAIF,IAAI,mBAAmB,EAAE,CAAC;QAExB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK;YAExD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAwB,CAAA;YAEtE,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC3C,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAClC,CAAC;QACH,CAAC,CAAC,CAAA;QAGF,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,KAAK;YACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAwB,CAAA;YACtE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAuB,CAAA;YAE1C,MAAM,OAAO,GAAgB;gBAC3B,EAAE,EAAE,QAAQ;gBACZ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS;gBAC5C,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,UAAU,CAAC,cAAc;gBACtE,WAAW,EAAE,CAAC,QAAQ,CAAC;aACxB,CAAA;YAED,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { QueryOptions, ToObjectOptions } from 'mongoose';
|
|
2
2
|
export declare const isHookIgnored: <T>(options: QueryOptions<T>) => boolean;
|
|
3
3
|
export declare const toObjectOptions: ToObjectOptions;
|
|
4
|
+
export declare const setPatchHistoryTTL: (ttl: number | string) => Promise<void>;
|
|
4
5
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE7D,eAAO,MAAM,aAAa,GAAI,CAAC,WAAW,YAAY,CAAC,CAAC,CAAC,KAAG,OAE3D,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,eAG7B,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAe,MAAM,GAAG,MAAM,KAAG,OAAO,CAAC,IAAI,CAqC3E,CAAA"}
|
|
@@ -18,5 +18,6 @@ export declare const patchEventEmitter: {
|
|
|
18
18
|
prependOnceListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
|
|
19
19
|
eventNames(): (string | symbol)[];
|
|
20
20
|
};
|
|
21
|
+
export { setPatchHistoryTTL } from './helpers';
|
|
21
22
|
export declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: IPluginOptions<T>) => void;
|
|
22
23
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA2B,MAAM,EAAE,MAAM,UAAU,CAAA;AAE/D,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAA;AAO7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;CAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAA2B,MAAM,EAAE,MAAM,UAAU,CAAA;AAE/D,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAA;AAO7D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;CAAK,CAAA;AAEnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAQ9C,eAAO,MAAM,kBAAkB,GAAmB,CAAC,UAAU,MAAM,CAAC,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAG,IA8CjG,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-patch-mongoose",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.8",
|
|
4
4
|
"description": "Patch history & events for mongoose models",
|
|
5
5
|
"author": "Alex Eagle",
|
|
6
6
|
"license": "MIT",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"fast-json-patch": "3.1.1",
|
|
79
79
|
"lodash": "4.17.21",
|
|
80
|
+
"ms": "2.1.3",
|
|
80
81
|
"omit-deep": "0.3.0",
|
|
81
82
|
"power-assign": "0.2.10",
|
|
82
83
|
"semver": "7.6.3"
|
|
@@ -84,12 +85,13 @@
|
|
|
84
85
|
"devDependencies": {
|
|
85
86
|
"@biomejs/biome": "1.9.4",
|
|
86
87
|
"@types/lodash": "4.17.13",
|
|
88
|
+
"@types/ms": "0.7.34",
|
|
87
89
|
"@types/node": "22.10.1",
|
|
88
90
|
"@types/semver": "7.5.8",
|
|
89
91
|
"@vitest/coverage-v8": "2.1.8",
|
|
90
92
|
"merge": "2.1.1",
|
|
91
93
|
"mongodb-memory-server": "10.1.2",
|
|
92
|
-
"mongoose": "8.8.
|
|
94
|
+
"mongoose": "8.8.4",
|
|
93
95
|
"open-cli": "8.0.0",
|
|
94
96
|
"typescript": "5.7.2",
|
|
95
97
|
"vitest": "2.1.8"
|
package/src/helpers.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import ms from 'ms'
|
|
2
|
+
|
|
3
|
+
import History from './models/History'
|
|
4
|
+
|
|
1
5
|
import type { QueryOptions, ToObjectOptions } from 'mongoose'
|
|
2
6
|
|
|
3
7
|
export const isHookIgnored = <T>(options: QueryOptions<T>): boolean => {
|
|
@@ -8,3 +12,42 @@ export const toObjectOptions: ToObjectOptions = {
|
|
|
8
12
|
depopulate: true,
|
|
9
13
|
virtuals: false,
|
|
10
14
|
}
|
|
15
|
+
|
|
16
|
+
export const setPatchHistoryTTL = async (ttl: number | string): Promise<void> => {
|
|
17
|
+
const name = 'createdAt_1_TTL' // To avoid collision with user defined index / manually created index
|
|
18
|
+
try {
|
|
19
|
+
const indexes = await History.collection.indexes()
|
|
20
|
+
const existingIndex = indexes?.find((index) => index.name === name)
|
|
21
|
+
|
|
22
|
+
// Drop the index if historyTTL is not set and index exists
|
|
23
|
+
if (!ttl && existingIndex) {
|
|
24
|
+
await History.collection.dropIndex(name)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const milliseconds = ms(ttl as string)
|
|
29
|
+
|
|
30
|
+
// Drop the index if historyTTL is less than 1 second and index exists
|
|
31
|
+
if (milliseconds < 1000 && existingIndex) {
|
|
32
|
+
await History.collection.dropIndex(name)
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const expireAfterSeconds = milliseconds / 1000
|
|
37
|
+
|
|
38
|
+
if (existingIndex && existingIndex.expireAfterSeconds === expireAfterSeconds) {
|
|
39
|
+
// Index already exists with the correct TTL, no need to recreate
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (existingIndex) {
|
|
44
|
+
// Drop the existing index if it exists and TTL is different
|
|
45
|
+
await History.collection.dropIndex(name)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Create a new index with the correct TTL if it doesn't exist or if the TTL is different
|
|
49
|
+
await History.collection.createIndex({ createdAt: 1 }, { expireAfterSeconds, name })
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error("Couldn't create or update index for history collection", err)
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import ms from 'ms'
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import History from '../src/models/History'
|
|
5
|
+
|
|
6
|
+
import { setPatchHistoryTTL } from '../src/helpers'
|
|
7
|
+
|
|
8
|
+
import type { Mock, MockInstance } from 'vitest'
|
|
9
|
+
|
|
10
|
+
vi.mock('../src/models/History', () => ({
|
|
11
|
+
default: {
|
|
12
|
+
collection: {
|
|
13
|
+
indexes: vi.fn(),
|
|
14
|
+
dropIndex: vi.fn(),
|
|
15
|
+
createIndex: vi.fn(),
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
}))
|
|
19
|
+
|
|
20
|
+
const name = 'createdAt_1_TTL'
|
|
21
|
+
|
|
22
|
+
describe('useTTL', () => {
|
|
23
|
+
let dropIndexSpy: MockInstance
|
|
24
|
+
let createIndexSpy: MockInstance
|
|
25
|
+
const indexes = History.collection.indexes as Mock
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.clearAllMocks()
|
|
29
|
+
dropIndexSpy = vi.spyOn(History.collection, 'dropIndex')
|
|
30
|
+
createIndexSpy = vi.spyOn(History.collection, 'createIndex')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
vi.restoreAllMocks()
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should drop the index if historyTTL is not set and index exists', async () => {
|
|
38
|
+
indexes.mockResolvedValue([{ name }])
|
|
39
|
+
|
|
40
|
+
// @ts-expect-error ttl can't be undefined in this case but we want to test it
|
|
41
|
+
await setPatchHistoryTTL(undefined)
|
|
42
|
+
expect(dropIndexSpy).toHaveBeenCalledWith(name)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('should drop the index if historyTTL is less than 1 second and index exists', async () => {
|
|
46
|
+
indexes.mockResolvedValue([{ name }])
|
|
47
|
+
|
|
48
|
+
await setPatchHistoryTTL('500ms')
|
|
49
|
+
expect(dropIndexSpy).toHaveBeenCalledWith(name)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should not recreate the index if it already exists with the correct TTL', async () => {
|
|
53
|
+
const ttl = '1h'
|
|
54
|
+
const expireAfterSeconds = ms(ttl) / 1000
|
|
55
|
+
|
|
56
|
+
indexes.mockResolvedValue([{ name, expireAfterSeconds }])
|
|
57
|
+
|
|
58
|
+
await setPatchHistoryTTL(ttl)
|
|
59
|
+
expect(dropIndexSpy).not.toHaveBeenCalled()
|
|
60
|
+
expect(createIndexSpy).not.toHaveBeenCalled()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should drop and recreate the index if TTL is different', async () => {
|
|
64
|
+
const ttlBefore = '1h'
|
|
65
|
+
const ttlAfter = '2h'
|
|
66
|
+
|
|
67
|
+
const expireAfterSecondsBefore = ms(ttlBefore) / 1000
|
|
68
|
+
const expireAfterSecondsAfter = ms(ttlAfter) / 1000
|
|
69
|
+
|
|
70
|
+
indexes.mockResolvedValue([{ name, expireAfterSeconds: expireAfterSecondsBefore }])
|
|
71
|
+
|
|
72
|
+
await setPatchHistoryTTL(ttlAfter)
|
|
73
|
+
expect(dropIndexSpy).toHaveBeenCalledWith(name)
|
|
74
|
+
expect(createIndexSpy).toHaveBeenCalledWith({ createdAt: 1 }, { expireAfterSeconds: expireAfterSecondsAfter, name })
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should create the index if it does not exist', async () => {
|
|
78
|
+
const ttl = '1h'
|
|
79
|
+
const expireAfterSeconds = ms(ttl) / 1000
|
|
80
|
+
|
|
81
|
+
indexes.mockResolvedValue([])
|
|
82
|
+
|
|
83
|
+
await setPatchHistoryTTL(ttl)
|
|
84
|
+
expect(createIndexSpy).toHaveBeenCalledWith({ createdAt: 1 }, { expireAfterSeconds, name })
|
|
85
|
+
})
|
|
86
|
+
})
|