ts-patch-mongoose 1.1.3 → 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 +71 -149
- 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 +68 -146
- 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 +76 -156
- 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-created.test.ts +225 -76
- package/tests/plugin-event-deleted.test.ts +54 -47
- package/tests/plugin-event-updated.test.ts +139 -15
package/src/plugin.ts
CHANGED
|
@@ -1,113 +1,44 @@
|
|
|
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
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (opts.omit) {
|
|
25
|
-
currentObject = omit(currentObject, opts.omit)
|
|
26
|
-
originalObject = omit(originalObject, opts.omit)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return { currentObject, originalObject }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async function updatePatch<T> (opts: IPluginOptions<T>, context: IContext<T>, current: HydratedDocument<T>, original: HydratedDocument<T>): Promise<void> {
|
|
33
|
-
const { currentObject, originalObject } = getObjects(opts, current, original)
|
|
34
|
-
|
|
35
|
-
if (_.isEmpty(originalObject) || _.isEmpty(currentObject)) return
|
|
36
|
-
|
|
37
|
-
const patch = jsonpatch.compare(originalObject, currentObject, true)
|
|
38
|
-
|
|
39
|
-
if (_.isEmpty(patch)) return
|
|
40
|
-
|
|
41
|
-
if (opts.eventUpdated) {
|
|
42
|
-
em.emit(opts.eventUpdated, { oldDoc: original, doc: current, patch })
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (opts.patchHistoryDisabled) return
|
|
46
|
-
|
|
47
|
-
let version = 0
|
|
48
|
-
|
|
49
|
-
const lastHistory = await History.findOne({ collectionId: original._id as Types.ObjectId }).sort('-version').exec()
|
|
50
|
-
|
|
51
|
-
if (lastHistory && lastHistory.version >= 0) {
|
|
52
|
-
version = lastHistory.version + 1
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
await History.create({
|
|
56
|
-
op: context.op,
|
|
57
|
-
modelName: context.modelName,
|
|
58
|
-
collectionName: context.collectionName,
|
|
59
|
-
collectionId: original._id as Types.ObjectId,
|
|
60
|
-
patch,
|
|
61
|
-
version
|
|
62
|
-
})
|
|
18
|
+
const toObjectOptions: ToObjectOptions = {
|
|
19
|
+
depopulate: true,
|
|
20
|
+
virtuals: false
|
|
63
21
|
}
|
|
64
22
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
collectionName: context.collectionName,
|
|
85
|
-
collectionId: doc._id as Types.ObjectId,
|
|
86
|
-
doc,
|
|
87
|
-
version: 0
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (!opts.patchHistoryDisabled) {
|
|
95
|
-
await History
|
|
96
|
-
.bulkWrite(bulk, { ordered: false })
|
|
97
|
-
.catch((err: MongooseError) => {
|
|
98
|
-
console.error(err)
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function createPatch<T> (opts: IPluginOptions<T>, context: IContext<T>): Promise<void> {
|
|
105
|
-
await bulkPatch(opts, context, 'eventCreated', 'createdDocs')
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async function deletePatch<T> (opts: IPluginOptions<T>, context: IContext<T>): Promise<void> {
|
|
109
|
-
await bulkPatch(opts, context, 'eventDeleted', 'deletedDocs')
|
|
110
|
-
}
|
|
23
|
+
const updateMethods = [
|
|
24
|
+
'update',
|
|
25
|
+
'updateOne',
|
|
26
|
+
'replaceOne',
|
|
27
|
+
'updateMany',
|
|
28
|
+
'findOneAndUpdate',
|
|
29
|
+
'findOneAndReplace',
|
|
30
|
+
'findByIdAndUpdate'
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const deleteMethods = [
|
|
34
|
+
'remove',
|
|
35
|
+
'findOneAndDelete',
|
|
36
|
+
'findOneAndRemove',
|
|
37
|
+
'findByIdAndDelete',
|
|
38
|
+
'findByIdAndRemove',
|
|
39
|
+
'deleteOne',
|
|
40
|
+
'deleteMany'
|
|
41
|
+
]
|
|
111
42
|
|
|
112
43
|
/**
|
|
113
44
|
* @description Patch patch event emitter
|
|
@@ -122,7 +53,7 @@ export const patchEventEmitter = em
|
|
|
122
53
|
*/
|
|
123
54
|
export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: IPluginOptions<T>): void {
|
|
124
55
|
schema.pre('save', async function (next) {
|
|
125
|
-
const current = this.toObject(
|
|
56
|
+
const current = this.toObject(toObjectOptions) as HydratedDocument<T>
|
|
126
57
|
const model = this.constructor as Model<T>
|
|
127
58
|
|
|
128
59
|
const context: IContext<T> = {
|
|
@@ -132,19 +63,16 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
132
63
|
createdDocs: [current]
|
|
133
64
|
}
|
|
134
65
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await updatePatch(opts, context, current, original)
|
|
142
|
-
}
|
|
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)
|
|
143
72
|
}
|
|
144
|
-
next()
|
|
145
|
-
} catch (error) {
|
|
146
|
-
next(error as CallbackError)
|
|
147
73
|
}
|
|
74
|
+
|
|
75
|
+
next()
|
|
148
76
|
})
|
|
149
77
|
|
|
150
78
|
schema.post('insertMany', async function (docs) {
|
|
@@ -158,7 +86,7 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
158
86
|
await createPatch(opts, context)
|
|
159
87
|
})
|
|
160
88
|
|
|
161
|
-
schema.pre(
|
|
89
|
+
schema.pre(updateMethods as MongooseQueryMiddleware[], async function (this: IHookContext<T>, next) {
|
|
162
90
|
const filter = this.getFilter()
|
|
163
91
|
const update = this.getUpdate() as Record<string, Partial<T>> | null
|
|
164
92
|
const options = this.getOptions()
|
|
@@ -173,54 +101,50 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
173
101
|
isNew: options.upsert && count === 0
|
|
174
102
|
}
|
|
175
103
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
delete update[key]
|
|
183
|
-
})
|
|
184
|
-
}
|
|
185
|
-
const cursor = this.model.find<HydratedDocument<T>>(filter).cursor()
|
|
186
|
-
await cursor.eachAsync(async (doc) => {
|
|
187
|
-
let current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
188
|
-
const original = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
189
|
-
current = assign(current, update)
|
|
190
|
-
_.forEach(commands, (command) => {
|
|
191
|
-
try {
|
|
192
|
-
current = assign(current, command)
|
|
193
|
-
} catch (error) {
|
|
194
|
-
// we catch assign keys that are not implemented
|
|
195
|
-
}
|
|
196
|
-
})
|
|
197
|
-
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]
|
|
198
110
|
})
|
|
199
|
-
next()
|
|
200
|
-
} catch (error) {
|
|
201
|
-
next(error as CallbackError)
|
|
202
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()
|
|
203
131
|
})
|
|
204
132
|
|
|
205
|
-
schema.post(
|
|
133
|
+
schema.post(updateMethods as MongooseQueryMiddleware[], async function (this: IHookContext<T>) {
|
|
206
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]
|
|
207
141
|
|
|
208
|
-
if (update && this._context.isNew) {
|
|
209
|
-
const cursor = this.model.findOne<HydratedDocument<T>>(update).cursor()
|
|
210
|
-
await cursor.eachAsync((doc) => {
|
|
211
|
-
const current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
|
|
212
|
-
if (this._context.createdDocs) {
|
|
213
|
-
this._context.createdDocs.push(current)
|
|
214
|
-
} else {
|
|
215
|
-
this._context.createdDocs = [current]
|
|
216
|
-
}
|
|
217
|
-
})
|
|
218
142
|
await createPatch(opts, this._context)
|
|
219
143
|
}
|
|
220
144
|
})
|
|
221
145
|
|
|
222
|
-
schema.
|
|
223
|
-
const original = this.toObject(
|
|
146
|
+
schema.post('remove', async function (this: HydratedDocument<T>) {
|
|
147
|
+
const original = this.toObject(toObjectOptions)
|
|
224
148
|
const model = this.constructor as Model<T>
|
|
225
149
|
|
|
226
150
|
const context: IContext<T> = {
|
|
@@ -229,18 +153,14 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
229
153
|
collectionName: opts.collectionName ?? model.collection.collectionName
|
|
230
154
|
}
|
|
231
155
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
em.emit(opts.eventDeleted, { oldDoc: original })
|
|
235
|
-
}
|
|
236
|
-
await deletePatch(opts, context)
|
|
237
|
-
next()
|
|
238
|
-
} catch (error) {
|
|
239
|
-
next(error as CallbackError)
|
|
156
|
+
if (opts.eventDeleted) {
|
|
157
|
+
em.emit(opts.eventDeleted, { oldDoc: original })
|
|
240
158
|
}
|
|
159
|
+
|
|
160
|
+
await deletePatch(opts, context)
|
|
241
161
|
})
|
|
242
162
|
|
|
243
|
-
schema.pre(
|
|
163
|
+
schema.pre(deleteMethods as MongooseQueryMiddleware[], options, async function (this: IHookContext<T>, next) {
|
|
244
164
|
const filter = this.getFilter()
|
|
245
165
|
const options = this.getOptions()
|
|
246
166
|
const ignore = options.__ignore as boolean
|
|
@@ -265,14 +185,14 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
|
|
|
265
185
|
}
|
|
266
186
|
}
|
|
267
187
|
|
|
268
|
-
if (opts.
|
|
269
|
-
await opts.
|
|
188
|
+
if (opts.preDeleteCallback && _.isArray(this._context.deletedDocs) && !_.isEmpty(this._context.deletedDocs)) {
|
|
189
|
+
await opts.preDeleteCallback(this._context.deletedDocs)
|
|
270
190
|
}
|
|
271
191
|
|
|
272
192
|
next()
|
|
273
193
|
})
|
|
274
194
|
|
|
275
|
-
schema.post(
|
|
195
|
+
schema.post(deleteMethods as MongooseQueryMiddleware[], options, async function (this: IHookContext<T>) {
|
|
276
196
|
await deletePatch(opts, this._context)
|
|
277
197
|
})
|
|
278
198
|
}
|
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
|
+
})
|