Thin MongoDB ODM built for Standard Schema
mongodb
zod
deno
1import { z } from "@zod/zod";
2import { connect, disconnect, type Input, Model } from "../mod.ts";
3import { MongoMemoryServer } from "mongodb-memory-server-core";
4
5export const userSchema = z.object({
6 name: z.string(),
7 email: z.email(),
8 age: z.number().int().positive().optional(),
9 createdAt: z.date().default(() => new Date()),
10});
11
12export type UserInsert = Input<typeof userSchema>;
13
14let mongoServer: MongoMemoryServer | null = null;
15let isSetup = false;
16let setupRefCount = 0;
17let activeDbName: string | null = null;
18
19export async function setupTestDb(dbName = "test_db") {
20 setupRefCount++;
21
22 // If we're already connected, just share the same database
23 if (isSetup) {
24 if (activeDbName !== dbName) {
25 throw new Error(
26 `Test DB already initialized for ${activeDbName}, requested ${dbName}`,
27 );
28 }
29 return;
30 }
31
32 try {
33 mongoServer = await MongoMemoryServer.create();
34 const uri = mongoServer.getUri();
35
36 await connect(uri, dbName);
37 activeDbName = dbName;
38 isSetup = true;
39 } catch (error) {
40 // Roll back refcount if setup failed so future attempts can retry
41 setupRefCount = Math.max(0, setupRefCount - 1);
42 throw error;
43 }
44}
45
46export async function teardownTestDb() {
47 if (setupRefCount === 0) {
48 return;
49 }
50
51 setupRefCount = Math.max(0, setupRefCount - 1);
52
53 if (isSetup && setupRefCount === 0) {
54 await disconnect();
55 if (mongoServer) {
56 await mongoServer.stop();
57 mongoServer = null;
58 }
59 activeDbName = null;
60 isSetup = false;
61 }
62}
63
64export function createUserModel(
65 collectionName = "users",
66): Model<typeof userSchema> {
67 return new Model(collectionName, userSchema);
68}
69
70export async function cleanupCollection(model: Model<typeof userSchema>) {
71 await model.delete({});
72}