ts-cache-mongoose 2.1.0 → 2.2.1
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/README.md +54 -1
- package/dist/index.cjs +73 -17
- package/dist/index.d.cts +4 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +73 -17
- package/dist/nest/index.cjs +1 -0
- package/dist/nest/index.mjs +1 -0
- package/package.json +20 -26
- package/biome.json +0 -47
- package/src/cache/Cache.ts +0 -72
- package/src/cache/engine/MemoryCacheEngine.ts +0 -41
- package/src/cache/engine/RedisCacheEngine.ts +0 -52
- package/src/extend/aggregate.ts +0 -51
- package/src/extend/query.ts +0 -81
- package/src/index.ts +0 -68
- package/src/key.ts +0 -10
- package/src/ms.ts +0 -66
- package/src/nest/cache.module.ts +0 -79
- package/src/nest/cache.service.ts +0 -37
- package/src/nest/index.ts +0 -4
- package/src/nest/interfaces.ts +0 -17
- package/src/sort-keys.ts +0 -38
- package/src/types.ts +0 -21
- package/src/version.ts +0 -18
- package/tests/cache-debug.test.ts +0 -73
- package/tests/cache-memory.test.ts +0 -217
- package/tests/cache-options.test.ts +0 -83
- package/tests/cache-redis.test.ts +0 -521
- package/tests/key.test.ts +0 -103
- package/tests/models/Story.ts +0 -29
- package/tests/models/User.ts +0 -39
- package/tests/mongo/.gitignore +0 -3
- package/tests/mongo/server.ts +0 -29
- package/tests/ms.test.ts +0 -113
- package/tests/nest.test.ts +0 -158
- package/tests/sort-keys.test.ts +0 -80
- package/tsconfig.json +0 -33
- package/vite.config.mts +0 -23
|
@@ -1,521 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { ObjectId } from 'bson'
|
|
4
|
-
import mongoose from 'mongoose'
|
|
5
|
-
import plugin from '../src/index'
|
|
6
|
-
import { StoryModel } from './models/Story'
|
|
7
|
-
import { UserModel } from './models/User'
|
|
8
|
-
import { server } from './mongo/server'
|
|
9
|
-
|
|
10
|
-
import type CacheMongoose from '../src/index'
|
|
11
|
-
|
|
12
|
-
describe('cache-redis', async () => {
|
|
13
|
-
const instance = server('cache-redis')
|
|
14
|
-
let cache: CacheMongoose
|
|
15
|
-
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
cache = plugin.init(mongoose, {
|
|
18
|
-
engine: 'redis',
|
|
19
|
-
engineOptions: {
|
|
20
|
-
host: 'localhost',
|
|
21
|
-
port: 6379,
|
|
22
|
-
},
|
|
23
|
-
defaultTTL: '10 seconds',
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
await instance.create()
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
afterAll(async () => {
|
|
30
|
-
await cache.clear()
|
|
31
|
-
await cache.close()
|
|
32
|
-
await instance.destroy()
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
beforeEach(async () => {
|
|
36
|
-
await mongoose.connection.collection('users').deleteMany({})
|
|
37
|
-
await mongoose.connection.collection('stories').deleteMany({})
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('should use cache', async () => {
|
|
41
|
-
const user = await UserModel.create({
|
|
42
|
-
name: 'John Doe',
|
|
43
|
-
role: 'admin',
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const user1 = await UserModel.findById(user._id).cache().exec()
|
|
47
|
-
await UserModel.findOneAndUpdate({ _id: user._id }, { name: 'John Doe 2' }).exec()
|
|
48
|
-
const user2 = await UserModel.findById(user._id).cache().exec()
|
|
49
|
-
|
|
50
|
-
expect(user1).not.toBeNull()
|
|
51
|
-
expect(user2).not.toBeNull()
|
|
52
|
-
expect(user1?._id.toString()).toBe(user2?._id.toString())
|
|
53
|
-
expect(user1?.name).toEqual(user2?.name)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should clear cache', async () => {
|
|
57
|
-
const user = await UserModel.create({
|
|
58
|
-
name: 'John Doe',
|
|
59
|
-
role: 'admin',
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
const cache1 = await UserModel.findById(user._id).cache().exec()
|
|
63
|
-
await UserModel.findByIdAndUpdate(user._id, { name: 'Steve' }).exec()
|
|
64
|
-
await cache.clear()
|
|
65
|
-
const cache2 = await UserModel.findById(user._id).cache().exec()
|
|
66
|
-
|
|
67
|
-
expect(cache1).not.toBeNull()
|
|
68
|
-
expect(cache2).not.toBeNull()
|
|
69
|
-
expect(cache1?._id.toString()).toBe(cache2?._id.toString())
|
|
70
|
-
expect(cache1?.name).not.toEqual(cache2?.name)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should use cache with custom-key-1', async () => {
|
|
74
|
-
const user = await UserModel.create({
|
|
75
|
-
name: 'John Doe',
|
|
76
|
-
role: 'admin',
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const cache1 = await UserModel.findById(user._id).cache('30 seconds', 'custom-key-1').exec()
|
|
80
|
-
await UserModel.findOneAndUpdate({ _id: user._id }, { name: 'John Doe 2' }).exec()
|
|
81
|
-
const cache2 = await UserModel.findById(user._id).cache('30 seconds', 'custom-key-1').exec()
|
|
82
|
-
|
|
83
|
-
expect(cache1).not.toBeNull()
|
|
84
|
-
expect(cache2).not.toBeNull()
|
|
85
|
-
expect(cache1?._id.toString()).toBe(cache2?._id.toString())
|
|
86
|
-
expect(cache1?.name).toEqual(cache2?.name)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should clear custom-key-2', async () => {
|
|
90
|
-
const user = await UserModel.create({
|
|
91
|
-
name: 'John Doe',
|
|
92
|
-
role: 'admin',
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
const cache1 = await UserModel.findById(user._id).cache('30 seconds', 'custom-key-2').exec()
|
|
96
|
-
await UserModel.updateOne({ _id: user._id }, { name: 'Steve' }).exec()
|
|
97
|
-
await cache.clear('custom-key-2')
|
|
98
|
-
const cache2 = await UserModel.findById(user._id).cache('30 seconds', 'custom-key-2').exec()
|
|
99
|
-
|
|
100
|
-
expect(cache1).not.toBeNull()
|
|
101
|
-
expect(cache2).not.toBeNull()
|
|
102
|
-
expect(cache1?._id.toString()).toBe(cache2?._id.toString())
|
|
103
|
-
expect(cache1?.name).not.toEqual(cache2?.name)
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
it('should use cache without cache options', async () => {
|
|
107
|
-
expect(cache).toBeDefined()
|
|
108
|
-
|
|
109
|
-
const user = await UserModel.create({
|
|
110
|
-
name: 'John Doe',
|
|
111
|
-
role: 'admin',
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
const cache1 = await UserModel.findById(user._id).cache().exec()
|
|
115
|
-
await UserModel.updateOne({ _id: user._id }, { name: 'John Doe 2' }).exec()
|
|
116
|
-
const cache2 = await UserModel.findById(user._id).cache().exec()
|
|
117
|
-
|
|
118
|
-
expect(cache1).not.toBeNull()
|
|
119
|
-
expect(cache2).not.toBeNull()
|
|
120
|
-
expect(cache1?._id.toString()).toBe(cache2?._id.toString())
|
|
121
|
-
expect(cache1?.name).toEqual(cache2?.name)
|
|
122
|
-
|
|
123
|
-
await UserModel.create([
|
|
124
|
-
{
|
|
125
|
-
name: 'Alice',
|
|
126
|
-
role: 'admin',
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: 'Bob',
|
|
130
|
-
role: 'admin',
|
|
131
|
-
},
|
|
132
|
-
])
|
|
133
|
-
|
|
134
|
-
const cache3 = await UserModel.find({ role: 'admin' }).cache().exec()
|
|
135
|
-
await UserModel.updateMany({ role: 'admin' }, { name: 'Steve' }).exec()
|
|
136
|
-
const cache4 = await UserModel.find({ role: 'admin' }).cache().exec()
|
|
137
|
-
|
|
138
|
-
expect(cache3).not.toBeNull()
|
|
139
|
-
expect(cache4).not.toBeNull()
|
|
140
|
-
expect(cache3?.length).toEqual(cache4?.length)
|
|
141
|
-
expect(cache3?.[0].name).toEqual(cache4?.[0].name)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
it('should use cache on aggregate', async () => {
|
|
145
|
-
await UserModel.create([
|
|
146
|
-
{ name: 'John', role: 'admin' },
|
|
147
|
-
{ name: 'Bob', role: 'admin' },
|
|
148
|
-
{ name: 'Alice', role: 'user' },
|
|
149
|
-
])
|
|
150
|
-
|
|
151
|
-
const cache1 = await UserModel.aggregate([{ $match: { role: 'admin' } }, { $group: { _id: '$role', count: { $sum: 1 } } }])
|
|
152
|
-
.cache('30 seconds')
|
|
153
|
-
.exec()
|
|
154
|
-
|
|
155
|
-
await UserModel.create({ name: 'Mark', role: 'admin' })
|
|
156
|
-
|
|
157
|
-
const cache2 = await UserModel.aggregate([{ $match: { role: 'admin' } }, { $group: { _id: '$role', count: { $sum: 1 } } }])
|
|
158
|
-
.cache('30 seconds')
|
|
159
|
-
.exec()
|
|
160
|
-
|
|
161
|
-
expect(cache1).not.toBeNull()
|
|
162
|
-
expect(cache2).not.toBeNull()
|
|
163
|
-
expect(cache1?.[0].count).toEqual(cache2?.[0].count)
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
it('should use cache on aggregate with custom-key', async () => {
|
|
167
|
-
await UserModel.create([
|
|
168
|
-
{ name: 'John', role: 'admin' },
|
|
169
|
-
{ name: 'Bob', role: 'admin' },
|
|
170
|
-
{ name: 'Alice', role: 'user' },
|
|
171
|
-
])
|
|
172
|
-
|
|
173
|
-
const cache1 = await UserModel.aggregate([{ $match: { role: 'admin' } }, { $group: { _id: '$role', count: { $sum: 1 } } }])
|
|
174
|
-
.cache('30 seconds', 'aggregate-custom-key')
|
|
175
|
-
.exec()
|
|
176
|
-
|
|
177
|
-
await UserModel.create({ name: 'Mark', role: 'admin' })
|
|
178
|
-
|
|
179
|
-
const cache2 = await UserModel.aggregate([{ $match: { role: 'admin' } }, { $group: { _id: '$role', count: { $sum: 1 } } }])
|
|
180
|
-
.cache('30 seconds', 'aggregate-custom-key')
|
|
181
|
-
.exec()
|
|
182
|
-
|
|
183
|
-
// Don't use cache key
|
|
184
|
-
const cache3 = await UserModel.aggregate([{ $match: { role: 'admin' } }, { $group: { _id: '$role', count: { $sum: 1 } } }]).exec()
|
|
185
|
-
|
|
186
|
-
expect(cache1).not.toBeNull()
|
|
187
|
-
expect(cache2).not.toBeNull()
|
|
188
|
-
expect(cache3).not.toBeNull()
|
|
189
|
-
expect(cache1?.[0].count).toEqual(cache2?.[0].count)
|
|
190
|
-
expect(cache1?.[0].count).not.toEqual(cache3?.[0].count)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('should test lean cache', async () => {
|
|
194
|
-
await UserModel.create([
|
|
195
|
-
{ name: 'John', role: 'admin' },
|
|
196
|
-
{ name: 'Bob', role: 'admin' },
|
|
197
|
-
{ name: 'Alice', role: 'user' },
|
|
198
|
-
])
|
|
199
|
-
|
|
200
|
-
const cache1 = await UserModel.find({ role: 'admin' }).lean().cache('30 seconds').exec()
|
|
201
|
-
await UserModel.create({ name: 'Mark', role: 'admin' })
|
|
202
|
-
const cache2 = await UserModel.find({ role: 'admin' }).lean().cache('30 seconds').exec()
|
|
203
|
-
|
|
204
|
-
expect(cache1).not.toBeNull()
|
|
205
|
-
expect(cache2).not.toBeNull()
|
|
206
|
-
expect(cache1?.length).toEqual(cache2?.length)
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
it('should cache with regex query', async () => {
|
|
210
|
-
await UserModel.create([
|
|
211
|
-
{ name: 'John', role: 'admin' },
|
|
212
|
-
{ name: 'Alice', role: 'user' },
|
|
213
|
-
{ name: 'Andy', role: 'user' },
|
|
214
|
-
])
|
|
215
|
-
|
|
216
|
-
const cache1 = await UserModel.find({ name: /^J/ }).cache('30 seconds').exec()
|
|
217
|
-
await UserModel.create({ name: 'Jenifer', role: 'admin' })
|
|
218
|
-
const cache2 = await UserModel.find({ name: /^J/ }).cache('30 seconds').exec()
|
|
219
|
-
|
|
220
|
-
expect(cache1).not.toBeNull()
|
|
221
|
-
expect(cache2).not.toBeNull()
|
|
222
|
-
expect(cache1?.length).toEqual(cache2?.length)
|
|
223
|
-
|
|
224
|
-
const cache3 = await UserModel.find({ name: /^A/ }).cache('30 seconds').exec()
|
|
225
|
-
await UserModel.create({ name: 'Alex', role: 'admin' })
|
|
226
|
-
const cache4 = await UserModel.find({ name: /^A/ }).cache('30 seconds').exec()
|
|
227
|
-
|
|
228
|
-
expect(cache3).not.toBeNull()
|
|
229
|
-
expect(cache4).not.toBeNull()
|
|
230
|
-
expect(cache3?.length).toEqual(cache4?.length)
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
it('should findOne', async () => {
|
|
234
|
-
await UserModel.create([
|
|
235
|
-
{ name: 'C', role: 'admin' },
|
|
236
|
-
{ name: 'V', role: 'user' },
|
|
237
|
-
{ name: 'G', role: 'user' },
|
|
238
|
-
])
|
|
239
|
-
|
|
240
|
-
const miss = await UserModel.findOne({ name: 'G' }).lean().cache('30 seconds').exec()
|
|
241
|
-
expect(miss).not.toBeNull()
|
|
242
|
-
|
|
243
|
-
expect(typeof miss?._id).toBe('object')
|
|
244
|
-
expect(miss?._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
245
|
-
|
|
246
|
-
expect(miss).toHaveProperty('name', 'G')
|
|
247
|
-
|
|
248
|
-
const hit = await UserModel.findOne({ name: 'G' }).lean().cache('30 seconds').exec()
|
|
249
|
-
expect(hit).not.toBeNull()
|
|
250
|
-
|
|
251
|
-
expect(typeof hit?._id).toBe('object')
|
|
252
|
-
expect(hit?._id instanceof ObjectId).toBeTruthy()
|
|
253
|
-
|
|
254
|
-
expect(hit).toHaveProperty('name', 'G')
|
|
255
|
-
|
|
256
|
-
expect(miss?._id.toString()).toBe(hit?._id.toString())
|
|
257
|
-
expect(miss?.name).toEqual(hit?.name)
|
|
258
|
-
expect(miss?.role).toEqual(hit?.role)
|
|
259
|
-
expect(miss?.createdAt).toEqual(hit?.createdAt)
|
|
260
|
-
expect(miss?.updatedAt).toEqual(hit?.updatedAt)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
it('should distinct("_id") and distinct("role") and distinct("createdAt")', async () => {
|
|
264
|
-
await UserModel.create({ name: 'i', role: 'admin' })
|
|
265
|
-
await UserModel.create({ name: 'p', role: 'user' })
|
|
266
|
-
await UserModel.create({ name: 'm', role: 'user' })
|
|
267
|
-
|
|
268
|
-
const miss = await UserModel.distinct('_id').cache('30 seconds').exec()
|
|
269
|
-
expect(miss).not.toBeNull()
|
|
270
|
-
expect(miss?.length).toBe(3)
|
|
271
|
-
|
|
272
|
-
expect(typeof miss?.[0]).toBe('object')
|
|
273
|
-
expect(miss?.[0] instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
274
|
-
|
|
275
|
-
const hit = await UserModel.distinct('_id').cache('30 seconds').exec()
|
|
276
|
-
expect(hit).not.toBeNull()
|
|
277
|
-
expect(hit?.length).toBe(3)
|
|
278
|
-
|
|
279
|
-
expect(typeof hit?.[0]).toBe('object')
|
|
280
|
-
expect(hit?.[0] instanceof ObjectId).toBeTruthy()
|
|
281
|
-
|
|
282
|
-
const cache4 = await UserModel.distinct('role').cache('30 seconds').exec()
|
|
283
|
-
expect(cache4).not.toBeNull()
|
|
284
|
-
expect(cache4?.length).toBe(2)
|
|
285
|
-
expect(cache4).toEqual(['admin', 'user'])
|
|
286
|
-
|
|
287
|
-
const cache5 = await UserModel.distinct('role').cache('30 seconds').exec()
|
|
288
|
-
expect(cache5).not.toBeNull()
|
|
289
|
-
expect(cache5?.length).toBe(2)
|
|
290
|
-
expect(cache5).toEqual(['admin', 'user'])
|
|
291
|
-
|
|
292
|
-
const cache6 = await UserModel.distinct('name').cache('30 seconds').exec()
|
|
293
|
-
expect(cache6).not.toBeNull()
|
|
294
|
-
expect(cache6?.length).toBe(3)
|
|
295
|
-
|
|
296
|
-
const cache7 = await UserModel.distinct('name').cache('30 seconds').exec()
|
|
297
|
-
|
|
298
|
-
expect(miss.map((id) => id.toString())).toEqual(hit.map((id) => id.toString()))
|
|
299
|
-
expect(cache4).toEqual(cache5)
|
|
300
|
-
expect(cache6).toEqual(cache7)
|
|
301
|
-
})
|
|
302
|
-
|
|
303
|
-
it('should test exceptions', async () => {
|
|
304
|
-
const user = await UserModel.create({ name: 'i', role: 'admin' })
|
|
305
|
-
const story1 = await StoryModel.create({ title: '1', userId: user._id })
|
|
306
|
-
const story2 = await StoryModel.create({ title: '2', userId: user._id })
|
|
307
|
-
|
|
308
|
-
const miss = await UserModel.findOne({ name: 'i' }).populate({ path: 'stories' }).lean().cache('30 seconds').exec()
|
|
309
|
-
const hit = await UserModel.findOne({ name: 'i' }).populate({ path: 'stories' }).lean().cache('30 seconds').exec()
|
|
310
|
-
|
|
311
|
-
expect(miss).not.toBeNull()
|
|
312
|
-
|
|
313
|
-
expect(typeof miss?._id).toBe('object')
|
|
314
|
-
expect(miss?._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
315
|
-
|
|
316
|
-
expect(miss?.name).toBe('i')
|
|
317
|
-
expect(miss?.stories).not.toBeNull()
|
|
318
|
-
expect(miss?.stories?.length).toBe(2)
|
|
319
|
-
|
|
320
|
-
expect(miss?.stories?.[0]._id.toString()).toBe(story1._id.toString())
|
|
321
|
-
|
|
322
|
-
expect(typeof miss?.stories?.[0]._id).toBe('object')
|
|
323
|
-
expect(miss?.stories?.[0]._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
324
|
-
|
|
325
|
-
expect(typeof miss?.stories?.[0].createdAt).toBe('object')
|
|
326
|
-
expect(miss?.stories?.[0].createdAt instanceof Date).toBeTruthy()
|
|
327
|
-
|
|
328
|
-
expect(miss?.stories?.[1]._id.toString()).toBe(story2._id.toString())
|
|
329
|
-
|
|
330
|
-
expect(typeof miss?.stories?.[1]._id).toBe('object')
|
|
331
|
-
expect(miss?.stories?.[1]._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
332
|
-
|
|
333
|
-
expect(typeof miss?.stories?.[1].createdAt).toBe('object')
|
|
334
|
-
expect(miss?.stories?.[1].createdAt instanceof Date).toBeTruthy()
|
|
335
|
-
|
|
336
|
-
expect(hit).not.toBeNull()
|
|
337
|
-
|
|
338
|
-
expect(typeof hit?._id).toBe('object')
|
|
339
|
-
expect(hit?._id instanceof ObjectId).toBeTruthy()
|
|
340
|
-
|
|
341
|
-
expect(hit?.name).toBe('i')
|
|
342
|
-
expect(hit?.stories).not.toBeNull()
|
|
343
|
-
expect(hit?.stories?.length).toBe(2)
|
|
344
|
-
|
|
345
|
-
expect(hit?.stories?.[0]._id.toString()).toBe(story1._id.toString())
|
|
346
|
-
|
|
347
|
-
expect(typeof hit?.stories?.[0]._id).toBe('object')
|
|
348
|
-
expect(hit?.stories?.[0]._id instanceof ObjectId).toBeTruthy()
|
|
349
|
-
|
|
350
|
-
expect(hit?.stories?.[0].createdAt instanceof Date).toBeTruthy()
|
|
351
|
-
expect(typeof hit?.stories?.[0].createdAt).toBe('object')
|
|
352
|
-
|
|
353
|
-
expect(hit?.stories?.[1]._id.toString()).toBe(story2._id.toString())
|
|
354
|
-
|
|
355
|
-
expect(typeof hit?.stories?.[1]._id).toBe('object')
|
|
356
|
-
expect(hit?.stories?.[1]._id instanceof ObjectId).toBeTruthy()
|
|
357
|
-
|
|
358
|
-
expect(hit?.stories?.[1].createdAt instanceof Date).toBeTruthy()
|
|
359
|
-
expect(typeof hit?.stories?.[1].createdAt).toBe('object')
|
|
360
|
-
|
|
361
|
-
expect(miss?._id.toString()).toBe(hit?._id.toString())
|
|
362
|
-
expect(miss?.name).toBe(hit?.name)
|
|
363
|
-
expect(miss?.role).toBe(hit?.role)
|
|
364
|
-
expect(miss?.createdAt?.toString()).toBe(hit?.createdAt?.toString())
|
|
365
|
-
expect(miss?.updatedAt?.toString()).toBe(hit?.updatedAt?.toString())
|
|
366
|
-
|
|
367
|
-
expect(miss?.stories?.[0]._id.toString()).toBe(hit?.stories?.[0]._id.toString())
|
|
368
|
-
expect(miss?.stories?.[0].title).toBe(hit?.stories?.[0].title)
|
|
369
|
-
expect(miss?.stories?.[0].userId.toString()).toBe(hit?.stories?.[0].userId.toString())
|
|
370
|
-
expect(miss?.stories?.[0].createdAt?.toString()).toBe(hit?.stories?.[0].createdAt?.toString())
|
|
371
|
-
expect(miss?.stories?.[0].updatedAt?.toString()).toBe(hit?.stories?.[0].updatedAt?.toString())
|
|
372
|
-
|
|
373
|
-
expect(miss?.stories?.[1]._id.toString()).toBe(hit?.stories?.[1]._id.toString())
|
|
374
|
-
expect(miss?.stories?.[1].title).toBe(hit?.stories?.[1].title)
|
|
375
|
-
expect(miss?.stories?.[1].userId.toString()).toBe(hit?.stories?.[1].userId.toString())
|
|
376
|
-
expect(miss?.stories?.[1].createdAt?.toString()).toBe(hit?.stories?.[1].createdAt?.toString())
|
|
377
|
-
expect(miss?.stories?.[1].updatedAt?.toString()).toBe(hit?.stories?.[1].updatedAt?.toString())
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
it('should not misclassify certain fields as objectIds', async () => {
|
|
381
|
-
// ObjectId.isValid will return true for multiple scenarios.
|
|
382
|
-
// A string being a potentially valid objectId should not be the
|
|
383
|
-
// determining factor on wether or not deserialize it as objectId.
|
|
384
|
-
const user = await UserModel.create({
|
|
385
|
-
name: '12CharString',
|
|
386
|
-
role: '660ef695677786928202dc1f',
|
|
387
|
-
})
|
|
388
|
-
const pureLean = await UserModel.findOne({ _id: user._id }).lean()
|
|
389
|
-
|
|
390
|
-
const miss = await UserModel.findOne({ _id: user._id }).lean().cache('30 seconds')
|
|
391
|
-
const hit = await UserModel.findOne({ _id: user._id }).lean().cache('30 seconds')
|
|
392
|
-
|
|
393
|
-
expect(pureLean).not.toBeNull()
|
|
394
|
-
expect(typeof pureLean?._id).toBe('object')
|
|
395
|
-
expect(typeof pureLean?.createdAt).toBe('object')
|
|
396
|
-
|
|
397
|
-
expect(miss).not.toBeNull()
|
|
398
|
-
expect(typeof miss?._id).toBe('object')
|
|
399
|
-
expect(typeof miss?.createdAt).toBe('object')
|
|
400
|
-
|
|
401
|
-
expect(hit).not.toBeNull()
|
|
402
|
-
expect(typeof hit?._id).toBe('object')
|
|
403
|
-
expect(typeof hit?.createdAt).toBe('object')
|
|
404
|
-
|
|
405
|
-
expect(miss?._id.toString()).toBe(hit?._id.toString())
|
|
406
|
-
expect(miss?.role).toEqual(hit?.role)
|
|
407
|
-
expect(miss?.createdAt).toEqual(hit?.createdAt)
|
|
408
|
-
|
|
409
|
-
const distinctMiss = await UserModel.distinct('_id').cache('30 seconds').lean().exec()
|
|
410
|
-
expect(distinctMiss).not.toBeNull()
|
|
411
|
-
expect(distinctMiss?.length).toBe(1)
|
|
412
|
-
expect(distinctMiss).toEqual([pureLean?._id])
|
|
413
|
-
|
|
414
|
-
const distinctHit = await UserModel.distinct('_id').cache('30 seconds').lean().exec()
|
|
415
|
-
expect(distinctHit).not.toBeNull()
|
|
416
|
-
expect(distinctHit?.length).toBe(1)
|
|
417
|
-
expect(distinctHit.map((id) => id.toString())).toEqual([pureLean?._id.toString()])
|
|
418
|
-
|
|
419
|
-
const distinctCreatedAtMiss = await UserModel.distinct('createdAt').cache('30 seconds').lean().exec()
|
|
420
|
-
expect(distinctCreatedAtMiss).not.toBeNull()
|
|
421
|
-
expect(distinctCreatedAtMiss?.length).toBe(1)
|
|
422
|
-
expect(typeof distinctCreatedAtMiss?.[0]).toBe('object')
|
|
423
|
-
expect(distinctCreatedAtMiss?.[0] instanceof Date).toBeTruthy()
|
|
424
|
-
expect(distinctCreatedAtMiss).toEqual([pureLean?.createdAt])
|
|
425
|
-
|
|
426
|
-
const distinctCreatedAtHit = await UserModel.distinct('createdAt').cache('30 seconds').lean().exec()
|
|
427
|
-
expect(distinctCreatedAtHit).not.toBeNull()
|
|
428
|
-
expect(distinctCreatedAtHit?.length).toBe(1)
|
|
429
|
-
expect(typeof distinctCreatedAtMiss?.[0]).toBe('object')
|
|
430
|
-
expect(distinctCreatedAtMiss?.[0] instanceof Date).toBeTruthy()
|
|
431
|
-
expect(distinctCreatedAtHit).toEqual([pureLean?.createdAt])
|
|
432
|
-
|
|
433
|
-
expect(miss?._id.toString()).toBe(hit?._id.toString())
|
|
434
|
-
expect(miss?.name).toBe(hit?.name)
|
|
435
|
-
expect(miss?.role).toBe(hit?.role)
|
|
436
|
-
expect(miss?.createdAt?.toString()).toBe(hit?.createdAt?.toString())
|
|
437
|
-
expect(miss?.updatedAt?.toString()).toBe(hit?.updatedAt?.toString())
|
|
438
|
-
})
|
|
439
|
-
|
|
440
|
-
it('should hydrate populated objects from cache', async () => {
|
|
441
|
-
const user = await UserModel.create({ name: 'Alex', role: 'user' })
|
|
442
|
-
const story1 = await StoryModel.create({ title: 'Ticket 1', userId: user._id })
|
|
443
|
-
const story2 = await StoryModel.create({ title: 'Ticket 2', userId: user._id })
|
|
444
|
-
|
|
445
|
-
const populatedOriginal = await UserModel.findOne({ name: 'Alex' }).populate('stories').lean().cache('1 minute').exec()
|
|
446
|
-
|
|
447
|
-
expect(populatedOriginal).not.toBeNull()
|
|
448
|
-
|
|
449
|
-
expect(typeof populatedOriginal?._id).toBe('object')
|
|
450
|
-
expect(populatedOriginal?._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
451
|
-
|
|
452
|
-
expect(populatedOriginal?.name).toBe('Alex')
|
|
453
|
-
expect(populatedOriginal?.stories).not.toBeNull()
|
|
454
|
-
expect(populatedOriginal?.stories?.length).toBe(2)
|
|
455
|
-
|
|
456
|
-
expect(populatedOriginal?.stories?.[0]._id.toString()).toBe(story1._id.toString())
|
|
457
|
-
|
|
458
|
-
expect(typeof populatedOriginal?.stories?.[0]._id).toBe('object')
|
|
459
|
-
expect(populatedOriginal?.stories?.[0]._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
460
|
-
|
|
461
|
-
expect(typeof populatedOriginal?.stories?.[0].createdAt).toBe('object')
|
|
462
|
-
expect(populatedOriginal?.stories?.[0].createdAt instanceof Date).toBeTruthy()
|
|
463
|
-
|
|
464
|
-
expect(populatedOriginal?.stories?.[1]._id.toString()).toBe(story2._id.toString())
|
|
465
|
-
|
|
466
|
-
expect(typeof populatedOriginal?.stories?.[1]._id).toBe('object')
|
|
467
|
-
expect(populatedOriginal?.stories?.[1]._id instanceof mongoose.Types.ObjectId).toBeTruthy()
|
|
468
|
-
|
|
469
|
-
expect(typeof populatedOriginal?.stories?.[1].createdAt).toBe('object')
|
|
470
|
-
expect(populatedOriginal?.stories?.[1].createdAt instanceof Date).toBeTruthy()
|
|
471
|
-
|
|
472
|
-
// Deleting user and stories, to ensure that the cache is used
|
|
473
|
-
await UserModel.deleteOne({ _id: user._id }).exec()
|
|
474
|
-
await StoryModel.deleteMany({ userId: user._id }).exec()
|
|
475
|
-
|
|
476
|
-
const populatedCache = await UserModel.findOne({ name: 'Alex' }).populate('stories').lean().cache('1 minute').exec()
|
|
477
|
-
|
|
478
|
-
expect(populatedCache).not.toBeNull()
|
|
479
|
-
|
|
480
|
-
expect(typeof populatedCache?._id).toBe('object')
|
|
481
|
-
expect(populatedCache?._id instanceof ObjectId).toBeTruthy()
|
|
482
|
-
|
|
483
|
-
expect(populatedCache?.name).toBe('Alex')
|
|
484
|
-
expect(populatedCache?.stories).not.toBeNull()
|
|
485
|
-
expect(populatedCache?.stories?.length).toBe(2)
|
|
486
|
-
|
|
487
|
-
expect(populatedCache?.stories?.[0]._id.toString()).toBe(story1._id.toString())
|
|
488
|
-
|
|
489
|
-
expect(typeof populatedCache?.stories?.[0]._id).toBe('object')
|
|
490
|
-
expect(populatedCache?.stories?.[0]._id instanceof ObjectId).toBeTruthy()
|
|
491
|
-
|
|
492
|
-
expect(typeof populatedCache?.stories?.[0].createdAt).toBe('object')
|
|
493
|
-
expect(populatedCache?.stories?.[0].createdAt instanceof Date).toBeTruthy()
|
|
494
|
-
|
|
495
|
-
expect(populatedCache?.stories?.[1]._id.toString()).toBe(story2._id.toString())
|
|
496
|
-
|
|
497
|
-
expect(typeof populatedCache?.stories?.[1]._id).toBe('object')
|
|
498
|
-
expect(populatedCache?.stories?.[1]._id instanceof ObjectId).toBeTruthy()
|
|
499
|
-
|
|
500
|
-
expect(typeof populatedCache?.stories?.[1].createdAt).toBe('object')
|
|
501
|
-
expect(populatedCache?.stories?.[1].createdAt instanceof Date).toBeTruthy()
|
|
502
|
-
|
|
503
|
-
expect(populatedOriginal?._id.toString()).toBe(populatedCache?._id.toString())
|
|
504
|
-
expect(populatedOriginal?.name).toBe(populatedCache?.name)
|
|
505
|
-
expect(populatedOriginal?.role).toBe(populatedCache?.role)
|
|
506
|
-
expect(populatedOriginal?.createdAt?.toString()).toBe(populatedCache?.createdAt?.toString())
|
|
507
|
-
expect(populatedOriginal?.updatedAt?.toString()).toBe(populatedCache?.updatedAt?.toString())
|
|
508
|
-
|
|
509
|
-
expect(populatedOriginal?.stories?.[0]._id.toString()).toBe(populatedCache?.stories?.[0]._id.toString())
|
|
510
|
-
expect(populatedOriginal?.stories?.[0].title).toBe(populatedCache?.stories?.[0].title)
|
|
511
|
-
expect(populatedOriginal?.stories?.[0].userId.toString()).toBe(populatedCache?.stories?.[0].userId.toString())
|
|
512
|
-
expect(populatedOriginal?.stories?.[0].createdAt?.toString()).toBe(populatedCache?.stories?.[0].createdAt?.toString())
|
|
513
|
-
expect(populatedOriginal?.stories?.[0].updatedAt?.toString()).toBe(populatedCache?.stories?.[0].updatedAt?.toString())
|
|
514
|
-
|
|
515
|
-
expect(populatedOriginal?.stories?.[1]._id.toString()).toBe(populatedCache?.stories?.[1]._id.toString())
|
|
516
|
-
expect(populatedOriginal?.stories?.[1].title).toBe(populatedCache?.stories?.[1].title)
|
|
517
|
-
expect(populatedOriginal?.stories?.[1].userId.toString()).toBe(populatedCache?.stories?.[1].userId.toString())
|
|
518
|
-
expect(populatedOriginal?.stories?.[1].createdAt?.toString()).toBe(populatedCache?.stories?.[1].createdAt?.toString())
|
|
519
|
-
expect(populatedOriginal?.stories?.[1].updatedAt?.toString()).toBe(populatedCache?.stories?.[1].updatedAt?.toString())
|
|
520
|
-
})
|
|
521
|
-
})
|
package/tests/key.test.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { Types } from 'mongoose'
|
|
4
|
-
import { getKey } from '../src/key'
|
|
5
|
-
|
|
6
|
-
const { ObjectId } = Types
|
|
7
|
-
|
|
8
|
-
describe('generateHash()', () => {
|
|
9
|
-
const data1 = {
|
|
10
|
-
foo: 42,
|
|
11
|
-
bar: {
|
|
12
|
-
baz: [3, 2, 1],
|
|
13
|
-
qux: 'hello',
|
|
14
|
-
_id: new ObjectId('5f9b3b3b3b3b3b3b3b3b3b3b'),
|
|
15
|
-
wow: {
|
|
16
|
-
word: 'world',
|
|
17
|
-
hey: {
|
|
18
|
-
waldo: true,
|
|
19
|
-
fred: null,
|
|
20
|
-
missing: undefined,
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const data2 = {
|
|
27
|
-
foo: 42,
|
|
28
|
-
bar: {
|
|
29
|
-
_id: new ObjectId('5f9b3b3b3b3b3b3b3b3b3b3b'),
|
|
30
|
-
baz: [3, 2, 1],
|
|
31
|
-
qux: 'hello',
|
|
32
|
-
wow: {
|
|
33
|
-
word: 'world',
|
|
34
|
-
hey: {
|
|
35
|
-
waldo: true,
|
|
36
|
-
fred: null,
|
|
37
|
-
missing: undefined,
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const data3 = {
|
|
44
|
-
_id: new ObjectId('5f9b3b3b3b3b3b3b3b3b3b3b'),
|
|
45
|
-
bar: {
|
|
46
|
-
qux: 'hello',
|
|
47
|
-
baz: [3, 2, 1],
|
|
48
|
-
wow: {
|
|
49
|
-
hey: {
|
|
50
|
-
fred: null,
|
|
51
|
-
waldo: true,
|
|
52
|
-
missing: undefined,
|
|
53
|
-
},
|
|
54
|
-
word: 'world',
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
foo: 42,
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const data4 = {
|
|
61
|
-
_id: new ObjectId('1f9b3b3b3b3b3b3b3b3b3b3b'),
|
|
62
|
-
bar: {
|
|
63
|
-
qux: 'hello',
|
|
64
|
-
baz: [3, 2, 1],
|
|
65
|
-
wow: {
|
|
66
|
-
hey: {
|
|
67
|
-
fred: null,
|
|
68
|
-
waldo: true,
|
|
69
|
-
missing: undefined,
|
|
70
|
-
},
|
|
71
|
-
word: 'world',
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
foo: 42,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
it('should generate hash keys for objects with different key orders', () => {
|
|
78
|
-
const hash1 = getKey(data1)
|
|
79
|
-
const hash2 = getKey(data2)
|
|
80
|
-
const hash3 = getKey(data3)
|
|
81
|
-
const hash4 = getKey(data4)
|
|
82
|
-
|
|
83
|
-
expect(hash1).toEqual(hash2)
|
|
84
|
-
expect(hash1).not.toEqual(hash3)
|
|
85
|
-
expect(hash3).not.toEqual(hash4)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should test dates', async () => {
|
|
89
|
-
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
90
|
-
const date = new Date()
|
|
91
|
-
const hash1 = getKey({
|
|
92
|
-
name: 'John Doe',
|
|
93
|
-
date: { $lte: date },
|
|
94
|
-
})
|
|
95
|
-
await wait(50)
|
|
96
|
-
const date2 = new Date()
|
|
97
|
-
const hash2 = getKey({
|
|
98
|
-
name: 'John Doe',
|
|
99
|
-
date: { $lte: date2 },
|
|
100
|
-
})
|
|
101
|
-
expect(hash1).not.toEqual(hash2)
|
|
102
|
-
})
|
|
103
|
-
})
|
package/tests/models/Story.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { model, models, Schema } from 'mongoose'
|
|
2
|
-
|
|
3
|
-
import type { Model, Types } from 'mongoose'
|
|
4
|
-
|
|
5
|
-
export interface Story {
|
|
6
|
-
_id: Types.ObjectId
|
|
7
|
-
userId: Types.ObjectId
|
|
8
|
-
title: string
|
|
9
|
-
createdAt: Date
|
|
10
|
-
updatedAt: Date
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const StorySchema = new Schema<Story>(
|
|
14
|
-
{
|
|
15
|
-
userId: {
|
|
16
|
-
type: Schema.Types.ObjectId,
|
|
17
|
-
ref: 'User',
|
|
18
|
-
required: true,
|
|
19
|
-
index: true,
|
|
20
|
-
},
|
|
21
|
-
title: {
|
|
22
|
-
type: String,
|
|
23
|
-
required: true,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
{ timestamps: true },
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
export const StoryModel = (models.Story as Model<Story> | undefined) ?? model<Story>('Story', StorySchema)
|
package/tests/models/User.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { model, models, Schema } from 'mongoose'
|
|
2
|
-
|
|
3
|
-
import type { HydratedDocument, Model, Types } from 'mongoose'
|
|
4
|
-
import type { Story } from './Story'
|
|
5
|
-
|
|
6
|
-
export interface User {
|
|
7
|
-
_id: Types.ObjectId
|
|
8
|
-
name: string
|
|
9
|
-
role: string
|
|
10
|
-
age?: number
|
|
11
|
-
createdAt?: Date
|
|
12
|
-
updatedAt?: Date
|
|
13
|
-
stories?: HydratedDocument<Story>[]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const UserSchema = new Schema<User>(
|
|
17
|
-
{
|
|
18
|
-
name: {
|
|
19
|
-
type: String,
|
|
20
|
-
required: true,
|
|
21
|
-
},
|
|
22
|
-
role: {
|
|
23
|
-
type: String,
|
|
24
|
-
required: true,
|
|
25
|
-
},
|
|
26
|
-
age: {
|
|
27
|
-
type: Number,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
{ timestamps: true },
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
UserSchema.virtual('stories', {
|
|
34
|
-
ref: 'Story',
|
|
35
|
-
localField: '_id',
|
|
36
|
-
foreignField: 'userId',
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
export const UserModel = (models.User as Model<User> | undefined) ?? model<User>('User', UserSchema)
|
package/tests/mongo/.gitignore
DELETED