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
This commit is contained in:
committed by
Florent Vilmart
parent
7af320932a
commit
de36d9640b
65
spec/PostgresConfigParser.spec.js
Normal file
65
spec/PostgresConfigParser.spec.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
const parser = require('../src/Adapters/Storage/Postgres/PostgresConfigParser');
|
||||||
|
|
||||||
|
const queryParamTests = {
|
||||||
|
'a=1&b=2': { a: '1', b: '2' },
|
||||||
|
'a=abcd%20efgh&b=abcd%3Defgh': { a: 'abcd efgh', b: 'abcd=efgh' },
|
||||||
|
'a=1&b&c=true': { a: '1', b: '', c: 'true' }
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('PostgresConfigParser.parseQueryParams', () => {
|
||||||
|
it('creates a map from a query string', () => {
|
||||||
|
|
||||||
|
for (const key in queryParamTests) {
|
||||||
|
const result = parser.parseQueryParams(key);
|
||||||
|
|
||||||
|
const testObj = queryParamTests[key];
|
||||||
|
|
||||||
|
expect(Object.keys(result).length)
|
||||||
|
.toEqual(Object.keys(testObj).length);
|
||||||
|
|
||||||
|
for (const k in result) {
|
||||||
|
expect(result[k]).toEqual(testObj[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const baseURI = 'postgres://username:password@localhost:5432/db-name'
|
||||||
|
|
||||||
|
const dbOptionsTest = {};
|
||||||
|
dbOptionsTest[`${baseURI}?ssl=true&binary=true&application_name=app_name&fallback_application_name=f_app_name&poolSize=10`] = {
|
||||||
|
ssl: true,
|
||||||
|
binary: true,
|
||||||
|
application_name: 'app_name',
|
||||||
|
fallback_application_name: 'f_app_name',
|
||||||
|
poolSize: 10
|
||||||
|
};
|
||||||
|
dbOptionsTest[`${baseURI}?ssl=&binary=aa`] = {
|
||||||
|
ssl: false,
|
||||||
|
binary: false
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('PostgresConfigParser.getDatabaseOptionsFromURI', () => {
|
||||||
|
it('creates a db options map from a query string', () => {
|
||||||
|
|
||||||
|
for (const key in dbOptionsTest) {
|
||||||
|
const result = parser.getDatabaseOptionsFromURI(key);
|
||||||
|
|
||||||
|
const testObj = dbOptionsTest[key];
|
||||||
|
|
||||||
|
for (const k in testObj) {
|
||||||
|
expect(result[k]).toEqual(testObj[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the poolSize to 10 if the it is not a number', () => {
|
||||||
|
|
||||||
|
const result = parser.getDatabaseOptionsFromURI(`${baseURI}?poolSize=sdf`);
|
||||||
|
|
||||||
|
expect(result.poolSize).toEqual(10);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
26
src/Adapters/Storage/Postgres/PostgresClient.js
Normal file
26
src/Adapters/Storage/Postgres/PostgresClient.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
const pgp = require('pg-promise')();
|
||||||
|
const parser = require('./PostgresConfigParser');
|
||||||
|
|
||||||
|
export function createClient(uri, databaseOptions) {
|
||||||
|
let client;
|
||||||
|
let dbOptions = {};
|
||||||
|
databaseOptions = databaseOptions || {};
|
||||||
|
|
||||||
|
if (uri) {
|
||||||
|
dbOptions = parser.getDatabaseOptionsFromURI(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in databaseOptions) {
|
||||||
|
dbOptions[key] = databaseOptions[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
client = pgp(dbOptions);
|
||||||
|
|
||||||
|
if (dbOptions.pgOptions) {
|
||||||
|
for (const key in dbOptions.pgOptions) {
|
||||||
|
client.pg.defaults[key] = dbOptions.pgOptions[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
53
src/Adapters/Storage/Postgres/PostgresConfigParser.js
Normal file
53
src/Adapters/Storage/Postgres/PostgresConfigParser.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function getDatabaseOptionsFromURI(uri) {
|
||||||
|
const databaseOptions = {};
|
||||||
|
|
||||||
|
const parsedURI = url.parse(uri);
|
||||||
|
const queryParams = parseQueryParams(parsedURI.query);
|
||||||
|
const authParts = parsedURI.auth ? parsedURI.auth.split(':') : [];
|
||||||
|
|
||||||
|
databaseOptions.host = parsedURI.hostname || 'localhost';
|
||||||
|
databaseOptions.port = parsedURI.port ? parseInt(parsedURI.port) : 5432;
|
||||||
|
databaseOptions.database = parsedURI.pathname
|
||||||
|
? parsedURI.pathname.substr(1)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
databaseOptions.user = authParts.length > 0 ? authParts[0] : '';
|
||||||
|
databaseOptions.password = authParts.length > 1 ? authParts[1] : '';
|
||||||
|
|
||||||
|
databaseOptions.ssl =
|
||||||
|
queryParams.ssl && queryParams.ssl.toLowerCase() === 'true' ? true : false;
|
||||||
|
databaseOptions.binary =
|
||||||
|
queryParams.binary && queryParams.binary.toLowerCase() === 'true' ? true : false;
|
||||||
|
|
||||||
|
databaseOptions.client_encoding = queryParams.client_encoding;
|
||||||
|
databaseOptions.application_name = queryParams.application_name;
|
||||||
|
databaseOptions.fallback_application_name = queryParams.fallback_application_name;
|
||||||
|
|
||||||
|
if (queryParams.poolSize) {
|
||||||
|
databaseOptions.poolSize = parseInt(queryParams.poolSize) || 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return databaseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseQueryParams(queryString) {
|
||||||
|
queryString = queryString || '';
|
||||||
|
|
||||||
|
return queryString
|
||||||
|
.split('&')
|
||||||
|
.reduce((p, c) => {
|
||||||
|
const parts = c.split('=');
|
||||||
|
p[decodeURIComponent(parts[0])] =
|
||||||
|
parts.length > 1
|
||||||
|
? decodeURIComponent(parts.slice(1).join('='))
|
||||||
|
: '';
|
||||||
|
return p;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parseQueryParams: parseQueryParams,
|
||||||
|
getDatabaseOptionsFromURI: getDatabaseOptionsFromURI
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const pgp = require('pg-promise')();
|
import { createClient } from './PostgresClient';
|
||||||
|
|
||||||
const PostgresRelationDoesNotExistError = '42P01';
|
const PostgresRelationDoesNotExistError = '42P01';
|
||||||
const PostgresDuplicateRelationError = '42P07';
|
const PostgresDuplicateRelationError = '42P07';
|
||||||
@@ -379,9 +379,10 @@ export class PostgresStorageAdapter {
|
|||||||
constructor({
|
constructor({
|
||||||
uri,
|
uri,
|
||||||
collectionPrefix = '',
|
collectionPrefix = '',
|
||||||
|
databaseOptions
|
||||||
}) {
|
}) {
|
||||||
this._collectionPrefix = collectionPrefix;
|
this._collectionPrefix = collectionPrefix;
|
||||||
this._client = pgp(uri);
|
this._client = createClient(uri, databaseOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureSchemaCollectionExists() {
|
_ensureSchemaCollectionExists() {
|
||||||
|
|||||||
@@ -260,7 +260,8 @@ class ParseServer {
|
|||||||
case 'postgres:':
|
case 'postgres:':
|
||||||
return new PostgresStorageAdapter({
|
return new PostgresStorageAdapter({
|
||||||
uri: databaseURI,
|
uri: databaseURI,
|
||||||
collectionPrefix
|
collectionPrefix,
|
||||||
|
databaseOptions
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
return new MongoStorageAdapter({
|
return new MongoStorageAdapter({
|
||||||
|
|||||||
Reference in New Issue
Block a user