Thin MongoDB ODM built for Standard Schema
mongodb zod deno

feat: Enhance mizzleORM with extended functionalities and improved documentation

- Update package version to 1.0.3.
- Enhance `MongoModel` with methods for `insertMany`, `findById`, `updateOne`, `replaceOne`, `deleteOne`, `count`, `aggregate`, and `findPaginated`.
- Improve README.md with more detailed explanations, installation instructions, quick start guide, project structure, development guidelines, and license information.
- Correct `.npmignore` to exclude the `examples/` directory instead of `example.js/`.

+158 -60
+1 -1
.npmignore
··· 1 1 node_modules/ 2 2 tests/ 3 - example.js/ 3 + examples/
+94 -50
README.md
··· 1 - # mizzleORM 1 + # **mizzleORM** 2 2 3 - A lightweight, fully type-safe MongoDB ODM in TypeScript, inspired by Drizzle ORM. 3 + A lightweight, type-safe ODM for MongoDB in TypeScript — inspired by [Drizzle ORM](https://orm.drizzle.team/) and built for developers who value simplicity, transparency, and strong typings. 4 4 5 - ## Features 5 + --- 6 6 7 - * **Schema-first:** Define and validate document schemas using Zod. 8 - * **Type-safe queries:** Auto-complete and type-safe insert/find/update/delete operations. 9 - * **Lightweight & modular:** No decorators, no runtime magic – everything is composable and transparent. 10 - * **Developer-first DX:** Simple, minimal API with great IDE support. 11 - * Works directly on top of MongoDB's native driver. 7 + ## ✨ Features 12 8 13 - ## Installation 9 + * **Schema-first:** Define and validate collections using [Zod](https://zod.dev/). 10 + * **Type-safe operations:** Auto-complete and strict typings for `insert`, `find`, `update`, and `delete`. 11 + * **Minimal & modular:** No decorators or magic. Just clean, composable APIs. 12 + * **Developer-friendly DX:** Great TypeScript support and IDE integration. 13 + * **Built on MongoDB native driver:** Zero overhead with full control. 14 + 15 + --- 16 + 17 + ## 📦 Installation 14 18 15 19 ```bash 16 20 npm install mizzleorm mongodb zod ··· 18 22 yarn add mizzleorm mongodb zod 19 23 ``` 20 24 21 - ## Usage 25 + --- 22 26 23 - ### 1. Define your schema 27 + ## 🚀 Quick Start 24 28 25 - ```typescript 29 + ### 1. Define a schema 30 + 31 + ```ts 26 32 // src/schemas/user.ts 27 33 import { z } from 'zod'; 28 34 import { defineModel } from 'mizzleorm'; ··· 37 43 export type User = z.infer<typeof userSchema>; 38 44 ``` 39 45 40 - ### 2. Connect to MongoDB and create a model 46 + --- 41 47 42 - ```typescript 43 - // src/index.ts or your main application file 44 - import { connect, MongoModel, InferModel, InsertType } from 'mizzleorm'; 45 - import { userSchema } from './schemas/user'; // Assuming you saved the schema above 48 + ### 2. Initialize connection and model 49 + 50 + ```ts 51 + // src/index.ts 52 + import { connect, disconnect, MongoModel, InferModel, InsertType } from 'mizzleorm'; 53 + import { userSchema } from './schemas/user'; 46 54 import { ObjectId } from 'mongodb'; 47 55 48 - // Infer types 49 56 type User = InferModel<typeof userSchema>; 50 57 type UserInsert = InsertType<typeof userSchema>; 51 58 ··· 53 60 await connect('mongodb://localhost:27017', 'your_database_name'); 54 61 const UserModel = new MongoModel('users', userSchema); 55 62 56 - // ... perform operations 63 + // Your operations go here 57 64 58 65 await disconnect(); 59 66 } ··· 61 68 main().catch(console.error); 62 69 ``` 63 70 71 + --- 72 + 64 73 ### 3. Perform operations 65 74 66 - ```typescript 67 - // Insert a document 75 + ```ts 76 + // Insert one 68 77 const newUser: UserInsert = { 69 78 name: 'John Doe', 70 79 email: 'john.doe@example.com', 71 80 age: 30, 72 81 }; 73 82 const insertResult = await UserModel.insertOne(newUser); 74 - console.log('Inserted user:', insertResult.insertedId); 75 83 76 - // Find documents 84 + // Find many 77 85 const users = await UserModel.find({ name: 'John Doe' }); 78 - console.log('Found users:', users); 79 86 80 - // Find one document 81 - const foundUser = await UserModel.findOne({ _id: new ObjectId(insertResult.insertedId) }); 82 - console.log('Found one user:', foundUser); 87 + // Find one 88 + const found = await UserModel.findOne({ _id: new ObjectId(insertResult.insertedId) }); 83 89 84 - // Update a document 85 - const updateResult = await UserModel.update( 86 - { _id: new ObjectId(insertResult.insertedId) }, 87 - { age: 31 } 88 - ); 89 - console.log('Updated user count:', updateResult.modifiedCount); 90 + // Update 91 + await UserModel.update({ name: 'John Doe' }, { age: 31 }); 90 92 91 - // Delete documents 92 - const deleteResult = await UserModel.delete({ name: 'John Doe' }); 93 - console.log('Deleted user count:', deleteResult.deletedCount); 93 + // Delete 94 + await UserModel.delete({ name: 'John Doe' }); 95 + 96 + // Insert many 97 + await UserModel.insertMany([ 98 + { name: 'Alice', email: 'alice@example.com', age: 25 }, 99 + { name: 'Bob', email: 'bob@example.com' }, 100 + ]); 101 + 102 + // Find by ID 103 + await UserModel.findById(insertResult.insertedId); 104 + 105 + // Update one 106 + await UserModel.updateOne({ name: 'Alice' }, { age: 26 }); 107 + 108 + // Replace one 109 + await UserModel.replaceOne({ name: 'Bob' }, { 110 + name: 'Bob', 111 + email: 'bob@newmail.com', 112 + age: 22, 113 + }); 114 + 115 + // Delete one 116 + await UserModel.deleteOne({ name: 'Alice' }); 117 + 118 + // Count 119 + const count = await UserModel.count({ age: { $gte: 18 } }); 120 + 121 + // Aggregation 122 + const aggregation = await UserModel.aggregate([ 123 + { $match: { age: { $gte: 18 } } }, 124 + { $group: { _id: null, avgAge: { $avg: '$age' } } }, 125 + ]); 126 + 127 + // Paginated query 128 + const paginated = await UserModel.findPaginated( 129 + { age: { $gte: 18 } }, 130 + { skip: 0, limit: 10, sort: { age: -1 } } 131 + ); 94 132 ``` 95 133 96 - ## Project Structure 134 + --- 135 + 136 + ## 🧠 Project Structure 97 137 98 138 ``` 99 - mongo-orm/ 139 + mizzleorm/ 100 140 ├── src/ 101 - │ ├── schema.ts # schema definition utility 141 + │ ├── schema.ts # Schema definition utility 102 142 │ ├── model.ts # MongoModel wrapper 103 - │ ├── client.ts # MongoDB connection 104 - │ ├── index.ts # public API export 105 - ├── examples/ 106 - │ └── user.ts # usage example 107 - ├── tests/ 143 + │ ├── client.ts # MongoDB client connection 144 + │ └── index.ts # Public API exports 145 + ├── examples/ # Example usage files 146 + │ └── user.ts 147 + ├── tests/ # Unit and integration tests 108 148 ├── package.json 109 149 ├── tsconfig.json 110 - ├── README.md 150 + └── README.md 111 151 ``` 112 152 113 - ## Development 153 + --- 114 154 115 - To build the project: 155 + ## 🛠 Development 156 + 157 + ### Build the library: 116 158 117 159 ```bash 118 160 npm run build 119 161 ``` 120 162 121 - To run the example: 163 + ### Run the example: 122 164 123 165 ```bash 124 166 npm run example 125 167 ``` 126 168 127 - ## License 169 + --- 128 170 129 - MIT 171 + ## 📄 License 130 172 173 + MIT — use it freely and contribute back if you'd like! 131 174 175 + ---
+1 -1
package.json
··· 1 1 { 2 2 "name": "mizzleorm", 3 - "version": "1.0.1", 3 + "version": "1.0.3", 4 4 "description": "A lightweight, fully type-safe MongoDB ODM in TypeScript, inspired by Drizzle ORM.", 5 5 "main": "dist/index.js", 6 6 "types": "dist/index.d.ts",
+62 -8
src/model.ts
··· 1 1 import { z } from 'zod'; 2 - import { Collection, InsertOneResult, UpdateResult, DeleteResult, Document, ObjectId, Filter } from 'mongodb'; 2 + import { 3 + Collection, 4 + InsertOneResult, 5 + InsertManyResult, 6 + UpdateResult, 7 + DeleteResult, 8 + Document, 9 + ObjectId, 10 + Filter, 11 + OptionalUnlessRequiredId, 12 + WithId 13 + } from 'mongodb'; 3 14 import { getDb } from './client'; 4 15 import { InsertType } from './schema'; 5 16 ··· 14 25 15 26 async insertOne(data: InsertType<T>): Promise<InsertOneResult<z.infer<T>>> { 16 27 const validatedData = this.schema.parse(data); 17 - return this.collection.insertOne(validatedData as any); 28 + return this.collection.insertOne(validatedData as OptionalUnlessRequiredId<z.infer<T>>); 29 + } 30 + 31 + async insertMany(data: InsertType<T>[]): Promise<InsertManyResult<z.infer<T>>> { 32 + const validatedData = data.map((item) => this.schema.parse(item)); 33 + return this.collection.insertMany(validatedData as OptionalUnlessRequiredId<z.infer<T>>[]); 34 + } 35 + 36 + find(query: Filter<z.infer<T>>): Promise<(WithId<z.infer<T>>)[]> { 37 + return this.collection.find(query).toArray(); 18 38 } 19 39 20 - find(query: Filter<z.infer<T>>): Promise<(z.infer<T> & { _id: ObjectId })[]> { 21 - return this.collection.find(query).toArray() as Promise<(z.infer<T> & { _id: ObjectId })[]>; 40 + findOne(query: Filter<z.infer<T>>): Promise<WithId<z.infer<T>> | null> { 41 + return this.collection.findOne(query); 22 42 } 23 43 24 - findOne(query: Filter<z.infer<T>>): Promise<(z.infer<T> & { _id: ObjectId }) | null> { 25 - return this.collection.findOne(query) as Promise<(z.infer<T> & { _id: ObjectId }) | null>; 44 + async findById(id: string | ObjectId): Promise<WithId<z.infer<T>> | null> { 45 + const objectId = typeof id === 'string' ? new ObjectId(id) : id; 46 + return this.findOne({ _id: objectId } as Filter<z.infer<T>>); 26 47 } 27 48 28 49 async update(query: Filter<z.infer<T>>, data: Partial<z.infer<T>>): Promise<UpdateResult> { 29 50 return this.collection.updateMany(query, { $set: data }); 30 51 } 31 52 32 - delete(query: Filter<z.infer<T>>): Promise<DeleteResult> { 53 + async updateOne(query: Filter<z.infer<T>>, data: Partial<z.infer<T>>): Promise<UpdateResult> { 54 + return this.collection.updateOne(query, { $set: data }); 55 + } 56 + 57 + async replaceOne(query: Filter<z.infer<T>>, data: InsertType<T>): Promise<UpdateResult> { 58 + const validatedData = this.schema.parse(data); 59 + return this.collection.replaceOne(query, validatedData as OptionalUnlessRequiredId<z.infer<T>>); 60 + } 61 + 62 + async delete(query: Filter<z.infer<T>>): Promise<DeleteResult> { 33 63 return this.collection.deleteMany(query); 34 64 } 65 + 66 + async deleteOne(query: Filter<z.infer<T>>): Promise<DeleteResult> { 67 + return this.collection.deleteOne(query); 68 + } 69 + 70 + async count(query: Filter<z.infer<T>>): Promise<number> { 71 + return this.collection.countDocuments(query); 72 + } 73 + 74 + async aggregate(pipeline: Document[]): Promise<any[]> { 75 + return this.collection.aggregate(pipeline).toArray(); 76 + } 77 + 78 + // Pagination support for find 79 + async findPaginated( 80 + query: Filter<z.infer<T>>, 81 + options: { skip?: number; limit?: number; sort?: Document } = {} 82 + ): Promise<(WithId<z.infer<T>>)[]> { 83 + return this.collection 84 + .find(query) 85 + .skip(options.skip ?? 0) 86 + .limit(options.limit ?? 10) 87 + .sort(options.sort ?? {}) 88 + .toArray(); 89 + } 35 90 } 36 91 37 -