Skip to content

Commit 0558589

Browse files
authored
Merge pull request #10 from Timeraa/RCD-98
feat(RCD-98): add support for distinct
2 parents eea9ae2 + ab28175 commit 0558589

File tree

4 files changed

+78
-16
lines changed

4 files changed

+78
-16
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ _These functions automatically handle caching_
2222
- find
2323
- findOne
2424
- countDocuments
25+
- distinct
2526

2627
**NOTE: When you update/insert/delete a document, the cache is not updated, you'll need to manually clear the cache using `customClass.clear()` or `customClass.keyv.clear()`**
2728

__tests__/index.test.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ afterAll(async () => {
1212
await connection.close();
1313
});
1414

15-
class TestClass extends MongoDBCaching {}
15+
class TestClass extends MongoDBCaching<{
16+
test: boolean;
17+
title: string;
18+
}> {}
1619

17-
const doc = { test: true },
18-
doc1 = { test: false };
20+
const doc = { test: true, title: "test" },
21+
doc1 = { test: false, title: "test" },
22+
doc2 = { test: true, title: "test2" };
1923

2024
describe("MongoDB-Caching", () => {
2125
let cacheClass: TestClass;
@@ -25,7 +29,7 @@ describe("MongoDB-Caching", () => {
2529
beforeAll(async () => {
2630
cacheClass = new TestClass(connection.db("test").collection("test"));
2731

28-
await cacheClass.collection.insertMany([doc, doc1]);
32+
await cacheClass.collection.insertMany([doc, doc1, doc2]);
2933
});
3034

3135
it("should have no context", () => {
@@ -77,7 +81,7 @@ describe("MongoDB-Caching", () => {
7781

7882
expect(dbCountDocumentsSpy).toHaveBeenCalledTimes(1);
7983

80-
expect(res).toBe(2);
84+
expect(res).toBe(3);
8185

8286
dbCountDocumentsSpy.mockRestore();
8387
});
@@ -93,7 +97,7 @@ describe("MongoDB-Caching", () => {
9397

9498
expect(dbCountDocumentsSpy).toHaveBeenCalledTimes(1);
9599

96-
expect(res).toBe(2);
100+
expect(res).toBe(3);
97101

98102
dbCountDocumentsSpy.mockRestore();
99103
});
@@ -111,7 +115,7 @@ describe("MongoDB-Caching", () => {
111115
const res = await cacheClass.find();
112116

113117
expect(dbFindSpy).toHaveBeenCalledTimes(1);
114-
expect(res).toMatchObject([doc, doc1]);
118+
expect(res).toMatchObject([doc, doc1, doc2]);
115119

116120
dbFindSpy.mockRestore();
117121
});
@@ -133,8 +137,8 @@ describe("MongoDB-Caching", () => {
133137
{ cursor: c => c.skip(1).toArray() }
134138
);
135139

136-
expect(res1).toHaveLength(1);
137-
expect(res1).toMatchObject([doc1]);
140+
expect(res1).toHaveLength(2);
141+
expect(res1).toMatchObject([doc1, doc2]);
138142
expect(dbFindSpy).toHaveBeenCalledTimes(2);
139143

140144
dbFindSpy.mockRestore();
@@ -148,7 +152,7 @@ describe("MongoDB-Caching", () => {
148152

149153
expect(dbFindSpy).toHaveBeenCalledTimes(1);
150154

151-
expect(res).toMatchObject([doc, doc1]);
155+
expect(res).toMatchObject([doc, doc1, doc2]);
152156

153157
dbFindSpy.mockRestore();
154158
});
@@ -197,4 +201,29 @@ describe("MongoDB-Caching", () => {
197201

198202
activeThrottlesSpy.mockClear();
199203
});
204+
205+
it("should return the distinct documents", async () => {
206+
const dbDistinctSpy = jest.spyOn(cacheClass.collection, "distinct");
207+
208+
const res = await cacheClass.distinct("title", {});
209+
210+
expect(dbDistinctSpy).toHaveBeenCalledTimes(1);
211+
212+
expect(res).toStrictEqual(["test", "test2"]);
213+
214+
dbDistinctSpy.mockRestore();
215+
});
216+
217+
it("should return the cached distinct documents", async () => {
218+
const dbDistinctSpy = jest.spyOn(cacheClass.collection, "distinct");
219+
220+
await cacheClass.distinct("title", {});
221+
const res = await cacheClass.distinct("title", {});
222+
223+
expect(dbDistinctSpy).toHaveBeenCalledTimes(1);
224+
225+
expect(res).toStrictEqual(["test", "test2"]);
226+
227+
dbDistinctSpy.mockRestore();
228+
});
200229
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mongodb-caching",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"description": "MongoDB with automatic Caching functionality using Keyv.",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",

src/index.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ import type {
88
Filter,
99
FindCursor,
1010
FindOptions,
11-
WithId
11+
WithId,
12+
Document,
13+
DistinctOptions
1214
} from "mongodb";
1315

14-
export default class MongoDBCaching<TSchema = any, TContext = any> {
16+
export default class MongoDBCaching<
17+
TSchema extends Document = Document,
18+
TContext = any
19+
> {
1520
keyv: Keyv;
1621
context?: TContext;
1722

@@ -69,12 +74,12 @@ export default class MongoDBCaching<TSchema = any, TContext = any> {
6974
filter: Filter<TSchema> = {},
7075
options?: {
7176
findOptions?: FindOptions<Document>;
72-
cursor: (c: FindCursor<WithId<TSchema>>) => Promise<WithId<TSchema>[]>;
77+
cursor?: (c: FindCursor<WithId<TSchema>>) => Promise<WithId<TSchema>[]>;
7378
ttl?: number;
7479
}
7580
): Promise<WithId<TSchema>[]> {
7681
const cacheKeyOptions = options
77-
? { ...options, cursor: options.cursor.toString() }
82+
? { ...options, cursor: options.cursor?.toString() }
7883
: undefined;
7984

8085
const cacheKey = "find-" + this.getCacheKey(filter, cacheKeyOptions);
@@ -85,7 +90,7 @@ export default class MongoDBCaching<TSchema = any, TContext = any> {
8590
if (cacheDoc) return cacheDoc;
8691

8792
const res =
88-
(await options?.cursor(
93+
(await options?.cursor?.(
8994
this.collection.find(filter, options.findOptions)
9095
)) ||
9196
(await this.collection.find(filter, options?.findOptions).toArray());
@@ -118,6 +123,33 @@ export default class MongoDBCaching<TSchema = any, TContext = any> {
118123
});
119124
}
120125

126+
async distinct<Key extends keyof WithId<TSchema>>(
127+
key: Key,
128+
filter: Filter<TSchema>,
129+
options?: {
130+
distinctOptions?: DistinctOptions;
131+
ttl?: number;
132+
}
133+
) {
134+
const cacheKey = `distinct-${key.toString()}-` + this.getCacheKey(filter);
135+
136+
return this.throttleFunction(cacheKey, async () => {
137+
const cacheDoc = await this.keyv.get(cacheKey);
138+
139+
if (cacheDoc) return cacheDoc;
140+
141+
const res = await this.collection.distinct(
142+
key,
143+
filter,
144+
options?.distinctOptions as DistinctOptions
145+
);
146+
147+
await this.keyv.set(cacheKey, res, options?.ttl);
148+
149+
return res;
150+
});
151+
}
152+
121153
async clear() {
122154
return this.keyv.clear();
123155
}

0 commit comments

Comments
 (0)