ts-patch-mongoose 1.1.4 → 1.1.5
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/.eslintrc +8 -3
- package/dist/cjs/patch.js +88 -0
- package/dist/cjs/patch.js.map +1 -0
- package/dist/cjs/plugin.js +50 -146
- package/dist/cjs/plugin.js.map +1 -1
- package/dist/cjs/types/interfaces/IPluginOptions.d.ts +1 -1
- package/dist/cjs/types/interfaces/IPluginOptions.d.ts.map +1 -1
- package/dist/cjs/types/patch.d.ts +12 -0
- package/dist/cjs/types/patch.d.ts.map +1 -0
- package/dist/cjs/types/plugin.d.ts.map +1 -1
- package/dist/esm/patch.js +79 -0
- package/dist/esm/patch.js.map +1 -0
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/plugin.mjs +47 -143
- package/dist/esm/types/interfaces/IPluginOptions.d.ts +1 -1
- package/dist/esm/types/interfaces/IPluginOptions.d.ts.map +1 -1
- package/dist/esm/types/patch.d.ts +12 -0
- package/dist/esm/types/patch.d.ts.map +1 -0
- package/dist/esm/types/plugin.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/interfaces/IPluginOptions.ts +1 -1
- package/src/patch.ts +101 -0
- package/src/plugin.ts +55 -155
- package/tests/em.test.ts +5 -5
- package/tests/patch.test.ts +141 -0
- package/tests/plugin-callback.test.ts +50 -0
- package/tests/plugin-event-deleted.test.ts +20 -13
package/src/plugin.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import _ from 'lodash'
|
|
2
|
-
import omit from 'omit-deep'
|
|
3
|
-
import jsonpatch from 'fast-json-patch'
|
|
4
2
|
import { assign } from 'power-assign'
|
|
5
3
|
|
|
6
|
-
import type {
|
|
4
|
+
import type { HydratedDocument, Model, MongooseQueryMiddleware, Schema, ToObjectOptions } from 'mongoose'
|
|
7
5
|
|
|
8
6
|
import type IPluginOptions from './interfaces/IPluginOptions'
|
|
9
7
|
import type IContext from './interfaces/IContext'
|
|
10
8
|
import type IHookContext from './interfaces/IHookContext'
|
|
11
9
|
|
|
10
|
+
import { createPatch, updatePatch, deletePatch } from './patch'
|
|
12
11
|
import em from './em'
|
|
13
|
-
import History from './models/History'
|
|
14
12
|
|
|
15
13
|
const options = {
|
|
16
14
|
document: false,
|
|
17
15
|
query: true
|
|
18
16
|
}
|
|
19
17
|
|
|
18
|
+
const toObjectOptions: ToObjectOptions = {
|
|
19
|
+
depopulate: true,
|
|
20
|
+
virtuals: false
|
|
21
|
+
}
|
|
22
|
+
|
|
20
23
|
const updateMethods = [
|
|
21
24
|
'update',
|
|
22
25
|
'updateOne',
|
|
@@ -37,98 +40,6 @@ const deleteMethods = [
|
|
|
37
40
|
'deleteMany'
|
|
38
41
|
]
|
|
39
42
|
|
|
40
|
-
function getObjects<T> (opts: IPluginOptions<T>, current: HydratedDocument<T>, original: HydratedDocument<T>): { currentObject: Partial<T>, originalObject: Partial<T> } {
|
|
41
|
-
let currentObject = JSON.parse(JSON.stringify(current)) as Partial<T>
|
|
42
|
-
let originalObject = JSON.parse(JSON.stringify(original)) as Partial<T>
|
|
43
|
-
|
|
44
|
-
if (opts.omit) {
|
|
45
|
-
currentObject = omit(currentObject, opts.omit)
|
|
46
|
-
originalObject = omit(originalObject, opts.omit)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return { currentObject, originalObject }
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function updatePatch<T> (opts: IPluginOptions<T>, context: IContext<T>, current: HydratedDocument<T>, original: HydratedDocument<T>): Promise<void> {
|
|
53
|
-
const { currentObject, originalObject } = getObjects(opts, current, original)
|
|
54
|
-
|
|
55
|
-
if (_.isEmpty(originalObject) || _.isEmpty(currentObject)) return
|
|
56
|
-
|
|
57
|
-
const patch = jsonpatch.compare(originalObject, currentObject, true)
|
|
58
|
-
|
|
59
|
-
if (_.isEmpty(patch)) return
|
|
60
|
-
|
|
61
|
-
if (opts.eventUpdated) {
|
|
62
|
-
em.emit(opts.eventUpdated, { oldDoc: original, doc: current, patch })
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (opts.patchHistoryDisabled) return
|
|
66
|
-
|
|
67
|
-
let version = 0
|
|
68
|
-
|
|
69
|
-
const lastHistory = await History.findOne({ collectionId: original._id as Types.ObjectId }).sort('-version').exec()
|
|
70
|
-
|
|
71
|
-
if (lastHistory && lastHistory.version >= 0) {
|
|
72
|
-
version = lastHistory.version + 1
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
await History.create({
|
|
76
|
-
op: context.op,
|
|
77
|
-
modelName: context.modelName,
|
|
78
|
-
collectionName: context.collectionName,
|
|
79
|
-
collectionId: original._id as Types.ObjectId,
|
|
80
|
-
patch,
|
|
81
|
-
version
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function bulkPatch<T> (opts: IPluginOptions<T>, context: IContext<T>, eventKey: 'eventCreated' | 'eventDeleted', docsKey: 'createdDocs' | 'deletedDocs'): Promise<void> {
|
|
86
|
-
const event = opts[eventKey]
|
|
87
|
-
const docs = context[docsKey]
|
|
88
|
-
const key = eventKey === 'eventCreated' ? 'doc' : 'oldDoc'
|
|
89
|
-
|
|
90
|
-
if (_.isEmpty(docs) || (!event && opts.patchHistoryDisabled)) return
|
|
91
|
-
|
|
92
|
-
const chunks = _.chunk(docs, 1000)
|
|
93
|
-
for await (const chunk of chunks) {
|
|
94
|
-
const bulk = []
|
|
95
|
-
for (const doc of chunk) {
|
|
96
|
-
if (event) em.emit(event, { [key]: doc })
|
|
97
|
-
|
|
98
|
-
if (!opts.patchHistoryDisabled) {
|
|
99
|
-
bulk.push({
|
|
100
|
-
insertOne: {
|
|
101
|
-
document: {
|
|
102
|
-
op: context.op,
|
|
103
|
-
modelName: context.modelName,
|
|
104
|
-
collectionName: context.collectionName,
|
|
105
|
-
collectionId: doc._id as Types.ObjectId,
|
|
106
|
-
doc,
|
|
107
|
-
version: 0
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!opts.patchHistoryDisabled) {
|
|
115
|
-
await History
|
|
116
|
-
.bulkWrite(bulk, { ordered: false })
|
|
117
|
-
.catch((err: MongooseError) => {
|
|
118
|
-
console.error(err)
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function createPatch<T> (opts: IPluginOptions<T>, context: IContext<T>): Promise<void> {
|
|
125
|
-
await bulkPatch(opts, context, 'eventCreated', 'createdDocs')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function deletePatch<T> (opts: IPluginOptions<T>, context: IContext<T>): Promise<void> {
|
|
129
|
-
await bulkPatch(opts, context, 'eventDeleted', 'deletedDocs')
|
|
130
|
-
}
|
|
131
|
-
|
|
132
43
|
/**
|
|
133
44
|
* @description Patch patch event emitter
|
|
134
45
|
*/
|
|
@@ -142,7 +53,7 @@ export const patchEventEmitter = em
|
|
|
142
53
|
*/
|
|
143
54
|
export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: IPluginOptions<T>): void {
|
|
144
55
|
schema.pre('save', async function (next) {
|
|
145
|
-
const current = this.toObject(
|
|
56
|
+
const current = this.toObject(toObjectOptions) as HydratedDocument<T>
|
|
146
57
|
const model = this.constructor as Model<T>
|
|
147
58
|
|
|
148
59
|
const context: IContext<T> = {
|
|
@@ -152,19 +63,16 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
152
63
|
createdDocs: [current]
|
|
153
64
|
}
|
|
154
65
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
await updatePatch(opts, context, current, original)
|
|
162
|
-
}
|
|
66
|
+
if (this.isNew) {
|
|
67
|
+
await createPatch(opts, context)
|
|
68
|
+
} else {
|
|
69
|
+
const original = await model.findById(current._id).exec()
|
|
70
|
+
if (original) {
|
|
71
|
+
await updatePatch(opts, context, current, original)
|
|
163
72
|
}
|
|
164
|
-
next()
|
|
165
|
-
} catch (error) {
|
|
166
|
-
next(error as CallbackError)
|
|
167
73
|
}
|
|
74
|
+
|
|
75
|
+
next()
|
|
168
76
|
})
|
|
169
77
|
|
|
170
78
|
schema.post('insertMany', async function (docs) {
|
|
@@ -193,54 +101,50 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
193
101
|
isNew: options.upsert && count === 0
|
|
194
102
|
}
|
|
195
103
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
delete update[key]
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
const cursor = this.model.find<HydratedDocument<T>>(filter).cursor()
|
|
206
|
-
await cursor.eachAsync(async (doc) => {
|
|
207
|
-
let current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
208
|
-
const original = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
209
|
-
current = assign(current, update)
|
|
210
|
-
_.forEach(commands, (command) => {
|
|
211
|
-
try {
|
|
212
|
-
current = assign(current, command)
|
|
213
|
-
} catch (error) {
|
|
214
|
-
// we catch assign keys that are not implemented
|
|
215
|
-
}
|
|
216
|
-
})
|
|
217
|
-
await updatePatch(opts, this._context, current, original)
|
|
104
|
+
const keys = _.keys(update).filter((key) => key.startsWith('$'))
|
|
105
|
+
if (update && !_.isEmpty(keys)) {
|
|
106
|
+
_.forEach(keys, (key) => {
|
|
107
|
+
commands.push({ [key]: update[key] })
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
109
|
+
delete update[key]
|
|
218
110
|
})
|
|
219
|
-
next()
|
|
220
|
-
} catch (error) {
|
|
221
|
-
next(error as CallbackError)
|
|
222
111
|
}
|
|
112
|
+
|
|
113
|
+
const cursor = this.model.find<HydratedDocument<T>>(filter).cursor()
|
|
114
|
+
await cursor.eachAsync(async (doc) => {
|
|
115
|
+
let current = doc.toObject(toObjectOptions) as HydratedDocument<T>
|
|
116
|
+
const original = doc.toObject(toObjectOptions) as HydratedDocument<T>
|
|
117
|
+
|
|
118
|
+
current = assign(current, update)
|
|
119
|
+
_.forEach(commands, (command) => {
|
|
120
|
+
try {
|
|
121
|
+
current = assign(current, command)
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// we catch assign keys that are not implemented
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
await updatePatch(opts, this._context, current, original)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
next()
|
|
223
131
|
})
|
|
224
132
|
|
|
225
133
|
schema.post(updateMethods as MongooseQueryMiddleware[], async function (this: IHookContext<T>) {
|
|
226
134
|
const update = this.getUpdate()
|
|
135
|
+
if (!update || !this._context.isNew) return
|
|
136
|
+
|
|
137
|
+
const found = await this.model.findOne<HydratedDocument<T>>(update).exec()
|
|
138
|
+
if (found) {
|
|
139
|
+
const current = found.toObject(toObjectOptions) as HydratedDocument<T>
|
|
140
|
+
this._context.createdDocs = [current]
|
|
227
141
|
|
|
228
|
-
if (update && this._context.isNew) {
|
|
229
|
-
const cursor = this.model.findOne<HydratedDocument<T>>(update).cursor()
|
|
230
|
-
await cursor.eachAsync((doc) => {
|
|
231
|
-
const current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
232
|
-
if (this._context.createdDocs) {
|
|
233
|
-
this._context.createdDocs.push(current)
|
|
234
|
-
} else {
|
|
235
|
-
this._context.createdDocs = [current]
|
|
236
|
-
}
|
|
237
|
-
})
|
|
238
142
|
await createPatch(opts, this._context)
|
|
239
143
|
}
|
|
240
144
|
})
|
|
241
145
|
|
|
242
|
-
schema.
|
|
243
|
-
const original = this.toObject(
|
|
146
|
+
schema.post('remove', async function (this: HydratedDocument<T>) {
|
|
147
|
+
const original = this.toObject(toObjectOptions)
|
|
244
148
|
const model = this.constructor as Model<T>
|
|
245
149
|
|
|
246
150
|
const context: IContext<T> = {
|
|
@@ -249,15 +153,11 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
249
153
|
collectionName: opts.collectionName ?? model.collection.collectionName
|
|
250
154
|
}
|
|
251
155
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
em.emit(opts.eventDeleted, { oldDoc: original })
|
|
255
|
-
}
|
|
256
|
-
await deletePatch(opts, context)
|
|
257
|
-
next()
|
|
258
|
-
} catch (error) {
|
|
259
|
-
next(error as CallbackError)
|
|
156
|
+
if (opts.eventDeleted) {
|
|
157
|
+
em.emit(opts.eventDeleted, { oldDoc: original })
|
|
260
158
|
}
|
|
159
|
+
|
|
160
|
+
await deletePatch(opts, context)
|
|
261
161
|
})
|
|
262
162
|
|
|
263
163
|
schema.pre(deleteMethods as MongooseQueryMiddleware[], options, async function (this: IHookContext<T>, next) {
|
|
@@ -285,8 +185,8 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
285
185
|
}
|
|
286
186
|
}
|
|
287
187
|
|
|
288
|
-
if (opts.
|
|
289
|
-
await opts.
|
|
188
|
+
if (opts.preDeleteCallback && _.isArray(this._context.deletedDocs) && !_.isEmpty(this._context.deletedDocs)) {
|
|
189
|
+
await opts.preDeleteCallback(this._context.deletedDocs)
|
|
290
190
|
}
|
|
291
191
|
|
|
292
192
|
next()
|
package/tests/em.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { patchEventEmitter } from '../src/plugin'
|
|
2
2
|
|
|
3
3
|
describe('em', () => {
|
|
4
4
|
it('should subscribe and count', async () => {
|
|
@@ -6,11 +6,11 @@ describe('em', () => {
|
|
|
6
6
|
const fn = () => {
|
|
7
7
|
count++
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
patchEventEmitter.on('test', fn)
|
|
10
|
+
patchEventEmitter.emit('test')
|
|
11
11
|
expect(count).toBe(1)
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
patchEventEmitter.off('test', fn)
|
|
13
|
+
patchEventEmitter.emit('test')
|
|
14
14
|
expect(count).toBe(1)
|
|
15
15
|
})
|
|
16
16
|
})
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import mongoose, { model } from 'mongoose'
|
|
2
|
+
|
|
3
|
+
import { getObjects, bulkPatch, updatePatch } from '../src/patch'
|
|
4
|
+
import { patchHistoryPlugin } from '../src/plugin'
|
|
5
|
+
|
|
6
|
+
import UserSchema from './schemas/UserSchema'
|
|
7
|
+
|
|
8
|
+
import { USER_DELETED } from './constants/events'
|
|
9
|
+
|
|
10
|
+
import type { HydratedDocument } from 'mongoose'
|
|
11
|
+
import type IPluginOptions from '../src/interfaces/IPluginOptions'
|
|
12
|
+
import type IUser from './interfaces/IUser'
|
|
13
|
+
import type IContext from '../src/interfaces/IContext'
|
|
14
|
+
|
|
15
|
+
import em from '../src/em'
|
|
16
|
+
|
|
17
|
+
jest.mock('../src/em', () => {
|
|
18
|
+
return {
|
|
19
|
+
emit: jest.fn()
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('patch tests', () => {
|
|
24
|
+
const uri = `${globalThis.__MONGO_URI__}${globalThis.__MONGO_DB_NAME__}`
|
|
25
|
+
|
|
26
|
+
UserSchema.plugin(patchHistoryPlugin, {
|
|
27
|
+
eventDeleted: USER_DELETED,
|
|
28
|
+
patchHistoryDisabled: true
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const User = model('User', UserSchema)
|
|
32
|
+
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
await mongoose.connect(uri)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
afterAll(async () => {
|
|
38
|
+
await mongoose.connection.close()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
beforeEach(async () => {
|
|
42
|
+
await mongoose.connection.collection('tests').deleteMany({})
|
|
43
|
+
await mongoose.connection.collection('patches').deleteMany({})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('getObjects', () => {
|
|
47
|
+
it('should omit properties from currentObject and originalObject based on the opts', async () => {
|
|
48
|
+
const original = await User.create({ name: 'John', role: 'user' })
|
|
49
|
+
const current = await User.create({ name: 'John', role: 'admin' })
|
|
50
|
+
|
|
51
|
+
const pluginOptions = {
|
|
52
|
+
omit: ['createdAt']
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const { currentObject, originalObject } = getObjects(pluginOptions, current, original)
|
|
56
|
+
|
|
57
|
+
expect(currentObject.name).toBe('John')
|
|
58
|
+
expect(currentObject.role).toBe('admin')
|
|
59
|
+
expect(currentObject.createdAt).toBeUndefined()
|
|
60
|
+
|
|
61
|
+
expect(originalObject.name).toBe('John')
|
|
62
|
+
expect(originalObject.role).toBe('user')
|
|
63
|
+
expect(originalObject.createdAt).toBeUndefined()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should not omit properties from currentObject and originalObject if opts is empty', async () => {
|
|
67
|
+
const original = await User.create({ name: 'John', role: 'user' })
|
|
68
|
+
const current = await User.create({ name: 'John', role: 'admin' })
|
|
69
|
+
|
|
70
|
+
const { currentObject, originalObject } = getObjects({}, current, original)
|
|
71
|
+
|
|
72
|
+
expect(currentObject.name).toBe('John')
|
|
73
|
+
expect(currentObject.role).toBe('admin')
|
|
74
|
+
expect(currentObject.createdAt).toBeDefined()
|
|
75
|
+
|
|
76
|
+
expect(originalObject.name).toBe('John')
|
|
77
|
+
expect(originalObject.role).toBe('user')
|
|
78
|
+
expect(originalObject.createdAt).toBeDefined()
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe('bulkPatch', () => {
|
|
83
|
+
it('should emit eventDeleted if opts.patchHistoryDisabled is false', async () => {
|
|
84
|
+
const doc = new User({ name: 'John', role: 'user' })
|
|
85
|
+
|
|
86
|
+
const pluginOptions: IPluginOptions<IUser> = {
|
|
87
|
+
eventDeleted: USER_DELETED,
|
|
88
|
+
patchHistoryDisabled: false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const context: IContext<IUser> = {
|
|
92
|
+
op: 'deleteOne',
|
|
93
|
+
modelName: 'User',
|
|
94
|
+
collectionName: 'users',
|
|
95
|
+
deletedDocs: [doc]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await bulkPatch(pluginOptions, context, 'eventDeleted', 'deletedDocs')
|
|
99
|
+
expect(em.emit).toHaveBeenCalled()
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should emit eventDeleted if opts.patchHistoryDisabled is true', async () => {
|
|
103
|
+
const doc = new User({ name: 'John', role: 'user' })
|
|
104
|
+
|
|
105
|
+
const pluginOptions: IPluginOptions<IUser> = {
|
|
106
|
+
eventDeleted: USER_DELETED,
|
|
107
|
+
patchHistoryDisabled: true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const context: IContext<IUser> = {
|
|
111
|
+
op: 'deleteOne',
|
|
112
|
+
modelName: 'User',
|
|
113
|
+
collectionName: 'users',
|
|
114
|
+
deletedDocs: [doc]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await bulkPatch(pluginOptions, context, 'eventDeleted', 'deletedDocs')
|
|
118
|
+
expect(em.emit).toHaveBeenCalled()
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('updatePatch', () => {
|
|
123
|
+
it('should return if one object is empty', async () => {
|
|
124
|
+
const current = await User.create({ name: 'John', role: 'user' })
|
|
125
|
+
|
|
126
|
+
const pluginOptions: IPluginOptions<IUser> = {
|
|
127
|
+
eventDeleted: USER_DELETED,
|
|
128
|
+
patchHistoryDisabled: true
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const context: IContext<IUser> = {
|
|
132
|
+
op: 'updateOne',
|
|
133
|
+
modelName: 'User',
|
|
134
|
+
collectionName: 'users'
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await updatePatch(pluginOptions, context, current, {} as HydratedDocument<IUser>)
|
|
138
|
+
expect(em.emit).not.toHaveBeenCalled()
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import mongoose, { model } from 'mongoose'
|
|
2
|
+
|
|
3
|
+
import UserSchema from './schemas/UserSchema'
|
|
4
|
+
import { patchHistoryPlugin } from '../src/plugin'
|
|
5
|
+
|
|
6
|
+
import { USER_CREATED } from './constants/events'
|
|
7
|
+
|
|
8
|
+
const preDeleteCallbackMock = jest.fn()
|
|
9
|
+
|
|
10
|
+
describe('plugin - event created & patch history disabled', () => {
|
|
11
|
+
const uri = `${globalThis.__MONGO_URI__}${globalThis.__MONGO_DB_NAME__}`
|
|
12
|
+
|
|
13
|
+
UserSchema.plugin(patchHistoryPlugin, {
|
|
14
|
+
eventCreated: USER_CREATED,
|
|
15
|
+
patchHistoryDisabled: true,
|
|
16
|
+
preDeleteCallback: preDeleteCallbackMock
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const User = model('User', UserSchema)
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
await mongoose.connect(uri)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
afterAll(async () => {
|
|
26
|
+
await mongoose.connection.close()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
beforeEach(async () => {
|
|
30
|
+
await mongoose.connection.collection('users').deleteMany({})
|
|
31
|
+
await mongoose.connection.collection('history').deleteMany({})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should deleteMany and execute preDeleteCallback', async () => {
|
|
35
|
+
await User.create([
|
|
36
|
+
{ name: 'John', role: 'user' },
|
|
37
|
+
{ name: 'Jane', role: 'user' },
|
|
38
|
+
{ name: 'Jack', role: 'user' }
|
|
39
|
+
])
|
|
40
|
+
|
|
41
|
+
const users = await User.find({})
|
|
42
|
+
expect(users).toHaveLength(3)
|
|
43
|
+
|
|
44
|
+
const [john, jane, jack] = users
|
|
45
|
+
|
|
46
|
+
await User.deleteMany({ role: 'user' })
|
|
47
|
+
expect(preDeleteCallbackMock).toHaveBeenCalledTimes(1)
|
|
48
|
+
expect(preDeleteCallbackMock).toHaveBeenCalledWith([john, jane, jack])
|
|
49
|
+
})
|
|
50
|
+
})
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import mongoose, { model } from 'mongoose'
|
|
2
2
|
|
|
3
|
+
import type { ToObjectOptions } from 'mongoose'
|
|
4
|
+
|
|
3
5
|
import UserSchema from './schemas/UserSchema'
|
|
4
6
|
import { patchHistoryPlugin } from '../src/plugin'
|
|
5
7
|
import History from '../src/models/History'
|
|
@@ -13,6 +15,11 @@ jest.mock('../src/em', () => {
|
|
|
13
15
|
}
|
|
14
16
|
})
|
|
15
17
|
|
|
18
|
+
const toObjectOptions: ToObjectOptions = {
|
|
19
|
+
depopulate: true,
|
|
20
|
+
virtuals: false
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
describe('plugin - event delete & patch history disabled', () => {
|
|
17
24
|
const uri = `${globalThis.__MONGO_URI__}${globalThis.__MONGO_DB_NAME__}`
|
|
18
25
|
|
|
@@ -45,7 +52,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
45
52
|
|
|
46
53
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
47
54
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
48
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
55
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
49
56
|
})
|
|
50
57
|
})
|
|
51
58
|
|
|
@@ -69,10 +76,10 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
69
76
|
|
|
70
77
|
expect(em.emit).toHaveBeenCalledTimes(2)
|
|
71
78
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
72
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
79
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
73
80
|
})
|
|
74
81
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
75
|
-
oldDoc: expect.objectContaining(alice.toObject(
|
|
82
|
+
oldDoc: expect.objectContaining(alice.toObject(toObjectOptions))
|
|
76
83
|
})
|
|
77
84
|
})
|
|
78
85
|
|
|
@@ -92,7 +99,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
92
99
|
|
|
93
100
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
94
101
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
95
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
102
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
96
103
|
})
|
|
97
104
|
})
|
|
98
105
|
|
|
@@ -112,7 +119,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
112
119
|
|
|
113
120
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
114
121
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
115
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
122
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
116
123
|
})
|
|
117
124
|
})
|
|
118
125
|
|
|
@@ -132,7 +139,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
132
139
|
|
|
133
140
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
134
141
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
135
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
142
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
136
143
|
})
|
|
137
144
|
})
|
|
138
145
|
|
|
@@ -152,7 +159,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
152
159
|
|
|
153
160
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
154
161
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
155
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
162
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
156
163
|
})
|
|
157
164
|
})
|
|
158
165
|
|
|
@@ -172,7 +179,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
172
179
|
|
|
173
180
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
174
181
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
175
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
182
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
176
183
|
})
|
|
177
184
|
})
|
|
178
185
|
|
|
@@ -192,7 +199,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
192
199
|
|
|
193
200
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
194
201
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
195
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
202
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
196
203
|
})
|
|
197
204
|
})
|
|
198
205
|
|
|
@@ -212,10 +219,10 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
212
219
|
|
|
213
220
|
expect(em.emit).toHaveBeenCalledTimes(2)
|
|
214
221
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
215
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
222
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
216
223
|
})
|
|
217
224
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
218
|
-
oldDoc: expect.objectContaining(alice.toObject(
|
|
225
|
+
oldDoc: expect.objectContaining(alice.toObject(toObjectOptions))
|
|
219
226
|
})
|
|
220
227
|
})
|
|
221
228
|
|
|
@@ -235,7 +242,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
235
242
|
|
|
236
243
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
237
244
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
238
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
245
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
239
246
|
})
|
|
240
247
|
})
|
|
241
248
|
|
|
@@ -248,7 +255,7 @@ describe('plugin - event delete & patch history disabled', () => {
|
|
|
248
255
|
|
|
249
256
|
expect(em.emit).toHaveBeenCalledTimes(1)
|
|
250
257
|
expect(em.emit).toHaveBeenCalledWith(USER_DELETED, {
|
|
251
|
-
oldDoc: expect.objectContaining(john.toObject(
|
|
258
|
+
oldDoc: expect.objectContaining(john.toObject(toObjectOptions))
|
|
252
259
|
})
|
|
253
260
|
})
|
|
254
261
|
})
|