mirror of
https://github.com/swc-project/swc.git
synced 2024-12-26 07:02:28 +03:00
208 lines
5.2 KiB
TypeScript
208 lines
5.2 KiB
TypeScript
// Loaded from https://raw.githubusercontent.com/deno-postgres/deno-postgres/master/connection/connection_params.ts
|
|
|
|
|
|
import { parseDsn } from "../utils.ts";
|
|
|
|
/**
|
|
* The connection string must match the following URI structure
|
|
*
|
|
* ```ts
|
|
* const connection = "postgres://user:password@hostname:port/database?application_name=application_name";
|
|
* ```
|
|
*
|
|
* Password, port and application name are optional parameters
|
|
*/
|
|
export type ConnectionString = string;
|
|
|
|
/**
|
|
* This function retrieves the connection options from the environmental variables
|
|
* as they are, without any extra parsing
|
|
*
|
|
* It will throw if no env permission was provided on startup
|
|
*/
|
|
function getPgEnv(): ConnectionOptions {
|
|
return {
|
|
database: Deno.env.get("PGDATABASE"),
|
|
hostname: Deno.env.get("PGHOST"),
|
|
port: Deno.env.get("PGPORT"),
|
|
user: Deno.env.get("PGUSER"),
|
|
password: Deno.env.get("PGPASSWORD"),
|
|
applicationName: Deno.env.get("PGAPPNAME"),
|
|
};
|
|
}
|
|
|
|
export class ConnectionParamsError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = "ConnectionParamsError";
|
|
}
|
|
}
|
|
|
|
interface TLSOptions {
|
|
/**
|
|
* This will force the connection to run over TLS
|
|
* If the server doesn't support TLS, the connection will fail
|
|
*
|
|
* default: `false`
|
|
* */
|
|
enforce: boolean;
|
|
}
|
|
|
|
export interface ConnectionOptions {
|
|
applicationName?: string;
|
|
database?: string;
|
|
hostname?: string;
|
|
password?: string;
|
|
port?: string | number;
|
|
tls?: TLSOptions;
|
|
user?: string;
|
|
}
|
|
|
|
export interface ConnectionParams {
|
|
applicationName: string;
|
|
database: string;
|
|
hostname: string;
|
|
password?: string;
|
|
port: number;
|
|
tls: TLSOptions;
|
|
user: string;
|
|
}
|
|
|
|
function formatMissingParams(missingParams: string[]) {
|
|
return `Missing connection parameters: ${
|
|
missingParams.join(
|
|
", ",
|
|
)
|
|
}`;
|
|
}
|
|
|
|
/**
|
|
* This validates the options passed are defined and have a value other than null
|
|
* or empty string, it throws a connection error otherwise
|
|
*
|
|
* @param has_env_access This parameter will change the error message if set to true,
|
|
* telling the user to pass env permissions in order to read environmental variables
|
|
*/
|
|
function assertRequiredOptions(
|
|
options: ConnectionOptions,
|
|
requiredKeys: (keyof ConnectionOptions)[],
|
|
// deno-lint-ignore camelcase
|
|
has_env_access: boolean,
|
|
) {
|
|
const missingParams: (keyof ConnectionOptions)[] = [];
|
|
for (const key of requiredKeys) {
|
|
if (
|
|
options[key] === "" ||
|
|
options[key] === null ||
|
|
options[key] === undefined
|
|
) {
|
|
missingParams.push(key);
|
|
}
|
|
}
|
|
|
|
if (missingParams.length) {
|
|
// deno-lint-ignore camelcase
|
|
let missing_params_message = formatMissingParams(missingParams);
|
|
if (!has_env_access) {
|
|
missing_params_message +=
|
|
"\nConnection parameters can be read from environment variables only if Deno is run with env permission";
|
|
}
|
|
|
|
throw new ConnectionParamsError(missing_params_message);
|
|
}
|
|
}
|
|
|
|
function parseOptionsFromDsn(connString: string): ConnectionOptions {
|
|
const dsn = parseDsn(connString);
|
|
|
|
if (dsn.driver !== "postgres") {
|
|
throw new ConnectionParamsError(
|
|
`Supplied DSN has invalid driver: ${dsn.driver}.`,
|
|
);
|
|
}
|
|
|
|
return {
|
|
...dsn,
|
|
applicationName: dsn.params.application_name,
|
|
};
|
|
}
|
|
|
|
const DEFAULT_OPTIONS = {
|
|
applicationName: "deno_postgres",
|
|
hostname: "127.0.0.1",
|
|
port: "5432",
|
|
tls: {
|
|
enforce: false,
|
|
},
|
|
};
|
|
|
|
export function createParams(
|
|
params: string | ConnectionOptions = {},
|
|
): ConnectionParams {
|
|
if (typeof params === "string") {
|
|
params = parseOptionsFromDsn(params);
|
|
}
|
|
|
|
let pgEnv: ConnectionOptions = {};
|
|
// deno-lint-ignore camelcase
|
|
let has_env_access = true;
|
|
try {
|
|
pgEnv = getPgEnv();
|
|
} catch (e) {
|
|
if (e instanceof Deno.errors.PermissionDenied) {
|
|
has_env_access = false;
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
let port: string;
|
|
if (params.port) {
|
|
port = String(params.port);
|
|
} else if (pgEnv.port) {
|
|
port = String(pgEnv.port);
|
|
} else {
|
|
port = DEFAULT_OPTIONS.port;
|
|
}
|
|
|
|
// TODO
|
|
// Perhaps username should be taken from the PC user as a default?
|
|
// deno-lint-ignore camelcase
|
|
const connection_options = {
|
|
applicationName: params.applicationName ?? pgEnv.applicationName ??
|
|
DEFAULT_OPTIONS.applicationName,
|
|
database: params.database ?? pgEnv.database,
|
|
hostname: params.hostname ?? pgEnv.hostname ?? DEFAULT_OPTIONS.hostname,
|
|
password: params.password ?? pgEnv.password,
|
|
port,
|
|
tls: {
|
|
enforce: !!params?.tls?.enforce ?? DEFAULT_OPTIONS.tls.enforce,
|
|
},
|
|
user: params.user ?? pgEnv.user,
|
|
};
|
|
|
|
assertRequiredOptions(
|
|
connection_options,
|
|
["database", "hostname", "port", "user", "applicationName"],
|
|
has_env_access,
|
|
);
|
|
|
|
// By this point all required parameters have been checked out
|
|
// by the assert function
|
|
// deno-lint-ignore camelcase
|
|
const connection_parameters: ConnectionParams = {
|
|
...connection_options,
|
|
database: connection_options.database as string,
|
|
port: parseInt(connection_options.port, 10),
|
|
user: connection_options.user as string,
|
|
};
|
|
|
|
if (isNaN(connection_parameters.port)) {
|
|
throw new ConnectionParamsError(
|
|
`Invalid port ${connection_parameters.port}`,
|
|
);
|
|
}
|
|
|
|
return connection_parameters;
|
|
}
|