@nimbus-cqrs/mongodb 2.0.0-beta.0
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 +85 -0
- package/README.md +26 -0
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts +700 -0
- package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/fmt/1.0.10/colors.js +903 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/_util.d.ts +3 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/_util.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/_util.js +13 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts +42 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/closest_string.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/closest_string.js +46 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/compare_similarity.d.ts +47 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/compare_similarity.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/compare_similarity.js +39 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts +23 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/levenshtein_distance.js +127 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/mod.d.ts +26 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/mod.js +27 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_camel_case.d.ts +16 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_camel_case.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_camel_case.js +22 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_kebab_case.d.ts +16 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_kebab_case.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_kebab_case.js +21 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_pascal_case.d.ts +16 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_pascal_case.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_pascal_case.js +21 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_snake_case.d.ts +16 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_snake_case.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/to_snake_case.js +21 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/word_similarity_sort.d.ts +42 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/word_similarity_sort.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/text/1.0.18/word_similarity_sort.js +43 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.d.ts +14 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/_util.js +65 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.d.ts +20 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/decode_time.js +43 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.d.ts +44 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/mod.js +47 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.d.ts +44 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/monotonic_ulid.js +51 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.d.ts +31 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/ulid/1.0.0/ulid.js +37 -0
- package/esm/index.d.ts +21 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +20 -0
- package/esm/lib/crud/aggregate.d.ts +31 -0
- package/esm/lib/crud/aggregate.d.ts.map +1 -0
- package/esm/lib/crud/aggregate.js +37 -0
- package/esm/lib/crud/bulkWrite.d.ts +25 -0
- package/esm/lib/crud/bulkWrite.d.ts.map +1 -0
- package/esm/lib/crud/bulkWrite.js +22 -0
- package/esm/lib/crud/countDocuments.d.ts +25 -0
- package/esm/lib/crud/countDocuments.d.ts.map +1 -0
- package/esm/lib/crud/countDocuments.js +22 -0
- package/esm/lib/crud/deleteMany.d.ts +25 -0
- package/esm/lib/crud/deleteMany.d.ts.map +1 -0
- package/esm/lib/crud/deleteMany.js +22 -0
- package/esm/lib/crud/deleteOne.d.ts +25 -0
- package/esm/lib/crud/deleteOne.d.ts.map +1 -0
- package/esm/lib/crud/deleteOne.js +22 -0
- package/esm/lib/crud/find.d.ts +39 -0
- package/esm/lib/crud/find.d.ts.map +1 -0
- package/esm/lib/crud/find.js +53 -0
- package/esm/lib/crud/findOne.d.ts +29 -0
- package/esm/lib/crud/findOne.d.ts.map +1 -0
- package/esm/lib/crud/findOne.js +38 -0
- package/esm/lib/crud/findOneAndDelete.d.ts +31 -0
- package/esm/lib/crud/findOneAndDelete.d.ts.map +1 -0
- package/esm/lib/crud/findOneAndDelete.js +44 -0
- package/esm/lib/crud/findOneAndReplace.d.ts +33 -0
- package/esm/lib/crud/findOneAndReplace.d.ts.map +1 -0
- package/esm/lib/crud/findOneAndReplace.js +45 -0
- package/esm/lib/crud/findOneAndUpdate.d.ts +33 -0
- package/esm/lib/crud/findOneAndUpdate.d.ts.map +1 -0
- package/esm/lib/crud/findOneAndUpdate.js +45 -0
- package/esm/lib/crud/insertMany.d.ts +25 -0
- package/esm/lib/crud/insertMany.d.ts.map +1 -0
- package/esm/lib/crud/insertMany.js +22 -0
- package/esm/lib/crud/insertOne.d.ts +25 -0
- package/esm/lib/crud/insertOne.d.ts.map +1 -0
- package/esm/lib/crud/insertOne.js +22 -0
- package/esm/lib/crud/replaceOne.d.ts +27 -0
- package/esm/lib/crud/replaceOne.d.ts.map +1 -0
- package/esm/lib/crud/replaceOne.js +23 -0
- package/esm/lib/crud/updateMany.d.ts +27 -0
- package/esm/lib/crud/updateMany.d.ts.map +1 -0
- package/esm/lib/crud/updateMany.js +23 -0
- package/esm/lib/crud/updateOne.d.ts +27 -0
- package/esm/lib/crud/updateOne.d.ts.map +1 -0
- package/esm/lib/crud/updateOne.js +23 -0
- package/esm/lib/deployCollection.d.ts +33 -0
- package/esm/lib/deployCollection.d.ts.map +1 -0
- package/esm/lib/deployCollection.js +125 -0
- package/esm/lib/handleMongoError.d.ts +10 -0
- package/esm/lib/handleMongoError.d.ts.map +1 -0
- package/esm/lib/handleMongoError.js +29 -0
- package/esm/lib/mongoConnectionManager.d.ts +107 -0
- package/esm/lib/mongoConnectionManager.d.ts.map +1 -0
- package/esm/lib/mongoConnectionManager.js +195 -0
- package/esm/lib/mongoJSON.d.ts +36 -0
- package/esm/lib/mongoJSON.d.ts.map +1 -0
- package/esm/lib/mongoJSON.js +96 -0
- package/esm/lib/repository.d.ts +145 -0
- package/esm/lib/repository.d.ts.map +1 -0
- package/esm/lib/repository.js +235 -0
- package/esm/lib/tracing.d.ts +17 -0
- package/esm/lib/tracing.d.ts.map +1 -0
- package/esm/lib/tracing.js +62 -0
- package/esm/package.json +3 -0
- package/package.json +35 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { NotFoundException } from '../deps/jsr.io/@nimbus/core/2.0.0/src/index.js';
|
|
2
|
+
import { toSnakeCase } from '../deps/jsr.io/@std/text/1.0.18/mod.js';
|
|
3
|
+
import { ObjectId } from 'mongodb';
|
|
4
|
+
import { bulkWrite } from './crud/bulkWrite.js';
|
|
5
|
+
import { countDocuments } from './crud/countDocuments.js';
|
|
6
|
+
import { deleteMany } from './crud/deleteMany.js';
|
|
7
|
+
import { deleteOne } from './crud/deleteOne.js';
|
|
8
|
+
import { find } from './crud/find.js';
|
|
9
|
+
import { findOne } from './crud/findOne.js';
|
|
10
|
+
import { insertMany } from './crud/insertMany.js';
|
|
11
|
+
import { insertOne } from './crud/insertOne.js';
|
|
12
|
+
import { replaceOne } from './crud/replaceOne.js';
|
|
13
|
+
/**
|
|
14
|
+
* Repository for interacting with a MongoDB Collection
|
|
15
|
+
* which provides a type-safe interface for MongoDB CRUD operations.
|
|
16
|
+
*
|
|
17
|
+
* Why do we not implement a generic repository interface?
|
|
18
|
+
*
|
|
19
|
+
* Implementing a generic repository interface is incredibly difficult in terms of
|
|
20
|
+
* mapping filter patterns to the Database without the user having to change a
|
|
21
|
+
* filter input when switching databases in the background.
|
|
22
|
+
*
|
|
23
|
+
* So we feel it is better to make the underlying data store obvious to the user
|
|
24
|
+
* and give the user a way to interact with the repository in a way that feels
|
|
25
|
+
* natural to the underlying data store.
|
|
26
|
+
*
|
|
27
|
+
* @param collection - MongoDB Collection instance
|
|
28
|
+
* @param entityType - Zod type for validating the data and ensure type safety
|
|
29
|
+
* @param entityName - Name for the entity, e.g. used in error messages like "Entity not found"
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { MongoDBRepository } from '@nimbus/mongodb';
|
|
34
|
+
* import { getEnv } from '@nimbus/utils';
|
|
35
|
+
* import { mongoClient } from './mongoDBClient.ts';
|
|
36
|
+
* import { User } from './user.type.ts';
|
|
37
|
+
* import { USER_COLLECTION } from './user.collection.ts';
|
|
38
|
+
*
|
|
39
|
+
* class UserRepository extends MongoDBRepository<User> {
|
|
40
|
+
* constructor() {
|
|
41
|
+
* const env = getEnv({ variables: ['MONGO_DB'] });
|
|
42
|
+
*
|
|
43
|
+
* super(
|
|
44
|
+
* mongoClient.db(env.MONGO_DB).collection(USER_COLLECTION.name),
|
|
45
|
+
* User,
|
|
46
|
+
* );
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* override _mapDocumentToEntity(doc: Document): User {
|
|
50
|
+
* return User.parse({
|
|
51
|
+
* _id: doc._id.toString(),
|
|
52
|
+
* email: doc.email,
|
|
53
|
+
* });
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* override _mapEntityToDocument(user: User): Document {
|
|
57
|
+
* return {
|
|
58
|
+
* _id: new ObjectId(user._id),
|
|
59
|
+
* email: user.email,
|
|
60
|
+
* };
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* export const userRepository = new UserRepository();
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export class MongoDBRepository {
|
|
68
|
+
_getCollection;
|
|
69
|
+
_entityType;
|
|
70
|
+
_entityName;
|
|
71
|
+
constructor(getCollection, entityType, entityName) {
|
|
72
|
+
this._getCollection = getCollection;
|
|
73
|
+
this._entityType = entityType;
|
|
74
|
+
this._entityName = entityName ?? 'Document';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Function to map the MongoDB Document to the Entity.
|
|
78
|
+
* ZodType.parse is used to ensure the data is valid and type-safe.
|
|
79
|
+
*/
|
|
80
|
+
_mapDocumentToEntity(doc) {
|
|
81
|
+
return this._entityType.parse(doc);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Function to map the Entity to a MongoDB Document.
|
|
85
|
+
*/
|
|
86
|
+
_mapEntityToDocument(item) {
|
|
87
|
+
return item;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Find one document based on a given filter.
|
|
91
|
+
*/
|
|
92
|
+
async findOne({ filter, }) {
|
|
93
|
+
try {
|
|
94
|
+
const collection = await this._getCollection();
|
|
95
|
+
const res = await findOne({
|
|
96
|
+
collection,
|
|
97
|
+
filter,
|
|
98
|
+
mapDocument: this._mapDocumentToEntity,
|
|
99
|
+
outputType: this._entityType,
|
|
100
|
+
});
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (error.name === 'NOT_FOUND_EXCEPTION') {
|
|
105
|
+
throw new NotFoundException(`${this._entityName} not found`, {
|
|
106
|
+
errorCode: `${toSnakeCase(this._entityName).toUpperCase()}_NOT_FOUND`,
|
|
107
|
+
reason: `Could not find ${this._entityName} matching the given filter`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Find multiple documents based on a given filter.
|
|
115
|
+
*/
|
|
116
|
+
async find({ filter, limit, skip, sort, project, options, }) {
|
|
117
|
+
const collection = await this._getCollection();
|
|
118
|
+
return find({
|
|
119
|
+
collection,
|
|
120
|
+
filter,
|
|
121
|
+
limit,
|
|
122
|
+
skip,
|
|
123
|
+
sort,
|
|
124
|
+
project,
|
|
125
|
+
mapDocument: this._mapDocumentToEntity,
|
|
126
|
+
outputType: this._entityType,
|
|
127
|
+
options,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Count all documents matching a given filter.
|
|
132
|
+
*/
|
|
133
|
+
async countDocuments({ filter, options, }) {
|
|
134
|
+
const collection = await this._getCollection();
|
|
135
|
+
return countDocuments({
|
|
136
|
+
collection,
|
|
137
|
+
filter,
|
|
138
|
+
options,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Insert a single new document.
|
|
143
|
+
*/
|
|
144
|
+
async insertOne({ item, }) {
|
|
145
|
+
const collection = await this._getCollection();
|
|
146
|
+
await insertOne({
|
|
147
|
+
collection,
|
|
148
|
+
document: this._mapEntityToDocument(item),
|
|
149
|
+
});
|
|
150
|
+
return item;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Insert multiple new documents.
|
|
154
|
+
*/
|
|
155
|
+
async insertMany({ items, options, }) {
|
|
156
|
+
const collection = await this._getCollection();
|
|
157
|
+
await insertMany({
|
|
158
|
+
collection,
|
|
159
|
+
documents: items.map(this._mapEntityToDocument),
|
|
160
|
+
options,
|
|
161
|
+
});
|
|
162
|
+
return items;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Replace a single document.
|
|
166
|
+
*/
|
|
167
|
+
async replaceOne({ item, options, }) {
|
|
168
|
+
const collection = await this._getCollection();
|
|
169
|
+
const res = await replaceOne({
|
|
170
|
+
collection,
|
|
171
|
+
filter: { _id: new ObjectId(item._id) },
|
|
172
|
+
replacement: this._mapEntityToDocument(item),
|
|
173
|
+
options,
|
|
174
|
+
});
|
|
175
|
+
if (res.matchedCount === 0) {
|
|
176
|
+
throw new NotFoundException(`${this._entityName} not found`, {
|
|
177
|
+
errorCode: `${toSnakeCase(this._entityName).toUpperCase()}_NOT_FOUND`,
|
|
178
|
+
reason: `Could not find ${this._entityName} with the id: ${item._id}`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return item;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Replace multiple documents.
|
|
185
|
+
*/
|
|
186
|
+
async replaceMany({ items, options, }) {
|
|
187
|
+
if (items.length > 0) {
|
|
188
|
+
const collection = await this._getCollection();
|
|
189
|
+
const operations = items.map((item) => ({
|
|
190
|
+
replaceOne: {
|
|
191
|
+
filter: { _id: new ObjectId(item._id) },
|
|
192
|
+
replacement: this._mapEntityToDocument(item),
|
|
193
|
+
},
|
|
194
|
+
}));
|
|
195
|
+
await bulkWrite({
|
|
196
|
+
collection,
|
|
197
|
+
operations: operations,
|
|
198
|
+
options,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return items;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Delete a single document.
|
|
205
|
+
*/
|
|
206
|
+
async deleteOne({ item, options, }) {
|
|
207
|
+
const collection = await this._getCollection();
|
|
208
|
+
const res = await deleteOne({
|
|
209
|
+
collection,
|
|
210
|
+
filter: { _id: new ObjectId(item._id) },
|
|
211
|
+
options,
|
|
212
|
+
});
|
|
213
|
+
if (res.deletedCount === 0) {
|
|
214
|
+
throw new NotFoundException(`${this._entityName} not found`, {
|
|
215
|
+
errorCode: `${toSnakeCase(this._entityName).toUpperCase()}_NOT_FOUND`,
|
|
216
|
+
reason: `Could not find ${this._entityName} with the id: ${item._id}`,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return item;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Delete multiple documents.
|
|
223
|
+
*/
|
|
224
|
+
async deleteMany({ items, options, }) {
|
|
225
|
+
const collection = await this._getCollection();
|
|
226
|
+
await deleteMany({
|
|
227
|
+
collection,
|
|
228
|
+
filter: {
|
|
229
|
+
_id: { $in: items.map((item) => new ObjectId(item._id)) },
|
|
230
|
+
},
|
|
231
|
+
options,
|
|
232
|
+
});
|
|
233
|
+
return items;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Collection, Document } from 'mongodb';
|
|
2
|
+
export declare const tracer: import("@opentelemetry/api").Tracer;
|
|
3
|
+
export declare const DB_SYSTEM = "mongodb";
|
|
4
|
+
/**
|
|
5
|
+
* Wraps an async function with OpenTelemetry tracing and metrics.
|
|
6
|
+
*
|
|
7
|
+
* Records:
|
|
8
|
+
* - `mongodb_operation_total` counter with operation, collection, and status labels
|
|
9
|
+
* - `mongodb_operation_duration_seconds` histogram with operation and collection labels
|
|
10
|
+
*
|
|
11
|
+
* @param operation - The MongoDB operation name (e.g., 'findOne', 'insertMany')
|
|
12
|
+
* @param collection - The MongoDB collection being operated on
|
|
13
|
+
* @param fn - The async function to execute within the span
|
|
14
|
+
* @returns The result of the async function
|
|
15
|
+
*/
|
|
16
|
+
export declare const withSpan: <T>(operation: string, collection: Collection<Document>, fn: () => Promise<T>) => Promise<T>;
|
|
17
|
+
//# sourceMappingURL=tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/lib/tracing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,eAAO,MAAM,MAAM,qCAA4B,CAAC;AAEhD,eAAO,MAAM,SAAS,YAAY,CAAC;AAgBnC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACtB,WAAW,MAAM,EACjB,YAAY,UAAU,CAAC,QAAQ,CAAC,EAChC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,KACrB,OAAO,CAAC,CAAC,CAoDX,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { metrics, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api';
|
|
2
|
+
export const tracer = trace.getTracer('nimbus');
|
|
3
|
+
export const DB_SYSTEM = 'mongodb';
|
|
4
|
+
const meter = metrics.getMeter('nimbus');
|
|
5
|
+
const operationCounter = meter.createCounter('mongodb_operation_total', {
|
|
6
|
+
description: 'Total number of MongoDB operations',
|
|
7
|
+
});
|
|
8
|
+
const operationDuration = meter.createHistogram('mongodb_operation_duration_seconds', {
|
|
9
|
+
description: 'Duration of MongoDB operations in seconds',
|
|
10
|
+
unit: 's',
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Wraps an async function with OpenTelemetry tracing and metrics.
|
|
14
|
+
*
|
|
15
|
+
* Records:
|
|
16
|
+
* - `mongodb_operation_total` counter with operation, collection, and status labels
|
|
17
|
+
* - `mongodb_operation_duration_seconds` histogram with operation and collection labels
|
|
18
|
+
*
|
|
19
|
+
* @param operation - The MongoDB operation name (e.g., 'findOne', 'insertMany')
|
|
20
|
+
* @param collection - The MongoDB collection being operated on
|
|
21
|
+
* @param fn - The async function to execute within the span
|
|
22
|
+
* @returns The result of the async function
|
|
23
|
+
*/
|
|
24
|
+
export const withSpan = (operation, collection, fn) => {
|
|
25
|
+
const startTime = performance.now();
|
|
26
|
+
const metricLabels = {
|
|
27
|
+
operation,
|
|
28
|
+
collection: collection.collectionName,
|
|
29
|
+
};
|
|
30
|
+
return tracer.startActiveSpan(`mongodb.${operation}`, {
|
|
31
|
+
kind: SpanKind.CLIENT,
|
|
32
|
+
attributes: {
|
|
33
|
+
'db.system': DB_SYSTEM,
|
|
34
|
+
'db.operation': operation,
|
|
35
|
+
'db.mongodb.collection': collection.collectionName,
|
|
36
|
+
},
|
|
37
|
+
}, async (span) => {
|
|
38
|
+
try {
|
|
39
|
+
const result = await fn();
|
|
40
|
+
// Record success metrics
|
|
41
|
+
operationCounter.add(1, { ...metricLabels, status: 'success' });
|
|
42
|
+
operationDuration.record((performance.now() - startTime) / 1000, metricLabels);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Record error metrics
|
|
47
|
+
operationCounter.add(1, { ...metricLabels, status: 'error' });
|
|
48
|
+
operationDuration.record((performance.now() - startTime) / 1000, metricLabels);
|
|
49
|
+
span.setStatus({
|
|
50
|
+
code: SpanStatusCode.ERROR,
|
|
51
|
+
message: error instanceof Error
|
|
52
|
+
? error.message
|
|
53
|
+
: 'Unknown error',
|
|
54
|
+
});
|
|
55
|
+
span.recordException(error instanceof Error ? error : new Error('Unknown error'));
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
span.end();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
package/esm/package.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nimbus-cqrs/mongodb",
|
|
3
|
+
"version": "2.0.0-beta.0",
|
|
4
|
+
"description": "MongoDB integration for the Nimbus CQRS framework.",
|
|
5
|
+
"author": "Daniel Gördes <d.goerdes@overlap.at> (https://overlap.at)",
|
|
6
|
+
"homepage": "https://nimbus.overlap.at",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/overlap-dev/Nimbus"
|
|
10
|
+
},
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/overlap-dev/Nimbus/issues"
|
|
14
|
+
},
|
|
15
|
+
"module": "./esm/index.js",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./esm/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@opentelemetry/api": "^1.9.1",
|
|
27
|
+
"mongodb": "^7.1.1",
|
|
28
|
+
"zod": "^4.3.6",
|
|
29
|
+
"@nimbus-cqrs/core": "^2.0.0-beta.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.0.0"
|
|
33
|
+
},
|
|
34
|
+
"_generatedBy": "dnt@dev"
|
|
35
|
+
}
|