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.
- package/README.md +148 -148
- package/dist/src/__test/mock_get_collection.d.mts +2 -0
- package/dist/src/factories/create_mongo_collection.d.mts +55 -11
- package/dist/src/usecases/mongo/operation/aggregate.d.mts +16 -0
- package/dist/src/usecases/mongo/operation/bulk_write.d.mts +15 -0
- package/dist/src/usecases/mongo/operation/find_one_and_delete.d.mts +16 -0
- package/dist/src/usecases/mongo/operation/find_one_and_replace.d.mts +18 -0
- package/dist/src/usecases/mongo/operation/find_one_and_update.d.mts +18 -0
- package/dist/src/usecases/mongo/operation/index.d.mts +5 -0
- package/dist/src/usecases/mongo/transformers/id/rename_to_mongo_id.d.mts +3 -0
- package/dist/src/usecases/mongo/transformers/object_id/ids_into_strings.d.mts +5 -0
- package/dist/src/usecases/mongo/transformers/object_id/strings_into_id.d.mts +3 -0
- package/dist/src/usecases/mongo/transformers/timestamps.d.mts +5 -0
- package/index.mjs +2 -2
- package/jsconfig.json +17 -20
- package/jsconfig.prod.json +12 -12
- package/package.json +40 -39
- package/src/__test/manage_mock_database.mjs +24 -24
- package/src/__test/manage_mock_registry.mjs +54 -54
- package/src/__test/mock_get_collection.mjs +22 -20
- package/src/data/errors/operation_fail.mjs +9 -9
- package/src/data/errors/unsupported_error.mjs +9 -9
- package/src/data/interfaces/mongo_operator.mjs +2 -2
- package/src/data/interfaces/native_collection.mjs +27 -27
- package/src/factories/create_mock_collection.mjs +173 -173
- package/src/factories/create_mongo_collection.mjs +224 -181
- package/src/factories/index.mjs +1 -1
- package/src/types.ts +31 -31
- package/src/usecases/index.mjs +1 -1
- package/src/usecases/mongo/generate_new_id.mjs +4 -4
- package/src/usecases/mongo/index.mjs +3 -3
- package/src/usecases/mongo/mongo_client.mjs +36 -36
- package/src/usecases/mongo/operation/additional/delete_one_or_throw.mjs +17 -17
- package/src/usecases/mongo/operation/additional/index.mjs +1 -1
- package/src/usecases/mongo/operation/aggregate.mjs +21 -0
- package/src/usecases/mongo/operation/bulk_write.mjs +54 -0
- package/src/usecases/mongo/operation/count.mjs +16 -16
- package/src/usecases/mongo/operation/delete_many.mjs +15 -15
- package/src/usecases/mongo/operation/delete_one.mjs +16 -16
- package/src/usecases/mongo/operation/find.mjs +34 -34
- package/src/usecases/mongo/operation/find_one.mjs +32 -32
- package/src/usecases/mongo/operation/find_one_and_delete.mjs +23 -0
- package/src/usecases/mongo/operation/find_one_and_replace.mjs +24 -0
- package/src/usecases/mongo/operation/find_one_and_update.mjs +40 -0
- package/src/usecases/mongo/operation/index.mjs +15 -10
- package/src/usecases/mongo/operation/insert_many.mjs +39 -39
- package/src/usecases/mongo/operation/insert_one.mjs +32 -32
- package/src/usecases/mongo/operation/update_many.mjs +39 -39
- package/src/usecases/mongo/operation/update_one.mjs +40 -40
- package/src/usecases/mongo/transformers/id/index.mjs +4 -4
- package/src/usecases/mongo/transformers/id/rename_find_options.mjs +12 -12
- package/src/usecases/mongo/transformers/id/rename_to_dev_id.mjs +14 -13
- package/src/usecases/mongo/transformers/id/rename_to_mongo_id.mjs +34 -13
- package/src/usecases/mongo/transformers/index.mjs +2 -2
- package/src/usecases/mongo/transformers/input_transformer.mjs +32 -32
- package/src/usecases/mongo/transformers/object_id/ids_into_strings.mjs +47 -30
- package/src/usecases/mongo/transformers/object_id/index.mjs +3 -3
- package/src/usecases/mongo/transformers/object_id/strings_into_id.mjs +90 -44
- package/src/usecases/mongo/transformers/output_transformer.mjs +18 -18
- package/src/usecases/mongo/transformers/timestamps.mjs +32 -22
|
@@ -1,182 +1,225 @@
|
|
|
1
|
-
import { Collection } from 'mongodb'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
|
|
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
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
* @param {import('
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
* @
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
* @
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
},
|
|
92
|
-
/**
|
|
93
|
-
*
|
|
94
|
-
* @
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
*
|
|
100
|
-
* @
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
106
|
-
* @param {import('mongodb').Filter<T>} query
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
*
|
|
112
|
-
* @param {import('mongodb').
|
|
113
|
-
*/
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* @param {import('mongodb').
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
* @param {import('mongodb').
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
*/
|
package/src/factories/index.mjs
CHANGED
|
@@ -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
|
}
|
package/src/usecases/index.mjs
CHANGED
|
@@ -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
|
+
}
|