ts-patch-mongoose 2.9.2 → 2.9.4

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/biome.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
2
+ "$schema": "https://biomejs.dev/schemas/2.3.1/schema.json",
3
3
  "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
4
4
  "files": {
5
5
  "ignoreUnknown": false,
package/dist/index.cjs CHANGED
@@ -1,18 +1,21 @@
1
1
  'use strict';
2
2
 
3
- var _ = require('lodash');
4
- var EventEmitter = require('node:events');
3
+ var isEmpty = require('lodash/isEmpty');
5
4
  var ms = require('ms');
6
5
  var mongoose = require('mongoose');
6
+ var isArray = require('lodash/isArray');
7
7
  var jsonpatch = require('fast-json-patch');
8
+ var chunk = require('lodash/chunk');
9
+ var isFunction = require('lodash/isFunction');
8
10
  var omit = require('omit-deep');
11
+ var EventEmitter = require('node:events');
12
+ var cloneDeep = require('lodash/cloneDeep');
13
+ var forEach = require('lodash/forEach');
14
+ var isObjectLike = require('lodash/isObjectLike');
15
+ var keys = require('lodash/keys');
9
16
  var powerAssign = require('power-assign');
10
17
  var semver = require('semver');
11
18
 
12
- class PatchEventEmitter extends EventEmitter {
13
- }
14
- const em = new PatchEventEmitter();
15
-
16
19
  const HistorySchema = new mongoose.Schema(
17
20
  {
18
21
  op: {
@@ -92,6 +95,10 @@ const setPatchHistoryTTL = async (ttl) => {
92
95
  }
93
96
  };
94
97
 
98
+ class PatchEventEmitter extends EventEmitter {
99
+ }
100
+ const em = new PatchEventEmitter();
101
+
95
102
  function isPatchHistoryEnabled(opts, context) {
96
103
  return !opts.patchHistoryDisabled && !context.ignorePatchHistory;
97
104
  }
@@ -104,24 +111,24 @@ function getJsonOmit(opts, doc) {
104
111
  }
105
112
  function getObjectOmit(opts, doc) {
106
113
  if (opts.omit) {
107
- return omit(_.isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit);
114
+ return omit(isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit);
108
115
  }
109
116
  return doc;
110
117
  }
111
118
  async function getUser(opts, doc) {
112
- if (_.isFunction(opts.getUser)) {
119
+ if (isFunction(opts.getUser)) {
113
120
  return await opts.getUser(doc);
114
121
  }
115
122
  return void 0;
116
123
  }
117
124
  async function getReason(opts, doc) {
118
- if (_.isFunction(opts.getReason)) {
125
+ if (isFunction(opts.getReason)) {
119
126
  return await opts.getReason(doc);
120
127
  }
121
128
  return void 0;
122
129
  }
123
130
  async function getMetadata(opts, doc) {
124
- if (_.isFunction(opts.getMetadata)) {
131
+ if (isFunction(opts.getMetadata)) {
125
132
  return await opts.getMetadata(doc);
126
133
  }
127
134
  return void 0;
@@ -144,11 +151,11 @@ async function bulkPatch(opts, context, eventKey, docsKey) {
144
151
  const event = opts[eventKey];
145
152
  const docs = context[docsKey];
146
153
  const key = eventKey === "eventCreated" ? "doc" : "oldDoc";
147
- if (_.isEmpty(docs) || !event && !history) return;
148
- const chunks = _.chunk(docs, 1e3);
149
- for await (const chunk of chunks) {
154
+ if (isEmpty(docs) || !event && !history) return;
155
+ const chunks = chunk(docs, 1e3);
156
+ for (const chunk2 of chunks) {
150
157
  const bulk = [];
151
- for (const doc of chunk) {
158
+ for (const doc of chunk2) {
152
159
  emitEvent(context, event, { [key]: doc });
153
160
  if (history) {
154
161
  const [user, reason, metadata] = await getData(opts, doc);
@@ -169,7 +176,7 @@ async function bulkPatch(opts, context, eventKey, docsKey) {
169
176
  });
170
177
  }
171
178
  }
172
- if (history && !_.isEmpty(bulk)) {
179
+ if (history && !isEmpty(bulk)) {
173
180
  await HistoryModel.bulkWrite(bulk, { ordered: false }).catch((error) => {
174
181
  console.error(error.message);
175
182
  });
@@ -183,9 +190,9 @@ async function updatePatch(opts, context, current, original) {
183
190
  const history = isPatchHistoryEnabled(opts, context);
184
191
  const currentObject = getJsonOmit(opts, current);
185
192
  const originalObject = getJsonOmit(opts, original);
186
- if (_.isEmpty(originalObject) || _.isEmpty(currentObject)) return;
193
+ if (isEmpty(originalObject) || isEmpty(currentObject)) return;
187
194
  const patch = jsonpatch.compare(originalObject, currentObject, true);
188
- if (_.isEmpty(patch)) return;
195
+ if (isEmpty(patch)) return;
189
196
  emitEvent(context, opts.eventUpdated, { oldDoc: original, doc: current, patch });
190
197
  if (history) {
191
198
  let version = 0;
@@ -227,16 +234,16 @@ const deleteHooksInitialize = (schema, opts) => {
227
234
  };
228
235
  if (["remove", "deleteMany"].includes(this._context.op) && !options.single) {
229
236
  const docs = await model.find(filter).lean().exec();
230
- if (!_.isEmpty(docs)) {
237
+ if (!isEmpty(docs)) {
231
238
  this._context.deletedDocs = docs;
232
239
  }
233
240
  } else {
234
241
  const doc = await model.findOne(filter).lean().exec();
235
- if (!_.isEmpty(doc)) {
242
+ if (!isEmpty(doc)) {
236
243
  this._context.deletedDocs = [doc];
237
244
  }
238
245
  }
239
- if (opts.preDelete && _.isArray(this._context.deletedDocs) && !_.isEmpty(this._context.deletedDocs)) {
246
+ if (opts.preDelete && isArray(this._context.deletedDocs) && !isEmpty(this._context.deletedDocs)) {
240
247
  await opts.preDelete(this._context.deletedDocs);
241
248
  }
242
249
  });
@@ -272,7 +279,7 @@ const saveHooksInitialize = (schema, opts) => {
272
279
  const updateMethods = ["update", "updateOne", "replaceOne", "updateMany", "findOneAndUpdate", "findOneAndReplace", "findByIdAndUpdate"];
273
280
  const assignUpdate = (document, update, commands) => {
274
281
  let updated = powerAssign.assign(document.toObject(toObjectOptions), update);
275
- _.forEach(commands, (command) => {
282
+ forEach(commands, (command) => {
276
283
  try {
277
284
  updated = powerAssign.assign(updated, command);
278
285
  } catch {
@@ -285,11 +292,11 @@ const assignUpdate = (document, update, commands) => {
285
292
  const splitUpdateAndCommands = (updateQuery) => {
286
293
  let update = {};
287
294
  const commands = [];
288
- if (!_.isEmpty(updateQuery) && !_.isArray(updateQuery) && _.isObjectLike(updateQuery)) {
289
- update = _.cloneDeep(updateQuery);
290
- const keysWithDollarSign = _.keys(update).filter((key) => key.startsWith("$"));
291
- if (!_.isEmpty(keysWithDollarSign)) {
292
- _.forEach(keysWithDollarSign, (key) => {
295
+ if (!isEmpty(updateQuery) && !isArray(updateQuery) && isObjectLike(updateQuery)) {
296
+ update = cloneDeep(updateQuery);
297
+ const keysWithDollarSign = keys(update).filter((key) => key.startsWith("$"));
298
+ if (!isEmpty(keysWithDollarSign)) {
299
+ forEach(keysWithDollarSign, (key) => {
293
300
  commands.push({ [key]: update[key] });
294
301
  delete update[key];
295
302
  });
@@ -330,13 +337,13 @@ const updateHooksInitialize = (schema, opts) => {
330
337
  let current = null;
331
338
  const filter = this.getFilter();
332
339
  const combined = assignUpdate(model.hydrate({}), update, commands);
333
- if (!_.isEmpty(update) && !current) {
340
+ if (!isEmpty(update) && !current) {
334
341
  current = await model.findOne(update).sort("desc").lean().exec();
335
342
  }
336
- if (!_.isEmpty(combined) && !current) {
343
+ if (!isEmpty(combined) && !current) {
337
344
  current = await model.findOne(combined).sort("desc").lean().exec();
338
345
  }
339
- if (!_.isEmpty(filter) && !current) {
346
+ if (!isEmpty(filter) && !current) {
340
347
  console.log("filter", filter);
341
348
  current = await model.findOne(filter).sort("desc").lean().exec();
342
349
  }
@@ -355,7 +362,6 @@ if (isMongoose6) {
355
362
  }
356
363
 
357
364
  const remove = isMongooseLessThan7 ? "remove" : "deleteOne";
358
- const patchEventEmitter = em;
359
365
  const patchHistoryPlugin = function plugin(schema, opts) {
360
366
  saveHooksInitialize(schema, opts);
361
367
  updateHooksInitialize(schema, opts);
@@ -372,7 +378,7 @@ const patchHistoryPlugin = function plugin(schema, opts) {
372
378
  if (isMongooseLessThan8) {
373
379
  schema.pre(remove, { document: true, query: false }, async function() {
374
380
  const original = this.toObject(toObjectOptions);
375
- if (opts.preDelete && !_.isEmpty(original)) {
381
+ if (opts.preDelete && !isEmpty(original)) {
376
382
  await opts.preDelete([original]);
377
383
  }
378
384
  });
@@ -390,6 +396,6 @@ const patchHistoryPlugin = function plugin(schema, opts) {
390
396
  }
391
397
  };
392
398
 
393
- exports.patchEventEmitter = patchEventEmitter;
399
+ exports.patchEventEmitter = em;
394
400
  exports.patchHistoryPlugin = patchHistoryPlugin;
395
401
  exports.setPatchHistoryTTL = setPatchHistoryTTL;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { HydratedDocument, Types, Query, Schema } from 'mongoose';
2
2
  import { Operation } from 'fast-json-patch';
3
+ import EventEmitter from 'node:events';
3
4
  import ms from 'ms';
4
5
 
5
6
  interface History {
@@ -49,28 +50,13 @@ interface PluginOptions<T> {
49
50
  preDelete?: (docs: HydratedDocument<T>[]) => Promise<void>;
50
51
  }
51
52
 
52
- declare const setPatchHistoryTTL: (ttl: number | ms.StringValue) => Promise<void>;
53
+ declare class PatchEventEmitter extends EventEmitter {
54
+ }
55
+ declare const em: PatchEventEmitter;
53
56
 
54
- declare const patchEventEmitter: {
55
- [EventEmitter.captureRejectionSymbol]?<K>(error: Error, event: string | symbol, ...args: any[]): void;
56
- addListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
57
- on<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
58
- once<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
59
- removeListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
60
- off<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
61
- removeAllListeners(eventName?: string | symbol | undefined): any;
62
- setMaxListeners(n: number): any;
63
- getMaxListeners(): number;
64
- listeners<K>(eventName: string | symbol): Function[];
65
- rawListeners<K>(eventName: string | symbol): Function[];
66
- emit<K>(eventName: string | symbol, ...args: any[]): boolean;
67
- listenerCount<K>(eventName: string | symbol, listener?: Function | undefined): number;
68
- prependListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
69
- prependOnceListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
70
- eventNames(): (string | symbol)[];
71
- };
57
+ declare const setPatchHistoryTTL: (ttl: number | ms.StringValue) => Promise<void>;
72
58
 
73
59
  declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: PluginOptions<T>) => void;
74
60
 
75
- export { patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
61
+ export { em as patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
76
62
  export type { History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { HydratedDocument, Types, Query, Schema } from 'mongoose';
2
2
  import { Operation } from 'fast-json-patch';
3
+ import EventEmitter from 'node:events';
3
4
  import ms from 'ms';
4
5
 
5
6
  interface History {
@@ -49,28 +50,13 @@ interface PluginOptions<T> {
49
50
  preDelete?: (docs: HydratedDocument<T>[]) => Promise<void>;
50
51
  }
51
52
 
52
- declare const setPatchHistoryTTL: (ttl: number | ms.StringValue) => Promise<void>;
53
+ declare class PatchEventEmitter extends EventEmitter {
54
+ }
55
+ declare const em: PatchEventEmitter;
53
56
 
54
- declare const patchEventEmitter: {
55
- [EventEmitter.captureRejectionSymbol]?<K>(error: Error, event: string | symbol, ...args: any[]): void;
56
- addListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
57
- on<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
58
- once<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
59
- removeListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
60
- off<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
61
- removeAllListeners(eventName?: string | symbol | undefined): any;
62
- setMaxListeners(n: number): any;
63
- getMaxListeners(): number;
64
- listeners<K>(eventName: string | symbol): Function[];
65
- rawListeners<K>(eventName: string | symbol): Function[];
66
- emit<K>(eventName: string | symbol, ...args: any[]): boolean;
67
- listenerCount<K>(eventName: string | symbol, listener?: Function | undefined): number;
68
- prependListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
69
- prependOnceListener<K>(eventName: string | symbol, listener: (...args: any[]) => void): any;
70
- eventNames(): (string | symbol)[];
71
- };
57
+ declare const setPatchHistoryTTL: (ttl: number | ms.StringValue) => Promise<void>;
72
58
 
73
59
  declare const patchHistoryPlugin: <T>(schema: Schema<T>, opts: PluginOptions<T>) => void;
74
60
 
75
- export { patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
61
+ export { em as patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
76
62
  export type { History, HookContext, Metadata, PatchContext, PatchEvent, PluginOptions, User };
package/dist/index.mjs CHANGED
@@ -1,16 +1,19 @@
1
- import _ from 'lodash';
2
- import EventEmitter from 'node:events';
1
+ import isEmpty from 'lodash/isEmpty';
3
2
  import ms from 'ms';
4
3
  import mongoose, { Schema, model } from 'mongoose';
4
+ import isArray from 'lodash/isArray';
5
5
  import jsonpatch from 'fast-json-patch';
6
+ import chunk from 'lodash/chunk';
7
+ import isFunction from 'lodash/isFunction';
6
8
  import omit from 'omit-deep';
9
+ import EventEmitter from 'node:events';
10
+ import cloneDeep from 'lodash/cloneDeep';
11
+ import forEach from 'lodash/forEach';
12
+ import isObjectLike from 'lodash/isObjectLike';
13
+ import keys from 'lodash/keys';
7
14
  import { assign } from 'power-assign';
8
15
  import { satisfies } from 'semver';
9
16
 
10
- class PatchEventEmitter extends EventEmitter {
11
- }
12
- const em = new PatchEventEmitter();
13
-
14
17
  const HistorySchema = new Schema(
15
18
  {
16
19
  op: {
@@ -90,6 +93,10 @@ const setPatchHistoryTTL = async (ttl) => {
90
93
  }
91
94
  };
92
95
 
96
+ class PatchEventEmitter extends EventEmitter {
97
+ }
98
+ const em = new PatchEventEmitter();
99
+
93
100
  function isPatchHistoryEnabled(opts, context) {
94
101
  return !opts.patchHistoryDisabled && !context.ignorePatchHistory;
95
102
  }
@@ -102,24 +109,24 @@ function getJsonOmit(opts, doc) {
102
109
  }
103
110
  function getObjectOmit(opts, doc) {
104
111
  if (opts.omit) {
105
- return omit(_.isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit);
112
+ return omit(isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit);
106
113
  }
107
114
  return doc;
108
115
  }
109
116
  async function getUser(opts, doc) {
110
- if (_.isFunction(opts.getUser)) {
117
+ if (isFunction(opts.getUser)) {
111
118
  return await opts.getUser(doc);
112
119
  }
113
120
  return void 0;
114
121
  }
115
122
  async function getReason(opts, doc) {
116
- if (_.isFunction(opts.getReason)) {
123
+ if (isFunction(opts.getReason)) {
117
124
  return await opts.getReason(doc);
118
125
  }
119
126
  return void 0;
120
127
  }
121
128
  async function getMetadata(opts, doc) {
122
- if (_.isFunction(opts.getMetadata)) {
129
+ if (isFunction(opts.getMetadata)) {
123
130
  return await opts.getMetadata(doc);
124
131
  }
125
132
  return void 0;
@@ -142,11 +149,11 @@ async function bulkPatch(opts, context, eventKey, docsKey) {
142
149
  const event = opts[eventKey];
143
150
  const docs = context[docsKey];
144
151
  const key = eventKey === "eventCreated" ? "doc" : "oldDoc";
145
- if (_.isEmpty(docs) || !event && !history) return;
146
- const chunks = _.chunk(docs, 1e3);
147
- for await (const chunk of chunks) {
152
+ if (isEmpty(docs) || !event && !history) return;
153
+ const chunks = chunk(docs, 1e3);
154
+ for (const chunk2 of chunks) {
148
155
  const bulk = [];
149
- for (const doc of chunk) {
156
+ for (const doc of chunk2) {
150
157
  emitEvent(context, event, { [key]: doc });
151
158
  if (history) {
152
159
  const [user, reason, metadata] = await getData(opts, doc);
@@ -167,7 +174,7 @@ async function bulkPatch(opts, context, eventKey, docsKey) {
167
174
  });
168
175
  }
169
176
  }
170
- if (history && !_.isEmpty(bulk)) {
177
+ if (history && !isEmpty(bulk)) {
171
178
  await HistoryModel.bulkWrite(bulk, { ordered: false }).catch((error) => {
172
179
  console.error(error.message);
173
180
  });
@@ -181,9 +188,9 @@ async function updatePatch(opts, context, current, original) {
181
188
  const history = isPatchHistoryEnabled(opts, context);
182
189
  const currentObject = getJsonOmit(opts, current);
183
190
  const originalObject = getJsonOmit(opts, original);
184
- if (_.isEmpty(originalObject) || _.isEmpty(currentObject)) return;
191
+ if (isEmpty(originalObject) || isEmpty(currentObject)) return;
185
192
  const patch = jsonpatch.compare(originalObject, currentObject, true);
186
- if (_.isEmpty(patch)) return;
193
+ if (isEmpty(patch)) return;
187
194
  emitEvent(context, opts.eventUpdated, { oldDoc: original, doc: current, patch });
188
195
  if (history) {
189
196
  let version = 0;
@@ -225,16 +232,16 @@ const deleteHooksInitialize = (schema, opts) => {
225
232
  };
226
233
  if (["remove", "deleteMany"].includes(this._context.op) && !options.single) {
227
234
  const docs = await model.find(filter).lean().exec();
228
- if (!_.isEmpty(docs)) {
235
+ if (!isEmpty(docs)) {
229
236
  this._context.deletedDocs = docs;
230
237
  }
231
238
  } else {
232
239
  const doc = await model.findOne(filter).lean().exec();
233
- if (!_.isEmpty(doc)) {
240
+ if (!isEmpty(doc)) {
234
241
  this._context.deletedDocs = [doc];
235
242
  }
236
243
  }
237
- if (opts.preDelete && _.isArray(this._context.deletedDocs) && !_.isEmpty(this._context.deletedDocs)) {
244
+ if (opts.preDelete && isArray(this._context.deletedDocs) && !isEmpty(this._context.deletedDocs)) {
238
245
  await opts.preDelete(this._context.deletedDocs);
239
246
  }
240
247
  });
@@ -270,7 +277,7 @@ const saveHooksInitialize = (schema, opts) => {
270
277
  const updateMethods = ["update", "updateOne", "replaceOne", "updateMany", "findOneAndUpdate", "findOneAndReplace", "findByIdAndUpdate"];
271
278
  const assignUpdate = (document, update, commands) => {
272
279
  let updated = assign(document.toObject(toObjectOptions), update);
273
- _.forEach(commands, (command) => {
280
+ forEach(commands, (command) => {
274
281
  try {
275
282
  updated = assign(updated, command);
276
283
  } catch {
@@ -283,11 +290,11 @@ const assignUpdate = (document, update, commands) => {
283
290
  const splitUpdateAndCommands = (updateQuery) => {
284
291
  let update = {};
285
292
  const commands = [];
286
- if (!_.isEmpty(updateQuery) && !_.isArray(updateQuery) && _.isObjectLike(updateQuery)) {
287
- update = _.cloneDeep(updateQuery);
288
- const keysWithDollarSign = _.keys(update).filter((key) => key.startsWith("$"));
289
- if (!_.isEmpty(keysWithDollarSign)) {
290
- _.forEach(keysWithDollarSign, (key) => {
293
+ if (!isEmpty(updateQuery) && !isArray(updateQuery) && isObjectLike(updateQuery)) {
294
+ update = cloneDeep(updateQuery);
295
+ const keysWithDollarSign = keys(update).filter((key) => key.startsWith("$"));
296
+ if (!isEmpty(keysWithDollarSign)) {
297
+ forEach(keysWithDollarSign, (key) => {
291
298
  commands.push({ [key]: update[key] });
292
299
  delete update[key];
293
300
  });
@@ -328,13 +335,13 @@ const updateHooksInitialize = (schema, opts) => {
328
335
  let current = null;
329
336
  const filter = this.getFilter();
330
337
  const combined = assignUpdate(model.hydrate({}), update, commands);
331
- if (!_.isEmpty(update) && !current) {
338
+ if (!isEmpty(update) && !current) {
332
339
  current = await model.findOne(update).sort("desc").lean().exec();
333
340
  }
334
- if (!_.isEmpty(combined) && !current) {
341
+ if (!isEmpty(combined) && !current) {
335
342
  current = await model.findOne(combined).sort("desc").lean().exec();
336
343
  }
337
- if (!_.isEmpty(filter) && !current) {
344
+ if (!isEmpty(filter) && !current) {
338
345
  console.log("filter", filter);
339
346
  current = await model.findOne(filter).sort("desc").lean().exec();
340
347
  }
@@ -353,7 +360,6 @@ if (isMongoose6) {
353
360
  }
354
361
 
355
362
  const remove = isMongooseLessThan7 ? "remove" : "deleteOne";
356
- const patchEventEmitter = em;
357
363
  const patchHistoryPlugin = function plugin(schema, opts) {
358
364
  saveHooksInitialize(schema, opts);
359
365
  updateHooksInitialize(schema, opts);
@@ -370,7 +376,7 @@ const patchHistoryPlugin = function plugin(schema, opts) {
370
376
  if (isMongooseLessThan8) {
371
377
  schema.pre(remove, { document: true, query: false }, async function() {
372
378
  const original = this.toObject(toObjectOptions);
373
- if (opts.preDelete && !_.isEmpty(original)) {
379
+ if (opts.preDelete && !isEmpty(original)) {
374
380
  await opts.preDelete([original]);
375
381
  }
376
382
  });
@@ -388,4 +394,4 @@ const patchHistoryPlugin = function plugin(schema, opts) {
388
394
  }
389
395
  };
390
396
 
391
- export { patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
397
+ export { em as patchEventEmitter, patchHistoryPlugin, setPatchHistoryTTL };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-patch-mongoose",
3
- "version": "2.9.2",
3
+ "version": "2.9.4",
4
4
  "description": "Patch history & events for mongoose models",
5
5
  "author": "ilovepixelart",
6
6
  "license": "MIT",
@@ -73,25 +73,25 @@
73
73
  "dependencies": {
74
74
  "@types/lodash": "4.17.20",
75
75
  "@types/ms": "2.1.0",
76
- "@types/semver": "7.7.0",
76
+ "@types/semver": "7.7.1",
77
77
  "fast-json-patch": "3.1.1",
78
78
  "lodash": "4.17.21",
79
79
  "ms": "2.1.3",
80
80
  "omit-deep": "0.3.0",
81
81
  "power-assign": "0.2.10",
82
- "semver": "7.7.2"
82
+ "semver": "7.7.3"
83
83
  },
84
84
  "devDependencies": {
85
- "@biomejs/biome": "2.2.0",
86
- "@types/node": "24.3.0",
87
- "@vitest/coverage-v8": "3.2.4",
88
- "mongodb-memory-server": "10.2.0",
89
- "mongoose": "8.17.1",
85
+ "@biomejs/biome": "2.3.1",
86
+ "@types/node": "24.9.1",
87
+ "@vitest/coverage-v8": "4.0.4",
88
+ "mongodb-memory-server": "10.2.3",
89
+ "mongoose": "8.19.2",
90
90
  "open-cli": "8.0.0",
91
- "pkgroll": "2.15.3",
91
+ "pkgroll": "2.20.1",
92
92
  "simple-git-hooks": "2.13.1",
93
- "typescript": "5.9.2",
94
- "vitest": "3.2.4"
93
+ "typescript": "5.9.3",
94
+ "vitest": "4.0.4"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "mongoose": ">=6.6.0 < 9"
@@ -1,4 +1,5 @@
1
- import _ from 'lodash'
1
+ import isArray from 'lodash/isArray'
2
+ import isEmpty from 'lodash/isEmpty'
2
3
  import { isHookIgnored } from '../helpers'
3
4
  import { deletePatch } from '../patch'
4
5
 
@@ -25,17 +26,17 @@ export const deleteHooksInitialize = <T>(schema: Schema<T>, opts: PluginOptions<
25
26
 
26
27
  if (['remove', 'deleteMany'].includes(this._context.op) && !options.single) {
27
28
  const docs = await model.find<T>(filter).lean().exec()
28
- if (!_.isEmpty(docs)) {
29
+ if (!isEmpty(docs)) {
29
30
  this._context.deletedDocs = docs as HydratedDocument<T>[]
30
31
  }
31
32
  } else {
32
33
  const doc = await model.findOne<T>(filter).lean().exec()
33
- if (!_.isEmpty(doc)) {
34
+ if (!isEmpty(doc)) {
34
35
  this._context.deletedDocs = [doc] as HydratedDocument<T>[]
35
36
  }
36
37
  }
37
38
 
38
- if (opts.preDelete && _.isArray(this._context.deletedDocs) && !_.isEmpty(this._context.deletedDocs)) {
39
+ if (opts.preDelete && isArray(this._context.deletedDocs) && !isEmpty(this._context.deletedDocs)) {
39
40
  await opts.preDelete(this._context.deletedDocs)
40
41
  }
41
42
  })
@@ -1,4 +1,9 @@
1
- import _ from 'lodash'
1
+ import cloneDeep from 'lodash/cloneDeep'
2
+ import forEach from 'lodash/forEach'
3
+ import isArray from 'lodash/isArray'
4
+ import isEmpty from 'lodash/isEmpty'
5
+ import isObjectLike from 'lodash/isObjectLike'
6
+ import keys from 'lodash/keys'
2
7
  import { assign } from 'power-assign'
3
8
  import { isHookIgnored, toObjectOptions } from '../helpers'
4
9
  import { createPatch, updatePatch } from '../patch'
@@ -11,7 +16,7 @@ const updateMethods = ['update', 'updateOne', 'replaceOne', 'updateMany', 'findO
11
16
  export const assignUpdate = <T>(document: HydratedDocument<T>, update: UpdateQuery<T>, commands: Record<string, unknown>[]): HydratedDocument<T> => {
12
17
  let updated = assign(document.toObject(toObjectOptions), update)
13
18
  // Try catch not working for of loop, keep it as is
14
- _.forEach(commands, (command) => {
19
+ forEach(commands, (command) => {
15
20
  try {
16
21
  updated = assign(updated, command)
17
22
  } catch {
@@ -28,11 +33,11 @@ export const splitUpdateAndCommands = <T>(updateQuery: UpdateWithAggregationPipe
28
33
  let update: UpdateQuery<T> = {}
29
34
  const commands: Record<string, unknown>[] = []
30
35
 
31
- if (!_.isEmpty(updateQuery) && !_.isArray(updateQuery) && _.isObjectLike(updateQuery)) {
32
- update = _.cloneDeep(updateQuery)
33
- const keysWithDollarSign = _.keys(update).filter((key) => key.startsWith('$'))
34
- if (!_.isEmpty(keysWithDollarSign)) {
35
- _.forEach(keysWithDollarSign, (key) => {
36
+ if (!isEmpty(updateQuery) && !isArray(updateQuery) && isObjectLike(updateQuery)) {
37
+ update = cloneDeep(updateQuery)
38
+ const keysWithDollarSign = keys(update).filter((key) => key.startsWith('$'))
39
+ if (!isEmpty(keysWithDollarSign)) {
40
+ forEach(keysWithDollarSign, (key) => {
36
41
  commands.push({ [key]: update[key] as unknown })
37
42
  delete update[key]
38
43
  })
@@ -83,15 +88,15 @@ export const updateHooksInitialize = <T>(schema: Schema<T>, opts: PluginOptions<
83
88
  let current: HydratedDocument<T> | null = null
84
89
  const filter = this.getFilter()
85
90
  const combined = assignUpdate(model.hydrate({}), update, commands)
86
- if (!_.isEmpty(update) && !current) {
91
+ if (!isEmpty(update) && !current) {
87
92
  current = (await model.findOne(update).sort('desc').lean().exec()) as HydratedDocument<T>
88
93
  }
89
94
 
90
- if (!_.isEmpty(combined) && !current) {
95
+ if (!isEmpty(combined) && !current) {
91
96
  current = (await model.findOne(combined).sort('desc').lean().exec()) as HydratedDocument<T>
92
97
  }
93
98
 
94
- if (!_.isEmpty(filter) && !current) {
99
+ if (!isEmpty(filter) && !current) {
95
100
  console.log('filter', filter)
96
101
  current = (await model.findOne(filter).sort('desc').lean().exec()) as HydratedDocument<T>
97
102
  }
package/src/index.ts CHANGED
@@ -1,5 +1,4 @@
1
- import _ from 'lodash'
2
- import em from './em'
1
+ import isEmpty from 'lodash/isEmpty'
3
2
  import { toObjectOptions } from './helpers'
4
3
  import { deleteHooksInitialize } from './hooks/delete-hooks'
5
4
  import { saveHooksInitialize } from './hooks/save-hooks'
@@ -15,8 +14,7 @@ const remove = isMongooseLessThan7 ? 'remove' : 'deleteOne'
15
14
  /**
16
15
  * @description Event emitter for patch operations.
17
16
  */
18
- export const patchEventEmitter = em
19
-
17
+ export { default as patchEventEmitter } from './em'
20
18
  export { setPatchHistoryTTL } from './helpers'
21
19
  export * from './types'
22
20
 
@@ -65,7 +63,7 @@ export const patchHistoryPlugin = function plugin<T>(schema: Schema<T>, opts: Pl
65
63
  // @ts-expect-error - Mongoose 7 and below
66
64
  const original = this.toObject(toObjectOptions) as HydratedDocument<T>
67
65
 
68
- if (opts.preDelete && !_.isEmpty(original)) {
66
+ if (opts.preDelete && !isEmpty(original)) {
69
67
  await opts.preDelete([original])
70
68
  }
71
69
  })
package/src/patch.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import jsonpatch from 'fast-json-patch'
2
- import _ from 'lodash'
2
+ import chunk from 'lodash/chunk'
3
+ import isEmpty from 'lodash/isEmpty'
4
+ import isFunction from 'lodash/isFunction'
3
5
  import omit from 'omit-deep'
4
6
  import em from './em'
5
7
  import { HistoryModel } from './model'
@@ -23,28 +25,28 @@ export function getJsonOmit<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>)
23
25
 
24
26
  export function getObjectOmit<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Partial<T> {
25
27
  if (opts.omit) {
26
- return omit(_.isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit)
28
+ return omit(isFunction(doc?.toObject) ? doc.toObject() : doc, opts.omit)
27
29
  }
28
30
 
29
31
  return doc
30
32
  }
31
33
 
32
34
  export async function getUser<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<User | undefined> {
33
- if (_.isFunction(opts.getUser)) {
35
+ if (isFunction(opts.getUser)) {
34
36
  return await opts.getUser(doc)
35
37
  }
36
38
  return undefined
37
39
  }
38
40
 
39
41
  export async function getReason<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<string | undefined> {
40
- if (_.isFunction(opts.getReason)) {
42
+ if (isFunction(opts.getReason)) {
41
43
  return await opts.getReason(doc)
42
44
  }
43
45
  return undefined
44
46
  }
45
47
 
46
48
  export async function getMetadata<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<Metadata | undefined> {
47
- if (_.isFunction(opts.getMetadata)) {
49
+ if (isFunction(opts.getMetadata)) {
48
50
  return await opts.getMetadata(doc)
49
51
  }
50
52
  return undefined
@@ -72,10 +74,10 @@ export async function bulkPatch<T>(opts: PluginOptions<T>, context: PatchContext
72
74
  const docs = context[docsKey]
73
75
  const key = eventKey === 'eventCreated' ? 'doc' : 'oldDoc'
74
76
 
75
- if (_.isEmpty(docs) || (!event && !history)) return
77
+ if (isEmpty(docs) || (!event && !history)) return
76
78
 
77
- const chunks = _.chunk(docs, 1000)
78
- for await (const chunk of chunks) {
79
+ const chunks = chunk(docs, 1000)
80
+ for (const chunk of chunks) {
79
81
  const bulk = []
80
82
 
81
83
  for (const doc of chunk) {
@@ -101,7 +103,7 @@ export async function bulkPatch<T>(opts: PluginOptions<T>, context: PatchContext
101
103
  }
102
104
  }
103
105
 
104
- if (history && !_.isEmpty(bulk)) {
106
+ if (history && !isEmpty(bulk)) {
105
107
  await HistoryModel.bulkWrite(bulk, { ordered: false }).catch((error: MongooseError) => {
106
108
  console.error(error.message)
107
109
  })
@@ -118,10 +120,10 @@ export async function updatePatch<T>(opts: PluginOptions<T>, context: PatchConte
118
120
 
119
121
  const currentObject = getJsonOmit(opts, current)
120
122
  const originalObject = getJsonOmit(opts, original)
121
- if (_.isEmpty(originalObject) || _.isEmpty(currentObject)) return
123
+ if (isEmpty(originalObject) || isEmpty(currentObject)) return
122
124
 
123
125
  const patch = jsonpatch.compare(originalObject, currentObject, true)
124
- if (_.isEmpty(patch)) return
126
+ if (isEmpty(patch)) return
125
127
 
126
128
  emitEvent(context, opts.eventUpdated, { oldDoc: original, doc: current, patch })
127
129
 
@@ -38,7 +38,7 @@ describe('patch tests', () => {
38
38
  })
39
39
 
40
40
  afterEach(async () => {
41
- vi.restoreAllMocks()
41
+ vi.clearAllMocks()
42
42
  })
43
43
 
44
44
  describe('getObjects', () => {
@@ -35,7 +35,7 @@ describe('plugin - event created & patch history disabled', () => {
35
35
  })
36
36
 
37
37
  afterEach(() => {
38
- vi.restoreAllMocks()
38
+ vi.clearAllMocks()
39
39
  })
40
40
 
41
41
  describe('normal cases', () => {
@@ -39,7 +39,7 @@ describe('plugin - global', () => {
39
39
  })
40
40
 
41
41
  afterEach(async () => {
42
- vi.restoreAllMocks()
42
+ vi.clearAllMocks()
43
43
  })
44
44
 
45
45
  it('should save array', async () => {
package/vite.config.mts CHANGED
@@ -6,8 +6,18 @@ export default defineConfig({
6
6
  name: 'node',
7
7
  environment: 'node',
8
8
  coverage: {
9
- reporter: ['lcov'],
9
+ provider: 'v8',
10
+ reporter: ['text', 'json', 'html', 'lcov'],
10
11
  include: ['src/**/*.ts'],
12
+ exclude: [
13
+ 'node_modules/**',
14
+ 'dist/**',
15
+ 'coverage/**',
16
+ '**/*.d.ts',
17
+ '**/*.config.*',
18
+ '**/tests/**',
19
+ 'examples/**',
20
+ ],
11
21
  },
12
22
  },
13
23
  })