Skip to content

Commit e4e1142

Browse files
authored
Merge pull request #3 from andrew-barnett/feat/multilevel-config
feat(multilevel-config): support multilevel config
2 parents db3f163 + 782b720 commit e4e1142

File tree

4 files changed

+136
-3
lines changed

4 files changed

+136
-3
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,10 @@ Parses a parameter string of the format key1=value1&key2=value2, optionally conv
3232
If the value types are to be converted, true and false are converted to booleans irrespective of case. Values are converted to numbers if they match the following regex ```/^[-+]?(\d+\.)?\d+(E[-+]?\d+)?$/i```.
3333

3434
If you need finer control of value conversions, leave parseValues at false and handle the conversions in your driver code.
35+
36+
If the driver supports multiple levels to the config object (like the MySQL driver), you can modify the `key` as follows:
37+
- `key1=value1&key2[subkey1]=value2` yields `{ key1: "value1", key2: { subkey1: "value2" } }`
38+
- `key1=value1&key2[subkey1][subsubkey1]=value2` yields `{ key1: "value1", key2: { subkey1: { subkey2: "value2" } } }`
39+
- `key1=value1&key2[]=value2` yields `{ key1: "value1", key2: [ "value2" ] }`
40+
- `key1=value1&key2[]=value2&key2[]=value3` yields `{ key1: "value1", key2: [ "value2", "value3" ] }`
41+
- `key1=value1&key2[0]=value2` yields `{ key1: "value1", key2: [ "value2" ] }`

index.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
var keyBreaker = /([^\[\]]+)|(\[\])/g,
2+
digitTest = /^\d+$/;
3+
14
function parseConnectionParams(paramstring, parseValues = false) {
25
const params = {};
36
const numberRegex = /^[-+]?(\d+\.)?\d+(E[-+]?\d+)?$/i;
@@ -13,9 +16,25 @@ function parseConnectionParams(paramstring, parseValues = false) {
1316
} :
1417
(value) => value;
1518

19+
// based on $.String.deparam: https://github.com/jupiterjs/jquerymx/blob/master/lang/string/deparam/deparam.js
1620
paramstring.split('&').map(s => {
1721
let [key, val] = s.split('=');
18-
params[key] = valuesPreprocessor(val);
22+
let current = params;
23+
let parts = key.match(keyBreaker);
24+
for(var i = 0; i < parts.length - 1; i++) {
25+
let part = parts[i];
26+
if(!current[part]) {
27+
// if what we are pointing to looks like an array
28+
current[part] = digitTest.test(parts[i+1]) || parts[i+1] == "[]" ? [] : {}
29+
}
30+
current = current[part];
31+
}
32+
let lastPart = parts[parts.length - 1];
33+
if(lastPart == "[]"){
34+
current.push(valuesPreprocessor(val));
35+
} else {
36+
current[lastPart] = valuesPreprocessor(val);
37+
}
1938
});
2039
}
2140

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "database-js-common",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "database-js common code",
55
"main": "index.js",
66
"scripts": {

test/index.test.js

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ const assert = require('assert');
33
describe('Test parseConnectionParams method', function () {
44
const parseConnectionParams = require('../.').parseConnectionParams;
55
const testedParamString = 'booleanTrue=true&booleanFalse=false&string=foo&integer=35&float=35.8';
6+
const testedSingleNestedObjectString = 'subkey[string]=foo&subkey[booleanTrue]=true&subkey[booleanFalse]=false&subkey[integer]=42&subkey[float]=98.6&array[0]=0&array[1]=98.6&array2[]=0&array2[]=98.6';
7+
const testedMultiNestedObjectString = 'subkey[subkey][string]=foo&subkey[subkey][booleanTrue]=true&subkey[subkey][booleanFalse]=false&subkey[subkey][integer]=42&subkey[subkey][float]=98.6&subkey[subkey][array][]=0&subkey[subkey][array][]=98.6&array[0][0]=0&array[0][1]=98.6&array[1][]=0&array[1][]=98.6';
68

79
describe('Test default not parsed values', function () {
810
const result = parseConnectionParams(testedParamString);
@@ -61,5 +63,110 @@ describe('Test parseConnectionParams method', function () {
6163
it('should be float', function () {
6264
assert.equal(result.float, 35.8)
6365
});
64-
})
66+
});
67+
68+
describe('Test parsing single-level nested objects', function () {
69+
const result = parseConnectionParams(testedSingleNestedObjectString, true);
70+
71+
it('should be parsed', function () {
72+
assert.ok(typeof result === 'object', 'result not parsed');
73+
});
74+
75+
it('should have object subkey', function () {
76+
assert.ok(typeof result.subkey === 'object', 'result subkey is not an object');
77+
});
78+
79+
it('subkey should be boolean true', function () {
80+
assert.equal(result.subkey.booleanTrue, true);
81+
});
82+
83+
it('subkey should be boolean false', function () {
84+
assert.equal(result.subkey.booleanFalse, false);
85+
});
86+
87+
it('subkey should be string', function () {
88+
assert.equal(result.subkey.string, 'foo');
89+
});
90+
91+
it('subkey should be integer', function () {
92+
assert.equal(result.subkey.integer, 42);
93+
});
94+
95+
it('subkey should be float', function () {
96+
assert.equal(result.subkey.float, 98.6);
97+
});
98+
99+
it('should have array subkey', function () {
100+
assert.ok(result.array.constructor === Array, 'result array is not an array');
101+
});
102+
103+
it('array length should be 2', function () {
104+
assert.equal(result.array.length, 2);
105+
});
106+
107+
it('array item should be integer', function () {
108+
assert.equal(result.array[0], 0);
109+
});
110+
111+
it('array item should be float', function () {
112+
assert.equal(result.array[1], 98.6);
113+
});
114+
115+
it('should have array2 subkey', function () {
116+
assert.ok(result.array2.constructor === Array, 'result array2 is not an array');
117+
});
118+
119+
it('array2 length should be 2', function () {
120+
assert.equal(result.array2.length, 2);
121+
});
122+
123+
it('array2 item should be integer', function () {
124+
assert.equal(result.array2[0], 0);
125+
});
126+
127+
it('array2 item should be float', function () {
128+
assert.equal(result.array2[1], 98.6);
129+
});
130+
});
131+
132+
describe('Test parsing multi-level nested objects', function () {
133+
const result = parseConnectionParams(testedMultiNestedObjectString, true);
134+
135+
it('should be parsed', function () {
136+
assert.ok(typeof result === 'object', 'result not parsed');
137+
});
138+
139+
it('should have object subkey', function () {
140+
assert.ok(typeof result.subkey === 'object', 'result subkey is not an object');
141+
});
142+
143+
it('should have object subkey object subkey', function () {
144+
assert.ok(typeof result.subkey.subkey === 'object', 'result subkey subkey is not an object');
145+
});
146+
147+
it('subkey should be boolean true', function () {
148+
assert.equal(result.subkey.subkey.booleanTrue, true);
149+
});
150+
151+
it('subkey should be boolean false', function () {
152+
assert.equal(result.subkey.subkey.booleanFalse, false);
153+
});
154+
155+
it('subkey should be string', function () {
156+
assert.equal(result.subkey.subkey.string, 'foo');
157+
});
158+
159+
it('subkey should be integer', function () {
160+
assert.equal(result.subkey.subkey.integer, 42);
161+
});
162+
163+
it('subkey should be float', function () {
164+
assert.equal(result.subkey.subkey.float, 98.6);
165+
});
166+
167+
it('subkey should be array', function () {
168+
assert.ok(result.subkey.subkey.array.constructor === Array, 'result subkey array is not an array');
169+
});
170+
});
171+
65172
});

0 commit comments

Comments
 (0)