parent
b6698ff89e
commit
1c905b1105
@ -1,5 +1,5 @@
|
||||
const mssql = require("mssql");
|
||||
const UrlPattern = require("url-pattern");
|
||||
const { ConnectionStringParser } = require("./utils");
|
||||
|
||||
class MSSQLConnector {
|
||||
#connected = false;
|
||||
@ -34,18 +34,17 @@ class MSSQLConnector {
|
||||
}
|
||||
|
||||
#parseDatabase() {
|
||||
const connectionPattern = new UrlPattern(
|
||||
"mssql\\://:username\\::password@*\\::port/:database*"
|
||||
);
|
||||
const match = connectionPattern.match(this.connectionString);
|
||||
this.database_id = match?.database;
|
||||
const connectionParser = new ConnectionStringParser({ scheme: "mssql" });
|
||||
const parsed = connectionParser.parse(this.connectionString);
|
||||
|
||||
this.database_id = parsed?.endpoint;
|
||||
this.connectionConfig = {
|
||||
...this.connectionConfig,
|
||||
user: match?.username,
|
||||
password: match?.password,
|
||||
database: match?.database,
|
||||
server: match?._[0],
|
||||
port: match?.port ? Number(match.port) : null,
|
||||
user: parsed?.username,
|
||||
password: parsed?.password,
|
||||
database: parsed?.endpoint,
|
||||
server: parsed?.hosts[0]?.host,
|
||||
port: parsed?.hosts[0]?.port,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const mysql = require("mysql2/promise");
|
||||
const UrlPattern = require("url-pattern");
|
||||
const { ConnectionStringParser } = require("./utils");
|
||||
|
||||
class MySQLConnector {
|
||||
#connected = false;
|
||||
@ -15,9 +15,9 @@ class MySQLConnector {
|
||||
}
|
||||
|
||||
#parseDatabase() {
|
||||
const connectionPattern = new UrlPattern("mysql\\://*@*/:database*");
|
||||
const match = connectionPattern.match(this.connectionString);
|
||||
return match?.database;
|
||||
const connectionParser = new ConnectionStringParser({ scheme: "mysql" });
|
||||
const parsed = connectionParser.parse(this.connectionString);
|
||||
return parsed?.endpoint;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
|
||||
@ -0,0 +1,182 @@
|
||||
// Credit: https://github.com/sindilevich/connection-string-parser
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConnectionStringParserOptions
|
||||
* @property {'mssql' | 'mysql' | 'postgresql' | 'db'} [scheme] - The scheme of the connection string
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConnectionStringObject
|
||||
* @property {string} scheme - The scheme of the connection string eg: mongodb, mssql, mysql, postgresql, etc.
|
||||
* @property {string} username - The username of the connection string
|
||||
* @property {string} password - The password of the connection string
|
||||
* @property {{host: string, port: number}[]} hosts - The hosts of the connection string
|
||||
* @property {string} endpoint - The endpoint (database name) of the connection string
|
||||
* @property {Object} options - The options of the connection string
|
||||
*/
|
||||
class ConnectionStringParser {
|
||||
static DEFAULT_SCHEME = "db";
|
||||
|
||||
/**
|
||||
* @param {ConnectionStringParserOptions} options
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.scheme =
|
||||
(options && options.scheme) || ConnectionStringParser.DEFAULT_SCHEME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a connection string object and returns a URI string of the form:
|
||||
*
|
||||
* scheme://[username[:password]@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[endpoint]][?options]
|
||||
* @param {Object} connectionStringObject The object that describes connection string parameters
|
||||
*/
|
||||
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);
|
||||
// Allow empty passwords
|
||||
if (connectionStringObject.password) {
|
||||
uri += ":" + encodeURIComponent(connectionStringObject.password);
|
||||
}
|
||||
uri += "@";
|
||||
}
|
||||
uri += this._formatAddress(connectionStringObject);
|
||||
// Only put a slash when there is an endpoint
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where scheme and hosts will always be present. Other fields will only be present in the result if they were
|
||||
* present in the input.
|
||||
* @param {string} uri The connection string URI
|
||||
* @returns {ConnectionStringObject} The connection string object
|
||||
*/
|
||||
parse(uri) {
|
||||
const connectionStringParser = new RegExp(
|
||||
"^\\s*" + // Optional whitespace padding at the beginning of the line
|
||||
"([^:]+)://" + // Scheme (Group 1)
|
||||
"(?:([^:@,/?=&]+)(?::([^:@,/?=&]+))?@)?" + // User (Group 2) and Password (Group 3)
|
||||
"([^@/?=&]+)" + // Host address(es) (Group 4)
|
||||
"(?:/([^:@,/?=&]+)?)?" + // Endpoint (Group 5)
|
||||
"(?:\\?([^:@,/?]+)?)?" + // Options (Group 6)
|
||||
"\\s*$", // Optional whitespace padding at the end of the line
|
||||
"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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the address portion of a connection string
|
||||
* @param {Object} connectionStringObject The object that describes connection string parameters
|
||||
*/
|
||||
_formatAddress(connectionStringObject) {
|
||||
return connectionStringObject.hosts
|
||||
.map(
|
||||
(address) =>
|
||||
encodeURIComponent(address.host) +
|
||||
(address.port
|
||||
? ":" + encodeURIComponent(address.port.toString(10))
|
||||
: "")
|
||||
)
|
||||
.join(",");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an address
|
||||
* @param {string} addresses The address(es) to process
|
||||
*/
|
||||
_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) };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses options
|
||||
* @param {string} options The options to process
|
||||
*/
|
||||
_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 };
|
||||
Loading…
Reference in New Issue
Block a user