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