@pi-r/mongodb 0.11.2 → 0.12.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.
package/client/index.js CHANGED
@@ -1,20 +1,28 @@
1
1
  "use strict";
2
- exports.DB_SOURCE_TYPE = exports.DB_SOURCE_CLIENT = void 0;
3
- exports.setCredential = setCredential;
4
- exports.executeQuery = executeQuery;
5
- exports.executeBatchQuery = executeBatchQuery;
6
- exports.checkTimeout = checkTimeout;
7
- exports.initCollection = initCollection;
8
- exports.getFilterValue = getFilterValue;
9
- exports.getSortValue = getSortValue;
10
- const path = require("node:path");
11
- const mongodb = require("mongodb");
12
- const Db = require("@e-mc/db");
13
- const Request = require("@e-mc/request");
14
- const types_1 = require("@e-mc/types");
15
- const util_1 = require("@e-mc/db/util");
16
- const DbPool = require("@pi-r/mongodb/client/pool");
2
+
3
+ const path = require('node:path');
4
+ const mongodb = require('mongodb');
5
+ const Db = require('@e-mc/db');
6
+ const Request = require('@e-mc/request');
7
+ const { DB_TYPE, asFunction, coerceObject, errorMessage, isError, isObject, isPlainObject, isString } = require('@e-mc/types');
8
+ const { getBasicAuth, parseConnectionString, parseServerAuth } = require('@e-mc/db/util');
9
+ const DbPool = require('@pi-r/mongodb/client/pool');
17
10
  const POOL_STATE = {};
11
+ let SERVER_API;
12
+ if (process.env.MONGODB_SERVER_API) {
13
+ try {
14
+ const api = JSON.parse(process.env.MONGODB_SERVER_API);
15
+ if (api == '1') {
16
+ SERVER_API = Object.freeze({ version: mongodb.ServerApiVersion.v1 });
17
+ }
18
+ else if (isPlainObject(api) && api.version) {
19
+ SERVER_API = Object.freeze(api);
20
+ }
21
+ }
22
+ catch (err) {
23
+ Db.writeFail(["Unable to configure client", "mongodb"], err);
24
+ }
25
+ }
18
26
  function getCacheObject(item) {
19
27
  const credential = item.credential;
20
28
  return { uri: item.uri, options: item.options, uuidKey: credential?.uuidKey };
@@ -22,12 +30,16 @@ function getCacheObject(item) {
22
30
  function setCredential(item) {
23
31
  const credential = this.getCredential(item);
24
32
  const options = item.options ||= {};
33
+ if (SERVER_API) {
34
+ options.serverApi ||= SERVER_API;
35
+ }
25
36
  let uri = item.uri;
26
37
  if (credential) {
27
- let { protocol, server, hostname, port, username, password } = (0, util_1.parseServerAuth)(credential, 27017), { auth, authMechanism = 'DEFAULT', authSource, authMechanismProperties } = credential, authentication = '';
38
+ const { auth, authMechanism = 'DEFAULT' } = credential;
39
+ let { protocol, server, hostname, port, username, password } = parseServerAuth(credential, 27017), authSource = credential.authSource, authentication = '';
28
40
  if (authMechanism === 'GSSAPI') {
29
41
  const principal = auth?.username || username || options.auth?.username;
30
- if ((0, types_1.isString)(principal)) {
42
+ if (isString(principal)) {
31
43
  authentication = encodeURIComponent(principal) + '@';
32
44
  }
33
45
  }
@@ -36,13 +48,13 @@ function setCredential(item) {
36
48
  }
37
49
  if (!uri || !Db.isURL(uri)) {
38
50
  if (!options.auth) {
39
- authentication = (0, util_1.getBasicAuth)(username, password);
51
+ authentication = getBasicAuth(username, password);
40
52
  }
41
53
  if (!server && hostname) {
42
54
  server = hostname + ':' + (port || 27017);
43
55
  }
44
56
  if (!server) {
45
- throw (0, types_1.errorMessage)("mongodb", 'Not defined', 'server/hostname');
57
+ throw errorMessage("mongodb", 'Not defined', 'server/hostname');
46
58
  }
47
59
  uri = (protocol || 'mongodb:') + '//' + authentication + server;
48
60
  }
@@ -57,7 +69,7 @@ function setCredential(item) {
57
69
  case 'MONGODB-X509': {
58
70
  for (const attr of ['tlsCertificateKeyFile', 'tlsCAFile', 'tlsCRLFile']) {
59
71
  const value = credential[attr];
60
- if ((0, types_1.isString)(value)) {
72
+ if (isString(value)) {
61
73
  if (Db.isPath(value, true)) {
62
74
  const pathname = path.resolve(value);
63
75
  if (this.canRead(pathname, { ownPermissionOnly: true })) {
@@ -114,16 +126,14 @@ function setCredential(item) {
114
126
  uri += '&tls=true';
115
127
  }
116
128
  else {
117
- throw (0, types_1.errorMessage)("mongodb", 'Missing TLS/SSL credentials');
129
+ throw errorMessage("mongodb", 'Missing TLS/SSL credentials');
118
130
  }
119
131
  authSource ||= '$external';
120
132
  break;
121
133
  }
122
134
  case 'GSSAPI':
123
135
  case 'MONGODB-AWS': {
124
- if ((0, types_1.isObject)(authMechanismProperties)) {
125
- options.authMechanismProperties = authMechanismProperties;
126
- }
136
+ options.authMechanismProperties = credential.authMechanismProperties;
127
137
  authSource ||= '$external';
128
138
  break;
129
139
  }
@@ -148,15 +158,15 @@ function setCredential(item) {
148
158
  }
149
159
  }
150
160
  else if (!uri) {
151
- throw (0, types_1.errorMessage)("mongodb", "Invalid credentials", 'uri');
161
+ throw errorMessage("mongodb", "Invalid credentials", 'uri');
152
162
  }
153
163
  const usePool = item.usePool;
154
164
  if (!usePool) {
155
165
  return;
156
166
  }
157
167
  let username, password, pool;
158
- if ((0, types_1.isString)(usePool)) {
159
- username = options.auth?.username || item.uri && (0, util_1.parseConnectionString)(item.uri)?.username;
168
+ if (isString(usePool)) {
169
+ username = options.auth?.username || item.uri && parseConnectionString(item.uri)?.username;
160
170
  if (username) {
161
171
  [password, pool] = DbPool.validateKey(POOL_STATE, username, usePool);
162
172
  if (pool) {
@@ -219,7 +229,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
219
229
  return [];
220
230
  }
221
231
  let parallel, checkObject, connectOnce, errorQuery, sessionKey, outCacheMiss;
222
- if ((0, types_1.isPlainObject)(options)) {
232
+ if (isPlainObject(options)) {
223
233
  ({ parallel, checkObject, connectOnce, errorQuery, sessionKey, outCacheMiss } = options);
224
234
  }
225
235
  else {
@@ -278,15 +288,22 @@ async function executeBatchQuery(batch, options = '', outResult) {
278
288
  item.transactionState &= ~64;
279
289
  return client;
280
290
  };
291
+ const applyOptions = (item, out) => {
292
+ out.signal ||= this.signal;
293
+ if (typeof item.timeoutMS === 'number') {
294
+ out.timeoutMS = item.timeoutMS;
295
+ }
296
+ return out;
297
+ };
281
298
  if (this.host?.username) {
282
299
  this.applyCommand(...batch);
283
300
  }
284
301
  for (let i = 0; i < length; ++i) {
285
302
  const item = batch[i];
286
- const { source, name, table, id, aggregate, distinct, sort, cacheObjectKey, ignoreCache } = item;
303
+ const { source, name, table, id, aggregate, distinct, sort, ignoreCache } = item;
287
304
  let { query, update, streamRow, limit = 0 } = item;
288
305
  if (!table) {
289
- const error = (0, types_1.errorMessage)(source, "Missing database table");
306
+ const error = errorMessage(source, "Missing database table");
290
307
  ++mongoCache;
291
308
  if (this.handleFail(error, item, { errorQuery })) {
292
309
  if (!parallel) {
@@ -307,15 +324,15 @@ async function executeBatchQuery(batch, options = '', outResult) {
307
324
  const credential = mongoCredential || onceCredential || getCacheObject(item);
308
325
  const cacheValue = ignoreCache === undefined ? sessionKey : Array.isArray(ignoreCache) ? { sessionKey, exclusiveOf: ignoreCache } : { sessionKey, renewCache: ignoreCache === 0 };
309
326
  const coercing = this.hasCoerce("mongodb", 'options', credential.uuidKey);
310
- const targetObject = typeof checkObject === 'string' ? coercing && (0, types_1.asFunction)(checkObject) : checkObject;
327
+ const targetObject = typeof checkObject === 'string' ? coercing ? asFunction(checkObject) : null : checkObject;
311
328
  if (coercing && typeof streamRow === 'string') {
312
- streamRow = (0, types_1.asFunction)(streamRow);
329
+ streamRow = asFunction(streamRow);
313
330
  }
314
331
  let queryString = '', rows, pipeline;
315
- if (caching && ignoreCache !== true && (!targetObject || typeof cacheObjectKey === 'string') && !streamRow) {
332
+ if (caching && ignoreCache !== true && (!targetObject || typeof item.cacheObjectKey === 'string') && !streamRow) {
316
333
  const collection = item.client?.collection;
317
334
  const db = item.client?.db;
318
- queryString = (name || '') + '_' + table + (sort ? '_' + Db.asString(sort, true) : '') + '_' + (limit > 0 ? limit.toString() : '0') + (db ? Db.asString(db, true) : '') + (collection ? Db.asString(collection, true) : '') + (targetObject ? targetObject.toString() + cacheObjectKey : '');
335
+ queryString = (name || '') + '_' + table + (item.withFields ? '_' + Db.asString(item.withFields, true) : '') + (sort ? '_' + Db.asString(sort, true) : '') + '_' + (limit > 0 ? limit.toString() : '0') + (db ? Db.asString(db, true) : '') + (collection ? Db.asString(collection, true) : '') + (targetObject ? targetObject.toString() + item.cacheObjectKey : '');
319
336
  }
320
337
  if (aggregate) {
321
338
  pipeline = Array.isArray(aggregate) ? aggregate : aggregate.pipeline;
@@ -368,13 +385,13 @@ async function executeBatchQuery(batch, options = '', outResult) {
368
385
  const instance = mongoClient || await getConnection(item, credential);
369
386
  const collection = await initCollection.call(this, instance, item);
370
387
  if (update && coercing) {
371
- (0, types_1.coerceObject)(update);
388
+ coerceObject(update);
372
389
  }
373
390
  if (Array.isArray(update)) {
374
391
  commandType = this.commandType.INSERT;
375
392
  const insertOptions = item.execute?.insert;
376
393
  if (insertOptions && coercing) {
377
- (0, types_1.coerceObject)(insertOptions);
394
+ coerceObject(insertOptions);
378
395
  }
379
396
  if (update.length === 1) {
380
397
  await collection.insertOne(update[0], insertOptions);
@@ -387,16 +404,16 @@ async function executeBatchQuery(batch, options = '', outResult) {
387
404
  let cursor;
388
405
  if (pipeline || query) {
389
406
  if (pipeline) {
390
- const aggregateOptions = (0, types_1.isPlainObject)(aggregate) ? aggregate.options : undefined;
407
+ const aggOptions = isPlainObject(aggregate) ? aggregate.options : undefined;
391
408
  if (coercing) {
392
409
  for (const doc of pipeline) {
393
- (0, types_1.coerceObject)(doc);
410
+ coerceObject(doc);
394
411
  }
395
- if (aggregateOptions) {
396
- (0, types_1.coerceObject)(aggregateOptions);
412
+ if (aggOptions) {
413
+ coerceObject(aggOptions);
397
414
  }
398
415
  }
399
- cursor = collection.aggregate(pipeline, aggregateOptions);
416
+ cursor = collection.aggregate(pipeline, applyOptions(item, aggOptions || {}));
400
417
  if (sort) {
401
418
  cursor.sort(getSortValue(sort, coercing)[0]);
402
419
  }
@@ -409,6 +426,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
409
426
  if (sort) {
410
427
  operation.sort = getSortValue(sort, coercing)[0];
411
428
  }
429
+ applyOptions(item, operation);
412
430
  if (limit === 1) {
413
431
  let document;
414
432
  if (update) {
@@ -424,25 +442,27 @@ async function executeBatchQuery(batch, options = '', outResult) {
424
442
  else {
425
443
  if (update && item.updateType === 1) {
426
444
  commandType = this.commandType.UPDATE;
427
- const updateOptions = item.execute?.update;
428
- if (updateOptions && coercing) {
429
- (0, types_1.coerceObject)(updateOptions);
430
- }
431
- await collection.updateMany(filter, update, updateOptions);
445
+ await collection.updateMany(filter, update, item.execute?.update);
432
446
  }
433
447
  cursor = collection.find(filter, operation);
434
448
  }
435
449
  }
436
450
  }
437
451
  else if (distinct) {
438
- const [a, b, c] = Array.isArray(distinct) ? distinct : [distinct];
439
- rows = await (b ? c ? collection.distinct(a, b, c) : collection.distinct(a, b) : collection.distinct(a));
452
+ let [a, b, c] = Array.isArray(distinct) ? distinct : [distinct];
453
+ if (typeof item.timeoutMS === 'number') {
454
+ (c ||= {}).timeoutMS = item.timeoutMS;
455
+ }
456
+ rows = await (c ? b ? collection.distinct(a, b, c) : collection.distinct(a, c) : b ? collection.distinct(a, b) : collection.distinct(a));
440
457
  }
441
458
  else if (!aggregate) {
442
- cursor = collection.find();
459
+ cursor = collection.find({}, applyOptions(item, {}));
443
460
  }
444
461
  if (cursor) {
445
462
  commandType = this.commandType.SELECT;
463
+ if (item.withFields) {
464
+ cursor.project(item.withFields);
465
+ }
446
466
  if (!pipeline) {
447
467
  if (sort) {
448
468
  cursor.sort(...getSortValue(sort, coercing));
@@ -463,7 +483,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
463
483
  if (err === false) {
464
484
  return;
465
485
  }
466
- if (err instanceof Error) {
486
+ if (isError(err)) {
467
487
  error = err;
468
488
  return;
469
489
  }
@@ -494,7 +514,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
494
514
  resolve(this.setQueryResult(source, DbPool.sanitize(mongoCredential || credential), queryString, rows, cacheValue));
495
515
  }
496
516
  else {
497
- throw (0, types_1.errorMessage)(source, "Missing database query");
517
+ throw errorMessage(source, "Missing database query");
498
518
  }
499
519
  }
500
520
  catch (err) {
@@ -520,7 +540,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
520
540
  parallel,
521
541
  disconnect() {
522
542
  for (const item of clients) {
523
- void item.close(true);
543
+ void item.close();
524
544
  }
525
545
  }
526
546
  }, outResult);
@@ -553,32 +573,39 @@ async function initCollection(target, item) {
553
573
  }
554
574
  function getFilterValue(query, coerce) {
555
575
  let value, options;
556
- if ((0, types_1.isObject)(query) && query.value && query.options) {
576
+ if (isObject(query) && query.value && query.options) {
557
577
  ({ value, options } = query);
558
578
  }
559
579
  else {
560
580
  value = query;
561
581
  }
562
582
  if (coerce) {
563
- (0, types_1.coerceObject)(value);
564
- if (options) {
565
- (0, types_1.coerceObject)(options);
566
- }
583
+ coerceObject(value);
567
584
  }
568
585
  return [value, options];
569
586
  }
570
587
  function getSortValue(sort, coerce) {
571
588
  let value, direction;
572
- if ((0, types_1.isObject)(sort) && sort.value && sort.direction) {
589
+ if (isObject(sort) && sort.value && sort.direction) {
573
590
  ({ value, direction } = sort);
574
591
  }
575
592
  else {
576
593
  value = sort;
577
594
  }
578
595
  if (coerce) {
579
- (0, types_1.coerceObject)(value);
596
+ coerceObject(value);
580
597
  }
581
598
  return [value, direction];
582
599
  }
583
- exports.DB_SOURCE_CLIENT = true;
584
- exports.DB_SOURCE_TYPE = types_1.DB_TYPE.NOSQL | types_1.DB_TYPE.DOCUMENT;
600
+ const DB_SOURCE_CLIENT = true;
601
+ const DB_SOURCE_TYPE = DB_TYPE.NOSQL | DB_TYPE.DOCUMENT;
602
+
603
+ exports.DB_SOURCE_CLIENT = DB_SOURCE_CLIENT;
604
+ exports.DB_SOURCE_TYPE = DB_SOURCE_TYPE;
605
+ exports.checkTimeout = checkTimeout;
606
+ exports.executeBatchQuery = executeBatchQuery;
607
+ exports.executeQuery = executeQuery;
608
+ exports.getFilterValue = getFilterValue;
609
+ exports.getSortValue = getSortValue;
610
+ exports.initCollection = initCollection;
611
+ exports.setCredential = setCredential;
package/client/pool.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
- const util_1 = require("@e-mc/db/util");
2
+
3
3
  const DbPool = require('@e-mc/db/pool');
4
4
  const POOL_ACTIVE = new WeakSet();
5
5
  class MongoDBPool extends DbPool {
6
- static CACHE_UNUSED = ['maxPoolSize', 'minPoolSize', 'connectTimeoutMS', 'socketTimeoutMS', 'maxConnecting', 'maxIdleTimeMS', 'waitQueueTimeoutMS', 'maxStalenessSeconds', 'localThresholdMS', 'serverSelectionTimeoutMS', 'heartbeatFrequencyMS', 'minHeartbeatFrequencyMS', 'timeoutMS', 'compressors', 'zlibCompressionLevel', 'srvMaxHosts', 'mongodbLogPath', 'mongodbLogComponentSeverities', 'mongodbLogMaxDocumentLength'];
6
+ static CACHE_UNUSED = ['maxPoolSize', 'minPoolSize', 'connectTimeoutMS', 'socketTimeoutMS', 'maxConnecting', 'maxIdleTimeMS', 'waitQueueTimeoutMS', 'maxStalenessSeconds', 'localThresholdMS', 'serverSelectionTimeoutMS', 'heartbeatFrequencyMS', 'minHeartbeatFrequencyMS', 'timeoutMS', 'compressors', 'zlibCompressionLevel', 'srvMaxHosts', 'serverMonitoringMode', 'mongodbLogPath', 'mongodbLogComponentSeverities', 'mongodbLogMaxDocumentLength'];
7
7
  static CACHE_IGNORE = ['pkFactory'];
8
8
  static asString(credential) {
9
9
  const { options, uri } = credential;
@@ -47,12 +47,7 @@ class MongoDBPool extends DbPool {
47
47
  if (this.closed) {
48
48
  return true;
49
49
  }
50
- const topology = this.client.topology;
51
- if (topology) {
52
- const name = Object.getOwnPropertySymbols(topology).find(sym => sym.toString() === 'Symbol(waitQueue)');
53
- return (0, util_1.checkEmpty)(name ? topology[name] : topology.waitQueue || topology.s.servers);
54
- }
55
- return false;
50
+ return this.client.topology?.waitQueue?.length === 0;
56
51
  }
57
52
  get closed() {
58
53
  const topology = this.client.topology;
@@ -62,4 +57,5 @@ class MongoDBPool extends DbPool {
62
57
  return this.client.s?.hasBeenClosed === true;
63
58
  }
64
59
  }
60
+
65
61
  module.exports = MongoDBPool;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/mongodb",
3
- "version": "0.11.2",
3
+ "version": "0.12.0",
4
4
  "description": "MongoDB client driver for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "types": "client/index.d.ts",
@@ -20,9 +20,9 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/pi-r#readme",
22
22
  "dependencies": {
23
- "@e-mc/db": "^0.13.9",
24
- "@e-mc/request": "^0.13.9",
25
- "@e-mc/types": "^0.13.9",
26
- "mongodb": "^6.21.0"
23
+ "@e-mc/db": "^0.14.0",
24
+ "@e-mc/request": "^0.14.0",
25
+ "@e-mc/types": "^0.14.0",
26
+ "mongodb": "^7.2.0"
27
27
  }
28
28
  }
package/types/index.d.ts CHANGED
@@ -24,7 +24,7 @@ export interface MongoDBAggregate {
24
24
  options?: AggregateOptions;
25
25
  }
26
26
 
27
- export interface MongoDBClientDBOptions {
27
+ export interface MongoDBClientDBOptions extends TimeoutAction {
28
28
  client?: {
29
29
  db?: DbOptions;
30
30
  collection?: CollectionOptions;
@@ -40,6 +40,7 @@ export interface MongoDBClientDBOptions {
40
40
  bulkWrite?: ClientBulkWriteModel[];
41
41
  aggregate?: MongoDBAggregate | Document[];
42
42
  sort?: Sort | string | MongoDBSortValue;
43
+ withFields?: Document;
43
44
  }
44
45
 
45
46
  export interface MongoDBFilterValue {
@@ -47,6 +48,10 @@ export interface MongoDBFilterValue {
47
48
  options?: CommandOperationOptions;
48
49
  }
49
50
 
51
+ export interface TimeoutAction {
52
+ timeoutMS?: number;
53
+ }
54
+
50
55
  export interface DbPoolCredential extends IdentifierAction {
51
56
  uri?: string;
52
57
  options?: MongoClientOptions;