Skip to content

Commit aef9056

Browse files
Merge pull request #300 from ilovepixelart/feature/metadata-update
Update metadata to support batch operations
2 parents 2cb7eee + 7192d10 commit aef9056

File tree

5 files changed

+28
-32
lines changed

5 files changed

+28
-32
lines changed

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,18 @@ export const BOOK_UPDATED = 'book-updated'
8181
export const BOOK_DELETED = 'book-deleted'
8282
```
8383

84-
Create your interface `IBook.ts`
84+
Create your type `Book` in `types.ts`
8585

8686
```typescript
8787
import type { Types } from 'mongoose'
8888

89-
interface IBook {
89+
export type Book = {
9090
title: string
9191
description?: string
9292
authorId: Types.ObjectId
9393
createdAt?: Date
9494
updatedAt?: Date
9595
}
96-
97-
export default IBook
9896
```
9997
10098
Setup your mongoose model `Book.ts`
@@ -103,7 +101,7 @@ Setup your mongoose model `Book.ts`
103101
import { Schema, model } from 'mongoose'
104102

105103
import type { HydratedDocument, Types } from 'mongoose'
106-
import type IBook from '../interfaces/IBook'
104+
import type { Book } from '../types'
107105

108106
import { patchHistoryPlugin, setPatchHistoryTTL } from 'ts-patch-mongoose'
109107
import { BOOK_CREATED, BOOK_UPDATED, BOOK_DELETED } from '../constants/events'
@@ -114,7 +112,7 @@ import { BOOK_CREATED, BOOK_UPDATED, BOOK_DELETED } from '../constants/events'
114112
// Execute this method after you connected to you database somewhere in your application.
115113
setPatchHistoryTTL('1 month')
116114

117-
const BookSchema = new Schema<IBook>({
115+
const BookSchema = new Schema<Book>({
118116
name: {
119117
title: String,
120118
required: true
@@ -142,21 +140,21 @@ BookSchema.plugin(patchHistoryPlugin, {
142140

143141
// Code bellow is abstract example, you can use any other way to get user, reason, metadata
144142
// These three properties will be added to patch history document automatically and give you flexibility to track who, why and when made changes to your documents
145-
getUser: async () => {
143+
getUser: async (doc: HydratedDocument<Book>) => {
146144
// For example: get user from http context
147145
// You should return an object, in case you want to save user to patch history
148146
return httpContext.get('user') as Record<string, unknown>
149147
},
150148

151149
// Reason of document (create/update/delete) like: 'Excel upload', 'Manual update', 'API call', etc.
152-
getReason: async () => {
150+
getReason: async (doc: HydratedDocument<Book>) => {
153151
// For example: get reason from http context, or any other place of your application
154152
// You shout return a string, in case you want to save reason to patch history
155153
return httpContext.get('reason') as string
156154
},
157155

158156
// You can provide any information you want to save in along with patch history
159-
getMetadata: async () => {
157+
getMetadata: async (doc: HydratedDocument<Book>) => {
160158
// For example: get metadata from http context, or any other place of your application
161159
// You should return an object, in case you want to save metadata to patch history
162160
return httpContext.get('metadata') as Record<string, unknown>

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
},
8484
"devDependencies": {
8585
"@biomejs/biome": "1.9.4",
86-
"@types/node": "22.14.0",
86+
"@types/node": "22.14.1",
8787
"@vitest/coverage-v8": "3.1.1",
8888
"mongodb-memory-server": "10.1.4",
8989
"mongoose": "8.13.2",

src/patch.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,23 @@ export function getObjectOmit<T>(opts: PluginOptions<T>, doc: HydratedDocument<T
3030
return doc
3131
}
3232

33-
export async function getUser<T>(opts: PluginOptions<T>): Promise<User | undefined> {
33+
export async function getUser<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<User | undefined> {
3434
if (_.isFunction(opts.getUser)) {
35-
return await opts.getUser()
35+
return await opts.getUser(doc)
3636
}
3737
return undefined
3838
}
3939

40-
export async function getReason<T>(opts: PluginOptions<T>): Promise<string | undefined> {
40+
export async function getReason<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<string | undefined> {
4141
if (_.isFunction(opts.getReason)) {
42-
return await opts.getReason()
42+
return await opts.getReason(doc)
4343
}
4444
return undefined
4545
}
4646

47-
export async function getMetadata<T>(opts: PluginOptions<T>): Promise<Metadata | undefined> {
47+
export async function getMetadata<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<Metadata | undefined> {
4848
if (_.isFunction(opts.getMetadata)) {
49-
return await opts.getMetadata()
49+
return await opts.getMetadata(doc)
5050
}
5151
return undefined
5252
}
@@ -55,8 +55,8 @@ export function getValue<T>(item: PromiseSettledResult<T>): T | undefined {
5555
return item.status === 'fulfilled' ? item.value : undefined
5656
}
5757

58-
export async function getData<T>(opts: PluginOptions<T>): Promise<[User | undefined, string | undefined, Metadata | undefined]> {
59-
return Promise.allSettled([getUser(opts), getReason(opts), getMetadata(opts)]).then(([user, reason, metadata]) => {
58+
export async function getData<T>(opts: PluginOptions<T>, doc: HydratedDocument<T>): Promise<[User | undefined, string | undefined, Metadata | undefined]> {
59+
return Promise.allSettled([getUser(opts, doc), getReason(opts, doc), getMetadata(opts, doc)]).then(([user, reason, metadata]) => {
6060
return [getValue(user), getValue(reason), getValue(metadata)]
6161
})
6262
}
@@ -75,8 +75,6 @@ export async function bulkPatch<T>(opts: PluginOptions<T>, context: PatchContext
7575

7676
if (_.isEmpty(docs) || (!event && !history)) return
7777

78-
const [user, reason, metadata] = await getData(opts)
79-
8078
const chunks = _.chunk(docs, 1000)
8179
for await (const chunk of chunks) {
8280
const bulk = []
@@ -85,6 +83,7 @@ export async function bulkPatch<T>(opts: PluginOptions<T>, context: PatchContext
8583
emitEvent(context, event, { [key]: doc })
8684

8785
if (history) {
86+
const [user, reason, metadata] = await getData(opts, doc)
8887
bulk.push({
8988
insertOne: {
9089
document: {
@@ -138,8 +137,7 @@ export async function updatePatch<T>(opts: PluginOptions<T>, context: PatchConte
138137
version = lastHistory.version + 1
139138
}
140139

141-
const [user, reason, metadata] = await getData(opts)
142-
140+
const [user, reason, metadata] = await getData(opts, current)
143141
await HistoryModel.create({
144142
op: context.op,
145143
modelName: context.modelName,

src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ export interface PluginOptions<T> {
4343
eventUpdated?: string
4444
eventCreated?: string
4545
eventDeleted?: string
46-
getUser?: () => Promise<User> | User
47-
getReason?: () => Promise<string> | string
48-
getMetadata?: () => Promise<Metadata> | Metadata
46+
getUser?: (doc: HydratedDocument<T>) => Promise<User> | User
47+
getReason?: (doc: HydratedDocument<T>) => Promise<string> | string
48+
getMetadata?: (doc: HydratedDocument<T>) => Promise<Metadata> | Metadata
4949
omit?: string[]
5050
patchHistoryDisabled?: boolean
5151
preDelete?: (docs: HydratedDocument<T>[]) => Promise<void>

0 commit comments

Comments
 (0)