momos 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Rhinobase
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # 🥟 Momos
2
+
3
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/rhinobase/momos)
4
+ [![npm version](https://img.shields.io/npm/v/momos.svg)](https://npmjs.org/package/momos "View this project on NPM")
5
+ [![npm downloads](https://img.shields.io/npm/dm/momos)](https://www.npmjs.com/package/momos)
6
+
7
+ A lightweight, type-safe MongoDB ORM that uses your validation schema for type-safe queries, inserts, and updates. Validates documents before insert/update operations automatically.
8
+
9
+ This lib supports all the validation libs which are [Standard Schema](https://standardschema.dev/) compliant (zod, valibot, arktype, etc.).
10
+
11
+ For documentation visit [honohub.dev](https://honohub.dev/docs/momos).
12
+
13
+ > [!Note]
14
+ > This package is still in development and your feedback is highly appreciated. If you have any suggestions or issues, please let us know by creating an issue on GitHub.
15
+
16
+ ## Contributing
17
+
18
+ Visit our [contributing docs](https://github.com/rhinobase/momos/blob/main/CONTRIBUTING.md).
package/dist/index.cjs ADDED
@@ -0,0 +1,375 @@
1
+ 'use strict';
2
+
3
+ class TypedCursor {
4
+ constructor(cursor) {
5
+ this.cursor = cursor;
6
+ }
7
+ /**
8
+ * Get the underlying MongoDB cursor
9
+ */
10
+ get raw() {
11
+ return this.cursor;
12
+ }
13
+ /**
14
+ * Returns all documents as an array
15
+ */
16
+ async toArray() {
17
+ return this.cursor.toArray();
18
+ }
19
+ /**
20
+ * Iterate over documents with a callback
21
+ */
22
+ async forEach(callback) {
23
+ for await (const doc of this.cursor) {
24
+ await callback(doc);
25
+ }
26
+ }
27
+ /**
28
+ * Map documents to a new type
29
+ */
30
+ map(transform) {
31
+ return new TypedCursor(this.cursor.map(transform));
32
+ }
33
+ /**
34
+ * Check if there are more documents
35
+ */
36
+ async hasNext() {
37
+ return this.cursor.hasNext();
38
+ }
39
+ /**
40
+ * Get the next document
41
+ */
42
+ async next() {
43
+ return this.cursor.next();
44
+ }
45
+ /**
46
+ * Close the cursor
47
+ */
48
+ async close() {
49
+ await this.cursor.close();
50
+ }
51
+ /**
52
+ * Make the cursor iterable
53
+ */
54
+ [Symbol.asyncIterator]() {
55
+ return this.cursor[Symbol.asyncIterator]();
56
+ }
57
+ }
58
+ class TypedFindCursor extends TypedCursor {
59
+ /**
60
+ * Map documents to a new type
61
+ */
62
+ map(transform) {
63
+ return new TypedFindCursor(this.cursor.map(transform));
64
+ }
65
+ /**
66
+ * Limit the number of documents returned
67
+ */
68
+ limit(count) {
69
+ this.cursor.limit(count);
70
+ return this;
71
+ }
72
+ /**
73
+ * Skip a number of documents
74
+ */
75
+ skip(count) {
76
+ this.cursor.skip(count);
77
+ return this;
78
+ }
79
+ /**
80
+ * Sort the documents
81
+ */
82
+ sort(sort) {
83
+ this.cursor.sort(sort);
84
+ return this;
85
+ }
86
+ /**
87
+ * Project specific fields
88
+ */
89
+ project(projection) {
90
+ this.cursor.project(projection);
91
+ return this;
92
+ }
93
+ /**
94
+ * Set batch size for cursor
95
+ */
96
+ batchSize(size) {
97
+ this.cursor.batchSize(size);
98
+ return this;
99
+ }
100
+ }
101
+ class TypedAggregationCursor extends TypedCursor {
102
+ /**
103
+ * Map documents to a new type
104
+ */
105
+ map(transform) {
106
+ return new TypedAggregationCursor(this.cursor.map(transform));
107
+ }
108
+ }
109
+
110
+ class ValidationError extends Error {
111
+ issues;
112
+ constructor(issues) {
113
+ const message = issues.map((i) => i.message).join(", ");
114
+ super(`Validation failed: ${message}`);
115
+ this.name = "ValidationError";
116
+ this.issues = issues;
117
+ }
118
+ }
119
+
120
+ async function validate(schema, data) {
121
+ const result = await schema["~standard"].validate(data);
122
+ if (result.issues) {
123
+ throw new ValidationError(result.issues);
124
+ }
125
+ return result.value;
126
+ }
127
+ async function validateMany(schema, data) {
128
+ return Promise.all(data.map((item) => validate(schema, item)));
129
+ }
130
+ async function isValid(schema, data) {
131
+ const result = await schema["~standard"].validate(data);
132
+ return !result.issues;
133
+ }
134
+
135
+ class TypedCollection {
136
+ collection;
137
+ schema;
138
+ shouldValidate;
139
+ constructor(collection, schema, options = {}) {
140
+ this.collection = collection;
141
+ this.schema = schema;
142
+ this.shouldValidate = options.validate !== false;
143
+ }
144
+ /**
145
+ * Get the underlying MongoDB collection
146
+ */
147
+ get raw() {
148
+ return this.collection;
149
+ }
150
+ /**
151
+ * Get the collection name
152
+ */
153
+ get collectionName() {
154
+ return this.collection.collectionName;
155
+ }
156
+ // ============================================
157
+ // INSERT OPERATIONS
158
+ // ============================================
159
+ /**
160
+ * Insert a single document
161
+ * Validates the document before insertion if validation is enabled
162
+ */
163
+ async insertOne(doc, options) {
164
+ const validated = this.shouldValidate ? await validate(this.schema, doc) : doc;
165
+ return this.collection.insertOne(validated, options);
166
+ }
167
+ /**
168
+ * Insert multiple documents
169
+ * Validates all documents before insertion if validation is enabled
170
+ */
171
+ async insertMany(docs, options) {
172
+ const validated = this.shouldValidate ? await validateMany(this.schema, docs) : docs;
173
+ return this.collection.insertMany(validated, options);
174
+ }
175
+ // ============================================
176
+ // FIND OPERATIONS
177
+ // ============================================
178
+ /**
179
+ * Find documents matching the filter
180
+ * Returns a typed cursor for further operations
181
+ */
182
+ find(filter = {}, options) {
183
+ const cursor = this.collection.find(filter, options);
184
+ return new TypedFindCursor(cursor);
185
+ }
186
+ /**
187
+ * Find a single document matching the filter
188
+ */
189
+ async findOne(filter = {}, options) {
190
+ const result = await this.collection.findOne(filter, options);
191
+ return result;
192
+ }
193
+ /**
194
+ * Find a document by its _id
195
+ */
196
+ async findById(id, options) {
197
+ return this.findOne({ _id: id }, options);
198
+ }
199
+ // ============================================
200
+ // UPDATE OPERATIONS
201
+ // ============================================
202
+ /**
203
+ * Update a single document
204
+ */
205
+ async updateOne(filter, update, options) {
206
+ return this.collection.updateOne(
207
+ filter,
208
+ update,
209
+ options
210
+ );
211
+ }
212
+ /**
213
+ * Update multiple documents
214
+ */
215
+ async updateMany(filter, update, options) {
216
+ return this.collection.updateMany(
217
+ filter,
218
+ update,
219
+ options
220
+ );
221
+ }
222
+ /**
223
+ * Replace a single document
224
+ * Validates the replacement document if validation is enabled
225
+ */
226
+ async replaceOne(filter, replacement, options) {
227
+ const validated = this.shouldValidate ? await validate(this.schema, replacement) : replacement;
228
+ return this.collection.replaceOne(
229
+ filter,
230
+ validated,
231
+ options
232
+ );
233
+ }
234
+ /**
235
+ * Find a document and update it atomically
236
+ */
237
+ async findOneAndUpdate(filter, update, options = {}) {
238
+ const result = await this.collection.findOneAndUpdate(
239
+ filter,
240
+ update,
241
+ options
242
+ );
243
+ return result;
244
+ }
245
+ /**
246
+ * Find a document and replace it atomically
247
+ * Validates the replacement document if validation is enabled
248
+ */
249
+ async findOneAndReplace(filter, replacement, options = {}) {
250
+ const validated = this.shouldValidate ? await validate(this.schema, replacement) : replacement;
251
+ const result = await this.collection.findOneAndReplace(
252
+ filter,
253
+ validated,
254
+ options
255
+ );
256
+ return result;
257
+ }
258
+ // ============================================
259
+ // DELETE OPERATIONS
260
+ // ============================================
261
+ /**
262
+ * Delete a single document
263
+ */
264
+ async deleteOne(filter, options) {
265
+ return this.collection.deleteOne(filter, options);
266
+ }
267
+ /**
268
+ * Delete multiple documents
269
+ */
270
+ async deleteMany(filter, options) {
271
+ return this.collection.deleteMany(filter, options);
272
+ }
273
+ /**
274
+ * Find a document and delete it atomically
275
+ */
276
+ async findOneAndDelete(filter, options = {}) {
277
+ const result = await this.collection.findOneAndDelete(
278
+ filter,
279
+ options
280
+ );
281
+ return result;
282
+ }
283
+ // ============================================
284
+ // COUNT OPERATIONS
285
+ // ============================================
286
+ /**
287
+ * Count documents matching the filter
288
+ */
289
+ async countDocuments(filter = {}, options) {
290
+ return this.collection.countDocuments(filter, options);
291
+ }
292
+ /**
293
+ * Get an estimated count of documents (faster, uses metadata)
294
+ */
295
+ async estimatedDocumentCount(options) {
296
+ return this.collection.estimatedDocumentCount(options);
297
+ }
298
+ // ============================================
299
+ // AGGREGATION
300
+ // ============================================
301
+ /**
302
+ * Run an aggregation pipeline
303
+ */
304
+ aggregate(pipeline, options) {
305
+ const cursor = this.collection.aggregate(pipeline, options);
306
+ return new TypedAggregationCursor(cursor);
307
+ }
308
+ // ============================================
309
+ // INDEX OPERATIONS
310
+ // ============================================
311
+ /**
312
+ * Create an index
313
+ */
314
+ async createIndex(indexSpec, options) {
315
+ return this.collection.createIndex(indexSpec, options);
316
+ }
317
+ /**
318
+ * Create multiple indexes
319
+ */
320
+ async createIndexes(indexSpecs, options) {
321
+ return this.collection.createIndexes(indexSpecs, options);
322
+ }
323
+ /**
324
+ * Drop an index
325
+ */
326
+ async dropIndex(indexName, options) {
327
+ await this.collection.dropIndex(indexName, options);
328
+ }
329
+ /**
330
+ * List all indexes
331
+ */
332
+ async indexes() {
333
+ return this.collection.indexes();
334
+ }
335
+ // ============================================
336
+ // UTILITY OPERATIONS
337
+ // ============================================
338
+ /**
339
+ * Get distinct values for a field
340
+ */
341
+ async distinct(field, filter = {}) {
342
+ const result = await this.collection.distinct(
343
+ field,
344
+ filter
345
+ );
346
+ return result;
347
+ }
348
+ /**
349
+ * Check if a document exists
350
+ */
351
+ async exists(filter) {
352
+ const count = await this.countDocuments(filter, { limit: 1 });
353
+ return count > 0;
354
+ }
355
+ /**
356
+ * Drop the collection
357
+ */
358
+ async drop() {
359
+ await this.collection.drop();
360
+ }
361
+ }
362
+ function defineCollection(db, name, schema, options = {}) {
363
+ const collection = db.collection(name);
364
+ return new TypedCollection(collection, schema, options);
365
+ }
366
+
367
+ exports.TypedAggregationCursor = TypedAggregationCursor;
368
+ exports.TypedCollection = TypedCollection;
369
+ exports.TypedCursor = TypedCursor;
370
+ exports.TypedFindCursor = TypedFindCursor;
371
+ exports.ValidationError = ValidationError;
372
+ exports.defineCollection = defineCollection;
373
+ exports.isValid = isValid;
374
+ exports.validate = validate;
375
+ exports.validateMany = validateMany;