|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectionStringParser { |
|
|
static DEFAULT_SCHEME = "db"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(options = {}) { |
|
|
this.scheme = |
|
|
(options && options.scheme) || ConnectionStringParser.DEFAULT_SCHEME; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
format(connectionStringObject) { |
|
|
if (!connectionStringObject) { |
|
|
return this.scheme + "://localhost"; |
|
|
} |
|
|
if ( |
|
|
this.scheme && |
|
|
connectionStringObject.scheme && |
|
|
this.scheme !== connectionStringObject.scheme |
|
|
) { |
|
|
throw new Error(`Scheme not supported: ${connectionStringObject.scheme}`); |
|
|
} |
|
|
|
|
|
let uri = |
|
|
(this.scheme || |
|
|
connectionStringObject.scheme || |
|
|
ConnectionStringParser.DEFAULT_SCHEME) + "://"; |
|
|
|
|
|
if (connectionStringObject.username) { |
|
|
uri += encodeURIComponent(connectionStringObject.username); |
|
|
|
|
|
if (connectionStringObject.password) { |
|
|
uri += ":" + encodeURIComponent(connectionStringObject.password); |
|
|
} |
|
|
uri += "@"; |
|
|
} |
|
|
uri += this._formatAddress(connectionStringObject); |
|
|
|
|
|
if (connectionStringObject.endpoint) { |
|
|
uri += "/" + encodeURIComponent(connectionStringObject.endpoint); |
|
|
} |
|
|
if ( |
|
|
connectionStringObject.options && |
|
|
Object.keys(connectionStringObject.options).length > 0 |
|
|
) { |
|
|
uri += |
|
|
"?" + |
|
|
Object.keys(connectionStringObject.options) |
|
|
.map( |
|
|
(option) => |
|
|
encodeURIComponent(option) + |
|
|
"=" + |
|
|
encodeURIComponent(connectionStringObject.options[option]) |
|
|
) |
|
|
.join("&"); |
|
|
} |
|
|
return uri; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parse(uri) { |
|
|
const connectionStringParser = new RegExp( |
|
|
"^\\s*" + |
|
|
"([^:]+)://" + |
|
|
"(?:([^:@,/?=&]+)(?::([^:@,/?=&]+))?@)?" + |
|
|
"([^@/?=&]+)" + |
|
|
"(?:/([^:@,/?=&]+)?)?" + |
|
|
"(?:\\?([^:@,/?]+)?)?" + |
|
|
"\\s*$", |
|
|
"gi" |
|
|
); |
|
|
const connectionStringObject = {}; |
|
|
|
|
|
if (!uri.includes("://")) { |
|
|
throw new Error(`No scheme found in URI ${uri}`); |
|
|
} |
|
|
|
|
|
const tokens = connectionStringParser.exec(uri); |
|
|
|
|
|
if (Array.isArray(tokens)) { |
|
|
connectionStringObject.scheme = tokens[1]; |
|
|
if (this.scheme && this.scheme !== connectionStringObject.scheme) { |
|
|
throw new Error(`URI must start with '${this.scheme}://'`); |
|
|
} |
|
|
connectionStringObject.username = tokens[2] |
|
|
? decodeURIComponent(tokens[2]) |
|
|
: tokens[2]; |
|
|
connectionStringObject.password = tokens[3] |
|
|
? decodeURIComponent(tokens[3]) |
|
|
: tokens[3]; |
|
|
connectionStringObject.hosts = this._parseAddress(tokens[4]); |
|
|
connectionStringObject.endpoint = tokens[5] |
|
|
? decodeURIComponent(tokens[5]) |
|
|
: tokens[5]; |
|
|
connectionStringObject.options = tokens[6] |
|
|
? this._parseOptions(tokens[6]) |
|
|
: tokens[6]; |
|
|
} |
|
|
return connectionStringObject; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_formatAddress(connectionStringObject) { |
|
|
return connectionStringObject.hosts |
|
|
.map( |
|
|
(address) => |
|
|
encodeURIComponent(address.host) + |
|
|
(address.port |
|
|
? ":" + encodeURIComponent(address.port.toString(10)) |
|
|
: "") |
|
|
) |
|
|
.join(","); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_parseAddress(addresses) { |
|
|
return addresses.split(",").map((address) => { |
|
|
const i = address.indexOf(":"); |
|
|
|
|
|
return i >= 0 |
|
|
? { |
|
|
host: decodeURIComponent(address.substring(0, i)), |
|
|
port: +address.substring(i + 1), |
|
|
} |
|
|
: { host: decodeURIComponent(address) }; |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_parseOptions(options) { |
|
|
const result = {}; |
|
|
|
|
|
options.split("&").forEach((option) => { |
|
|
const i = option.indexOf("="); |
|
|
|
|
|
if (i >= 0) { |
|
|
result[decodeURIComponent(option.substring(0, i))] = decodeURIComponent( |
|
|
option.substring(i + 1) |
|
|
); |
|
|
} |
|
|
}); |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = { ConnectionStringParser }; |
|
|
|