@toa.io/storages.mongodb 1.0.0-alpha.8 → 1.0.0-alpha.81
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/package.json +8 -8
- package/src/client.js +39 -10
- package/src/factory.js +1 -3
- package/src/record.js +6 -19
- package/src/storage.js +119 -71
- package/src/translate.js +9 -5
- package/test/record.test.js +0 -15
- package/src/collection.js +0 -69
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/storages.mongodb",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.81",
|
|
4
4
|
"description": "Toa MongoDB Storage Connector",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@toa.io/
|
|
23
|
-
"@toa.io/
|
|
24
|
-
"@toa.io/
|
|
25
|
-
"@toa.io/
|
|
26
|
-
"
|
|
27
|
-
"
|
|
22
|
+
"@toa.io/conveyor": "1.0.0-alpha.63",
|
|
23
|
+
"@toa.io/core": "1.0.0-alpha.81",
|
|
24
|
+
"@toa.io/generic": "1.0.0-alpha.63",
|
|
25
|
+
"@toa.io/pointer": "1.0.0-alpha.63",
|
|
26
|
+
"mongodb": "6.7.0",
|
|
27
|
+
"openspan": "1.0.0-alpha.79",
|
|
28
28
|
"saslprep": "1.0.3"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "99c366c07ee6a34206ecb15d46c0f53e46eb9b06"
|
|
31
31
|
}
|
package/src/client.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @typedef {import('@toa.io/core').Locator} Locator
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
const { console } = require('openspan')
|
|
9
10
|
const { Connector } = require('@toa.io/core')
|
|
10
11
|
const { resolve } = require('@toa.io/pointer')
|
|
11
12
|
const { ID } = require('./deployment')
|
|
@@ -17,6 +18,8 @@ const { MongoClient } = require('mongodb')
|
|
|
17
18
|
const INSTANCES = {}
|
|
18
19
|
|
|
19
20
|
class Client extends Connector {
|
|
21
|
+
name
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* @public
|
|
22
25
|
* @type {import('mongodb').Collection}
|
|
@@ -57,17 +60,27 @@ class Client extends Connector {
|
|
|
57
60
|
*/
|
|
58
61
|
async open () {
|
|
59
62
|
const urls = await this.resolveURLs()
|
|
63
|
+
const dbname = this.resolveDB()
|
|
60
64
|
|
|
61
|
-
this.
|
|
65
|
+
this.name = this.locator.lowercase
|
|
66
|
+
this.key = getKey(dbname, urls)
|
|
62
67
|
|
|
63
68
|
INSTANCES[this.key] ??= this.createInstance(urls)
|
|
64
69
|
|
|
65
70
|
this.instance = await INSTANCES[this.key]
|
|
66
71
|
this.instance.count++
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const db = this.instance.client.db(dbname)
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
this.collection = await db.createCollection(this.name)
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (e.code !== ALREADY_EXISTS) {
|
|
79
|
+
throw e
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.collection = db.collection(this.name)
|
|
83
|
+
}
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
/**
|
|
@@ -95,7 +108,7 @@ class Client extends Connector {
|
|
|
95
108
|
const client = new MongoClient(urls.join(','), OPTIONS)
|
|
96
109
|
const hosts = urls.map((str) => new URL(str).host)
|
|
97
110
|
|
|
98
|
-
console.info('Connecting to MongoDB
|
|
111
|
+
console.info('Connecting to MongoDB', { address: hosts.join(', ') })
|
|
99
112
|
|
|
100
113
|
await client.connect()
|
|
101
114
|
|
|
@@ -116,16 +129,32 @@ class Client extends Connector {
|
|
|
116
129
|
return await resolve(ID, this.locator.id)
|
|
117
130
|
}
|
|
118
131
|
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @private
|
|
135
|
+
* @return {string}
|
|
136
|
+
*/
|
|
137
|
+
resolveDB () {
|
|
138
|
+
if (process.env.TOA_CONTEXT !== undefined) {
|
|
139
|
+
return process.env.TOA_CONTEXT
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (process.env.TOA_DEV === '1') {
|
|
143
|
+
return 'toa-dev'
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
throw new Error('Environment variable TOA_CONTEXT is not defined')
|
|
147
|
+
}
|
|
119
148
|
}
|
|
120
149
|
|
|
121
|
-
function getKey (urls) {
|
|
122
|
-
return urls.sort().join(' ')
|
|
150
|
+
function getKey (db, urls) {
|
|
151
|
+
return db + ':' + urls.sort().join(' ')
|
|
123
152
|
}
|
|
124
153
|
|
|
125
154
|
const OPTIONS = {
|
|
126
|
-
ignoreUndefined: true
|
|
127
|
-
connectTimeoutMS: 0,
|
|
128
|
-
serverSelectionTimeoutMS: 0
|
|
155
|
+
ignoreUndefined: true
|
|
129
156
|
}
|
|
130
157
|
|
|
158
|
+
const ALREADY_EXISTS = 48
|
|
159
|
+
|
|
131
160
|
exports.Client = Client
|
package/src/factory.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { Client } = require('./client')
|
|
4
|
-
const { Collection } = require('./collection')
|
|
5
4
|
const { Storage } = require('./storage')
|
|
6
5
|
|
|
7
6
|
class Factory {
|
|
8
7
|
storage (locator, entity) {
|
|
9
8
|
const client = new Client(locator)
|
|
10
|
-
const connection = new Collection(client)
|
|
11
9
|
|
|
12
|
-
return new Storage(
|
|
10
|
+
return new Storage(client, entity)
|
|
13
11
|
}
|
|
14
12
|
}
|
|
15
13
|
|
package/src/record.js
CHANGED
|
@@ -1,29 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* @returns {toa.mongodb.Record}
|
|
6
|
-
*/
|
|
7
|
-
const to = (entity) => {
|
|
8
|
-
const {
|
|
9
|
-
id,
|
|
10
|
-
...rest
|
|
11
|
-
} = entity
|
|
3
|
+
function to (entity) {
|
|
4
|
+
const { id, ...rest } = entity
|
|
12
5
|
|
|
13
6
|
return /** @type {toa.mongodb.Record} */ { _id: id, ...rest }
|
|
14
7
|
}
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
const from = (record) => {
|
|
21
|
-
if (record === undefined || record === null) return null
|
|
9
|
+
function from (record) {
|
|
10
|
+
if (record === undefined || record === null)
|
|
11
|
+
return null
|
|
22
12
|
|
|
23
|
-
const {
|
|
24
|
-
_id,
|
|
25
|
-
...rest
|
|
26
|
-
} = record
|
|
13
|
+
const { _id, ...rest } = record
|
|
27
14
|
|
|
28
15
|
return { id: _id, ...rest }
|
|
29
16
|
}
|
package/src/storage.js
CHANGED
|
@@ -1,57 +1,69 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
exceptions
|
|
6
|
-
} = require('@toa.io/core')
|
|
7
|
-
|
|
3
|
+
const { Connector, exceptions } = require('@toa.io/core')
|
|
4
|
+
const { console } = require('openspan')
|
|
8
5
|
const { translate } = require('./translate')
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
from
|
|
12
|
-
} = require('./record')
|
|
6
|
+
const { to, from } = require('./record')
|
|
7
|
+
const { ReturnDocument } = require('mongodb')
|
|
13
8
|
|
|
14
9
|
class Storage extends Connector {
|
|
15
|
-
#
|
|
10
|
+
#client
|
|
11
|
+
|
|
12
|
+
/** @type {import('mongodb').Collection} */
|
|
13
|
+
#collection
|
|
16
14
|
#entity
|
|
17
15
|
|
|
18
|
-
constructor (
|
|
16
|
+
constructor (client, entity) {
|
|
19
17
|
super()
|
|
20
18
|
|
|
21
|
-
this.#
|
|
19
|
+
this.#client = client
|
|
22
20
|
this.#entity = entity
|
|
23
21
|
|
|
24
|
-
this.depends(
|
|
22
|
+
this.depends(client)
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
async open () {
|
|
26
|
+
this.#collection = this.#client.collection
|
|
27
|
+
|
|
28
28
|
await this.index()
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
async get (query) {
|
|
32
|
-
const {
|
|
33
|
-
criteria,
|
|
34
|
-
options
|
|
35
|
-
} = translate(query)
|
|
32
|
+
const { criteria, options } = translate(query)
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
this.debug('findOne', { criteria, options })
|
|
35
|
+
|
|
36
|
+
const record = await this.#collection.findOne(criteria, options)
|
|
38
37
|
|
|
39
38
|
return from(record)
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
async find (query) {
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const { criteria, options } = translate(query)
|
|
43
|
+
|
|
44
|
+
criteria._deleted = null
|
|
45
|
+
|
|
46
|
+
this.debug('find', { criteria, options })
|
|
47
|
+
|
|
48
|
+
const recordset = await this.#collection.find(criteria, options).toArray()
|
|
48
49
|
|
|
49
50
|
return recordset.map((item) => from(item))
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
async stream (query = undefined) {
|
|
54
|
+
const { criteria, options } = translate(query)
|
|
55
|
+
|
|
56
|
+
this.debug('find (stream)', { criteria, options })
|
|
57
|
+
|
|
58
|
+
return this.#collection.find(criteria, options).stream({ transform: from })
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
async add (entity) {
|
|
53
62
|
const record = to(entity)
|
|
54
|
-
|
|
63
|
+
|
|
64
|
+
this.debug('insertOne', { record })
|
|
65
|
+
|
|
66
|
+
const result = await this.#collection.insertOne(record)
|
|
55
67
|
|
|
56
68
|
return result.acknowledged
|
|
57
69
|
}
|
|
@@ -61,57 +73,86 @@ class Storage extends Connector {
|
|
|
61
73
|
_id: entity.id,
|
|
62
74
|
_version: entity._version - 1
|
|
63
75
|
}
|
|
64
|
-
|
|
76
|
+
|
|
77
|
+
const record = to(entity)
|
|
78
|
+
|
|
79
|
+
this.debug('findOneAndReplace', { criteria, record })
|
|
80
|
+
|
|
81
|
+
const result = await this.#collection.findOneAndReplace(criteria, record)
|
|
65
82
|
|
|
66
83
|
return result !== null
|
|
67
84
|
}
|
|
68
85
|
|
|
69
|
-
async store (entity) {
|
|
86
|
+
async store (entity, attempt = 0) {
|
|
70
87
|
try {
|
|
71
|
-
if (entity._version === 1)
|
|
88
|
+
if (entity._version === 1)
|
|
72
89
|
return await this.add(entity)
|
|
73
|
-
|
|
90
|
+
else
|
|
74
91
|
return await this.set(entity)
|
|
75
|
-
}
|
|
76
92
|
} catch (error) {
|
|
77
93
|
if (error.code === ERR_DUPLICATE_KEY) {
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
const id = error.keyPattern === undefined
|
|
95
|
+
? error.message.includes(' index: _id_ ') // AWS DocumentDB
|
|
96
|
+
: error.keyPattern._id === 1
|
|
97
|
+
|
|
98
|
+
if (id)
|
|
99
|
+
return false
|
|
100
|
+
else
|
|
101
|
+
throw new exceptions.DuplicateException(this.#client.name, entity)
|
|
102
|
+
} else if (error.cause?.code === 'ECONNREFUSED') {
|
|
103
|
+
// This is temporary and should be replaced with a class decorator.
|
|
104
|
+
if (attempt > 10)
|
|
105
|
+
throw error
|
|
106
|
+
|
|
107
|
+
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
108
|
+
|
|
109
|
+
return this.store(entity)
|
|
110
|
+
} else
|
|
80
111
|
throw error
|
|
81
|
-
}
|
|
82
112
|
}
|
|
83
113
|
}
|
|
84
114
|
|
|
85
|
-
async upsert (query, changeset
|
|
86
|
-
const {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
async upsert (query, changeset) {
|
|
116
|
+
const { criteria, options } = translate(query)
|
|
117
|
+
|
|
118
|
+
if (!('_deleted' in changeset) || changeset._deleted === null) {
|
|
119
|
+
delete criteria._deleted
|
|
120
|
+
changeset._deleted = null
|
|
121
|
+
}
|
|
90
122
|
|
|
91
123
|
const update = {
|
|
92
124
|
$set: { ...changeset },
|
|
93
125
|
$inc: { _version: 1 }
|
|
94
126
|
}
|
|
95
127
|
|
|
96
|
-
|
|
97
|
-
delete insert._version
|
|
128
|
+
options.returnDocument = ReturnDocument.AFTER
|
|
98
129
|
|
|
99
|
-
|
|
130
|
+
this.debug('findOneAndUpdate', { criteria, update, options })
|
|
100
131
|
|
|
101
|
-
|
|
102
|
-
insert._id = criteria._id
|
|
103
|
-
} else {
|
|
104
|
-
return null
|
|
105
|
-
} // this shouldn't ever happen
|
|
132
|
+
const result = await this.#collection.findOneAndUpdate(criteria, update, options)
|
|
106
133
|
|
|
107
|
-
|
|
108
|
-
|
|
134
|
+
return from(result)
|
|
135
|
+
}
|
|
109
136
|
|
|
110
|
-
|
|
137
|
+
async ensure (query, properties, state) {
|
|
138
|
+
let { criteria, options } = translate(query)
|
|
111
139
|
|
|
112
|
-
|
|
140
|
+
if (query === undefined)
|
|
141
|
+
criteria = properties
|
|
113
142
|
|
|
114
|
-
|
|
143
|
+
const update = { $setOnInsert: to(state) }
|
|
144
|
+
|
|
145
|
+
options.upsert = true
|
|
146
|
+
options.returnDocument = ReturnDocument.AFTER
|
|
147
|
+
|
|
148
|
+
console.debug('Database query', { method: 'findOneAndUpdate', criteria, update, options })
|
|
149
|
+
|
|
150
|
+
const result = await this.#collection.findOneAndUpdate(criteria, update, options)
|
|
151
|
+
|
|
152
|
+
if (result._deleted !== undefined && result._deleted !== null)
|
|
153
|
+
return null
|
|
154
|
+
else
|
|
155
|
+
return from(result)
|
|
115
156
|
}
|
|
116
157
|
|
|
117
158
|
async index () {
|
|
@@ -134,16 +175,13 @@ class Storage extends Connector {
|
|
|
134
175
|
|
|
135
176
|
const sparse = this.checkFields(Object.keys(fields))
|
|
136
177
|
|
|
137
|
-
await this.#
|
|
138
|
-
name,
|
|
139
|
-
sparse
|
|
140
|
-
})
|
|
178
|
+
await this.#collection.createIndex(fields, { name, sparse })
|
|
141
179
|
|
|
142
180
|
indexes.push(name)
|
|
143
181
|
}
|
|
144
182
|
}
|
|
145
183
|
|
|
146
|
-
await this.
|
|
184
|
+
await this.removeObsoleteIndexes(indexes)
|
|
147
185
|
}
|
|
148
186
|
|
|
149
187
|
async uniqueIndex (name, properties, sparse = false) {
|
|
@@ -154,23 +192,29 @@ class Storage extends Connector {
|
|
|
154
192
|
|
|
155
193
|
name = 'unique_' + name
|
|
156
194
|
|
|
157
|
-
await this.#
|
|
158
|
-
name,
|
|
159
|
-
unique: true,
|
|
160
|
-
sparse
|
|
161
|
-
})
|
|
195
|
+
await this.#collection.createIndex(fields, { name, unique: true, sparse })
|
|
162
196
|
|
|
163
197
|
return name
|
|
164
198
|
}
|
|
165
199
|
|
|
166
|
-
async
|
|
167
|
-
const current = await this
|
|
200
|
+
async removeObsoleteIndexes (desired) {
|
|
201
|
+
const current = await this.getCurrentIndexes()
|
|
168
202
|
const obsolete = current.filter((name) => !desired.includes(name))
|
|
169
203
|
|
|
170
204
|
if (obsolete.length > 0) {
|
|
171
|
-
console.info(
|
|
205
|
+
console.info('Removing obsolete indexes', { indexes: obsolete.join(', ') })
|
|
172
206
|
|
|
173
|
-
await this.#
|
|
207
|
+
await Promise.all(obsolete.map((name) => this.#collection.dropIndex(name)))
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async getCurrentIndexes () {
|
|
212
|
+
try {
|
|
213
|
+
const array = await this.#collection.listIndexes().toArray()
|
|
214
|
+
|
|
215
|
+
return array.map(({ name }) => name).filter((name) => name !== '_id_')
|
|
216
|
+
} catch {
|
|
217
|
+
return []
|
|
174
218
|
}
|
|
175
219
|
}
|
|
176
220
|
|
|
@@ -178,24 +222,28 @@ class Storage extends Connector {
|
|
|
178
222
|
const optional = []
|
|
179
223
|
|
|
180
224
|
for (const field of fields) {
|
|
181
|
-
if (!(field in this.#entity.schema.properties))
|
|
225
|
+
if (!(field in this.#entity.schema.properties))
|
|
182
226
|
throw new Error(`Index field '${field}' is not defined.`)
|
|
183
|
-
}
|
|
184
227
|
|
|
185
|
-
if (!this.#entity.schema.required?.includes(field))
|
|
228
|
+
if (!this.#entity.schema.required?.includes(field))
|
|
186
229
|
optional.push(field)
|
|
187
|
-
}
|
|
188
230
|
}
|
|
189
231
|
|
|
190
232
|
if (optional.length > 0) {
|
|
191
|
-
console.info(
|
|
233
|
+
console.info('Index fields are optional, creating sparse index', { fields: optional.join(', ') })
|
|
192
234
|
|
|
193
235
|
return true
|
|
194
|
-
} else
|
|
236
|
+
} else
|
|
195
237
|
return false
|
|
196
|
-
}
|
|
197
238
|
}
|
|
198
239
|
|
|
240
|
+
debug (method, attributes) {
|
|
241
|
+
console.debug('Database query', {
|
|
242
|
+
collection: this.#client.name,
|
|
243
|
+
method,
|
|
244
|
+
...attributes
|
|
245
|
+
})
|
|
246
|
+
}
|
|
199
247
|
}
|
|
200
248
|
|
|
201
249
|
const INDEX_TYPES = {
|
package/src/translate.js
CHANGED
|
@@ -7,12 +7,16 @@ const parse = { ...require('./translate/criteria'), ...require('./translate/opti
|
|
|
7
7
|
* @returns {{criteria: Object, options: Object}}
|
|
8
8
|
*/
|
|
9
9
|
const translate = (query) => {
|
|
10
|
-
const result = {
|
|
10
|
+
const result = {
|
|
11
|
+
criteria: query?.criteria === undefined ? {} : parse.criteria(query.criteria),
|
|
12
|
+
options: query?.options === undefined ? {} : parse.options(query.options)
|
|
13
|
+
}
|
|
11
14
|
|
|
12
|
-
if (query
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (query
|
|
15
|
+
if (query?.id !== undefined)
|
|
16
|
+
result.criteria._id = query.id
|
|
17
|
+
|
|
18
|
+
if (query?.version !== undefined)
|
|
19
|
+
result.criteria._version = query.version
|
|
16
20
|
|
|
17
21
|
return result
|
|
18
22
|
}
|
package/test/record.test.js
CHANGED
|
@@ -47,19 +47,4 @@ describe('from', () => {
|
|
|
47
47
|
_version: 0
|
|
48
48
|
})
|
|
49
49
|
})
|
|
50
|
-
|
|
51
|
-
it('should not modify argument', () => {
|
|
52
|
-
/** @type {toa.mongodb.Record} */
|
|
53
|
-
const record = {
|
|
54
|
-
_id: '1',
|
|
55
|
-
_version: 0
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
from(record)
|
|
59
|
-
|
|
60
|
-
expect(record).toStrictEqual({
|
|
61
|
-
_id: '1',
|
|
62
|
-
_version: 0
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
50
|
})
|
package/src/collection.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { Connector } = require('@toa.io/core')
|
|
4
|
-
|
|
5
|
-
class Collection extends Connector {
|
|
6
|
-
#client
|
|
7
|
-
#collection
|
|
8
|
-
|
|
9
|
-
constructor (client) {
|
|
10
|
-
super()
|
|
11
|
-
|
|
12
|
-
this.#client = client
|
|
13
|
-
|
|
14
|
-
this.depends(client)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async open () {
|
|
18
|
-
this.#collection = this.#client.collection
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** @hot */
|
|
22
|
-
async get (query, options) {
|
|
23
|
-
return /** @type {toa.mongodb.Record} */ this.#collection.findOne(query, options)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** @hot */
|
|
27
|
-
async find (query, options) {
|
|
28
|
-
const cursor = this.#collection.find(query, options)
|
|
29
|
-
|
|
30
|
-
return cursor.toArray()
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** @hot */
|
|
34
|
-
async add (record) {
|
|
35
|
-
return await this.#collection.insertOne(record)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** @hot */
|
|
39
|
-
async replace (query, record, options) {
|
|
40
|
-
return await this.#collection.findOneAndReplace(query, record, options)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** @hot */
|
|
44
|
-
async update (query, update, options) {
|
|
45
|
-
return this.#collection.findOneAndUpdate(query, update, options)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async index (keys, options) {
|
|
49
|
-
return this.#collection.createIndex(keys, options)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async indexes () {
|
|
53
|
-
try {
|
|
54
|
-
const array = await this.#collection.listIndexes().toArray()
|
|
55
|
-
|
|
56
|
-
return array.map(({ name }) => name).filter((name) => name !== '_id_')
|
|
57
|
-
} catch {
|
|
58
|
-
return []
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async dropIndexes (names) {
|
|
63
|
-
const all = names.map((name) => this.#collection.dropIndex(name))
|
|
64
|
-
|
|
65
|
-
return Promise.all(all)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
exports.Collection = Collection
|