assai 2.0.0 → 2.1.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.
Files changed (60) hide show
  1. package/README.md +148 -148
  2. package/dist/src/__test/mock_get_collection.d.mts +2 -0
  3. package/dist/src/factories/create_mongo_collection.d.mts +55 -11
  4. package/dist/src/usecases/mongo/operation/aggregate.d.mts +16 -0
  5. package/dist/src/usecases/mongo/operation/bulk_write.d.mts +15 -0
  6. package/dist/src/usecases/mongo/operation/find_one_and_delete.d.mts +16 -0
  7. package/dist/src/usecases/mongo/operation/find_one_and_replace.d.mts +18 -0
  8. package/dist/src/usecases/mongo/operation/find_one_and_update.d.mts +18 -0
  9. package/dist/src/usecases/mongo/operation/index.d.mts +5 -0
  10. package/dist/src/usecases/mongo/transformers/id/rename_to_mongo_id.d.mts +3 -0
  11. package/dist/src/usecases/mongo/transformers/object_id/ids_into_strings.d.mts +5 -0
  12. package/dist/src/usecases/mongo/transformers/object_id/strings_into_id.d.mts +3 -0
  13. package/dist/src/usecases/mongo/transformers/timestamps.d.mts +5 -0
  14. package/index.mjs +2 -2
  15. package/jsconfig.json +17 -20
  16. package/jsconfig.prod.json +12 -12
  17. package/package.json +40 -39
  18. package/src/__test/manage_mock_database.mjs +24 -24
  19. package/src/__test/manage_mock_registry.mjs +54 -54
  20. package/src/__test/mock_get_collection.mjs +22 -20
  21. package/src/data/errors/operation_fail.mjs +9 -9
  22. package/src/data/errors/unsupported_error.mjs +9 -9
  23. package/src/data/interfaces/mongo_operator.mjs +2 -2
  24. package/src/data/interfaces/native_collection.mjs +27 -27
  25. package/src/factories/create_mock_collection.mjs +173 -173
  26. package/src/factories/create_mongo_collection.mjs +224 -181
  27. package/src/factories/index.mjs +1 -1
  28. package/src/types.ts +31 -31
  29. package/src/usecases/index.mjs +1 -1
  30. package/src/usecases/mongo/generate_new_id.mjs +4 -4
  31. package/src/usecases/mongo/index.mjs +3 -3
  32. package/src/usecases/mongo/mongo_client.mjs +36 -36
  33. package/src/usecases/mongo/operation/additional/delete_one_or_throw.mjs +17 -17
  34. package/src/usecases/mongo/operation/additional/index.mjs +1 -1
  35. package/src/usecases/mongo/operation/aggregate.mjs +21 -0
  36. package/src/usecases/mongo/operation/bulk_write.mjs +54 -0
  37. package/src/usecases/mongo/operation/count.mjs +16 -16
  38. package/src/usecases/mongo/operation/delete_many.mjs +15 -15
  39. package/src/usecases/mongo/operation/delete_one.mjs +16 -16
  40. package/src/usecases/mongo/operation/find.mjs +34 -34
  41. package/src/usecases/mongo/operation/find_one.mjs +32 -32
  42. package/src/usecases/mongo/operation/find_one_and_delete.mjs +23 -0
  43. package/src/usecases/mongo/operation/find_one_and_replace.mjs +24 -0
  44. package/src/usecases/mongo/operation/find_one_and_update.mjs +40 -0
  45. package/src/usecases/mongo/operation/index.mjs +15 -10
  46. package/src/usecases/mongo/operation/insert_many.mjs +39 -39
  47. package/src/usecases/mongo/operation/insert_one.mjs +32 -32
  48. package/src/usecases/mongo/operation/update_many.mjs +39 -39
  49. package/src/usecases/mongo/operation/update_one.mjs +40 -40
  50. package/src/usecases/mongo/transformers/id/index.mjs +4 -4
  51. package/src/usecases/mongo/transformers/id/rename_find_options.mjs +12 -12
  52. package/src/usecases/mongo/transformers/id/rename_to_dev_id.mjs +14 -13
  53. package/src/usecases/mongo/transformers/id/rename_to_mongo_id.mjs +34 -13
  54. package/src/usecases/mongo/transformers/index.mjs +2 -2
  55. package/src/usecases/mongo/transformers/input_transformer.mjs +32 -32
  56. package/src/usecases/mongo/transformers/object_id/ids_into_strings.mjs +47 -30
  57. package/src/usecases/mongo/transformers/object_id/index.mjs +3 -3
  58. package/src/usecases/mongo/transformers/object_id/strings_into_id.mjs +90 -44
  59. package/src/usecases/mongo/transformers/output_transformer.mjs +18 -18
  60. package/src/usecases/mongo/transformers/timestamps.mjs +32 -22
@@ -1,182 +1,225 @@
1
- import { Collection } from 'mongodb'
2
- import {
3
- count, deleteMany, deleteOne,
4
- deleteOneOrThrow,
5
- find, findOne,
6
- getClient,
7
- insertMany, insertOne, updateMany, updateOne
8
- } from '../usecases/mongo/index.mjs'
9
-
10
- /**
11
- * Generates a collection object that automatically manage ObjectId conversion to string.
12
- *
13
- * This method will read the string DATABASE_URL to create a connection. If you have it in another
14
- * location, you will need to pass it at `connectionString` property inside the options parameter.
15
- *
16
- * The connection is cached by default. Use `collectionGetter` and `cachedCollectionGetter` to
17
- * customize this behavior.
18
- * @template {import('../types.js').MongoDocument} T
19
- * @param {string} name
20
- * @param {IcreateCollectionOptions<T>} [options]
21
- */
22
- export function createMongoCollection(name, options = {}) {
23
-
24
- /** @type {Collection<T> | null} */
25
- let _collection = null
26
- const collectionOptions = options
27
-
28
- async function getCollection() {
29
- const {
30
- connectionString, dbName, options: createOptions,
31
- cachableCollectionGetter, collectionGetter,
32
- } = options
33
-
34
- // Connection getter from options
35
- if (collectionGetter != null) return await collectionGetter()
36
-
37
- // Checking cache
38
- if (_collection) return _collection
39
-
40
- // Cache function from options
41
- if (cachableCollectionGetter != null) {
42
- _collection = await cachableCollectionGetter()
43
- return _collection
44
- }
45
-
46
- // Default connection getter
47
- const client = await getClient({ connectionString })
48
- let db = client.db(dbName, createOptions)
49
- /** @type {Collection<T>} */
50
- _collection = db.collection(name)
51
- return _collection
52
- }
53
-
54
- return {
55
- /**
56
- * Returns the native driver.
57
- */
58
- getCollection,
59
- /**
60
- * @param {import('mongodb').Filter<T>} query
61
- */
62
- count: async (query = {}) => await count({ query, getCollection }),
63
- /**
64
- * @template {import('../types.js').Projection<T>} K
65
- * @param {import('mongodb').Filter<T>} query
66
- * @param {import('../types.js').FindOptions<T, K>} options
67
- * @returns {Promise<T[]>}
68
- */
69
- find: async (query, options = {}) => {
70
- return await find({ query, options, getCollection, collectionOptions })
71
- },
72
- /**
73
- * @template {import('../types.js').Projection<T> | undefined} K
74
- * @param {import('mongodb').Filter<T>} query
75
- * @param {import('../types.js').FindOptions<T,K>} options
76
- * @returns {Promise<T | null>}
77
- */
78
- findOne: async (query, options = {}) => {
79
- return await findOne({ query, options, collectionOptions, getCollection })
80
- },
81
- /**
82
- * @param {import('../types.js').Optional<T, 'id'>} doc
83
- * @returns {Promise<T>}
84
- */
85
- insertOne: async (doc) => {
86
- return await insertOne({
87
- doc,
88
- getCollection,
89
- collectionOptions,
90
- })
91
- },
92
- /**
93
- *
94
- * @param {import('../types.js').Optional<T, 'id'>[]} docs
95
- * @returns {Promise<T[]>}
96
- */
97
- insertMany: async (docs) => await insertMany({ docs, collectionOptions, getCollection }),
98
- /**
99
- * @param {import('mongodb').Filter<T>} query
100
- * @returns {Promise<boolean>}
101
- */
102
- deleteOne: async (query) => await deleteOne({ query, getCollection }),
103
- /**
104
- * Deletes the first document to match the query.
105
- * This method will throw an error if no documents were deleted.
106
- * @param {import('mongodb').Filter<T>} query
107
- * @throw {@link OperationFail} If not document was deleted
108
- */
109
- deleteOneOrThrow: async query => await deleteOneOrThrow({ query, getCollection }),
110
- /**
111
- *
112
- * @param {import('mongodb').Filter<T>} query
113
- */
114
- deleteMany: async (query) => await deleteMany({ query, getCollection }),
115
- /**
116
- * @param {import('mongodb').Filter<T>} query
117
- * @param {import('mongodb').UpdateFilter<T>} update
118
- * @param {import('mongodb').UpdateOptions} [options]
119
- */
120
- updateOne: async (query, update, options) => await updateOne({
121
- query, update, options, collectionOptions, getCollection,
122
- }),
123
- /**
124
- * @param {import('mongodb').Filter<T>} query
125
- * @param {import('mongodb').UpdateFilter<T>} update
126
- * @param {import('mongodb').UpdateOptions} [options]
127
- */
128
- updateMany: async (query, update, options) => await updateMany({
129
- query, update, options, collectionOptions, getCollection,
130
- })
131
- }
132
- }
133
-
134
- /**
135
- * @template {import('../types.js').MongoDocument} T
136
- * @callback IcollectionGetter
137
- * @returns {Promise<Collection<T>>}
138
- */
139
-
140
- /**
141
- * @template {import('../types.js').MongoDocument} T
142
- * @typedef {object} IcreateCollectionOptions
143
- * @property {IcollectionGetter<T>} [options.collectionGetter]
144
- * A custom function to get the collection object from mongodb driver.
145
- *
146
- * This will be not be cached and will be used on every operation such as insertOne or findOne.
147
- *
148
- * If you wish to cache the collection object, see `cachableCollectionGetter`.
149
- *
150
- * Example:
151
- * ```js
152
- * collectionGetter: async () => await getMyCollection()
153
- * ```
154
- *
155
- * @property {IcollectionGetter<T>} [options.cachableCollectionGetter]
156
- * Same as `collectionGetter`. But the object is cached.
157
- *
158
- * Example:
159
- * ```js
160
- * cachableCollectionGetter: async () => await getMyCollection()
161
- * ```
162
- *
163
- * @property {string} [options.connectionString]
164
- * A custom connection string. If none is given, `process.env.DATABASE_URL` will be used.
165
- *
166
- * @property {string} [dbName] The name of the database.
167
- *
168
- * @property {import('mongodb').DbOptions} [options] The options used when initializing the client.
169
- *
170
- * @property {ItimestampConfiguration} [timestamps]
171
- */
172
-
173
- /**
174
- * @typedef {object} ItimestampConfiguration
175
- * @property {'fromId' | 'generate' | 'none'} createdAt
176
- * @property {'generate' | 'none'} updatedAt
177
- */
178
-
179
- /**
180
- * @template {import('../types.js').MongoDocument} T
181
- * @typedef {Awaited<ReturnType<typeof createMongoCollection<T>>>} ICollection
1
+ import { Collection } from 'mongodb'
2
+ import {
3
+ aggregate, bulkWrite,
4
+ count, deleteMany, deleteOne,
5
+ deleteOneOrThrow,
6
+ find, findOne, findOneAndDelete, findOneAndReplace, findOneAndUpdate,
7
+ getClient,
8
+ insertMany, insertOne, updateMany, updateOne
9
+ } from '../usecases/mongo/index.mjs'
10
+
11
+ /**
12
+ * Generates a collection object that automatically manage ObjectId conversion to string.
13
+ *
14
+ * This method will read the string DATABASE_URL to create a connection. If you have it in another
15
+ * location, you will need to pass it at `connectionString` property inside the options parameter.
16
+ *
17
+ * The connection is cached by default. Use `collectionGetter` to customize this behavior.
18
+ * @template {import('../types.js').MongoDocument} T
19
+ * @param {string} name
20
+ * @param {IcreateCollectionOptions<T>} [options]
21
+ */
22
+ export function createMongoCollection(name, options = {}) {
23
+
24
+ /** @type {Collection<T> | null} */
25
+ let _collection = null
26
+ const collectionOptions = options
27
+
28
+ async function getCollection() {
29
+ const {
30
+ connectionString, dbName, options: createOptions,
31
+ collectionGetter,
32
+ } = options
33
+
34
+ // Connection getter from options
35
+ if (collectionGetter != null) return await collectionGetter()
36
+
37
+ // Checking cache
38
+ if (_collection) return _collection
39
+
40
+ // Default connection getter
41
+ const client = await getClient({ connectionString })
42
+ let db = client.db(dbName, createOptions)
43
+ /** @type {Collection<T>} */
44
+ _collection = db.collection(name)
45
+ return _collection
46
+ }
47
+
48
+ return {
49
+ /**
50
+ * Returns the native driver.
51
+ */
52
+ getCollection,
53
+ /**
54
+ * @param {import('mongodb').Filter<T>} query
55
+ */
56
+ count: async (query = {}) => await count({ query, getCollection }),
57
+ /**
58
+ * @template {import('../types.js').Projection<T>} K
59
+ * @param {import('mongodb').Filter<T>} query
60
+ * @param {import('../types.js').FindOptions<T, K>} options
61
+ * @returns {Promise<T[]>}
62
+ */
63
+ find: async (query, options = {}) => {
64
+ return await find({ query, options, getCollection, collectionOptions })
65
+ },
66
+ /**
67
+ * @template {import('../types.js').Projection<T> | undefined} K
68
+ * @param {import('mongodb').Filter<T>} query
69
+ * @param {import('../types.js').FindOptions<T,K>} options
70
+ * @returns {Promise<T | null>}
71
+ */
72
+ findOne: async (query, options = {}) => {
73
+ return await findOne({ query, options, collectionOptions, getCollection })
74
+ },
75
+ /**
76
+ * @param {import('../types.js').Optional<T, 'id'>} doc
77
+ * @returns {Promise<T>}
78
+ */
79
+ insertOne: async (doc) => {
80
+ return await insertOne({
81
+ doc,
82
+ getCollection,
83
+ collectionOptions,
84
+ })
85
+ },
86
+ /**
87
+ *
88
+ * @param {import('../types.js').Optional<T, 'id'>[]} docs
89
+ * @returns {Promise<T[]>}
90
+ */
91
+ insertMany: async (docs) => await insertMany({ docs, collectionOptions, getCollection }),
92
+ /**
93
+ * @param {import('mongodb').Filter<T>} query
94
+ * @returns {Promise<boolean>}
95
+ */
96
+ deleteOne: async (query) => await deleteOne({ query, getCollection }),
97
+ /**
98
+ * Deletes the first document to match the query.
99
+ * This method will throw an error if no documents were deleted.
100
+ * @param {import('mongodb').Filter<T>} query
101
+ * @throw {@link OperationFail} If not document was deleted
102
+ */
103
+ deleteOneOrThrow: async query => await deleteOneOrThrow({ query, getCollection }),
104
+ /**
105
+ *
106
+ * @param {import('mongodb').Filter<T>} query
107
+ */
108
+ deleteMany: async (query) => await deleteMany({ query, getCollection }),
109
+ /**
110
+ * @param {import('mongodb').Filter<T>} query
111
+ * @param {import('mongodb').UpdateFilter<T>} update
112
+ * @param {import('mongodb').UpdateOptions} [options]
113
+ */
114
+ updateOne: async (query, update, options) => await updateOne({
115
+ query, update, options, collectionOptions, getCollection,
116
+ }),
117
+ /**
118
+ * @param {import('mongodb').Filter<T>} query
119
+ * @param {import('mongodb').UpdateFilter<T>} update
120
+ * @param {import('mongodb').UpdateOptions} [options]
121
+ */
122
+ updateMany: async (query, update, options) => await updateMany({
123
+ query, update, options, collectionOptions, getCollection,
124
+ }),
125
+ /**
126
+ * @param {import('mongodb').Document[]} pipeline
127
+ * @param {import('mongodb').AggregateOptions} [options]
128
+ * @returns {Promise<T[]>}
129
+ */
130
+ aggregate: async (pipeline, options) => await aggregate({
131
+ pipeline, options, getCollection, collectionOptions,
132
+ }),
133
+ /**
134
+ * @param {import('mongodb').AnyBulkWriteOperation<T>[]} operations
135
+ * @param {import('mongodb').BulkWriteOptions} [options]
136
+ */
137
+ bulkWrite: async (operations, options) => await bulkWrite({
138
+ operations, options, getCollection, collectionOptions,
139
+ }),
140
+ /**
141
+ * Atomically finds a document, applies the update, and returns the document.
142
+ * By default returns the document as it was **before** the update.
143
+ * Pass `{ returnDocument: 'after' }` in options to get the updated version.
144
+ * @param {import('mongodb').Filter<T>} query
145
+ * @param {import('mongodb').UpdateFilter<T>} update
146
+ * @param {import('mongodb').FindOneAndUpdateOptions} [options]
147
+ * @returns {Promise<T | null>}
148
+ */
149
+ findOneAndUpdate: async (query, update, options) => await findOneAndUpdate({
150
+ query, update, options, getCollection, collectionOptions,
151
+ }),
152
+ /**
153
+ * Atomically finds a document, deletes it, and returns the deleted document.
154
+ * @param {import('mongodb').Filter<T>} query
155
+ * @param {import('mongodb').FindOneAndDeleteOptions} [options]
156
+ * @returns {Promise<T | null>}
157
+ */
158
+ findOneAndDelete: async (query, options) => await findOneAndDelete({
159
+ query, options, getCollection, collectionOptions,
160
+ }),
161
+ /**
162
+ * Atomically finds a document, replaces it with `replacement`, and returns a document.
163
+ * By default returns the document as it was **before** the replacement.
164
+ * Pass `{ returnDocument: 'after' }` in options to get the new version.
165
+ * @param {import('mongodb').Filter<T>} query
166
+ * @param {import('mongodb').WithoutId<T>} replacement
167
+ * @param {import('mongodb').FindOneAndReplaceOptions} [options]
168
+ * @returns {Promise<T | null>}
169
+ */
170
+ findOneAndReplace: async (query, replacement, options) => await findOneAndReplace({
171
+ query, replacement, options, getCollection, collectionOptions,
172
+ }),
173
+ }
174
+ }
175
+
176
+ /**
177
+ * @template {import('../types.js').MongoDocument} T
178
+ * @callback IcollectionGetter
179
+ * @returns {Promise<Collection<T>>}
180
+ */
181
+
182
+ /**
183
+ * @template {import('../types.js').MongoDocument} T
184
+ * @typedef {object} IcreateCollectionOptions
185
+ * @property {IcollectionGetter<T>} [options.collectionGetter]
186
+ * A custom function to get the collection object from mongodb driver.
187
+ *
188
+ * This will be not be cached and will be used on every operation such as insertOne or findOne.
189
+ *
190
+ * If you wish to cache the collection object, see `cachableCollectionGetter`.
191
+ *
192
+ * Example:
193
+ * ```js
194
+ * collectionGetter: async () => await getMyCollection()
195
+ * ```
196
+ *
197
+ * @property {string} [options.connectionString]
198
+ * A custom connection string. If none is given, `process.env.DATABASE_URL` will be used.
199
+ *
200
+ * @property {string} [dbName] The name of the database.
201
+ *
202
+ * @property {import('mongodb').DbOptions} [options] The options used when initializing the client.
203
+ *
204
+ * @property {ItimestampConfiguration} [timestamps] Configured how the package manages 'createdAt'
205
+ * and 'updatedAt'.
206
+ */
207
+
208
+ /**
209
+ * @typedef {object} ItimestampConfiguration
210
+ * @property {'fromId' | 'generate' | 'none'} createdAt
211
+ * Changes how the 'createdAt' field is managed:
212
+ * - 'fromId': the field is generated when you use `find` or `findOne` and is calculated using _id.
213
+ * But it does not exist in the database.
214
+ * - 'generate': the field is generated when you use `insertOne` or `insertMany`. The value exist in
215
+ * the database.
216
+ * - 'none': no value is generated at any time.
217
+ * @property {'generate' | 'none'} updatedAt
218
+ * - 'generate': the value is generated when you use `insertOne` or `insertMany` and is updated on
219
+ * `updateOne` and `updateMany`.
220
+ */
221
+
222
+ /**
223
+ * @template {import('../types.js').MongoDocument} T
224
+ * @typedef {Awaited<ReturnType<typeof createMongoCollection<T>>>} ICollection
182
225
  */
@@ -1 +1 @@
1
- export * from './create_mongo_collection.mjs'
1
+ export * from './create_mongo_collection.mjs'
package/src/types.ts CHANGED
@@ -1,32 +1,32 @@
1
- import { FindOptions as FO } from 'mongodb'
2
-
3
- export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
4
-
5
- export type MongoDocument = {
6
- id: string
7
- [key: string]: any
8
- }
9
-
10
- export type RequiredIfPresent<T, U> = {
11
- [P in keyof T]: P extends keyof U ? Required<T[P]> : T[P];
12
- };
13
-
14
- type NonNullProjection<T extends MongoDocument> = Partial<Record<keyof T, 1 | 0>>
15
-
16
- export type Projection<T extends MongoDocument> = NonNullProjection<T> | undefined
17
-
18
- type GivenProjectionReturnType<T extends MongoDocument, P extends NonNullProjection<T>> =
19
- P extends Partial<Record<keyof T, 0>>
20
- ? {
21
- [K in keyof T as P[K] extends 0 ? never : K]: T[K]
22
- }
23
- : {
24
- [K in keyof T as P[K] extends 1 ? K : never]: T[K]
25
- };
26
-
27
- export type ProjectionReturnType<T extends MongoDocument, P extends Projection<T>> =
28
- P extends NonNullProjection<T> ? GivenProjectionReturnType<T, P> : T
29
-
30
- export type FindOptions<T extends MongoDocument, K extends Projection<T>> = Omit<FO, 'projection'> & {
31
- projection?: K
1
+ import { FindOptions as FO } from 'mongodb'
2
+
3
+ export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
4
+
5
+ export type MongoDocument = {
6
+ id: string
7
+ [key: string]: any
8
+ }
9
+
10
+ export type RequiredIfPresent<T, U> = {
11
+ [P in keyof T]: P extends keyof U ? Required<T[P]> : T[P];
12
+ };
13
+
14
+ type NonNullProjection<T extends MongoDocument> = Partial<Record<keyof T, 1 | 0>>
15
+
16
+ export type Projection<T extends MongoDocument> = NonNullProjection<T> | undefined
17
+
18
+ type GivenProjectionReturnType<T extends MongoDocument, P extends NonNullProjection<T>> =
19
+ P extends Partial<Record<keyof T, 0>>
20
+ ? {
21
+ [K in keyof T as P[K] extends 0 ? never : K]: T[K]
22
+ }
23
+ : {
24
+ [K in keyof T as P[K] extends 1 ? K : never]: T[K]
25
+ };
26
+
27
+ export type ProjectionReturnType<T extends MongoDocument, P extends Projection<T>> =
28
+ P extends NonNullProjection<T> ? GivenProjectionReturnType<T, P> : T
29
+
30
+ export type FindOptions<T extends MongoDocument, K extends Projection<T>> = Omit<FO, 'projection'> & {
31
+ projection?: K
32
32
  }
@@ -1 +1 @@
1
- export * as mongo from './mongo/index.mjs'
1
+ export * as mongo from './mongo/index.mjs'
@@ -1,5 +1,5 @@
1
- import { ObjectId } from 'mongodb'
2
-
3
- export function generateNewId() {
4
- return new ObjectId().toHexString()
1
+ import { ObjectId } from 'mongodb'
2
+
3
+ export function generateNewId() {
4
+ return new ObjectId().toHexString()
5
5
  }
@@ -1,3 +1,3 @@
1
- export * from './generate_new_id.mjs'
2
- export * from './mongo_client.mjs'
3
- export * from './operation/index.mjs'
1
+ export * from './generate_new_id.mjs'
2
+ export * from './mongo_client.mjs'
3
+ export * from './operation/index.mjs'
@@ -1,37 +1,37 @@
1
- import { MongoClient } from 'mongodb'
2
- import { OperationFail } from '../../data/errors/operation_fail.mjs'
3
-
4
- /** @type {MongoClient | null} */
5
- let client = null
6
-
7
- /**
8
- *
9
- * @param {object} params
10
- * @param {string} [params.connectionString]
11
- */
12
- export async function getClient({
13
- connectionString,
14
- } = {}) {
15
- if (!client) {
16
- function getCS() {
17
- if (typeof connectionString == 'string') return connectionString
18
- const DATABASE_URL = process.env.DATABASE_URL
19
- if (DATABASE_URL == null) {
20
- throw new OperationFail('DATABASE_URL not configured')
21
- }
22
- return DATABASE_URL
23
- }
24
- const cs = getCS()
25
- client = await MongoClient.connect(cs)
26
- }
27
- return client
28
- }
29
-
30
- export async function closeClient() {
31
- if (client == null) {
32
- return false
33
- }
34
- await client?.close()
35
- client = null
36
- return true
1
+ import { MongoClient } from 'mongodb'
2
+ import { OperationFail } from '../../data/errors/operation_fail.mjs'
3
+
4
+ /** @type {MongoClient | null} */
5
+ let client = null
6
+
7
+ /**
8
+ *
9
+ * @param {object} params
10
+ * @param {string} [params.connectionString]
11
+ */
12
+ export async function getClient({
13
+ connectionString,
14
+ } = {}) {
15
+ if (!client) {
16
+ function getCS() {
17
+ if (typeof connectionString == 'string') return connectionString
18
+ const DATABASE_URL = process.env.DATABASE_URL
19
+ if (DATABASE_URL == null) {
20
+ throw new OperationFail('DATABASE_URL not configured')
21
+ }
22
+ return DATABASE_URL
23
+ }
24
+ const cs = getCS()
25
+ client = await MongoClient.connect(cs)
26
+ }
27
+ return client
28
+ }
29
+
30
+ export async function closeClient() {
31
+ if (client == null) {
32
+ return false
33
+ }
34
+ await client?.close()
35
+ client = null
36
+ return true
37
37
  }
@@ -1,18 +1,18 @@
1
- import { Collection } from 'mongodb'
2
- import { OperationFail } from '../../../../data/errors/operation_fail.mjs'
3
- import { deleteOne } from '../delete_one.mjs'
4
-
5
- /**
6
- * @template {import('../../../../types.js').MongoDocument} T
7
- * @param {object} param
8
- * @param {import('mongodb').Filter<T>} param.query
9
- * @param {() => Promise<Collection<T>>} param.getCollection
10
- */
11
- export async function deleteOneOrThrow({
12
- query, getCollection,
13
- }) {
14
- const deleted = await deleteOne({ query, getCollection })
15
- if (!deleted) {
16
- throw new OperationFail('Delete one did not delete any documents')
17
- }
1
+ import { Collection } from 'mongodb'
2
+ import { OperationFail } from '../../../../data/errors/operation_fail.mjs'
3
+ import { deleteOne } from '../delete_one.mjs'
4
+
5
+ /**
6
+ * @template {import('../../../../types.js').MongoDocument} T
7
+ * @param {object} param
8
+ * @param {import('mongodb').Filter<T>} param.query
9
+ * @param {() => Promise<Collection<T>>} param.getCollection
10
+ */
11
+ export async function deleteOneOrThrow({
12
+ query, getCollection,
13
+ }) {
14
+ const deleted = await deleteOne({ query, getCollection })
15
+ if (!deleted) {
16
+ throw new OperationFail('Delete one did not delete any documents')
17
+ }
18
18
  }
@@ -1 +1 @@
1
- export * from './delete_one_or_throw.mjs'
1
+ export * from './delete_one_or_throw.mjs'
@@ -0,0 +1,21 @@
1
+ import { Collection } from 'mongodb'
2
+ import { renameToMongoId, stringsIntoId } from '../transformers/index.mjs'
3
+ import { outputTransformer } from '../transformers/output_transformer.mjs'
4
+
5
+ /**
6
+ * @template {import('../../../types.js').MongoDocument} T
7
+ * @param {object} parameter
8
+ * @param {() => Promise<Collection<T>>} parameter.getCollection
9
+ * @param {import('mongodb').Document[]} parameter.pipeline
10
+ * @param {import('mongodb').AggregateOptions} [parameter.options]
11
+ * @param {import('../../../factories/create_mongo_collection.mjs').IcreateCollectionOptions<T>} [parameter.collectionOptions]
12
+ * @returns {Promise<T[]>}
13
+ */
14
+ export async function aggregate({ getCollection, pipeline, options, collectionOptions }) {
15
+ const finalPipeline = stringsIntoId(renameToMongoId(pipeline))
16
+
17
+ const col = await getCollection()
18
+ const docs = await col.aggregate(finalPipeline, options).toArray()
19
+ // @ts-ignore
20
+ return docs.map((doc) => outputTransformer({ document: doc, collectionOptions }))
21
+ }