Skip to content

Commit

Permalink
Fixes for delete cases and coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
ilovepixelart committed Apr 10, 2023
1 parent 7f11040 commit 812ffa4
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 66 deletions.
111 changes: 74 additions & 37 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ async function createPatch<T> (opts: IPluginOptions<T>, context: IContext<T>, cu
})
}

async function deletePatch<T> (opts: IPluginOptions<T>, context: IContext<T>): Promise<void> {
if (_.isEmpty(context.deletedDocs) || (!opts.eventDeleted && opts.patchHistoryDisabled)) return

const chunks = _.chunk(context.deletedDocs, 1000)
for await (const chunk of chunks) {
const bulk = []
for (const oldDoc of chunk) {
if (opts.eventDeleted) {
em.emit(opts.eventDeleted, { oldDoc })
}
if (!opts.patchHistoryDisabled) {
bulk.push({
insertOne: {
document: {
op: context.op,
modelName: context.modelName,
collectionName: context.collectionName,
collectionId: oldDoc._id as Types.ObjectId,
doc: oldDoc,
version: 0
}
}
})
}
}

if (!opts.patchHistoryDisabled) {
await History
.bulkWrite(bulk, { ordered: false })
.catch((err: MongooseError) => {
console.error(err)
})
}
}
}

/**
* @description Patch patch event emitter
*/
Expand Down Expand Up @@ -140,8 +176,8 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
delete update[key]
})
}
const cursor = this.model.find(filter).cursor()
await cursor.eachAsync(async (doc: HydratedDocument<T>) => {
const cursor = this.model.find<HydratedDocument<T>>(filter).cursor()
await cursor.eachAsync(async (doc) => {
let current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
current = assign(current, update)
_.forEach(commands, (command) => {
Expand All @@ -163,8 +199,8 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
const update = this.getUpdate()

if (update && this._context.isNew) {
const cursor = this.model.findOne(update).cursor()
await cursor.eachAsync(async (doc: HydratedDocument<T>) => {
const cursor = this.model.findOne<HydratedDocument<T>>(update).cursor()
await cursor.eachAsync(async (doc) => {
const current = doc.toObject({ depopulate: true }) as HydratedDocument<T>
if (opts.eventCreated) {
em.emit(opts.eventCreated, { doc: current })
Expand All @@ -174,6 +210,27 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
}
})

schema.pre('remove', async function (this: HydratedDocument<T>, next) {
const original = this.toObject({ depopulate: true })
const model = this.constructor as Model<T>

const context: IContext<T> = {
op: 'delete',
modelName: opts.modelName ?? model.modelName,
collectionName: opts.collectionName ?? model.collection.collectionName
}

try {
if (opts.eventDeleted) {
em.emit(opts.eventDeleted, { oldDoc: original })
}
await deletePatch(opts, context)
next()
} catch (error) {
next(error as CallbackError)
}
})

schema.pre(['remove', 'findOneAndDelete', 'findOneAndRemove', 'deleteOne', 'deleteMany'], options, async function (this: IHookContext<T>, next) {
const filter = this.getFilter()
const options = this.getOptions()
Expand All @@ -186,8 +243,18 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
}

if (!ignore) {
context.deletedDocs = await this.model.find(filter).exec()
if (opts.preDeleteManyCallback) {
if (['remove', 'deleteMany'].includes(context.op) && !options.single) {
const docs = await this.model.find<HydratedDocument<T>>(filter).exec()
if (!_.isEmpty(docs)) {
context.deletedDocs = docs
}
} else {
const doc = await this.model.findOne<HydratedDocument<T>>(filter).exec()
if (!_.isEmpty(doc)) {
context.deletedDocs = [doc]
}
}
if (opts.preDeleteManyCallback && context.deletedDocs) {
await opts.preDeleteManyCallback(context.deletedDocs)
}
}
Expand All @@ -197,36 +264,6 @@ export const patchHistoryPlugin = function plugin<T> (schema: Schema<T>, opts: I
})

schema.post(['remove', 'findOneAndDelete', 'findOneAndRemove', 'deleteOne', 'deleteMany'], options, async function (this: IHookContext<T>) {
if (_.isEmpty(this._context.deletedDocs) || (!opts.eventDeleted && opts.patchHistoryDisabled)) return

const chunks = _.chunk(this._context.deletedDocs, 1000)
for await (const chunk of chunks) {
const bulk = []
for (const oldDoc of chunk) {
if (opts.eventDeleted) {
em.emit(opts.eventDeleted, { oldDoc })
}
if (!opts.patchHistoryDisabled) {
bulk.push({
insertOne: {
document: {
op: this._context.op,
modelName: this._context.modelName,
collectionName: this._context.collectionName,
collectionId: oldDoc._id as Types.ObjectId,
doc: oldDoc,
version: 0
}
}
})
}
}

if (!opts.patchHistoryDisabled) {
await History.bulkWrite(bulk, { ordered: false }).catch((err: MongooseError) => {
console.error(err)
})
}
}
await deletePatch(opts, this._context)
})
}
6 changes: 3 additions & 3 deletions tests/constants/events.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export const USER_CREATED_EVENT = 'testCreated'
export const USER_UPDATED_EVENT = 'testUpdated'
export const USER_DELETED_EVENT = 'testDeleted'
export const USER_CREATED = 'user-created'
export const USER_UPDATED = 'user-updated'
export const USER_DELETED = 'user-deleted'
Loading

0 comments on commit 812ffa4

Please sign in to comment.