@e22m4u/js-repository-mongodb-adapter 0.0.16 → 0.0.17
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 +1 -1
- package/src/mongodb-adapter.js +13 -201
- package/src/mongodb-adapter.spec.js +1 -151
- package/src/utils/index.js +1 -1
- package/src/utils/wait-async.js +0 -21
- package/src/utils/wait-async.spec.js +0 -37
package/package.json
CHANGED
package/src/mongodb-adapter.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/* eslint no-unused-vars: 0 */
|
|
2
2
|
import {ObjectId} from 'mongodb';
|
|
3
3
|
import {MongoClient} from 'mongodb';
|
|
4
|
-
import {
|
|
5
|
-
import {waitAsync} from './utils/index.js';
|
|
4
|
+
import {isIsoDate} from './utils/index.js';
|
|
6
5
|
import {isObjectId} from './utils/index.js';
|
|
7
6
|
import {Adapter} from '@e22m4u/js-repository';
|
|
8
7
|
import {DataType} from '@e22m4u/js-repository';
|
|
9
|
-
import {isIsoDate} from './utils/is-iso-date.js';
|
|
10
8
|
import {capitalize} from '@e22m4u/js-repository';
|
|
11
9
|
import {createMongodbUrl} from './utils/index.js';
|
|
12
10
|
import {ServiceContainer} from '@e22m4u/js-service';
|
|
@@ -70,50 +68,14 @@ const MONGODB_OPTION_NAMES = [
|
|
|
70
68
|
'zlibCompressionLevel',
|
|
71
69
|
];
|
|
72
70
|
|
|
73
|
-
/**
|
|
74
|
-
* Mongo client events.
|
|
75
|
-
* 5.8.1
|
|
76
|
-
*
|
|
77
|
-
* @type {string[]}
|
|
78
|
-
*/
|
|
79
|
-
const MONGO_CLIENT_EVENTS = [
|
|
80
|
-
'connectionPoolCreated',
|
|
81
|
-
'connectionPoolReady',
|
|
82
|
-
'connectionPoolCleared',
|
|
83
|
-
'connectionPoolClosed',
|
|
84
|
-
'connectionCreated',
|
|
85
|
-
'connectionReady',
|
|
86
|
-
'connectionClosed',
|
|
87
|
-
'connectionCheckOutStarted',
|
|
88
|
-
'connectionCheckOutFailed',
|
|
89
|
-
'connectionCheckedOut',
|
|
90
|
-
'connectionCheckedIn',
|
|
91
|
-
'commandStarted',
|
|
92
|
-
'commandSucceeded',
|
|
93
|
-
'commandFailed',
|
|
94
|
-
'serverOpening',
|
|
95
|
-
'serverClosed',
|
|
96
|
-
'serverDescriptionChanged',
|
|
97
|
-
'topologyOpening',
|
|
98
|
-
'topologyClosed',
|
|
99
|
-
'topologyDescriptionChanged',
|
|
100
|
-
'error',
|
|
101
|
-
'timeout',
|
|
102
|
-
'close',
|
|
103
|
-
'serverHeartbeatStarted',
|
|
104
|
-
'serverHeartbeatSucceeded',
|
|
105
|
-
'serverHeartbeatFailed',
|
|
106
|
-
];
|
|
107
|
-
|
|
108
71
|
/**
|
|
109
72
|
* Default settings.
|
|
110
73
|
*
|
|
111
|
-
* @type {
|
|
74
|
+
* @type {object}
|
|
112
75
|
*/
|
|
113
76
|
const DEFAULT_SETTINGS = {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
serverSelectionTimeoutMS: 2000,
|
|
77
|
+
// connectTimeoutMS: 2500,
|
|
78
|
+
// serverSelectionTimeoutMS: 2500,
|
|
117
79
|
};
|
|
118
80
|
|
|
119
81
|
/**
|
|
@@ -123,74 +85,27 @@ export class MongodbAdapter extends Adapter {
|
|
|
123
85
|
/**
|
|
124
86
|
* Mongodb instance.
|
|
125
87
|
*
|
|
88
|
+
* @type {MongoClient}
|
|
126
89
|
* @private
|
|
127
90
|
*/
|
|
128
91
|
_client;
|
|
129
92
|
|
|
130
93
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* @type {Map<any, any>}
|
|
134
|
-
* @private
|
|
135
|
-
*/
|
|
136
|
-
_collections = new Map();
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Connected.
|
|
94
|
+
* Client.
|
|
140
95
|
*
|
|
141
|
-
* @
|
|
142
|
-
* @private
|
|
96
|
+
* @returns {MongoClient}
|
|
143
97
|
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Connected.
|
|
148
|
-
*
|
|
149
|
-
* @return {boolean}
|
|
150
|
-
*/
|
|
151
|
-
get connected() {
|
|
152
|
-
return this._connected;
|
|
98
|
+
get client() {
|
|
99
|
+
return this._client;
|
|
153
100
|
}
|
|
154
101
|
|
|
155
102
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* @type {boolean}
|
|
159
|
-
* @private
|
|
160
|
-
*/
|
|
161
|
-
_connecting = false;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Connecting.
|
|
165
|
-
*
|
|
166
|
-
* @return {boolean}
|
|
167
|
-
*/
|
|
168
|
-
get connecting() {
|
|
169
|
-
return this._connecting;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Event emitter.
|
|
103
|
+
* Collections.
|
|
174
104
|
*
|
|
105
|
+
* @type {Map<any, any>}
|
|
175
106
|
* @private
|
|
176
107
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Event emitter.
|
|
181
|
-
*
|
|
182
|
-
* @returns {EventEmitter}
|
|
183
|
-
*/
|
|
184
|
-
get emitter() {
|
|
185
|
-
if (this._emitter) return this._emitter;
|
|
186
|
-
this._emitter = new EventEmitter();
|
|
187
|
-
const emit = this._emitter.emit;
|
|
188
|
-
this._emitter.emit = function (name, ...args) {
|
|
189
|
-
emit.call(this, '*', name, ...args);
|
|
190
|
-
return emit.call(this, name, ...args);
|
|
191
|
-
};
|
|
192
|
-
return this._emitter;
|
|
193
|
-
}
|
|
108
|
+
_collections = new Map();
|
|
194
109
|
|
|
195
110
|
/**
|
|
196
111
|
* Constructor.
|
|
@@ -205,90 +120,9 @@ export class MongodbAdapter extends Adapter {
|
|
|
205
120
|
settings.port = settings.port || 27017;
|
|
206
121
|
settings.database = settings.database || settings.db || 'database';
|
|
207
122
|
super(container, settings);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Connect.
|
|
212
|
-
*
|
|
213
|
-
* @return {Promise<*|undefined>}
|
|
214
|
-
* @private
|
|
215
|
-
*/
|
|
216
|
-
async connect() {
|
|
217
|
-
if (this._connecting) {
|
|
218
|
-
await waitAsync(500);
|
|
219
|
-
return this.connect();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (this._connected) return;
|
|
223
|
-
this._connecting = true;
|
|
224
|
-
|
|
225
123
|
const options = selectObjectKeys(this.settings, MONGODB_OPTION_NAMES);
|
|
226
124
|
const url = createMongodbUrl(this.settings);
|
|
227
|
-
|
|
228
|
-
// console.log(`Connecting to ${url}`);
|
|
229
|
-
if (this._client) {
|
|
230
|
-
this._client.removeAllListeners();
|
|
231
|
-
this._client.close(true);
|
|
232
|
-
}
|
|
233
125
|
this._client = new MongoClient(url, options);
|
|
234
|
-
for (const event of MONGO_CLIENT_EVENTS) {
|
|
235
|
-
const listener = (...args) => this.emitter.emit(event, ...args);
|
|
236
|
-
this._client.on(event, listener);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const {reconnectInterval} = this.settings;
|
|
240
|
-
const connectFn = async () => {
|
|
241
|
-
if (this._connecting === false) return;
|
|
242
|
-
this.emitter.emit('connecting');
|
|
243
|
-
try {
|
|
244
|
-
await this._client.connect();
|
|
245
|
-
} catch (e) {
|
|
246
|
-
this.emitter.emit('error', e);
|
|
247
|
-
console.error(e);
|
|
248
|
-
// console.log('MongoDB connection failed!');
|
|
249
|
-
// console.log(`Reconnecting after ${reconnectInterval} ms.`);
|
|
250
|
-
await waitAsync(reconnectInterval);
|
|
251
|
-
return connectFn();
|
|
252
|
-
}
|
|
253
|
-
// console.log('MongoDB is connected.');
|
|
254
|
-
this._connected = true;
|
|
255
|
-
this._connecting = false;
|
|
256
|
-
reconnectOnClose();
|
|
257
|
-
this.emitter.emit('connected');
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const reconnectOnClose = () =>
|
|
261
|
-
this._client.once('serverClosed', event => {
|
|
262
|
-
this.emitter.emit('disconnected', event);
|
|
263
|
-
if (this._connected) {
|
|
264
|
-
this._connected = false;
|
|
265
|
-
this._connecting = true;
|
|
266
|
-
// console.log('MongoDB lost connection!');
|
|
267
|
-
// console.log(event);
|
|
268
|
-
// console.log(`Reconnecting after ${reconnectInterval} ms.`);
|
|
269
|
-
setTimeout(() => connectFn(), reconnectInterval);
|
|
270
|
-
} else {
|
|
271
|
-
// console.log('MongoDB connection closed.');
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
return connectFn();
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Disconnect.
|
|
280
|
-
*
|
|
281
|
-
* @return {Promise<undefined>}
|
|
282
|
-
*/
|
|
283
|
-
async disconnect() {
|
|
284
|
-
this._connected = false;
|
|
285
|
-
this._connecting = false;
|
|
286
|
-
if (this._client) {
|
|
287
|
-
const client = this._client;
|
|
288
|
-
this._client = undefined;
|
|
289
|
-
await client.close();
|
|
290
|
-
client.removeAllListeners();
|
|
291
|
-
}
|
|
292
126
|
}
|
|
293
127
|
|
|
294
128
|
/**
|
|
@@ -326,19 +160,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
326
160
|
return value;
|
|
327
161
|
}
|
|
328
162
|
|
|
329
|
-
/**
|
|
330
|
-
* Coerce iso date.
|
|
331
|
-
*
|
|
332
|
-
* @param value
|
|
333
|
-
* @return {*|Date}
|
|
334
|
-
* @private
|
|
335
|
-
*/
|
|
336
|
-
_coerceIsoDate(value) {
|
|
337
|
-
if (value === null) return value;
|
|
338
|
-
if (isIsoDate(value)) return new Date(value);
|
|
339
|
-
return value;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
163
|
/**
|
|
343
164
|
* To database.
|
|
344
165
|
*
|
|
@@ -419,7 +240,7 @@ export class MongodbAdapter extends Adapter {
|
|
|
419
240
|
if (collection) return collection;
|
|
420
241
|
const tableName =
|
|
421
242
|
this.getService(ModelDefinitionUtils).getTableNameByModelName(modelName);
|
|
422
|
-
collection = this.
|
|
243
|
+
collection = this.client.db(this.settings.database).collection(tableName);
|
|
423
244
|
this._collections.set(modelName, collection);
|
|
424
245
|
return collection;
|
|
425
246
|
}
|
|
@@ -716,7 +537,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
716
537
|
* @return {Promise<object>}
|
|
717
538
|
*/
|
|
718
539
|
async create(modelName, modelData, filter = undefined) {
|
|
719
|
-
await this.connect();
|
|
720
540
|
const idPropName = this._getIdPropName(modelName);
|
|
721
541
|
const idValue = modelData[idPropName];
|
|
722
542
|
if (idValue == null) {
|
|
@@ -752,7 +572,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
752
572
|
* @return {Promise<object>}
|
|
753
573
|
*/
|
|
754
574
|
async replaceById(modelName, id, modelData, filter = undefined) {
|
|
755
|
-
await this.connect();
|
|
756
575
|
id = this._coerceId(id);
|
|
757
576
|
const idPropName = this._getIdPropName(modelName);
|
|
758
577
|
modelData[idPropName] = id;
|
|
@@ -779,7 +598,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
779
598
|
* @return {Promise<object>}
|
|
780
599
|
*/
|
|
781
600
|
async patchById(modelName, id, modelData, filter = undefined) {
|
|
782
|
-
await this.connect();
|
|
783
601
|
id = this._coerceId(id);
|
|
784
602
|
const idPropName = this._getIdPropName(modelName);
|
|
785
603
|
delete modelData[idPropName];
|
|
@@ -804,7 +622,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
804
622
|
* @return {Promise<object[]>}
|
|
805
623
|
*/
|
|
806
624
|
async find(modelName, filter = undefined) {
|
|
807
|
-
await this.connect();
|
|
808
625
|
filter = filter || {};
|
|
809
626
|
const query = this._buildQuery(modelName, filter.where);
|
|
810
627
|
const sort = this._buildSort(modelName, filter.order);
|
|
@@ -826,7 +643,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
826
643
|
* @return {Promise<object>}
|
|
827
644
|
*/
|
|
828
645
|
async findById(modelName, id, filter = undefined) {
|
|
829
|
-
await this.connect();
|
|
830
646
|
id = this._coerceId(id);
|
|
831
647
|
const table = this._getCollection(modelName);
|
|
832
648
|
const projection = this._buildProjection(
|
|
@@ -847,7 +663,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
847
663
|
* @return {Promise<number>}
|
|
848
664
|
*/
|
|
849
665
|
async delete(modelName, where = undefined) {
|
|
850
|
-
await this.connect();
|
|
851
666
|
const table = this._getCollection(modelName);
|
|
852
667
|
const query = this._buildQuery(modelName, where);
|
|
853
668
|
const {deletedCount} = await table.deleteMany(query);
|
|
@@ -862,7 +677,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
862
677
|
* @return {Promise<boolean>}
|
|
863
678
|
*/
|
|
864
679
|
async deleteById(modelName, id) {
|
|
865
|
-
await this.connect();
|
|
866
680
|
id = this._coerceId(id);
|
|
867
681
|
const table = this._getCollection(modelName);
|
|
868
682
|
const {deletedCount} = await table.deleteOne({_id: id});
|
|
@@ -877,7 +691,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
877
691
|
* @return {Promise<boolean>}
|
|
878
692
|
*/
|
|
879
693
|
async exists(modelName, id) {
|
|
880
|
-
await this.connect();
|
|
881
694
|
id = this._coerceId(id);
|
|
882
695
|
const table = this._getCollection(modelName);
|
|
883
696
|
const result = await table.findOne({_id: id}, {});
|
|
@@ -892,7 +705,6 @@ export class MongodbAdapter extends Adapter {
|
|
|
892
705
|
* @return {Promise<number>}
|
|
893
706
|
*/
|
|
894
707
|
async count(modelName, where = undefined) {
|
|
895
|
-
await this.connect();
|
|
896
708
|
const query = this._buildQuery(modelName, where);
|
|
897
709
|
const table = this._getCollection(modelName);
|
|
898
710
|
return await table.count(query);
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import net from 'net';
|
|
2
|
-
import chai from 'chai';
|
|
3
1
|
import {expect} from 'chai';
|
|
4
2
|
import {ObjectId} from 'mongodb';
|
|
5
3
|
import {MongoClient} from 'mongodb';
|
|
6
4
|
import {format} from '@e22m4u/js-format';
|
|
7
|
-
import {Service} from '@e22m4u/js-service';
|
|
8
5
|
import {Schema} from '@e22m4u/js-repository';
|
|
9
6
|
import {DataType} from '@e22m4u/js-repository';
|
|
10
7
|
import {createMongodbUrl} from './utils/index.js';
|
|
11
8
|
import {MongodbAdapter} from './mongodb-adapter.js';
|
|
12
9
|
import {AdapterRegistry} from '@e22m4u/js-repository';
|
|
13
10
|
import {DEFAULT_PRIMARY_KEY_PROPERTY_NAME as DEF_PK} from '@e22m4u/js-repository';
|
|
14
|
-
const sandbox = chai.spy.sandbox();
|
|
15
11
|
|
|
16
12
|
const CONFIG = {
|
|
17
13
|
host: process.env.MONGODB_HOST || 'localhost',
|
|
@@ -35,162 +31,16 @@ describe('MongodbAdapter', function () {
|
|
|
35
31
|
this.timeout(15000);
|
|
36
32
|
|
|
37
33
|
afterEach(async function () {
|
|
38
|
-
sandbox.restore();
|
|
39
34
|
await MDB_CLIENT.db(CONFIG.database).dropDatabase();
|
|
40
35
|
});
|
|
41
36
|
|
|
42
37
|
after(async function () {
|
|
43
38
|
for await (const adapter of ADAPTERS_STACK) {
|
|
44
|
-
await adapter.
|
|
39
|
+
await adapter.client.close(true);
|
|
45
40
|
}
|
|
46
41
|
await MDB_CLIENT.close(true);
|
|
47
42
|
});
|
|
48
43
|
|
|
49
|
-
it('updates "connected" and "connecting" properties', async function () {
|
|
50
|
-
const S = new Service();
|
|
51
|
-
const events = [];
|
|
52
|
-
const adapter = new MongodbAdapter(S.container, CONFIG);
|
|
53
|
-
adapter.emitter.addListener('*', name => events.push(name));
|
|
54
|
-
expect(adapter.connected).to.be.false;
|
|
55
|
-
expect(adapter.connecting).to.be.false;
|
|
56
|
-
expect(events).to.be.empty;
|
|
57
|
-
const promise = adapter.connect();
|
|
58
|
-
expect(adapter.connected).to.be.false;
|
|
59
|
-
expect(adapter.connecting).to.be.true;
|
|
60
|
-
expect(events).to.include('serverOpening');
|
|
61
|
-
expect(events).to.not.include('connectionPoolReady');
|
|
62
|
-
expect(events).to.not.include('serverClosed');
|
|
63
|
-
await promise;
|
|
64
|
-
expect(adapter.connected).to.be.true;
|
|
65
|
-
expect(adapter.connecting).to.be.false;
|
|
66
|
-
expect(events).to.include('connectionPoolReady');
|
|
67
|
-
expect(events).to.not.include('serverClosed');
|
|
68
|
-
await adapter.disconnect();
|
|
69
|
-
expect(adapter.connected).to.be.false;
|
|
70
|
-
expect(adapter.connecting).to.be.false;
|
|
71
|
-
expect(events).to.include('serverClosed');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('emits "connecting", "connected" and "disconnected" events', async function () {
|
|
75
|
-
const S = new Service();
|
|
76
|
-
const events = [];
|
|
77
|
-
const adapter = new MongodbAdapter(S.container, CONFIG);
|
|
78
|
-
adapter.emitter.addListener('*', name => events.push(name));
|
|
79
|
-
expect(adapter.connected).to.be.false;
|
|
80
|
-
expect(adapter.connecting).to.be.false;
|
|
81
|
-
expect(events).to.be.empty;
|
|
82
|
-
const promise = adapter.connect();
|
|
83
|
-
expect(adapter.connected).to.be.false;
|
|
84
|
-
expect(adapter.connecting).to.be.true;
|
|
85
|
-
expect(events).to.include('connecting');
|
|
86
|
-
expect(events).to.not.include('connected');
|
|
87
|
-
expect(events).to.not.include('disconnected');
|
|
88
|
-
await promise;
|
|
89
|
-
expect(adapter.connected).to.be.true;
|
|
90
|
-
expect(adapter.connecting).to.be.false;
|
|
91
|
-
expect(events).to.include('connected');
|
|
92
|
-
expect(events).to.not.include('disconnected');
|
|
93
|
-
await adapter.disconnect();
|
|
94
|
-
expect(adapter.connected).to.be.false;
|
|
95
|
-
expect(adapter.connecting).to.be.false;
|
|
96
|
-
expect(events).to.include('disconnected');
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('reconnects on server selection error', function (done) {
|
|
100
|
-
const S = new Service();
|
|
101
|
-
const server = net.createServer();
|
|
102
|
-
let startupCounter = 0;
|
|
103
|
-
server.listen(0, 'localhost', 2, () => {
|
|
104
|
-
startupCounter++;
|
|
105
|
-
expect(startupCounter).to.be.eq(1);
|
|
106
|
-
const {address, port} = server.address();
|
|
107
|
-
const attemptsLimit = 3;
|
|
108
|
-
const serverSelectionTimeoutMS = 50;
|
|
109
|
-
const adapter = new MongodbAdapter(S.container, {
|
|
110
|
-
port,
|
|
111
|
-
host: address,
|
|
112
|
-
reconnectInterval: 0,
|
|
113
|
-
serverSelectionTimeoutMS,
|
|
114
|
-
});
|
|
115
|
-
let attempts = 0;
|
|
116
|
-
const startTime = new Date();
|
|
117
|
-
adapter.emitter.addListener('connecting', () => {
|
|
118
|
-
++attempts;
|
|
119
|
-
if (attempts !== attemptsLimit) return;
|
|
120
|
-
const duration = new Date() - startTime;
|
|
121
|
-
const accuracy = 10;
|
|
122
|
-
server.close();
|
|
123
|
-
adapter.disconnect();
|
|
124
|
-
expect(adapter.connect).to.have.been.called.once;
|
|
125
|
-
const attemptMs = duration / (attemptsLimit - 1);
|
|
126
|
-
expect(attemptMs).to.be.gte(serverSelectionTimeoutMS - accuracy);
|
|
127
|
-
expect(attemptMs).to.be.lte(serverSelectionTimeoutMS + accuracy);
|
|
128
|
-
done();
|
|
129
|
-
});
|
|
130
|
-
adapter.emitter.addListener('error', error => {
|
|
131
|
-
expect(error.message).to.be.eq(
|
|
132
|
-
'Server selection timed out after 50 ms',
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
sandbox.on(adapter, 'connect');
|
|
136
|
-
adapter.connect();
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('reconnects on implicit disconnect', function (done) {
|
|
141
|
-
const S = new Service();
|
|
142
|
-
const reconnectsLimit = 2;
|
|
143
|
-
const reconnectInterval = 50;
|
|
144
|
-
const adapter = new MongodbAdapter(S.container, {
|
|
145
|
-
...CONFIG,
|
|
146
|
-
reconnectInterval,
|
|
147
|
-
});
|
|
148
|
-
let startTime;
|
|
149
|
-
let connects = 0;
|
|
150
|
-
let reconnects = 0;
|
|
151
|
-
adapter.emitter.on('connected', () => {
|
|
152
|
-
++connects;
|
|
153
|
-
if (connects === 1) {
|
|
154
|
-
adapter._client.close();
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
++reconnects;
|
|
158
|
-
if (startTime == null) startTime = new Date();
|
|
159
|
-
if (reconnects < reconnectsLimit) {
|
|
160
|
-
adapter._client.close();
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const duration = new Date() - startTime;
|
|
164
|
-
const accuracy = 10;
|
|
165
|
-
adapter.disconnect();
|
|
166
|
-
expect(adapter.connect).to.have.been.called.once;
|
|
167
|
-
const attemptMs = duration / (reconnectsLimit - 1);
|
|
168
|
-
expect(attemptMs).to.be.gt(reconnectInterval - accuracy);
|
|
169
|
-
expect(attemptMs).to.be.lt(reconnectInterval + accuracy);
|
|
170
|
-
expect(connects).to.be.eq(reconnectsLimit + 1);
|
|
171
|
-
done();
|
|
172
|
-
});
|
|
173
|
-
sandbox.on(adapter, 'connect');
|
|
174
|
-
adapter.connect();
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('does not reconnect on explicit disconnect', function (done) {
|
|
178
|
-
const S = new Service();
|
|
179
|
-
const reconnectInterval = 0;
|
|
180
|
-
const adapter = new MongodbAdapter(S.container, {
|
|
181
|
-
...CONFIG,
|
|
182
|
-
reconnectInterval,
|
|
183
|
-
});
|
|
184
|
-
adapter.emitter.once('connected', () => {
|
|
185
|
-
adapter.emitter.once('connecting', () => {
|
|
186
|
-
throw new Error('Unexpected reconnection');
|
|
187
|
-
});
|
|
188
|
-
adapter.emitter.once('disconnected', () => setTimeout(() => done(), 50));
|
|
189
|
-
adapter.disconnect();
|
|
190
|
-
});
|
|
191
|
-
adapter.connect();
|
|
192
|
-
});
|
|
193
|
-
|
|
194
44
|
describe('create', function () {
|
|
195
45
|
it('generates a new identifier when a value of a primary key is not provided', async function () {
|
|
196
46
|
const schema = createSchema();
|
package/src/utils/index.js
CHANGED
package/src/utils/wait-async.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {InvalidArgumentError} from '@e22m4u/js-repository';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Wait.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* await waitAsync(1000); // 1sec
|
|
9
|
-
* ```
|
|
10
|
-
*
|
|
11
|
-
* @param {number} ms Milliseconds
|
|
12
|
-
* @returns {Promise<undefined>}
|
|
13
|
-
*/
|
|
14
|
-
export function waitAsync(ms) {
|
|
15
|
-
if (typeof ms !== 'number')
|
|
16
|
-
throw new InvalidArgumentError(
|
|
17
|
-
'The first argument of "waitAsync" must be a Number, but %v given.',
|
|
18
|
-
ms,
|
|
19
|
-
);
|
|
20
|
-
return new Promise(r => setTimeout(() => r(), ms));
|
|
21
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {expect} from 'chai';
|
|
2
|
-
import {format} from '@e22m4u/js-format';
|
|
3
|
-
import {waitAsync} from './wait-async.js';
|
|
4
|
-
|
|
5
|
-
describe('wait', function () {
|
|
6
|
-
it('requires the first argument as a number', function () {
|
|
7
|
-
const throwable = v => () => waitAsync(v);
|
|
8
|
-
const error = v =>
|
|
9
|
-
format(
|
|
10
|
-
'The first argument of "waitAsync" must be a Number, but %s given.',
|
|
11
|
-
v,
|
|
12
|
-
);
|
|
13
|
-
expect(throwable('string')).to.throw(error('"string"'));
|
|
14
|
-
expect(throwable('')).to.throw(error('""'));
|
|
15
|
-
expect(throwable(true)).to.throw(error('true'));
|
|
16
|
-
expect(throwable(false)).to.throw(error('false'));
|
|
17
|
-
expect(throwable([])).to.throw(error('Array'));
|
|
18
|
-
expect(throwable({})).to.throw(error('Object'));
|
|
19
|
-
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
20
|
-
expect(throwable(null)).to.throw(error('null'));
|
|
21
|
-
throwable(10)();
|
|
22
|
-
throwable(0)();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('returns a promise that resolves after given milliseconds', async function () {
|
|
26
|
-
const startTime = new Date();
|
|
27
|
-
const delayMs = 15;
|
|
28
|
-
const accuracyMs = 5;
|
|
29
|
-
const promise = waitAsync(delayMs);
|
|
30
|
-
expect(promise).to.be.instanceof(Promise);
|
|
31
|
-
await promise;
|
|
32
|
-
const endTime = new Date();
|
|
33
|
-
const duration = endTime - startTime;
|
|
34
|
-
expect(duration).to.be.gte(delayMs - accuracyMs);
|
|
35
|
-
expect(duration).to.be.lte(delayMs + accuracyMs);
|
|
36
|
-
});
|
|
37
|
-
});
|