Skip to content

Commit de36d96

Browse files
kulshekharflovilmart
authored andcommitted
Allow configuration options for Postgres (#2873)
* Allow configuration options for Postgres * Fix the use of incorrect options object. * Refactor and test the postgres config parser. * Remove unnecessary try/catch * Remove unnecessary try/catch * Add blank line at the end of the test file * Rename file for consistency purposes
1 parent 7af3209 commit de36d96

File tree

5 files changed

+149
-3
lines changed

5 files changed

+149
-3
lines changed

spec/PostgresConfigParser.spec.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const parser = require('../src/Adapters/Storage/Postgres/PostgresConfigParser');
2+
3+
const queryParamTests = {
4+
'a=1&b=2': { a: '1', b: '2' },
5+
'a=abcd%20efgh&b=abcd%3Defgh': { a: 'abcd efgh', b: 'abcd=efgh' },
6+
'a=1&b&c=true': { a: '1', b: '', c: 'true' }
7+
}
8+
9+
describe('PostgresConfigParser.parseQueryParams', () => {
10+
it('creates a map from a query string', () => {
11+
12+
for (const key in queryParamTests) {
13+
const result = parser.parseQueryParams(key);
14+
15+
const testObj = queryParamTests[key];
16+
17+
expect(Object.keys(result).length)
18+
.toEqual(Object.keys(testObj).length);
19+
20+
for (const k in result) {
21+
expect(result[k]).toEqual(testObj[k]);
22+
}
23+
}
24+
25+
})
26+
});
27+
28+
const baseURI = 'postgres://username:password@localhost:5432/db-name'
29+
30+
const dbOptionsTest = {};
31+
dbOptionsTest[`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=10`] = {
32+
ssl: true,
33+
binary: true,
34+
application_name: 'app_name',
35+
fallback_application_name: 'f_app_name',
36+
poolSize: 10
37+
};
38+
dbOptionsTest[`${baseURI}?ssl=&binary=aa`] = {
39+
ssl: false,
40+
binary: false
41+
}
42+
43+
describe('PostgresConfigParser.getDatabaseOptionsFromURI', () => {
44+
it('creates a db options map from a query string', () => {
45+
46+
for (const key in dbOptionsTest) {
47+
const result = parser.getDatabaseOptionsFromURI(key);
48+
49+
const testObj = dbOptionsTest[key];
50+
51+
for (const k in testObj) {
52+
expect(result[k]).toEqual(testObj[k]);
53+
}
54+
}
55+
56+
});
57+
58+
it('sets the poolSize to 10 if the it is not a number', () => {
59+
60+
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=sdf`);
61+
62+
expect(result.poolSize).toEqual(10);
63+
64+
});
65+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const pgp = require('pg-promise')();
2+
const parser = require('./PostgresConfigParser');
3+
4+
export function createClient(uri, databaseOptions) {
5+
let client;
6+
let dbOptions = {};
7+
databaseOptions = databaseOptions || {};
8+
9+
if (uri) {
10+
dbOptions = parser.getDatabaseOptionsFromURI(uri);
11+
}
12+
13+
for (const key in databaseOptions) {
14+
dbOptions[key] = databaseOptions[key];
15+
}
16+
17+
client = pgp(dbOptions);
18+
19+
if (dbOptions.pgOptions) {
20+
for (const key in dbOptions.pgOptions) {
21+
client.pg.defaults[key] = dbOptions.pgOptions[key];
22+
}
23+
}
24+
25+
return client;
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const url = require('url');
2+
3+
function getDatabaseOptionsFromURI(uri) {
4+
const databaseOptions = {};
5+
6+
const parsedURI = url.parse(uri);
7+
const queryParams = parseQueryParams(parsedURI.query);
8+
const authParts = parsedURI.auth ? parsedURI.auth.split(':') : [];
9+
10+
databaseOptions.host = parsedURI.hostname || 'localhost';
11+
databaseOptions.port = parsedURI.port ? parseInt(parsedURI.port) : 5432;
12+
databaseOptions.database = parsedURI.pathname
13+
? parsedURI.pathname.substr(1)
14+
: undefined;
15+
16+
databaseOptions.user = authParts.length > 0 ? authParts[0] : '';
17+
databaseOptions.password = authParts.length > 1 ? authParts[1] : '';
18+
19+
databaseOptions.ssl =
20+
queryParams.ssl && queryParams.ssl.toLowerCase() === 'true' ? true : false;
21+
databaseOptions.binary =
22+
queryParams.binary && queryParams.binary.toLowerCase() === 'true' ? true : false;
23+
24+
databaseOptions.client_encoding = queryParams.client_encoding;
25+
databaseOptions.application_name = queryParams.application_name;
26+
databaseOptions.fallback_application_name = queryParams.fallback_application_name;
27+
28+
if (queryParams.poolSize) {
29+
databaseOptions.poolSize = parseInt(queryParams.poolSize) || 10;
30+
}
31+
32+
return databaseOptions;
33+
}
34+
35+
function parseQueryParams(queryString) {
36+
queryString = queryString || '';
37+
38+
return queryString
39+
.split('&')
40+
.reduce((p, c) => {
41+
const parts = c.split('=');
42+
p[decodeURIComponent(parts[0])] =
43+
parts.length > 1
44+
? decodeURIComponent(parts.slice(1).join('='))
45+
: '';
46+
return p;
47+
}, {});
48+
}
49+
50+
module.exports = {
51+
parseQueryParams: parseQueryParams,
52+
getDatabaseOptionsFromURI: getDatabaseOptionsFromURI
53+
};

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const pgp = require('pg-promise')();
1+
import { createClient } from './PostgresClient';
22

33
const PostgresRelationDoesNotExistError = '42P01';
44
const PostgresDuplicateRelationError = '42P07';
@@ -379,9 +379,10 @@ export class PostgresStorageAdapter {
379379
constructor({
380380
uri,
381381
collectionPrefix = '',
382+
databaseOptions
382383
}) {
383384
this._collectionPrefix = collectionPrefix;
384-
this._client = pgp(uri);
385+
this._client = createClient(uri, databaseOptions);
385386
}
386387

387388
_ensureSchemaCollectionExists() {

src/ParseServer.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ class ParseServer {
260260
case 'postgres:':
261261
return new PostgresStorageAdapter({
262262
uri: databaseURI,
263-
collectionPrefix
263+
collectionPrefix,
264+
databaseOptions
264265
});
265266
default:
266267
return new MongoStorageAdapter({

0 commit comments

Comments
 (0)