Skip to content

Commit

Permalink
Rewrite and add proper tests
Browse files Browse the repository at this point in the history
  • Loading branch information
snewcomer committed Jan 9, 2022
1 parent d9582e0 commit 877fc19
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 27 deletions.
57 changes: 36 additions & 21 deletions lib/route-recognizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,32 +688,47 @@ class RouteRecognizer<THandler = string> {
}

generateQueryString(params: Params): string {
const pairs: string[] = [];
const keys: string[] = Object.keys(params);
keys.sort();
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = params[key];
if (value == null) {
continue;
const reducer = (obj: Params, parentPrefix: string | null = null) => (prev: string[], key: string) => {
const val = obj[key];
if (val === null || val === undefined) {
return prev;
}
let pair = encodeURIComponent(key);
if (isArray(value)) {
for (let j = 0; j < value.length; j++) {
const arrayPair = key + "[]" + "=" + encodeURIComponent(value[j]);
pairs.push(arrayPair);
}
} else {
pair += "=" + encodeURIComponent(value as string);
pairs.push(pair);

const prefix = parentPrefix ? `${parentPrefix}[${key}]` : key;

if (val == null || typeof val === 'function') {
prev.push(`${prefix}=`);
return prev;
}
}

if (isArray(val)) {
for (let j = 0; j < val.length; j++) {
// handle array query params. array format brackets. (Other options are indices a[0]=b&a[1]=c or repeat a=b&a=c)
if (['string', 'number', 'boolean'].includes(typeof val[j])) {
const arrayPair = key + "[]" + "=" + encodeURIComponent(val[j]);
prev.push(arrayPair);
} else {
prev.push(Object.keys(val[j] as Params).sort().reduce(reducer(val[j] as Params, prefix + `[${j}]`), []).join('&'));
}
}

if (pairs.length === 0) {
return "";
return prev;
} else if (['string', 'number', 'boolean'].includes(typeof val)) {
prev.push(`${prefix}=${encodeURIComponent(val as string)}`);
return prev;
}

prev.push(Object.keys(val as Params).sort().reduce(reducer(val as Params, parentPrefix ? prefix : `${prefix}=`), []).join('&'));
return prev;
};

const sortedKeys = Object.keys(params).sort();
// avoid appending unnecessary '?'
if (!sortedKeys.length || sortedKeys.every((k) => params[k] === undefined || params[k] === null)) {
return '';
}

return "?" + pairs.join("&");
return '?' + sortedKeys.reduce(reducer(params), []).join('&');
}

parseQueryString(queryString: string): QueryParams {
Expand Down
19 changes: 13 additions & 6 deletions tests/recognizer-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,7 @@ QUnit.test("Deserialize query param nested object", (assert: Assert) => {
router.add([{ path: "/foo/bar", handler }]);

const results = router.recognize("/foo/bar?filter=[user][name][$contains]=nick");
const p = results && results.queryParams;
assert.deepEqual(p, { filter: { user: { name: { $contains: 'scoot' } } } });
assert.deepEqual(results!.queryParams, { filter: { user: { name: { $contains: 'nick' } } } });
});

QUnit.test("Multiple `/` routes recognize", (assert: Assert) => {
Expand Down Expand Up @@ -1639,15 +1638,15 @@ QUnit.module("Route Generation", hooks => {
QUnit.test(
"Parsing and generation results into the same input string",
(assert: Assert) => {
const query = "filter%20data=date";
const query = "filter data=date";
assert.equal(
router.generateQueryString(router.parseQueryString(query)),
"?" + query
);
}
);

QUnit.only("Generation works with query params", (assert: Assert) => {
QUnit.test("Generation works with query params", (assert: Assert) => {
assert.equal(
router.generate("index", { queryParams: { filter: "date" } }),
"/?filter=date"
Expand Down Expand Up @@ -1732,8 +1731,16 @@ QUnit.module("Route Generation", hooks => {
"/?filter=date&sort=0"
);
assert.equal(
router.generate("index", { queryParams: { filter: { user: { name: { $contains: 'scoot' } } }, sort: 0 } }),
"/?filter=[user][name][$contains]=scoot"
router.generate("index", { queryParams: { filter: { age: 10, user: { name: { $contains: 'scoot' } } }, sort: 0 } }),
"/?filter=[age]=10&filter=[user][name][$contains]=scoot&sort=0"
);
assert.equal(
router.generate("index", { queryParams: { sort: 0, filter: { age: 0, user: { name: { $contains: 'scoot' } } } } }),
"/?filter=[age]=0&filter=[user][name][$contains]=scoot&sort=0"
);
assert.equal(
router.generate("index", { queryParams: { sort: 0, filter: { name: 'bike', children: [{ name: { $contains: 'scoot' } }] } }, sort: 0 }),
"/?filter=[children][0][name][$contains]=scoot&filter=[name]=bike&sort=0"
);
});

Expand Down

0 comments on commit 877fc19

Please sign in to comment.