@toa.io/storages.mongodb 1.0.0-alpha.9 → 1.0.0-alpha.91
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 +121 -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.91",
|
|
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.91",
|
|
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.91",
|
|
28
28
|
"saslprep": "1.0.3"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "fb3644243517fad0327e75e055c1f663cee503d8"
|
|
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,14 @@ 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 })
|
|
179
|
+
.catch((e) => console.warn('Index creation failed', { name, fields, error: e }))
|
|
141
180
|
|
|
142
181
|
indexes.push(name)
|
|
143
182
|
}
|
|
144
183
|
}
|
|
145
184
|
|
|
146
|
-
await this.
|
|
185
|
+
await this.removeObsoleteIndexes(indexes)
|
|
147
186
|
}
|
|
148
187
|
|
|
149
188
|
async uniqueIndex (name, properties, sparse = false) {
|
|
@@ -154,23 +193,30 @@ class Storage extends Connector {
|
|
|
154
193
|
|
|
155
194
|
name = 'unique_' + name
|
|
156
195
|
|
|
157
|
-
await this.#
|
|
158
|
-
name,
|
|
159
|
-
unique: true,
|
|
160
|
-
sparse
|
|
161
|
-
})
|
|
196
|
+
await this.#collection.createIndex(fields, { name, unique: true, sparse })
|
|
197
|
+
.catch((e) => console.warn('Unique index creation failed', { name, fields, error: e }))
|
|
162
198
|
|
|
163
199
|
return name
|
|
164
200
|
}
|
|
165
201
|
|
|
166
|
-
async
|
|
167
|
-
const current = await this
|
|
202
|
+
async removeObsoleteIndexes (desired) {
|
|
203
|
+
const current = await this.getCurrentIndexes()
|
|
168
204
|
const obsolete = current.filter((name) => !desired.includes(name))
|
|
169
205
|
|
|
170
206
|
if (obsolete.length > 0) {
|
|
171
|
-
console.info(
|
|
207
|
+
console.info('Removing obsolete indexes', { indexes: obsolete.join(', ') })
|
|
172
208
|
|
|
173
|
-
await this.#
|
|
209
|
+
await Promise.all(obsolete.map((name) => this.#collection.dropIndex(name)))
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async getCurrentIndexes () {
|
|
214
|
+
try {
|
|
215
|
+
const array = await this.#collection.listIndexes().toArray()
|
|
216
|
+
|
|
217
|
+
return array.map(({ name }) => name).filter((name) => name !== '_id_')
|
|
218
|
+
} catch {
|
|
219
|
+
return []
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
|
|
@@ -178,24 +224,28 @@ class Storage extends Connector {
|
|
|
178
224
|
const optional = []
|
|
179
225
|
|
|
180
226
|
for (const field of fields) {
|
|
181
|
-
if (!(field in this.#entity.schema.properties))
|
|
227
|
+
if (!(field in this.#entity.schema.properties))
|
|
182
228
|
throw new Error(`Index field '${field}' is not defined.`)
|
|
183
|
-
}
|
|
184
229
|
|
|
185
|
-
if (!this.#entity.schema.required?.includes(field))
|
|
230
|
+
if (!this.#entity.schema.required?.includes(field))
|
|
186
231
|
optional.push(field)
|
|
187
|
-
}
|
|
188
232
|
}
|
|
189
233
|
|
|
190
234
|
if (optional.length > 0) {
|
|
191
|
-
console.info(
|
|
235
|
+
console.info('Index fields are optional, creating sparse index', { fields: optional.join(', ') })
|
|
192
236
|
|
|
193
237
|
return true
|
|
194
|
-
} else
|
|
238
|
+
} else
|
|
195
239
|
return false
|
|
196
|
-
}
|
|
197
240
|
}
|
|
198
241
|
|
|
242
|
+
debug (method, attributes) {
|
|
243
|
+
console.debug('Database query', {
|
|
244
|
+
collection: this.#client.name,
|
|
245
|
+
method,
|
|
246
|
+
...attributes
|
|
247
|
+
})
|
|
248
|
+
}
|
|
199
249
|
}
|
|
200
250
|
|
|
201
251
|
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
|