liwi-mongo 9.2.0 → 10.0.0

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.
Files changed (32) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/definitions/MongoBaseModel.d.ts +7 -0
  3. package/dist/definitions/MongoBaseModel.d.ts.map +1 -0
  4. package/dist/{MongoConnection.d.ts → definitions/MongoConnection.d.ts} +0 -0
  5. package/dist/definitions/MongoConnection.d.ts.map +1 -0
  6. package/dist/{MongoCursor.d.ts → definitions/MongoCursor.d.ts} +0 -0
  7. package/dist/definitions/MongoCursor.d.ts.map +1 -0
  8. package/dist/{MongoQueryCollection.d.ts → definitions/MongoQueryCollection.d.ts} +1 -1
  9. package/dist/definitions/MongoQueryCollection.d.ts.map +1 -0
  10. package/dist/{MongoQuerySingleItem.d.ts → definitions/MongoQuerySingleItem.d.ts} +1 -1
  11. package/dist/definitions/MongoQuerySingleItem.d.ts.map +1 -0
  12. package/dist/{MongoStore.d.ts → definitions/MongoStore.d.ts} +0 -0
  13. package/dist/definitions/MongoStore.d.ts.map +1 -0
  14. package/dist/{createMongoSubscribeStore.d.ts → definitions/createMongoSubscribeStore.d.ts} +0 -0
  15. package/dist/definitions/createMongoSubscribeStore.d.ts.map +1 -0
  16. package/dist/{index.d.ts → definitions/index.d.ts} +0 -0
  17. package/dist/definitions/index.d.ts.map +1 -0
  18. package/dist/{index-node14.mjs → index-node16.mjs} +12 -110
  19. package/dist/{index-node14.mjs.map → index-node16.mjs.map} +1 -1
  20. package/package.json +16 -21
  21. package/src/.eslintrc.json +1 -1
  22. package/dist/MongoBaseModel.d.ts +0 -7
  23. package/dist/MongoBaseModel.d.ts.map +0 -1
  24. package/dist/MongoConnection.d.ts.map +0 -1
  25. package/dist/MongoCursor.d.ts.map +0 -1
  26. package/dist/MongoQueryCollection.d.ts.map +0 -1
  27. package/dist/MongoQuerySingleItem.d.ts.map +0 -1
  28. package/dist/MongoStore.d.ts.map +0 -1
  29. package/dist/createMongoSubscribeStore.d.ts.map +0 -1
  30. package/dist/index-node14.cjs +0 -683
  31. package/dist/index-node14.cjs.map +0 -1
  32. package/dist/index.d.ts.map +0 -1
@@ -1,683 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- const mongodb = require('mongodb');
6
- const liwiStore = require('liwi-store');
7
- const liwiSubscribeStore = require('liwi-subscribe-store');
8
- const mingo = require('mingo');
9
- const nightingaleLogger = require('nightingale-logger');
10
-
11
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
12
-
13
- const mongodb__default = /*#__PURE__*/_interopDefaultLegacy(mongodb);
14
- const mingo__default = /*#__PURE__*/_interopDefaultLegacy(mingo);
15
-
16
- class MongoCursor extends liwiStore.AbstractStoreCursor {
17
- // key in AbstractCursor
18
- constructor(store, cursor) {
19
- super(store);
20
- this.cursor = cursor;
21
- }
22
-
23
- advance(count) {
24
- this.cursor.skip(count);
25
- }
26
-
27
- next() {
28
- return this.cursor.next().then(value => {
29
- this._result = value;
30
- this.key = value?._id;
31
- return this.key;
32
- });
33
- }
34
-
35
- limit(newLimit) {
36
- this.cursor.limit(newLimit);
37
- return Promise.resolve(this);
38
- }
39
-
40
- result() {
41
- if (!this._result) throw new Error('Cannot call result() before next()');
42
- return Promise.resolve(this._result);
43
- }
44
-
45
- close() {
46
- if (this.cursor) {
47
- this.cursor.close();
48
- }
49
-
50
- return Promise.resolve();
51
- }
52
-
53
- toArray() {
54
- return this.cursor.toArray();
55
- }
56
-
57
- }
58
-
59
- /* eslint-disable complexity, max-lines */
60
-
61
- const identityTransformer$1 = model => model;
62
-
63
- class MongoQueryCollection extends liwiSubscribeStore.AbstractSubscribableStoreQuery {
64
- constructor(store, options, transformer = identityTransformer$1) {
65
- super();
66
- this.store = store;
67
- this.options = options;
68
- this.transformer = transformer;
69
- }
70
-
71
- createTestCriteria() {
72
- if (!this.testCriteria) {
73
- if (!this.options.criteria) {
74
- return () => true;
75
- }
76
-
77
- const mingoQuery = new mingo__default.Query(this.options.criteria);
78
- this.testCriteria = mingoQuery.test.bind(mingoQuery);
79
- }
80
-
81
- return this.testCriteria;
82
- }
83
-
84
- async fetch(onFulfilled) {
85
- const [result, count] = await Promise.all([this.createMongoCursor().then(cursor => cursor.toArray()), this.store.count()]);
86
- return onFulfilled({
87
- result: result.map(this.transformer),
88
- meta: {
89
- total: count
90
- },
91
- info: {
92
- sort: this.options.sort,
93
- limit: this.options.limit,
94
- keyPath: this.store.keyPath
95
- }
96
- });
97
- }
98
-
99
- _subscribe(callback, _includeInitial) {
100
- const store = super.getSubscribeStore();
101
- const testCriteria = this.createTestCriteria();
102
- const promise = _includeInitial ? this.fetch(({
103
- result,
104
- meta,
105
- info
106
- }) => {
107
- callback(null, [{
108
- type: 'initial',
109
- initial: result,
110
- queryInfo: info,
111
- meta
112
- }]);
113
- }) : Promise.resolve();
114
- const unsubscribe = store.subscribe(action => {
115
- const changes = [];
116
-
117
- switch (action.type) {
118
- case 'inserted':
119
- {
120
- const filtered = action.next.filter(testCriteria);
121
-
122
- if (filtered.length > 0) {
123
- changes.push({
124
- type: 'inserted',
125
- result: filtered.map(this.transformer)
126
- });
127
- }
128
-
129
- break;
130
- }
131
-
132
- case 'deleted':
133
- {
134
- const filtered = action.prev.filter(testCriteria);
135
-
136
- if (filtered.length > 0) {
137
- changes.push({
138
- type: 'deleted',
139
- keys: filtered.map(object => object[this.store.keyPath])
140
- });
141
- }
142
-
143
- break;
144
- }
145
-
146
- case 'updated':
147
- {
148
- const {
149
- deleted,
150
- updated,
151
- inserted
152
- } = {
153
- deleted: [],
154
- updated: [],
155
- inserted: []
156
- };
157
- action.changes.forEach(([prevObject, nextObject]) => {
158
- if (testCriteria(prevObject)) {
159
- if (!testCriteria(nextObject)) {
160
- deleted.push(prevObject[this.store.keyPath]);
161
- } else {
162
- updated.push(this.transformer(nextObject));
163
- }
164
- } else if (testCriteria(nextObject)) {
165
- inserted.push(this.transformer(nextObject));
166
- }
167
- });
168
-
169
- if (deleted.length > 0) {
170
- changes.push({
171
- type: 'deleted',
172
- keys: deleted
173
- });
174
- }
175
-
176
- if (updated.length > 0) {
177
- changes.push({
178
- type: 'updated',
179
- result: updated
180
- });
181
- }
182
-
183
- if (inserted.length > 0) {
184
- changes.push({
185
- type: 'inserted',
186
- result: inserted
187
- });
188
- }
189
-
190
- break;
191
- }
192
-
193
- default:
194
- throw new Error('Unsupported type');
195
- }
196
-
197
- if (changes.length === 0) return;
198
- callback(null, changes);
199
- }); // let _feed;
200
- // const promise = this.queryCallback(this.store.query(), this.store.r)
201
- // .changes({
202
- // includeInitial: _includeInitial,
203
- // includeStates: true,
204
- // includeTypes: true,
205
- // includeOffsets: true,
206
- // })
207
- // .then((feed) => {
208
- // if (args.length === 0) {
209
- // _feed = feed;
210
- // delete this._promise;
211
- // }
212
- //
213
- // feed.each(callback);
214
- // return feed;
215
- // });
216
- //
217
- // if (args.length === 0) this._promise = promise;
218
-
219
- return {
220
- stop: unsubscribe,
221
- cancel: unsubscribe,
222
- then: (onFulfilled, onRejected) => promise.then(onFulfilled, onRejected)
223
- };
224
- }
225
-
226
- async createMongoCursor() {
227
- const cursor = await this.store.cursor(this.options.criteria, this.options.sort);
228
-
229
- if (this.options.skip) {
230
- cursor.advance(this.options.skip);
231
- }
232
-
233
- if (this.options.limit) {
234
- await cursor.limit(this.options.limit);
235
- }
236
-
237
- return cursor;
238
- }
239
-
240
- }
241
-
242
- const identityTransformer = model => model;
243
-
244
- class MongoQuerySingleItem extends liwiSubscribeStore.AbstractSubscribableStoreQuery {
245
- constructor(store, options, transformer = identityTransformer) {
246
- super();
247
- this.store = store;
248
- this.options = options;
249
- this.transformer = transformer;
250
- }
251
-
252
- createMingoTestCriteria() {
253
- if (!this.testCriteria) {
254
- if (!this.options.criteria) {
255
- return () => true;
256
- }
257
-
258
- const mingoQuery = new mingo__default.Query(this.options.criteria);
259
- this.testCriteria = mingoQuery.test.bind(mingoQuery);
260
- }
261
-
262
- return this.testCriteria;
263
- }
264
-
265
- async fetch(onFulfilled) {
266
- const cursor = await this.createMongoCursor();
267
- await cursor.limit(1);
268
- return cursor.toArray().then(result => {
269
- const item = result.length === 0 ? null : this.transformer(result[0]);
270
- return onFulfilled({
271
- result: item,
272
- meta: {
273
- total: result === null ? 0 : 1
274
- },
275
- info: {
276
- limit: 1,
277
- keyPath: this.store.keyPath
278
- }
279
- });
280
- });
281
- }
282
-
283
- _subscribe(callback, _includeInitial) {
284
- const store = super.getSubscribeStore();
285
- const testCriteria = this.createMingoTestCriteria();
286
- const promise = _includeInitial ? this.fetch(({
287
- result,
288
- meta,
289
- info
290
- }) => {
291
- callback(null, [{
292
- type: 'initial',
293
- initial: result,
294
- queryInfo: info,
295
- meta
296
- }]);
297
- }) : Promise.resolve();
298
- const unsubscribe = store.subscribe(async action => {
299
- const changes = [];
300
-
301
- switch (action.type) {
302
- case 'inserted':
303
- {
304
- const filtered = action.next.filter(testCriteria);
305
-
306
- if (filtered.length > 0) {
307
- changes.push({
308
- type: 'updated',
309
- result: this.transformer(filtered[0])
310
- });
311
- }
312
-
313
- break;
314
- }
315
-
316
- case 'deleted':
317
- {
318
- const filtered = action.prev.filter(testCriteria);
319
-
320
- if (filtered.length > 0) {
321
- changes.push({
322
- type: 'deleted',
323
- keys: filtered.map(object => object[this.store.keyPath])
324
- });
325
- }
326
-
327
- break;
328
- }
329
-
330
- case 'updated':
331
- {
332
- const filtered = action.changes.filter(([prev, next]) => testCriteria(prev));
333
-
334
- if (filtered.length > 0) {
335
- if (this.options.sort) {
336
- const {
337
- result
338
- } = await this.fetch(res => res);
339
- changes.push({
340
- type: 'updated',
341
- result
342
- });
343
- } else if (filtered.length !== 1) {
344
- throw new Error('should not match more than 1, use sort if you can have multiple match');
345
- } else {
346
- const [, next] = filtered[0];
347
- changes.push({
348
- type: 'updated',
349
- result: testCriteria(next) ? this.transformer(next) : null
350
- });
351
- }
352
- } else if (filtered.length === 0) ;
353
-
354
- break;
355
- }
356
-
357
- default:
358
- throw new Error('Unsupported type');
359
- }
360
-
361
- if (changes.length === 0) return;
362
- callback(null, changes);
363
- });
364
- return {
365
- stop: unsubscribe,
366
- cancel: unsubscribe,
367
- then: (onFulfilled, onRejected) => promise.then(onFulfilled, onRejected)
368
- };
369
- }
370
-
371
- async createMongoCursor() {
372
- const cursor = await this.store.cursor(this.options.criteria, this.options.sort);
373
-
374
- if (this.options.limit) {
375
- await cursor.limit(this.options.limit);
376
- }
377
-
378
- return cursor;
379
- }
380
-
381
- }
382
-
383
- /* eslint-disable max-lines */
384
- class MongoStore {
385
- keyPath = '_id';
386
-
387
- constructor(connection, collectionName) {
388
- this.connection = connection;
389
-
390
- if (!collectionName) {
391
- throw new Error(`Invalid collectionName: "${collectionName}"`);
392
- }
393
-
394
- this._collection = connection.getConnection().then(client => {
395
- this._collection = client.db().collection(collectionName);
396
- return this._collection;
397
- }, err => {
398
- this._collection = Promise.reject(err);
399
- return this._collection;
400
- });
401
- }
402
-
403
- get collection() {
404
- if (this.connection.connectionFailed) {
405
- return Promise.reject(new Error('MongoDB connection failed'));
406
- }
407
-
408
- return Promise.resolve(this._collection);
409
- }
410
-
411
- createQuerySingleItem(options, transformer) {
412
- return new MongoQuerySingleItem(this, options, transformer);
413
- }
414
-
415
- createQueryCollection(options, transformer) {
416
- return new MongoQueryCollection(this, options, transformer);
417
- }
418
-
419
- async insertOne(object) {
420
- if (!object._id) {
421
- object._id = new mongodb__default.ObjectId().toString();
422
- }
423
-
424
- if (!object.created) object.created = new Date();
425
- if (!object.updated) object.updated = new Date();
426
- const collection = await this.collection;
427
- const {
428
- acknowledged: isAcknowledged
429
- } = await collection.insertOne( // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
430
- object);
431
-
432
- if (!isAcknowledged) {
433
- throw new Error('Fail to insert');
434
- }
435
-
436
- return object;
437
- }
438
-
439
- async replaceOne(object) {
440
- if (!object.updated) object.updated = new Date();
441
- const collection = await this.collection;
442
- await collection.replaceOne({
443
- _id: object._id
444
- }, object);
445
- return object;
446
- }
447
-
448
- async upsertOne(object, setOnInsertPartialObject) {
449
- const result = await this.upsertOneWithInfo(object, setOnInsertPartialObject);
450
- return result.object;
451
- }
452
-
453
- async upsertOneWithInfo(object, setOnInsertPartialObject) {
454
- const $setOnInsert = {
455
- created: object.created || new Date(),
456
- ...setOnInsertPartialObject
457
- };
458
-
459
- if (!object.updated) {
460
- object.updated = new Date();
461
- }
462
-
463
- const $set = { ...object
464
- };
465
- delete $set.created;
466
- const collection = await this.collection;
467
- const {
468
- upsertedCount
469
- } = await collection.updateOne({
470
- _id: object._id
471
- }, {
472
- $set,
473
- $setOnInsert
474
- }, {
475
- upsert: true
476
- });
477
-
478
- if (upsertedCount) {
479
- Object.assign(object, $setOnInsert);
480
- }
481
-
482
- return {
483
- object: object,
484
- inserted: !!upsertedCount
485
- };
486
- }
487
-
488
- replaceSeveral(objects) {
489
- return Promise.all(objects.map(object => this.replaceOne(object)));
490
- }
491
-
492
- async partialUpdateByKey(key, partialUpdate, criteria) {
493
- const collection = await this.collection;
494
- const commandResult = await collection.updateOne({
495
- _id: key,
496
- ...criteria
497
- }, partialUpdate);
498
-
499
- if (!commandResult.acknowledged) {
500
- console.error(commandResult);
501
- throw new Error('Update failed');
502
- }
503
-
504
- const object = await this.findByKey(key);
505
- return object;
506
- }
507
-
508
- partialUpdateOne(object, partialUpdate) {
509
- return this.partialUpdateByKey(object._id, partialUpdate);
510
- }
511
-
512
- partialUpdateMany(criteria, partialUpdate) {
513
- return this.collection.then(collection => // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
514
- collection.updateMany(criteria, partialUpdate)).then(() => undefined); // TODO return updated object
515
- }
516
-
517
- deleteByKey(key, criteria) {
518
- return this.collection.then(collection => collection.deleteOne({
519
- _id: key,
520
- ...criteria
521
- })).then(() => undefined);
522
- }
523
-
524
- deleteOne(object) {
525
- return this.deleteByKey(object._id);
526
- }
527
-
528
- deleteMany(selector) {
529
- return this.collection.then(collection => collection.deleteMany(selector)).then(() => undefined);
530
- }
531
-
532
- async count(filter) {
533
- const collection = await this.collection;
534
- return filter ? collection.countDocuments(filter) : collection.countDocuments();
535
- }
536
-
537
- async cursor(filter, sort) {
538
- const collection = await this.collection;
539
- const findCursor = filter ? collection.find(filter) : collection.find();
540
- if (sort) findCursor.sort(sort);
541
- return new MongoCursor(this, findCursor);
542
- }
543
-
544
- async findByKey(key, criteria) {
545
- const collection = await this.collection;
546
- const result = await collection.findOne({
547
- _id: key,
548
- ...criteria
549
- });
550
- return result || undefined;
551
- }
552
-
553
- findAll(criteria, sort) {
554
- return this.cursor(criteria, sort).then(cursor => cursor.toArray());
555
- }
556
-
557
- async findOne(filter, sort) {
558
- const collection = await this.collection;
559
- const result = await collection.findOne(filter, {
560
- sort
561
- });
562
- return result || undefined;
563
- }
564
-
565
- }
566
-
567
- const logger = new nightingaleLogger.Logger('liwi:mongo:MongoConnection');
568
- class MongoConnection extends liwiStore.AbstractConnection {
569
- // TODO interface
570
- constructor(config) {
571
- super();
572
-
573
- if (!config.has('host')) {
574
- config.set('host', 'localhost');
575
- }
576
-
577
- if (!config.has('port')) {
578
- config.set('port', '27017');
579
- }
580
-
581
- if (!config.has('database')) {
582
- throw new Error('Missing config database');
583
- }
584
-
585
- const buildConnectionString = redactCredentials => `mongodb://${config.has('user') ? `${redactCredentials ? `${config.get('user').slice(0, 2)}[redacted]` : config.get('user')}:${redactCredentials ? '[redacted]' : config.get('password')}@` : ''}` + `${config.get('host')}:${config.get('port')}/${config.get('database')}`;
586
-
587
- const connectionString = buildConnectionString(false);
588
- const connectionStringRedacted = buildConnectionString(true);
589
- this.connect(connectionString, connectionStringRedacted);
590
- }
591
-
592
- connect(connectionString, connectionStringRedacted) {
593
- logger.info('connecting', {
594
- connectionStringRedacted
595
- });
596
- const connectPromise = mongodb__default.MongoClient.connect(connectionString).then(connection => {
597
- logger.info('connected', {
598
- connectionStringRedacted
599
- });
600
- connection.on('close', () => {
601
- logger.warn('close', {
602
- connectionStringRedacted
603
- });
604
- this.connectionFailed = true;
605
-
606
- this.getConnection = () => {
607
- throw new Error('MongoDB connection closed');
608
- };
609
- });
610
- connection.on('timeout', () => {
611
- logger.warn('timeout', {
612
- connectionStringRedacted
613
- });
614
- this.connectionFailed = true;
615
-
616
- this.getConnection = () => {
617
- throw new Error('MongoDB connection timeout');
618
- };
619
- });
620
- connection.on('reconnect', () => {
621
- logger.warn('reconnect', {
622
- connectionStringRedacted
623
- });
624
- this.connectionFailed = false;
625
-
626
- this.getConnection = () => Promise.resolve(this._connection);
627
- });
628
- connection.on('error', err => {
629
- logger.warn('error', {
630
- connectionStringRedacted,
631
- err
632
- });
633
- });
634
- this._connection = connection;
635
- this._connecting = undefined;
636
-
637
- this.getConnection = () => Promise.resolve(this._connection);
638
-
639
- return connection;
640
- }).catch(err => {
641
- logger.info('not connected', {
642
- connectionStringRedacted
643
- });
644
- console.error(err.message || err); // throw err;
645
-
646
- process.nextTick(() => {
647
- // eslint-disable-next-line unicorn/no-process-exit
648
- process.exit(1);
649
- });
650
- throw err;
651
- });
652
-
653
- this.getConnection = () => Promise.resolve(connectPromise);
654
-
655
- this._connecting = this.getConnection();
656
- }
657
-
658
- getConnection() {
659
- throw new Error('call connect()');
660
- }
661
-
662
- async close() {
663
- this.getConnection = () => Promise.reject(new Error('Connection closed'));
664
-
665
- if (this._connection) {
666
- await this._connection.close();
667
- this._connection = undefined;
668
- } else if (this._connecting) {
669
- await this._connecting;
670
- await this.close();
671
- }
672
- }
673
-
674
- }
675
-
676
- function createMongoSubscribeStore(mongoStore) {
677
- return new liwiSubscribeStore.SubscribeStore(mongoStore);
678
- }
679
-
680
- exports.MongoConnection = MongoConnection;
681
- exports.MongoStore = MongoStore;
682
- exports.createMongoSubscribeStore = createMongoSubscribeStore;
683
- //# sourceMappingURL=index-node14.cjs.map