Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for options parameter in connection URLs #551

Merged
merged 3 commits into from Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .README/USAGE.md
Expand Up @@ -13,6 +13,7 @@ Supported parameters:
|Name|Meaning|Default|
|---|---|---|
|`application_name`|[`application_name`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME)||
|`options`|[`options`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS)||
|`sslmode`|[`sslmode`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) (supported values: `disable`, `no-verify`, `require`)|`disable`|

Note that unless listed above, other [libpq parameters](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS) are not supported.
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -436,6 +436,7 @@ Supported parameters:
|Name|Meaning|Default|
|---|---|---|
|`application_name`|[`application_name`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME)||
|`options`|[`options`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS)||
|`sslmode`|[`sslmode`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) (supported values: `disable`, `no-verify`, `require`)|`disable`|

Note that unless listed above, other [libpq parameters](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS) are not supported.
Expand Down
1 change: 1 addition & 0 deletions src/factories/createPoolConfiguration.ts
Expand Up @@ -15,6 +15,7 @@ export const createPoolConfiguration = (
application_name: connectionOptions.applicationName,
database: connectionOptions.databaseName,
host: connectionOptions.host,
options: connectionOptions.options,
password: connectionOptions.password,
port: connectionOptions.port,
ssl: false,
Expand Down
23 changes: 23 additions & 0 deletions src/helpers/createIntegrationTests.ts
Expand Up @@ -1347,4 +1347,27 @@ export const createIntegrationTests = (
['foo'],
);
});

test('command line options are passed to the underlying connection', async (t) => {
const options = encodeURIComponent('-c search_path=test_schema');
const pool = await createPool(t.context.dsn + '?options=' + options, {
PgPool,
});

await pool.query(sql.unsafe`
CREATE SCHEMA test_schema;
`);

// The table should be created within test_schema due to the search_path option.
await pool.query(sql.unsafe`
CREATE TABLE test_table (id SERIAL PRIMARY KEY);
`);

// The table we created will be the only one in the test_schema.
const tableName = await pool.oneFirst(sql.unsafe`
SELECT table_name FROM information_schema.tables WHERE table_schema = 'test_schema'
`);

t.is(tableName, 'test_table');
});
};
1 change: 1 addition & 0 deletions src/types.ts
Expand Up @@ -18,6 +18,7 @@ export type ConnectionOptions = {
applicationName?: string;
databaseName?: string;
host?: string;
options?: string;
password?: string;
port?: number;
sslMode?: 'disable' | 'no-verify' | 'require';
Expand Down
4 changes: 4 additions & 0 deletions src/utilities/parseDsn.test.ts
Expand Up @@ -31,6 +31,10 @@ test('postgresql://localhost/?&application_name=baz', testParse, {
applicationName: 'baz',
host: 'localhost',
});
test('postgresql://localhost/?options=-c%20search_path%3Dfoo', testParse, {
host: 'localhost',
options: '-c search_path=foo',
});
test('postgresql://fo%2Fo:b%2Far@localhost/ba%2Fz', testParse, {
databaseName: 'ba/z',
host: 'localhost',
Expand Down
5 changes: 5 additions & 0 deletions src/utilities/parseDsn.ts
Expand Up @@ -44,6 +44,7 @@ export const parseDsn = (dsn: string): ConnectionOptions => {

const {
application_name: applicationName,
options,
sslmode: sslMode,
...unsupportedOptions
} = Object.fromEntries(url.searchParams);
Expand All @@ -61,6 +62,10 @@ export const parseDsn = (dsn: string): ConnectionOptions => {
connectionOptions.applicationName = applicationName;
}

if (options) {
connectionOptions.options = options;
}

if (sslMode) {
connectionOptions.sslMode = sslMode as ConnectionOptions['sslMode'];
}
Expand Down
1 change: 1 addition & 0 deletions src/utilities/stringifyDsn.test.ts
Expand Up @@ -11,6 +11,7 @@ const dsns = [
'postgresql://foo:bar@localhost',
'postgresql://foo@localhost/bar',
'postgresql://foo@localhost/bar?application_name=foo',
'postgresql://foo@localhost/bar?options=-c%20search_path%3Dfoo',
'postgresql://foo@localhost/bar?sslmode=no-verify',
'postgresql://fo%2Fo:b%2Far@localhost/ba%2Fz',
];
Expand Down
6 changes: 6 additions & 0 deletions src/utilities/stringifyDsn.ts
Expand Up @@ -3,6 +3,7 @@ import { stringify } from 'node:querystring';

type NamedParameters = {
application_name?: string;
options?: string;
sslmode?: string;
};

Expand All @@ -11,6 +12,7 @@ export const stringifyDsn = (connectionOptions: ConnectionOptions): string => {
applicationName,
databaseName,
host,
options,
password,
port,
sslMode,
Expand Down Expand Up @@ -46,6 +48,10 @@ export const stringifyDsn = (connectionOptions: ConnectionOptions): string => {
namedParameters.application_name = applicationName;
}

if (options) {
namedParameters.options = options;
}

if (sslMode) {
namedParameters.sslmode = sslMode;
}
Expand Down
1 change: 1 addition & 0 deletions types/pg.d.ts
Expand Up @@ -21,6 +21,7 @@ declare module 'pg' {
idle_in_transaction_session_timeout?: number | undefined;
keepAlive?: boolean | undefined;
keepAliveInitialDelayMillis?: number | undefined;
options?: string | undefined;
parseInputDatesAsUTC?: boolean | undefined;
password?: string | (() => Promise<string> | string) | undefined;
port?: number | undefined;
Expand Down