UNPKG

6.45 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10Object.defineProperty(exports, "__esModule", { value: true });
11const mongodb_1 = require("mongodb");
12const common_1 = require("../common");
13const _1 = require(".");
14/**
15 * Provides functionality to manage connection to a MongoDB database.
16 */
17class DatabaseConnector {
18 /**
19 * Constructs the `DatabaseConnector` object.
20 *
21 * @param reconnectTimeoutMillis Reconnect timeout in milliseconds
22 */
23 constructor(reconnectTimeoutMillis) {
24 this.reconnectTimeoutMillis =
25 reconnectTimeoutMillis != null
26 ? reconnectTimeoutMillis
27 : DatabaseConnector.DEFAULT_RECONNECT_TIMEOUT_MILLIS;
28 }
29 /**
30 * Connects to database.
31 *
32 * @param config Database configuration
33 */
34 connect(config) {
35 return __awaiter(this, void 0, void 0, function* () {
36 let uri, databaseName;
37 if (typeof config === 'string') {
38 uri = config;
39 databaseName = this.getDbName(uri);
40 }
41 else if (_1.isSeederDatabaseConfigObject(config)) {
42 uri = this.getDbConnectionUri(config);
43 databaseName = config.name;
44 }
45 else {
46 throw new Error('You have to pass connection URI or database config object');
47 }
48 return this.connectWithUri(uri, databaseName);
49 });
50 }
51 /**
52 * Connects to database using database connection URI.
53 *
54 * @param dbConnectionUri Database connection URI
55 * @param dbName Database name
56 */
57 connectWithUri(dbConnectionUri, dbName) {
58 return __awaiter(this, void 0, void 0, function* () {
59 common_1.log(`Connecting to ${this.maskUriCredentials(dbConnectionUri)}...`);
60 const startMillis = new Date().getTime();
61 let client;
62 do {
63 try {
64 client = yield mongodb_1.MongoClient.connect(dbConnectionUri, {
65 ignoreUndefined: true,
66 useNewUrlParser: true,
67 });
68 }
69 catch (err) {
70 if (_1.checkTimeout(startMillis, this.reconnectTimeoutMillis)) {
71 throw new Error(`Timeout ${this.reconnectTimeoutMillis}s expired while connecting to database due to: ${err.name}: ${err.message}`);
72 }
73 common_1.log(`${err.message}\nRetrying...`);
74 yield _1.sleep(DatabaseConnector.SLEEP_INTERVAL_MILLIS);
75 }
76 } while (!client);
77 common_1.log('Connection with database established.');
78 this.client = client;
79 const db = client.db(dbName);
80 return new _1.Database(db);
81 });
82 }
83 /**
84 * Closes connection with database.
85 */
86 close() {
87 return __awaiter(this, void 0, void 0, function* () {
88 common_1.log('Closing connection...');
89 if (!this.client || !this.client.isConnected()) {
90 return;
91 }
92 yield this.client.close(true);
93 });
94 }
95 /**
96 * Constructs database connection URI from database configuration object.
97 *
98 * @param param0 Database connection object
99 */
100 getDbConnectionUri({ protocol, host, port, name, username, password, options, }) {
101 const credentials = username
102 ? `${username}${password ? `:${password}` : ''}@`
103 : '';
104 const optsUriPart = options ? this.getOptionsUriPart(options) : '';
105 const portUriPart = protocol !== 'mongodb+srv' ? `:${port}` : '';
106 return `${protocol}://${credentials}${host}${portUriPart}/${name}${optsUriPart}`;
107 }
108 /**
109 * Constructs database connection options query string from database configuration object.
110 *
111 * @param options Database configuration object
112 */
113 getOptionsUriPart(options) {
114 return Object.keys(options).reduce((previousUri, currentKey) => {
115 let uriPartFirstChar;
116 if (previousUri == '') {
117 uriPartFirstChar = '?';
118 }
119 else {
120 uriPartFirstChar = '&';
121 }
122 return `${previousUri}${uriPartFirstChar}${currentKey}=${options[currentKey]}`;
123 }, '');
124 }
125 /**
126 * Detects database connection credentials and masks them, replacing with masked URI credentials token.
127 *
128 * @param uri Database connection URI
129 */
130 maskUriCredentials(uri) {
131 if (!uri.includes('@')) {
132 return uri;
133 }
134 const creds = uri.substring(uri.indexOf('://') + 3, uri.indexOf('@'));
135 return uri.replace(creds, DatabaseConnector.MASKED_URI_CREDENTIALS);
136 }
137 /**
138 * Extracts database name from database connection URI.
139 *
140 * @param dbConnectionUri Database connection URI
141 */
142 getDbName(dbConnectionUri) {
143 const url = dbConnectionUri.replace('mongodb://', '');
144 const parts = url.split('/');
145 if (parts.length === 1) {
146 // Database not given, return the default one
147 return DatabaseConnector.DEFAULT_DB_NAME;
148 }
149 const lastPart = parts[parts.length - 1];
150 const givenDbName = lastPart.split('?')[0];
151 return givenDbName ? givenDbName : DatabaseConnector.DEFAULT_DB_NAME;
152 }
153}
154/**
155 * Default database name.
156 */
157DatabaseConnector.DEFAULT_DB_NAME = 'admin';
158/**
159 * Default reconnect timeout in milliseconds.
160 */
161DatabaseConnector.DEFAULT_RECONNECT_TIMEOUT_MILLIS = 10000;
162/**
163 * Sleep interval in milliseconds.
164 */
165DatabaseConnector.SLEEP_INTERVAL_MILLIS = 500;
166/**
167 * Masked URI credentials token.
168 */
169DatabaseConnector.MASKED_URI_CREDENTIALS = '[secure]';
170exports.DatabaseConnector = DatabaseConnector;
171//# sourceMappingURL=database-connector.js.map
\No newline at end of file