cry-db 2.4.11 → 2.4.13
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/dist/base.mjs +1 -1
- package/dist/base.mjs.map +1 -1
- package/dist/db.mjs.map +1 -1
- package/dist/mongo.d.mts +10 -1
- package/dist/mongo.d.mts.map +1 -1
- package/dist/mongo.mjs +318 -129
- package/dist/mongo.mjs.map +1 -1
- package/dist/repo.d.mts.map +1 -1
- package/dist/repo.mjs.map +1 -1
- package/dist/types.d.mts +32 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +2 -1
package/dist/mongo.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as bcrypt from 'bcrypt';
|
|
2
|
+
import { Formatter, FracturedJsonOptions } from 'fracturedjsonjs';
|
|
2
3
|
import cloneDeep from "lodash.clonedeep";
|
|
3
4
|
import { ObjectId, ReadConcern, ReadPreference, Timestamp, WriteConcern } from 'mongodb';
|
|
4
5
|
import { TypedEmitter } from "tiny-typed-emitter";
|
|
@@ -35,6 +36,34 @@ const TRANSACTION_OPTIONS = {
|
|
|
35
36
|
writeConcern: new WriteConcern("majority")
|
|
36
37
|
}
|
|
37
38
|
};
|
|
39
|
+
// FracturedJson formatter for readable object logging
|
|
40
|
+
const fjOptions = new FracturedJsonOptions();
|
|
41
|
+
fjOptions.MaxTotalLineLength = 120;
|
|
42
|
+
fjOptions.MaxInlineComplexity = 2;
|
|
43
|
+
const fjFormatter = new Formatter();
|
|
44
|
+
fjFormatter.Options = fjOptions;
|
|
45
|
+
const fj = (obj) => {
|
|
46
|
+
var _a;
|
|
47
|
+
if (obj === null || obj === undefined)
|
|
48
|
+
return String(obj);
|
|
49
|
+
if (typeof obj !== 'object')
|
|
50
|
+
return String(obj);
|
|
51
|
+
try {
|
|
52
|
+
return (_a = fjFormatter.Serialize(obj)) !== null && _a !== void 0 ? _a : JSON.stringify(obj);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return JSON.stringify(obj);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
// Wrap log methods to auto-format objects with fracturedjson
|
|
59
|
+
const fjArgs = (args) => args.map(a => typeof a === 'object' && a !== null ? fj(a) : a);
|
|
60
|
+
const fjLog = {
|
|
61
|
+
debug: (...args) => { log.debug(...fjArgs(args)); },
|
|
62
|
+
trace: (...args) => { log.trace(...fjArgs(args)); },
|
|
63
|
+
info: (...args) => { log.info(...fjArgs(args)); },
|
|
64
|
+
warn: (...args) => { log.warn(...fjArgs(args)); },
|
|
65
|
+
error: (...args) => { log.error(...fjArgs(args)); },
|
|
66
|
+
};
|
|
38
67
|
// export const DummyExportToFixTsCompilation = true;
|
|
39
68
|
export class Mongo extends Db {
|
|
40
69
|
constructor(db, url) {
|
|
@@ -51,18 +80,18 @@ export class Mongo extends Db {
|
|
|
51
80
|
this.emitter = new TypedEmitter();
|
|
52
81
|
this.user = undefined;
|
|
53
82
|
this.audit = undefined;
|
|
54
|
-
|
|
83
|
+
fjLog.debug('new Mongo:', this.url, this.db);
|
|
55
84
|
}
|
|
56
85
|
on(evt, listener) {
|
|
57
|
-
|
|
86
|
+
fjLog.debug("on", evt, listener);
|
|
58
87
|
this.emitter.on(evt, listener);
|
|
59
88
|
}
|
|
60
89
|
off(evt, listener) {
|
|
61
|
-
|
|
90
|
+
fjLog.debug("off", evt, listener);
|
|
62
91
|
this.emitter.off(evt, listener);
|
|
63
92
|
}
|
|
64
93
|
once(evt, listener) {
|
|
65
|
-
|
|
94
|
+
fjLog.debug("once", evt, listener);
|
|
66
95
|
this.emitter.once(evt, listener);
|
|
67
96
|
}
|
|
68
97
|
setUser(username) {
|
|
@@ -137,18 +166,18 @@ export class Mongo extends Db {
|
|
|
137
166
|
this.revisions = true;
|
|
138
167
|
}
|
|
139
168
|
if (enabled)
|
|
140
|
-
|
|
169
|
+
fjLog.debug("publishing rev events");
|
|
141
170
|
return this.emittingPublishRevEvents = enabled;
|
|
142
171
|
}
|
|
143
172
|
emitsPublishRevEvents() {
|
|
144
173
|
return this.emittingPublishRevEvents;
|
|
145
174
|
}
|
|
146
175
|
async distinct(collection, field) {
|
|
147
|
-
|
|
176
|
+
fjLog.debug('distinct called', collection, field);
|
|
148
177
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
149
178
|
return await conn.distinct(field);
|
|
150
179
|
}, false, { operation: "distinct", collection, field });
|
|
151
|
-
|
|
180
|
+
fjLog.debug('distinct returns', ret);
|
|
152
181
|
return ret;
|
|
153
182
|
}
|
|
154
183
|
async count(collection, query = {}, opts = {}) {
|
|
@@ -157,11 +186,11 @@ export class Mongo extends Db {
|
|
|
157
186
|
if (!query._deleted)
|
|
158
187
|
query._deleted = { $exists: false };
|
|
159
188
|
}
|
|
160
|
-
|
|
189
|
+
fjLog.debug('count called', collection, query, opts);
|
|
161
190
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
162
191
|
return await conn.countDocuments(query, opts);
|
|
163
192
|
}, false, { operation: "count", collection, query, opts });
|
|
164
|
-
|
|
193
|
+
fjLog.debug('count returns', ret);
|
|
165
194
|
return ret;
|
|
166
195
|
}
|
|
167
196
|
async find(collection, query = {}, opts = {}) {
|
|
@@ -171,12 +200,12 @@ export class Mongo extends Db {
|
|
|
171
200
|
if (!query._deleted)
|
|
172
201
|
query._deleted = { $exists: false };
|
|
173
202
|
}
|
|
174
|
-
|
|
203
|
+
fjLog.debug('find called', collection, query, opts);
|
|
175
204
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
176
205
|
let r = this._applyQueryOpts(conn.find(query, this._buildFindOptions(opts)), opts);
|
|
177
206
|
return this._processReturnedObject(await r.toArray());
|
|
178
207
|
}, false, { operation: "find", collection, query, opts });
|
|
179
|
-
|
|
208
|
+
fjLog.debug('find returns', ret);
|
|
180
209
|
return ret;
|
|
181
210
|
}
|
|
182
211
|
async findAll(collection, query = {}, opts = {}) {
|
|
@@ -186,7 +215,7 @@ export class Mongo extends Db {
|
|
|
186
215
|
let r = this._applyQueryOpts(conn.find(query, this._buildFindOptions(opts)), opts);
|
|
187
216
|
return this._processReturnedObject(await r.toArray());
|
|
188
217
|
}, false, { operation: "findAll", collection, query, opts });
|
|
189
|
-
|
|
218
|
+
fjLog.debug('findAll returns', ret);
|
|
190
219
|
return ret;
|
|
191
220
|
}
|
|
192
221
|
async findNewer(collection, timestamp, query = {}, opts = {}) {
|
|
@@ -195,17 +224,17 @@ export class Mongo extends Db {
|
|
|
195
224
|
if (!query._deleted)
|
|
196
225
|
query._deleted = { $exists: false };
|
|
197
226
|
}
|
|
198
|
-
|
|
227
|
+
fjLog.debug('findNewer called', collection, timestamp, query, opts);
|
|
199
228
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
200
229
|
let r = this._applyQueryOpts(conn.find(query, this._buildFindOptions(opts)).sort({ _ts: 1 }), opts);
|
|
201
230
|
return this._processReturnedObject(await r.toArray());
|
|
202
231
|
}, false, { operation: "findNewer", collection, timestamp, query, opts });
|
|
203
|
-
|
|
232
|
+
fjLog.debug('findNewer returns', ret);
|
|
204
233
|
return ret;
|
|
205
234
|
}
|
|
206
235
|
async findNewerMany(spec = []) {
|
|
207
236
|
var _a;
|
|
208
|
-
|
|
237
|
+
fjLog.debug('findNewerMany called', spec);
|
|
209
238
|
const dbName = this.db; // Capture db at operation start
|
|
210
239
|
let conn = await this.connect();
|
|
211
240
|
const getOneColl = async (coll) => {
|
|
@@ -216,12 +245,12 @@ export class Mongo extends Db {
|
|
|
216
245
|
query._deleted = { $exists: false };
|
|
217
246
|
}
|
|
218
247
|
if (process.env.MONGO_DEBUG_FINDNEWERMANY) {
|
|
219
|
-
|
|
248
|
+
fjLog.debug("findNewerMany <-", coll.collection, coll.timestamp, coll.query, " -> ", JSON.stringify(query));
|
|
220
249
|
}
|
|
221
250
|
let r = this._applyQueryOpts(conn.db(dbName).collection(coll.collection).find(query, {}).sort({ _ts: 1 }), opts);
|
|
222
251
|
let data = await r.toArray();
|
|
223
252
|
if (process.env.MONGO_DEBUG_FINDNEWERMANY) {
|
|
224
|
-
|
|
253
|
+
fjLog.debug("findNewerMany ->", coll.collection, JSON.stringify(data, null, 2));
|
|
225
254
|
}
|
|
226
255
|
return { collection: coll.collection, data };
|
|
227
256
|
};
|
|
@@ -246,7 +275,7 @@ export class Mongo extends Db {
|
|
|
246
275
|
async latestTimestamps(collections) {
|
|
247
276
|
assert(collections);
|
|
248
277
|
assert(collections instanceof Array);
|
|
249
|
-
|
|
278
|
+
fjLog.debug('latestTimestamps called', collections);
|
|
250
279
|
const dbName = this.db; // Capture db at operation start
|
|
251
280
|
let conn = await this.connect();
|
|
252
281
|
const getOne = async (collection) => {
|
|
@@ -268,13 +297,13 @@ export class Mongo extends Db {
|
|
|
268
297
|
let out = {};
|
|
269
298
|
(await Promise.all(promises)).forEach(r => { if (r.ts)
|
|
270
299
|
out[r.collection] = r.ts; });
|
|
271
|
-
|
|
300
|
+
fjLog.debug('latestTimestamps returns', out);
|
|
272
301
|
return out;
|
|
273
302
|
}
|
|
274
303
|
async latestTimestamp(collection) {
|
|
275
304
|
var _a;
|
|
276
305
|
assert(collection);
|
|
277
|
-
|
|
306
|
+
fjLog.debug('latestTimestamp called', collection);
|
|
278
307
|
const dbName = this.db; // Capture db at operation start
|
|
279
308
|
let conn = await this.connect();
|
|
280
309
|
let cursor = conn
|
|
@@ -286,7 +315,7 @@ export class Mongo extends Db {
|
|
|
286
315
|
.limit(1);
|
|
287
316
|
let res = await cursor.toArray();
|
|
288
317
|
let ts = (_a = res === null || res === void 0 ? void 0 : res[0]) === null || _a === void 0 ? void 0 : _a._ts;
|
|
289
|
-
|
|
318
|
+
fjLog.debug('latestTimestamp returns', ts);
|
|
290
319
|
return ts;
|
|
291
320
|
}
|
|
292
321
|
_createQueryForNewer(timestamp, query) {
|
|
@@ -304,7 +333,7 @@ export class Mongo extends Db {
|
|
|
304
333
|
}
|
|
305
334
|
// async findAfter<T>(collection: string, csq: number, query: QuerySpec<T> = {}, opts: QueryOpts = {}): Promise<T[]> {
|
|
306
335
|
// // query._csq = { $gt: csq };
|
|
307
|
-
//
|
|
336
|
+
// fjLog.debug('findAfter called', collection, csq, query, opts)
|
|
308
337
|
// let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
309
338
|
// let optsIn: FindOptions<any> = {}
|
|
310
339
|
// if (opts.readPreference) optsIn.readPreference = opts.readPreference;
|
|
@@ -319,12 +348,12 @@ export class Mongo extends Db {
|
|
|
319
348
|
// if (opts.collation) r = r.collation(opts.collation);
|
|
320
349
|
// return this._processReturnedObject(await r.toArray());
|
|
321
350
|
// }, false, { operation: "findNewer", collection, csq, query, opts });
|
|
322
|
-
//
|
|
351
|
+
// fjLog.debug('findNewer returns', ret)
|
|
323
352
|
// return ret;
|
|
324
353
|
// }
|
|
325
354
|
// async findAfterMany<T>(spec: GetAfterSpec<T>[] = []):
|
|
326
355
|
// Promise<Record<string, any[]>> {
|
|
327
|
-
//
|
|
356
|
+
// fjLog.debug('findAfterMany called', spec)
|
|
328
357
|
// let conn = await this.connect()
|
|
329
358
|
// const getOneColl = async (coll: GetAfterSpec<T>): Promise<{ collection: string, data: any[] }> => {
|
|
330
359
|
// let r = conn
|
|
@@ -351,9 +380,9 @@ export class Mongo extends Db {
|
|
|
351
380
|
// }
|
|
352
381
|
// async findNewerFromDate<T>(collection: string, date: Date | string, query: QuerySpec<T> = {}, opts: QueryOpts = {}): Promise<T[]> {
|
|
353
382
|
// let ts = new Timestamp({ i: new Date(date).valueOf() % 1000, t: new Date(date).valueOf() / 1000 });
|
|
354
|
-
//
|
|
383
|
+
// fjLog.debug('findNewerFromDate called', collection, date, query, opts)
|
|
355
384
|
// let ret = await Mongo.prototype.findNewer.call(this, collection, ts, query, opts) // prevent calling Repo.findNewer
|
|
356
|
-
//
|
|
385
|
+
// fjLog.debug('findNewerFromDate returns', ret)
|
|
357
386
|
// return ret as T[];
|
|
358
387
|
// }
|
|
359
388
|
async findOne(collection, query, projection, opts = {}) {
|
|
@@ -365,9 +394,9 @@ export class Mongo extends Db {
|
|
|
365
394
|
query._deleted = { $exists: false };
|
|
366
395
|
}
|
|
367
396
|
// if (!query._blocked) query._blocked = { $exists: false }; // intentionally - blocked records are returned
|
|
368
|
-
|
|
397
|
+
fjLog.debug('findOne called', collection, query, projection);
|
|
369
398
|
let ret = await this.executeTransactionally(collection, async (conn) => await conn.findOne(query, { ...(projection ? { projection } : {}), ...this._sessionOpt() }), false, { operation: "findOne", collection, query, projection });
|
|
370
|
-
|
|
399
|
+
fjLog.debug('findOne returns', ret);
|
|
371
400
|
return this._processReturnedObject(ret);
|
|
372
401
|
}
|
|
373
402
|
async findById(collection, id, projection, opts = {}) {
|
|
@@ -380,15 +409,15 @@ export class Mongo extends Db {
|
|
|
380
409
|
_id: Mongo._toId(id),
|
|
381
410
|
// _deleted: { $exists: false }
|
|
382
411
|
};
|
|
383
|
-
|
|
384
|
-
|
|
412
|
+
fjLog.debug('findById called', dbName, collection, id, projection);
|
|
413
|
+
fjLog.trace('findById executing with query', collection, query, projection);
|
|
385
414
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
386
415
|
let r = await conn.findOne(query, { ...(projection ? { projection } : {}), ...this._sessionOpt() });
|
|
387
416
|
return r;
|
|
388
417
|
}, false, { operation: "findById", collection, id, projection });
|
|
389
418
|
if ((ret === null || ret === void 0 ? void 0 : ret._deleted) && this.softdelete && !opts.returnDeleted)
|
|
390
419
|
ret = null;
|
|
391
|
-
|
|
420
|
+
fjLog.debug('findById returns', ret);
|
|
392
421
|
return this._processReturnedObject(ret);
|
|
393
422
|
}
|
|
394
423
|
async findByIds(collection, ids, projection, opts = {}) {
|
|
@@ -398,7 +427,7 @@ export class Mongo extends Db {
|
|
|
398
427
|
return [];
|
|
399
428
|
const dbName = this.db;
|
|
400
429
|
const objectIds = ids.map(id => Mongo._toId(id));
|
|
401
|
-
|
|
430
|
+
fjLog.debug('findByIds called', dbName, collection, ids, projection);
|
|
402
431
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
403
432
|
let query = { _id: { $in: objectIds } };
|
|
404
433
|
if (this.softdelete && !opts.returnDeleted) {
|
|
@@ -407,7 +436,7 @@ export class Mongo extends Db {
|
|
|
407
436
|
let r = conn.find(query, { ...(projection ? { projection } : {}), ...this._sessionOpt() });
|
|
408
437
|
return await r.toArray();
|
|
409
438
|
}, false, { operation: "findByIds", collection, ids, projection });
|
|
410
|
-
|
|
439
|
+
fjLog.debug('findByIds returns', ret);
|
|
411
440
|
return this._processReturnedObject(ret);
|
|
412
441
|
}
|
|
413
442
|
async updateOne(collection, query, update, options = { returnFullObject: false }) {
|
|
@@ -423,7 +452,7 @@ export class Mongo extends Db {
|
|
|
423
452
|
...this._sessionOpt()
|
|
424
453
|
};
|
|
425
454
|
update = await this._processUpdateObject(update);
|
|
426
|
-
|
|
455
|
+
fjLog.debug('updateOne called', collection, query, update);
|
|
427
456
|
let seqKeys = this._findSequenceKeys(update.$set);
|
|
428
457
|
let obj = await this.executeTransactionally(collection, async (conn, client) => {
|
|
429
458
|
update.$set = update.$set || {};
|
|
@@ -438,7 +467,7 @@ export class Mongo extends Db {
|
|
|
438
467
|
await this._publishAndAudit('update', dbName, collection, resObj);
|
|
439
468
|
return resObj;
|
|
440
469
|
}, !!seqKeys, { operation: "updateOne", collection, query, update, options });
|
|
441
|
-
|
|
470
|
+
fjLog.debug('updateOne returns', obj);
|
|
442
471
|
return this._processReturnedObject(await obj);
|
|
443
472
|
}
|
|
444
473
|
async save(collection, update, id = undefined, options = { returnFullObject: false }) {
|
|
@@ -453,7 +482,7 @@ export class Mongo extends Db {
|
|
|
453
482
|
};
|
|
454
483
|
let _id = Mongo.toId(id || update._id) || Mongo.newid();
|
|
455
484
|
update = await this._processUpdateObject(update);
|
|
456
|
-
|
|
485
|
+
fjLog.debug('save called', collection, id, update);
|
|
457
486
|
let seqKeys = this._findSequenceKeys(update.$set);
|
|
458
487
|
let obj = await this.executeTransactionally(collection, async (conn, client) => {
|
|
459
488
|
update.$set = update.$set || {};
|
|
@@ -468,14 +497,14 @@ export class Mongo extends Db {
|
|
|
468
497
|
await this._publishAndAudit('update', dbName, collection, resObj);
|
|
469
498
|
return resObj;
|
|
470
499
|
}, !!seqKeys, { operation: "save", collection, _id, update, options });
|
|
471
|
-
|
|
500
|
+
fjLog.debug('save returns', obj);
|
|
472
501
|
return this._processReturnedObject(await obj);
|
|
473
502
|
}
|
|
474
503
|
async update(collection, query, update) {
|
|
475
504
|
assert(collection);
|
|
476
505
|
assert(query);
|
|
477
506
|
assert(update);
|
|
478
|
-
// if (this.syncSupport)
|
|
507
|
+
// if (this.syncSupport) fjLog.warn("update does not increase _csq, avoit it.")
|
|
479
508
|
if (!Object.keys(update).length)
|
|
480
509
|
return { n: 0, ok: false };
|
|
481
510
|
const dbName = this.db; // Capture db at operation start
|
|
@@ -487,7 +516,7 @@ export class Mongo extends Db {
|
|
|
487
516
|
...this._sessionOpt()
|
|
488
517
|
};
|
|
489
518
|
update = await this._processUpdateObject(update);
|
|
490
|
-
|
|
519
|
+
fjLog.debug('update called', collection, query, update);
|
|
491
520
|
let seqKeys = this._findSequenceKeys(update.$set);
|
|
492
521
|
let obj = await this.executeTransactionally(collection, async (conn, client) => {
|
|
493
522
|
update.$set = update.$set || {};
|
|
@@ -495,7 +524,7 @@ export class Mongo extends Db {
|
|
|
495
524
|
await this._processSequenceField(client, dbName, collection, update.$set, seqKeys);
|
|
496
525
|
if (update.$set === undefined || Object.keys(update.$set).length === 0)
|
|
497
526
|
delete update.$set;
|
|
498
|
-
|
|
527
|
+
fjLog.debug('update called', collection, query, update);
|
|
499
528
|
let res = await conn.updateMany(query, update, opts);
|
|
500
529
|
let resObj = {
|
|
501
530
|
n: res.modifiedCount,
|
|
@@ -504,7 +533,7 @@ export class Mongo extends Db {
|
|
|
504
533
|
await this._publishAndAudit('updateMany', dbName, collection, resObj);
|
|
505
534
|
return resObj;
|
|
506
535
|
}, !!seqKeys, { operation: "update", collection, query, update });
|
|
507
|
-
|
|
536
|
+
fjLog.debug('update returns', obj);
|
|
508
537
|
return await obj;
|
|
509
538
|
}
|
|
510
539
|
async upsert(collection, query, update, options = { returnFullObject: false }) {
|
|
@@ -522,10 +551,10 @@ export class Mongo extends Db {
|
|
|
522
551
|
returnDocument: "after",
|
|
523
552
|
...this._sessionOpt()
|
|
524
553
|
};
|
|
525
|
-
|
|
554
|
+
fjLog.debug('upsert called', collection, query, update);
|
|
526
555
|
update = await this._processUpdateObject(update);
|
|
527
556
|
let seqKeys = this._findSequenceKeys(update.$set);
|
|
528
|
-
|
|
557
|
+
fjLog.debug('upsert processed', collection, query, update);
|
|
529
558
|
if (Object.keys(query).length === 0)
|
|
530
559
|
query._id = Mongo.newid();
|
|
531
560
|
let ret = await this.executeTransactionally(collection, async (conn, client) => {
|
|
@@ -547,14 +576,14 @@ export class Mongo extends Db {
|
|
|
547
576
|
;
|
|
548
577
|
return ret;
|
|
549
578
|
}, !!seqKeys, { operation: "upsert", query, update, options });
|
|
550
|
-
|
|
579
|
+
fjLog.debug('upsert returns', ret);
|
|
551
580
|
return this._processReturnedObject(await ret);
|
|
552
581
|
}
|
|
553
582
|
async insert(collection, insert) {
|
|
554
583
|
assert(collection, "collection can't be null");
|
|
555
584
|
assert(insert, "insert can't be null");
|
|
556
585
|
assert(typeof insert === "object", "insert must be an object");
|
|
557
|
-
|
|
586
|
+
fjLog.debug('insert called', collection, insert);
|
|
558
587
|
const dbName = this.db; // Capture db at operation start
|
|
559
588
|
insert = this.replaceIds(insert);
|
|
560
589
|
if (this.revisions) {
|
|
@@ -571,14 +600,174 @@ export class Mongo extends Db {
|
|
|
571
600
|
await this._publishAndAudit('insert', dbName, collection, fullObj);
|
|
572
601
|
return fullObj;
|
|
573
602
|
}, !!seqKeys, { operation: "insert", collection, insert });
|
|
574
|
-
|
|
603
|
+
fjLog.debug('insert returns', ret);
|
|
575
604
|
return this._processReturnedObject(await ret);
|
|
576
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* Efficiently updates many collections at once.
|
|
608
|
+
* Returns ids of object actually updated and deleted and errors for unsucessful updates/deletes.
|
|
609
|
+
*
|
|
610
|
+
* if this.emittingPublishRevEvents===true, emits one PublishRevsPayloadBatch per collection
|
|
611
|
+
*
|
|
612
|
+
* @param collectionsBatches
|
|
613
|
+
*/
|
|
614
|
+
async updateCollections(collectionsBatches) {
|
|
615
|
+
assert(collectionsBatches, "collectionsBatches can't be null");
|
|
616
|
+
assert(collectionsBatches instanceof Array, "collectionsBatches must be an Array");
|
|
617
|
+
fjLog.debug('updateCollections called', collectionsBatches.length, 'collections');
|
|
618
|
+
const dbName = this.db;
|
|
619
|
+
const conn = await this.connect();
|
|
620
|
+
const results = [];
|
|
621
|
+
// Process each collection's batches
|
|
622
|
+
for (const collectionRequest of collectionsBatches) {
|
|
623
|
+
// Each collectionRequest is an array of { collection, batch } for the same collection
|
|
624
|
+
for (const req of collectionRequest) {
|
|
625
|
+
const { collection, batch } = req;
|
|
626
|
+
const { updates, deletes } = batch;
|
|
627
|
+
const result = {
|
|
628
|
+
collection,
|
|
629
|
+
results: {
|
|
630
|
+
updatedIds: [],
|
|
631
|
+
deletedIds: [],
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
const batchData = [];
|
|
635
|
+
const errors = [];
|
|
636
|
+
// Process updates in parallel
|
|
637
|
+
if (updates === null || updates === void 0 ? void 0 : updates.length) {
|
|
638
|
+
const updatePromises = updates.map(async ({ _id, update }) => {
|
|
639
|
+
try {
|
|
640
|
+
const objectId = Mongo._toId(_id);
|
|
641
|
+
const processedUpdate = await this._processUpdateObject({ ...update });
|
|
642
|
+
const opts = {
|
|
643
|
+
upsert: false,
|
|
644
|
+
returnDocument: "after",
|
|
645
|
+
...this._sessionOpt()
|
|
646
|
+
};
|
|
647
|
+
const res = await conn
|
|
648
|
+
.db(dbName)
|
|
649
|
+
.collection(collection)
|
|
650
|
+
.findOneAndUpdate({ _id: objectId }, processedUpdate, opts);
|
|
651
|
+
if (res) {
|
|
652
|
+
const retObj = this._removeUnchanged(res, processedUpdate, false);
|
|
653
|
+
this._processReturnedObject(retObj);
|
|
654
|
+
return { success: true, _id, data: retObj, operation: 'update' };
|
|
655
|
+
}
|
|
656
|
+
return { success: false, _id, error: 'Document not found' };
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
return { success: false, _id, error: err.message || String(err) };
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
const updateResults = await Promise.all(updatePromises);
|
|
663
|
+
for (const res of updateResults) {
|
|
664
|
+
if (res.success && res.data) {
|
|
665
|
+
result.results.updatedIds.push(res._id);
|
|
666
|
+
batchData.push({ operation: res.operation, data: res.data });
|
|
667
|
+
}
|
|
668
|
+
else if (!res.success && res.error) {
|
|
669
|
+
errors.push({ _id: String(res._id), error: res.error });
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// Process deletes in parallel
|
|
674
|
+
if (deletes === null || deletes === void 0 ? void 0 : deletes.length) {
|
|
675
|
+
const deletePromises = deletes.map(async ({ _id }) => {
|
|
676
|
+
try {
|
|
677
|
+
const objectId = Mongo._toId(_id);
|
|
678
|
+
if (!this.softdelete) {
|
|
679
|
+
const res = await conn
|
|
680
|
+
.db(dbName)
|
|
681
|
+
.collection(collection)
|
|
682
|
+
.findOneAndDelete({ _id: objectId }, this._sessionOpt());
|
|
683
|
+
if (res) {
|
|
684
|
+
this._processReturnedObject(res);
|
|
685
|
+
return { success: true, _id, data: res, operation: 'delete' };
|
|
686
|
+
}
|
|
687
|
+
return { success: false, _id, error: 'Document not found' };
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
const del = {
|
|
691
|
+
$set: { _deleted: new Date() },
|
|
692
|
+
$inc: { _rev: 1 },
|
|
693
|
+
$currentDate: { _ts: { $type: 'timestamp' } }
|
|
694
|
+
};
|
|
695
|
+
const opts = {
|
|
696
|
+
upsert: false,
|
|
697
|
+
returnDocument: "after",
|
|
698
|
+
...this._sessionOpt()
|
|
699
|
+
};
|
|
700
|
+
const res = await conn
|
|
701
|
+
.db(dbName)
|
|
702
|
+
.collection(collection)
|
|
703
|
+
.findOneAndUpdate({ _id: objectId }, del, opts);
|
|
704
|
+
if (res) {
|
|
705
|
+
this._processReturnedObject(res);
|
|
706
|
+
return { success: true, _id, data: res, operation: 'delete' };
|
|
707
|
+
}
|
|
708
|
+
return { success: false, _id, error: 'Document not found' };
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch (err) {
|
|
712
|
+
return { success: false, _id, error: err.message || String(err) };
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
const deleteResults = await Promise.all(deletePromises);
|
|
716
|
+
for (const res of deleteResults) {
|
|
717
|
+
if (res.success && res.data) {
|
|
718
|
+
result.results.deletedIds.push(res._id);
|
|
719
|
+
batchData.push({ operation: res.operation, data: res.data });
|
|
720
|
+
}
|
|
721
|
+
else if (!res.success && res.error) {
|
|
722
|
+
errors.push({ _id: String(res._id), error: res.error });
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
// Set errors if any
|
|
727
|
+
if (errors.length > 0 && errors[0]) {
|
|
728
|
+
result.results.errors = errors[0];
|
|
729
|
+
}
|
|
730
|
+
// Emit batch events per collection
|
|
731
|
+
if (batchData.length > 0) {
|
|
732
|
+
if (this.emittingPublishEvents || this.auditing) {
|
|
733
|
+
this.emit("publish", {
|
|
734
|
+
channel: `db/${dbName}/${collection}`,
|
|
735
|
+
payload: {
|
|
736
|
+
operation: "batch",
|
|
737
|
+
db: dbName,
|
|
738
|
+
collection,
|
|
739
|
+
data: batchData
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
if (this.emittingPublishRevEvents) {
|
|
744
|
+
const payload = {
|
|
745
|
+
operation: "batch",
|
|
746
|
+
db: dbName,
|
|
747
|
+
collection,
|
|
748
|
+
data: batchData.map(item => ({
|
|
749
|
+
operation: item.operation,
|
|
750
|
+
_id: item.data._id,
|
|
751
|
+
_ts: item.data._ts,
|
|
752
|
+
}))
|
|
753
|
+
};
|
|
754
|
+
this.emit("publishRev", {
|
|
755
|
+
channel: `dbrev/${dbName}/${collection}`,
|
|
756
|
+
payload,
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
results.push(result);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
fjLog.debug('updateCollections returns', results);
|
|
764
|
+
return results;
|
|
765
|
+
}
|
|
577
766
|
async upsertBatch(collection, batch) {
|
|
578
767
|
assert(collection, "collection can't be null");
|
|
579
768
|
assert(batch, "batch can't be null");
|
|
580
769
|
assert(batch instanceof Array, "batch must be an Array");
|
|
581
|
-
|
|
770
|
+
fjLog.debug('upsertBatch called', collection, batch);
|
|
582
771
|
const dbName = this.db; // Capture db at operation start
|
|
583
772
|
batch = this.replaceIds(batch);
|
|
584
773
|
await Promise.all(batch.map(item => this._processHashedKeys(item === null || item === void 0 ? void 0 : item.update)));
|
|
@@ -652,14 +841,14 @@ export class Mongo extends Db {
|
|
|
652
841
|
}
|
|
653
842
|
return changes;
|
|
654
843
|
}, false, { operation: "upsertBatch", collection, batch });
|
|
655
|
-
|
|
844
|
+
fjLog.debug('upsertBatch returns', ret);
|
|
656
845
|
return ret;
|
|
657
846
|
}
|
|
658
847
|
async insertMany(collection, insert) {
|
|
659
848
|
assert(collection, "collection can't be null");
|
|
660
849
|
assert(insert, "insert can't be null");
|
|
661
850
|
assert(insert instanceof Array, "insert must be an Array");
|
|
662
|
-
|
|
851
|
+
fjLog.debug('insertMany called', collection, insert);
|
|
663
852
|
const dbName = this.db; // Capture db at operation start
|
|
664
853
|
insert = this.replaceIds(insert);
|
|
665
854
|
await Promise.all(insert.map(item => this._processHashedKeys(item)));
|
|
@@ -682,7 +871,7 @@ export class Mongo extends Db {
|
|
|
682
871
|
}
|
|
683
872
|
return ret;
|
|
684
873
|
}, false, { operation: "insertMany", collection, insert });
|
|
685
|
-
|
|
874
|
+
fjLog.debug('insertMany returns', ret);
|
|
686
875
|
return ret;
|
|
687
876
|
}
|
|
688
877
|
async deleteOne(collection, query) {
|
|
@@ -692,14 +881,14 @@ export class Mongo extends Db {
|
|
|
692
881
|
query = this.replaceIds(query);
|
|
693
882
|
if (!this.softdelete) {
|
|
694
883
|
const opts = this._sessionOpt();
|
|
695
|
-
|
|
884
|
+
fjLog.debug('deleteOne called', this.softdelete, collection, query);
|
|
696
885
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
697
886
|
let obj = await conn.findOneAndDelete(query, opts);
|
|
698
887
|
if (obj)
|
|
699
888
|
await this._publishAndAudit('delete', dbName, collection, obj);
|
|
700
889
|
return obj;
|
|
701
890
|
}, false, { operation: "deleteOne", collection, query, softdelete: this.softdelete });
|
|
702
|
-
|
|
891
|
+
fjLog.debug('deleteOne returns', ret);
|
|
703
892
|
return ret;
|
|
704
893
|
}
|
|
705
894
|
else {
|
|
@@ -708,7 +897,7 @@ export class Mongo extends Db {
|
|
|
708
897
|
returnDocument: "after",
|
|
709
898
|
...this._sessionOpt()
|
|
710
899
|
};
|
|
711
|
-
|
|
900
|
+
fjLog.debug('deleteOne called', collection, query);
|
|
712
901
|
let ret = await this.executeTransactionally(collection, async (conn /*, client*/) => {
|
|
713
902
|
let del = {
|
|
714
903
|
$set: { _deleted: new Date() },
|
|
@@ -721,7 +910,7 @@ export class Mongo extends Db {
|
|
|
721
910
|
await this._publishAndAudit('delete', dbName, collection, obj);
|
|
722
911
|
return obj;
|
|
723
912
|
}, false, { operation: "deleteOne", collection, query, softdelete: this.softdelete });
|
|
724
|
-
|
|
913
|
+
fjLog.debug('deleteOne returns', ret);
|
|
725
914
|
return ret;
|
|
726
915
|
}
|
|
727
916
|
}
|
|
@@ -733,7 +922,7 @@ export class Mongo extends Db {
|
|
|
733
922
|
};
|
|
734
923
|
const dbName = this.db; // Capture db at operation start
|
|
735
924
|
query = this.replaceIds(query);
|
|
736
|
-
|
|
925
|
+
fjLog.debug('blockOne called', collection, query);
|
|
737
926
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
738
927
|
query._blocked = { $exists: 0 };
|
|
739
928
|
let update = {
|
|
@@ -750,7 +939,7 @@ export class Mongo extends Db {
|
|
|
750
939
|
await this._publishAndAudit('update', dbName, collection, obj);
|
|
751
940
|
return obj;
|
|
752
941
|
}, false, { operation: "blockOne", collection, query });
|
|
753
|
-
|
|
942
|
+
fjLog.debug('blockOne returns', ret);
|
|
754
943
|
return ret;
|
|
755
944
|
}
|
|
756
945
|
async unblockOne(collection, query) {
|
|
@@ -761,7 +950,7 @@ export class Mongo extends Db {
|
|
|
761
950
|
};
|
|
762
951
|
const dbName = this.db; // Capture db at operation start
|
|
763
952
|
query = this.replaceIds(query);
|
|
764
|
-
|
|
953
|
+
fjLog.debug('unblockOne called', collection, query);
|
|
765
954
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
766
955
|
query._blocked = { $exists: 1 };
|
|
767
956
|
let update = {
|
|
@@ -778,7 +967,7 @@ export class Mongo extends Db {
|
|
|
778
967
|
await this._publishAndAudit('update', dbName, collection, obj);
|
|
779
968
|
return obj;
|
|
780
969
|
}, false, { operation: "unblockOne", collection, query });
|
|
781
|
-
|
|
970
|
+
fjLog.debug('unblockOne returns', ret);
|
|
782
971
|
return ret;
|
|
783
972
|
}
|
|
784
973
|
async hardDeleteOne(collection, query) {
|
|
@@ -793,7 +982,7 @@ export class Mongo extends Db {
|
|
|
793
982
|
returnDocument: "after",
|
|
794
983
|
...this._sessionOpt()
|
|
795
984
|
};
|
|
796
|
-
|
|
985
|
+
fjLog.debug('hardDeleteOne called', collection, query);
|
|
797
986
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
798
987
|
let obj = await conn.findOneAndDelete(query, opts);
|
|
799
988
|
if (obj) {
|
|
@@ -801,18 +990,18 @@ export class Mongo extends Db {
|
|
|
801
990
|
}
|
|
802
991
|
return obj;
|
|
803
992
|
}, false, { operation: "hardDeleteOne", collection, query });
|
|
804
|
-
|
|
993
|
+
fjLog.debug('hardDeleteOne returns', ret);
|
|
805
994
|
return ret;
|
|
806
995
|
}
|
|
807
996
|
async delete(collection, query) {
|
|
808
997
|
assert(collection);
|
|
809
998
|
assert(query);
|
|
810
|
-
// if (this.syncSupport)
|
|
999
|
+
// if (this.syncSupport) fjLog.warn("delete does not increase _csq, avoit it.")
|
|
811
1000
|
const dbName = this.db; // Capture db at operation start
|
|
812
1001
|
query = this.replaceIds(query);
|
|
813
1002
|
if (!this.softdelete) {
|
|
814
1003
|
const opts = this._sessionOpt();
|
|
815
|
-
|
|
1004
|
+
fjLog.debug('delete called', collection, query);
|
|
816
1005
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
817
1006
|
let obj = await conn.deleteMany(query, opts);
|
|
818
1007
|
let resObj = {
|
|
@@ -822,7 +1011,7 @@ export class Mongo extends Db {
|
|
|
822
1011
|
await this._publishAndAudit('deleteMany', dbName, collection, resObj);
|
|
823
1012
|
return resObj;
|
|
824
1013
|
}, false, { operation: "delete", collection, query, softdelete: this.softdelete });
|
|
825
|
-
|
|
1014
|
+
fjLog.debug('delete returns', ret);
|
|
826
1015
|
return ret;
|
|
827
1016
|
}
|
|
828
1017
|
else {
|
|
@@ -832,7 +1021,7 @@ export class Mongo extends Db {
|
|
|
832
1021
|
...this._sessionOpt()
|
|
833
1022
|
};
|
|
834
1023
|
let date = new Date();
|
|
835
|
-
|
|
1024
|
+
fjLog.debug('delete called', collection, query);
|
|
836
1025
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
837
1026
|
let upd = {
|
|
838
1027
|
$set: { _deleted: date },
|
|
@@ -847,18 +1036,18 @@ export class Mongo extends Db {
|
|
|
847
1036
|
await this._publishAndAudit('deleteMany', dbName, collection, resObj);
|
|
848
1037
|
return resObj;
|
|
849
1038
|
}, false, { operation: "delete", collection, query, softdelete: this.softdelete });
|
|
850
|
-
|
|
1039
|
+
fjLog.debug('delete returns', ret);
|
|
851
1040
|
return ret;
|
|
852
1041
|
}
|
|
853
1042
|
}
|
|
854
1043
|
async hardDelete(collection, query) {
|
|
855
1044
|
assert(collection);
|
|
856
1045
|
assert(query);
|
|
857
|
-
// if (this.syncSupport)
|
|
1046
|
+
// if (this.syncSupport) fjLog.warn("hardDelete does not increase _csq, avoit it.")
|
|
858
1047
|
const dbName = this.db; // Capture db at operation start
|
|
859
1048
|
query = this.replaceIds(query);
|
|
860
1049
|
const opts = this._sessionOpt();
|
|
861
|
-
|
|
1050
|
+
fjLog.debug('hardDelete called', collection, query);
|
|
862
1051
|
let ret = await this.executeTransactionally(collection, async (conn) => {
|
|
863
1052
|
let obj = await conn.deleteMany(query, opts);
|
|
864
1053
|
let resObj = {
|
|
@@ -868,12 +1057,12 @@ export class Mongo extends Db {
|
|
|
868
1057
|
await this._publishAndAudit('deleteMany', dbName, collection, resObj);
|
|
869
1058
|
return resObj;
|
|
870
1059
|
}, false, { operation: "hardDelete", collection, query, softdelete: this.softdelete });
|
|
871
|
-
|
|
1060
|
+
fjLog.debug('hardDelete returns', ret);
|
|
872
1061
|
return ret;
|
|
873
1062
|
}
|
|
874
1063
|
async testHash(collection, query, field, unhashedValue) {
|
|
875
1064
|
let _field;
|
|
876
|
-
|
|
1065
|
+
fjLog.debug('testHash called', collection, query, field, unhashedValue);
|
|
877
1066
|
if (typeof field === "object") {
|
|
878
1067
|
if (Object.keys(field).length === 1)
|
|
879
1068
|
[_field, unhashedValue] = Object.entries(field)[0];
|
|
@@ -888,11 +1077,11 @@ export class Mongo extends Db {
|
|
|
888
1077
|
let conn = await this.connect();
|
|
889
1078
|
let obj = await conn.db(dbName).collection(collection).findOne(query, { projection: { [_field]: 1 }, ...this._sessionOpt() });
|
|
890
1079
|
if (!obj || !obj[_field]) {
|
|
891
|
-
|
|
1080
|
+
fjLog.debug('testHash returns false', obj);
|
|
892
1081
|
return false;
|
|
893
1082
|
}
|
|
894
1083
|
let res = await bcrypt.compare(unhashedValue, obj[_field].hash);
|
|
895
|
-
|
|
1084
|
+
fjLog.debug('testHash returns', res);
|
|
896
1085
|
return res;
|
|
897
1086
|
}
|
|
898
1087
|
async aggregate(collection, pipeline, opts = {
|
|
@@ -900,7 +1089,7 @@ export class Mongo extends Db {
|
|
|
900
1089
|
}) {
|
|
901
1090
|
assert(collection);
|
|
902
1091
|
assert(pipeline instanceof Array);
|
|
903
|
-
|
|
1092
|
+
fjLog.debug('aggregate called', collection, pipeline);
|
|
904
1093
|
pipeline = this.replaceIds(pipeline);
|
|
905
1094
|
if (this.session)
|
|
906
1095
|
opts.session = this.session;
|
|
@@ -908,7 +1097,7 @@ export class Mongo extends Db {
|
|
|
908
1097
|
let res = await conn.aggregate(pipeline, opts).toArray();
|
|
909
1098
|
return res;
|
|
910
1099
|
}, false, { operation: "aggregate", collection, pipeline, opts });
|
|
911
|
-
|
|
1100
|
+
fjLog.debug('aggregare returns', ret);
|
|
912
1101
|
return ret;
|
|
913
1102
|
}
|
|
914
1103
|
async isUnique(collection, field, value, id) {
|
|
@@ -916,7 +1105,7 @@ export class Mongo extends Db {
|
|
|
916
1105
|
assert(field);
|
|
917
1106
|
if (!value)
|
|
918
1107
|
return false;
|
|
919
|
-
|
|
1108
|
+
fjLog.debug('isUnique called', collection, field, value, id);
|
|
920
1109
|
let _id = id === null || id === void 0 ? void 0 : id.toString();
|
|
921
1110
|
let query = typeof value === "object" ? value : { [field]: value };
|
|
922
1111
|
query = this.replaceIds(query);
|
|
@@ -926,21 +1115,21 @@ export class Mongo extends Db {
|
|
|
926
1115
|
return res;
|
|
927
1116
|
}, false, { operation: "isUnique", collection, field, value, id });
|
|
928
1117
|
let ret = true;
|
|
929
|
-
|
|
930
|
-
|
|
1118
|
+
fjLog.debug(`isUnique query`, query);
|
|
1119
|
+
fjLog.debug(`isUnique matches`, matches);
|
|
931
1120
|
for (let match of matches || []) {
|
|
932
1121
|
if (match._id.toString() !== _id && !match._deleted) {
|
|
933
1122
|
ret = false;
|
|
934
1123
|
return false;
|
|
935
1124
|
}
|
|
936
1125
|
}
|
|
937
|
-
|
|
1126
|
+
fjLog.debug('isUnique returns', ret);
|
|
938
1127
|
return ret;
|
|
939
1128
|
}
|
|
940
1129
|
async collectFieldValues(collection, field, inArray = false, opts) {
|
|
941
1130
|
assert(collection);
|
|
942
1131
|
assert(field);
|
|
943
|
-
|
|
1132
|
+
fjLog.debug('collectFieldValues called', collection, field);
|
|
944
1133
|
let pipeline = [
|
|
945
1134
|
{ $group: { _id: '$' + field } },
|
|
946
1135
|
{ $sort: { _id: 1 } }
|
|
@@ -956,34 +1145,34 @@ export class Mongo extends Db {
|
|
|
956
1145
|
return res;
|
|
957
1146
|
}, false, { operation: "collectFieldValues", collection, field, inArray, pipeline, opts });
|
|
958
1147
|
let ret = res === null || res === void 0 ? void 0 : res.map((v) => v._id);
|
|
959
|
-
|
|
1148
|
+
fjLog.debug('collectFieldValues returns', ret);
|
|
960
1149
|
return ret;
|
|
961
1150
|
}
|
|
962
1151
|
async dropCollection(collection) {
|
|
963
1152
|
assert(collection);
|
|
964
|
-
|
|
1153
|
+
fjLog.debug('dropCollection called', this.auditCollections);
|
|
965
1154
|
const dbName = this.db; // Capture db at operation start
|
|
966
1155
|
let client = await this.connect();
|
|
967
1156
|
let existing = await client.db(dbName).collections();
|
|
968
1157
|
if (existing.map((c) => c.collectionName).includes(collection)) {
|
|
969
1158
|
await client.db(dbName).dropCollection(collection);
|
|
970
1159
|
}
|
|
971
|
-
|
|
1160
|
+
fjLog.debug('dropCollection returns');
|
|
972
1161
|
}
|
|
973
1162
|
async resetCollectionSync(collection) {
|
|
974
1163
|
assert(collection);
|
|
975
|
-
|
|
1164
|
+
fjLog.debug('resetCollectionSync called for', collection);
|
|
976
1165
|
const dbName = this.db; // Capture db at operation start
|
|
977
1166
|
let client = await this.connect();
|
|
978
1167
|
await client.db(dbName)
|
|
979
1168
|
.collection(SEQUENCES_COLLECTION)
|
|
980
1169
|
.findOneAndDelete({ collection });
|
|
981
|
-
|
|
1170
|
+
fjLog.debug(`resetCollectionSync for ${collection} returns`);
|
|
982
1171
|
}
|
|
983
1172
|
async dropCollections(collections) {
|
|
984
1173
|
assert(collections);
|
|
985
1174
|
assert(collections instanceof Array);
|
|
986
|
-
|
|
1175
|
+
fjLog.debug('dropCollections called', this.auditCollections);
|
|
987
1176
|
const dbName = this.db; // Capture db at operation start
|
|
988
1177
|
let client = await this.connect();
|
|
989
1178
|
let existing = await client.db(dbName).collections();
|
|
@@ -992,12 +1181,12 @@ export class Mongo extends Db {
|
|
|
992
1181
|
await client.db(dbName).dropCollection(collection);
|
|
993
1182
|
}
|
|
994
1183
|
}
|
|
995
|
-
|
|
1184
|
+
fjLog.debug('dropCollections returns');
|
|
996
1185
|
}
|
|
997
1186
|
async createCollections(collections) {
|
|
998
1187
|
assert(collections);
|
|
999
1188
|
assert(collections instanceof Array);
|
|
1000
|
-
|
|
1189
|
+
fjLog.debug('createCollections called', this.auditCollections);
|
|
1001
1190
|
const dbName = this.db; // Capture db at operation start
|
|
1002
1191
|
let client = await this.connect();
|
|
1003
1192
|
let existing = await this.getCollections();
|
|
@@ -1006,22 +1195,22 @@ export class Mongo extends Db {
|
|
|
1006
1195
|
await client.db(dbName).createCollection(collection);
|
|
1007
1196
|
}
|
|
1008
1197
|
}
|
|
1009
|
-
|
|
1198
|
+
fjLog.debug('createCollections returns');
|
|
1010
1199
|
}
|
|
1011
1200
|
async createCollection(collection) {
|
|
1012
1201
|
assert(collection);
|
|
1013
|
-
|
|
1202
|
+
fjLog.debug('createCollection called', collection);
|
|
1014
1203
|
const dbName = this.db; // Capture db at operation start
|
|
1015
1204
|
let client = await this.connect();
|
|
1016
1205
|
let existing = await this.getCollections();
|
|
1017
1206
|
if (!existing.includes(collection)) {
|
|
1018
1207
|
await client.db(dbName).createCollection(collection);
|
|
1019
1208
|
}
|
|
1020
|
-
|
|
1209
|
+
fjLog.debug('createCollection returns');
|
|
1021
1210
|
}
|
|
1022
1211
|
async dbLogPurge(collection, _id) {
|
|
1023
1212
|
assert(collection);
|
|
1024
|
-
|
|
1213
|
+
fjLog.debug('dblogPurge called', collection, _id);
|
|
1025
1214
|
const dbName = this.db; // Capture db at operation start
|
|
1026
1215
|
let ret = await this.executeTransactionally(collection, async () => {
|
|
1027
1216
|
let cond = { db: dbName, collection, };
|
|
@@ -1037,12 +1226,12 @@ export class Mongo extends Db {
|
|
|
1037
1226
|
n: ret.deletedCount
|
|
1038
1227
|
};
|
|
1039
1228
|
}, false, { operation: "dbLogPurge", collection, _id });
|
|
1040
|
-
|
|
1229
|
+
fjLog.debug('dblogPurge returns', ret);
|
|
1041
1230
|
return ret;
|
|
1042
1231
|
}
|
|
1043
1232
|
async dbLogGet(collection, _id) {
|
|
1044
1233
|
assert(collection);
|
|
1045
|
-
|
|
1234
|
+
fjLog.debug('dblogGet called', collection, _id);
|
|
1046
1235
|
const dbName = this.db; // Capture db at operation start
|
|
1047
1236
|
let ret = await this.executeTransactionally(collection, async () => {
|
|
1048
1237
|
let cond = { db: dbName, collection };
|
|
@@ -1057,7 +1246,7 @@ export class Mongo extends Db {
|
|
|
1057
1246
|
.toArray();
|
|
1058
1247
|
return ret;
|
|
1059
1248
|
}, false, { operation: "dbLogGet", collection, _id });
|
|
1060
|
-
|
|
1249
|
+
fjLog.debug('dblogGet returns', ret);
|
|
1061
1250
|
return ret;
|
|
1062
1251
|
}
|
|
1063
1252
|
// HELPER FUNCTIONS
|
|
@@ -1121,32 +1310,32 @@ export class Mongo extends Db {
|
|
|
1121
1310
|
if (this.session) {
|
|
1122
1311
|
try {
|
|
1123
1312
|
if (await this.inTransaction()) {
|
|
1124
|
-
|
|
1313
|
+
fjLog.warn("Aborting active transaction during close");
|
|
1125
1314
|
await this.session.abortTransaction();
|
|
1126
|
-
|
|
1315
|
+
fjLog.info("transaction aborted");
|
|
1127
1316
|
}
|
|
1128
1317
|
await this.session.endSession();
|
|
1129
|
-
|
|
1318
|
+
fjLog.info("session ended");
|
|
1130
1319
|
}
|
|
1131
1320
|
catch (err) {
|
|
1132
|
-
|
|
1321
|
+
fjLog.error(`Error ending session ${err.message}`);
|
|
1133
1322
|
}
|
|
1134
1323
|
}
|
|
1135
1324
|
// 2. Clean up event listeners
|
|
1136
1325
|
try {
|
|
1137
1326
|
this.emitter.removeAllListeners();
|
|
1138
|
-
|
|
1327
|
+
fjLog.debug("event listeners removed");
|
|
1139
1328
|
}
|
|
1140
1329
|
catch (err) {
|
|
1141
|
-
|
|
1330
|
+
fjLog.error(`Error removing event listeners ${err.message}`);
|
|
1142
1331
|
}
|
|
1143
1332
|
// 3. Close parent connection
|
|
1144
1333
|
try {
|
|
1145
1334
|
await super.close(force);
|
|
1146
|
-
|
|
1335
|
+
fjLog.info("connection closed");
|
|
1147
1336
|
}
|
|
1148
1337
|
catch (err) {
|
|
1149
|
-
|
|
1338
|
+
fjLog.debug(`close parent connection failed: ${err.message || err}`);
|
|
1150
1339
|
}
|
|
1151
1340
|
// 4. Clean up state
|
|
1152
1341
|
this.session = undefined;
|
|
@@ -1166,13 +1355,13 @@ export class Mongo extends Db {
|
|
|
1166
1355
|
let client = await this.connect();
|
|
1167
1356
|
if (!this.session) {
|
|
1168
1357
|
this.session = client.startSession();
|
|
1169
|
-
|
|
1358
|
+
fjLog.info("session started");
|
|
1170
1359
|
}
|
|
1171
1360
|
let session = this.session;
|
|
1172
1361
|
await session.withTransaction(async () => await funct(client, session));
|
|
1173
1362
|
if (!hadSession) {
|
|
1174
1363
|
session.endSession();
|
|
1175
|
-
|
|
1364
|
+
fjLog.info("session ended");
|
|
1176
1365
|
this.session = undefined;
|
|
1177
1366
|
}
|
|
1178
1367
|
return;
|
|
@@ -1181,7 +1370,7 @@ export class Mongo extends Db {
|
|
|
1181
1370
|
if (!hadSession && this.session) {
|
|
1182
1371
|
try {
|
|
1183
1372
|
await this.session.endSession();
|
|
1184
|
-
|
|
1373
|
+
fjLog.info("session ended after error");
|
|
1185
1374
|
}
|
|
1186
1375
|
catch { /* ignore cleanup errors */ }
|
|
1187
1376
|
this.session = undefined;
|
|
@@ -1196,24 +1385,24 @@ export class Mongo extends Db {
|
|
|
1196
1385
|
try {
|
|
1197
1386
|
if (!this.session) {
|
|
1198
1387
|
this.session = client.startSession(TRANSACTION_OPTIONS);
|
|
1199
|
-
|
|
1388
|
+
fjLog.info("session started");
|
|
1200
1389
|
}
|
|
1201
1390
|
if (!await this.inTransaction()) {
|
|
1202
1391
|
await this.session.startTransaction();
|
|
1203
|
-
|
|
1392
|
+
fjLog.info("transaction started");
|
|
1204
1393
|
}
|
|
1205
1394
|
}
|
|
1206
1395
|
catch (err) {
|
|
1207
|
-
|
|
1396
|
+
fjLog.error('startTransaction error', err);
|
|
1208
1397
|
try {
|
|
1209
1398
|
if (this.session) {
|
|
1210
1399
|
await this.session.endSession();
|
|
1211
|
-
|
|
1400
|
+
fjLog.info("session ended");
|
|
1212
1401
|
}
|
|
1213
1402
|
this.session = undefined;
|
|
1214
1403
|
}
|
|
1215
1404
|
catch (e) {
|
|
1216
|
-
|
|
1405
|
+
fjLog.error("startTransaction - error in endSession", e.message || e);
|
|
1217
1406
|
}
|
|
1218
1407
|
return;
|
|
1219
1408
|
}
|
|
@@ -1226,13 +1415,13 @@ export class Mongo extends Db {
|
|
|
1226
1415
|
return;
|
|
1227
1416
|
let session = this.session;
|
|
1228
1417
|
await session.commitTransaction();
|
|
1229
|
-
|
|
1418
|
+
fjLog.info("transaction committed");
|
|
1230
1419
|
session.endSession();
|
|
1231
1420
|
this.session = undefined;
|
|
1232
|
-
|
|
1421
|
+
fjLog.info("session ended");
|
|
1233
1422
|
}
|
|
1234
1423
|
catch (err) {
|
|
1235
|
-
|
|
1424
|
+
fjLog.error(`commitTransaction error ${err.message || err}`);
|
|
1236
1425
|
}
|
|
1237
1426
|
}
|
|
1238
1427
|
async abortTransaction() {
|
|
@@ -1243,13 +1432,13 @@ export class Mongo extends Db {
|
|
|
1243
1432
|
return;
|
|
1244
1433
|
let session = this.session;
|
|
1245
1434
|
await session.abortTransaction();
|
|
1246
|
-
|
|
1435
|
+
fjLog.info("transaction aborted");
|
|
1247
1436
|
await session.endSession();
|
|
1248
1437
|
this.session = undefined;
|
|
1249
|
-
|
|
1438
|
+
fjLog.info("session ended");
|
|
1250
1439
|
}
|
|
1251
1440
|
catch (err) {
|
|
1252
|
-
|
|
1441
|
+
fjLog.error(`abortTransaction error ${err.message || err}`);
|
|
1253
1442
|
}
|
|
1254
1443
|
}
|
|
1255
1444
|
async _try_once(useTransaction, f, collection, dbName) {
|
|
@@ -1274,7 +1463,7 @@ export class Mongo extends Db {
|
|
|
1274
1463
|
await this.abortTransaction();
|
|
1275
1464
|
}
|
|
1276
1465
|
catch (abortErr) {
|
|
1277
|
-
|
|
1466
|
+
fjLog.debug(`abort transaction failed: ${abortErr.message || abortErr}`);
|
|
1278
1467
|
}
|
|
1279
1468
|
throw err;
|
|
1280
1469
|
}
|
|
@@ -1289,13 +1478,13 @@ export class Mongo extends Db {
|
|
|
1289
1478
|
return await this._try_once(useTransaction, f, collection, dbName);
|
|
1290
1479
|
}
|
|
1291
1480
|
catch (err) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1481
|
+
fjLog.error(`Mongo command has failed for ${dbName}.${collection} - ${(this.session ? "ROLLBACK - " : "")} ${err.message || err}`);
|
|
1482
|
+
fjLog.error(debugObject);
|
|
1483
|
+
fjLog.debug(err);
|
|
1295
1484
|
let x = ((err === null || err === void 0 ? void 0 : err.message) || (err === null || err === void 0 ? void 0 : err.toString()) || "").toString();
|
|
1296
1485
|
// test for duplicate ID insert
|
|
1297
1486
|
if ((x === null || x === void 0 ? void 0 : x.match(/E11000/gi)) && debugObject.operation === "insert") {
|
|
1298
|
-
|
|
1487
|
+
fjLog.error("Duplicate ID insert - ignoring and returning inserted object");
|
|
1299
1488
|
return debugObject.insert;
|
|
1300
1489
|
}
|
|
1301
1490
|
let isRepeatable = x.match(/Topology is closed, please connect/i)
|
|
@@ -1306,21 +1495,21 @@ export class Mongo extends Db {
|
|
|
1306
1495
|
|| x.match(/Connection pool closed/i);
|
|
1307
1496
|
if (isRepeatable) {
|
|
1308
1497
|
try {
|
|
1309
|
-
|
|
1498
|
+
fjLog.error("Trying to reopen connection and repeat as");
|
|
1310
1499
|
await this.close();
|
|
1311
1500
|
// a single retry
|
|
1312
1501
|
await super.connect();
|
|
1313
1502
|
let ret = await this._try_once(useTransaction, f, collection, dbName);
|
|
1314
|
-
|
|
1315
|
-
|
|
1503
|
+
fjLog.error("OK - Retry succeeded.");
|
|
1504
|
+
fjLog.error("");
|
|
1316
1505
|
return ret;
|
|
1317
1506
|
}
|
|
1318
1507
|
catch (err2) {
|
|
1319
1508
|
/* intentional */
|
|
1320
1509
|
if (debugObject)
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1510
|
+
fjLog.error(debugObject);
|
|
1511
|
+
fjLog.error(`FAIL - Retry failed: ${err2.message || err2}`);
|
|
1512
|
+
fjLog.error("");
|
|
1324
1513
|
}
|
|
1325
1514
|
}
|
|
1326
1515
|
throw err;
|
|
@@ -1572,7 +1761,7 @@ export class Mongo extends Db {
|
|
|
1572
1761
|
return toPublish;
|
|
1573
1762
|
}
|
|
1574
1763
|
emit(event, what) {
|
|
1575
|
-
|
|
1764
|
+
fjLog.debug("emitting", event, what);
|
|
1576
1765
|
if (event === "publish")
|
|
1577
1766
|
this.emitter.emit(event, what);
|
|
1578
1767
|
if (event === "publishRev")
|
|
@@ -1606,11 +1795,11 @@ export class Mongo extends Db {
|
|
|
1606
1795
|
auditRecord.user = user;
|
|
1607
1796
|
if (audit)
|
|
1608
1797
|
auditRecord.audit = audit;
|
|
1609
|
-
|
|
1798
|
+
fjLog.trace('AUDITING', auditRecord);
|
|
1610
1799
|
let ret = await client.db(db)
|
|
1611
1800
|
.collection(this.auditCollectionName)
|
|
1612
1801
|
.insertOne(auditRecord, this._sessionOpt());
|
|
1613
|
-
|
|
1802
|
+
fjLog.debug('AUDITED', auditRecord, ret.insertedId);
|
|
1614
1803
|
}
|
|
1615
1804
|
_sessionOpt() {
|
|
1616
1805
|
return this.session ? { session: this.session } : {};
|