diff --git a/src/PublicAPI.ts b/src/PublicAPI.ts index 349cf42a..50574f3b 100644 --- a/src/PublicAPI.ts +++ b/src/PublicAPI.ts @@ -845,7 +845,7 @@ export default class PublicAPI extends Core { return this.follow(`${this[shortIDSymbol]}:${model}`); }) .then((request) => { - request.withTemplateParameters(optionsToQuery(options, this.getLink(`${this[shortIDSymbol]}:${model}`).href)); + request.withTemplateParameters(optionsToQuery(options, this.getLink(`${this[shortIDSymbol]}:${model}`).href, true)); return get(this[environmentSymbol], request); }) .then(([res, traversal]) => createList(res, this[environmentSymbol], traversal, `${this[shortIDSymbol]}:${model}`)); diff --git a/src/helper.ts b/src/helper.ts index ea12f9b6..85dbab6c 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -500,9 +500,10 @@ const modifier = { * * @param {filterOptions} options filter options * @param {string?} templateURL optional templateURL for validating inputs + * @param {boolean?} encode if true it will encode the parameter values (eg. to support text filter with ',' or '+') * @returns {object} translated querystring object */ -export function optionsToQuery(options: filterOptions, templateURL?: string): any { +export function optionsToQuery(options: filterOptions, templateURL?: string, encode: boolean = false): any { const out: any = {}; if (options) { @@ -540,7 +541,9 @@ export function optionsToQuery(options: filterOptions, templateURL?: string): an throw new Error('_fields array must contain only strings'); } out[key] = (>options[key]).join(','); - } else if (typeof options[key] === 'string' || typeof options[key] === 'number' || typeof options[key] === 'boolean') { + } else if (typeof options[key] === 'string') { + out[key] = encode ? encodeURIComponent(options[key]) : options[key]; + } else if (typeof options[key] === 'number' || typeof options[key] === 'boolean') { out[key] = options[key]; } else if (options[key] instanceof Date) { out[key] = (options[key]).toISOString(); @@ -556,6 +559,8 @@ export function optionsToQuery(options: filterOptions, templateURL?: string): an } if (options[key][searchKey] instanceof Date) { out[`${key}${modifier[searchKey]}`] = options[key][searchKey].toISOString(); + } else if (typeof options[key][searchKey] === 'string') { + out[`${key}${modifier[searchKey]}`] = encode ? encodeURIComponent(options[key][searchKey]) : options[key][searchKey]; } else { out[`${key}${modifier[searchKey]}`] = options[key][searchKey]; } @@ -569,7 +574,8 @@ export function optionsToQuery(options: filterOptions, templateURL?: string): an if (invalid.length > 0) { throw new Error(`${key}.${searchKey} array must contain only strings or numbers`); } - out[key] = options[key][searchKey].join(modifier[searchKey]); + const array = options[key][searchKey].map(value => encode ? encodeURIComponent(value) : value); + out[key] = array.join(modifier[searchKey]); break; default: throw new Error(`No handling of ${key}.${searchKey} filter supported.`); diff --git a/test/Core.test.js b/test/Core.test.js index d5276808..2e43a046 100644 --- a/test/Core.test.js +++ b/test/Core.test.js @@ -836,10 +836,14 @@ describe('optionsToQuery', () => { helper.optionsToQuery(obj).should.have.property('property', 'value'); }); it('should have exact filter with date', () => { - const date = new Date() + const date = new Date(); const obj = { property: { exact: date } }; helper.optionsToQuery(obj).should.have.property('property', date.toISOString()); }); + it('should have exact filter with number', () => { + const obj = { property: { exact: 0 } }; + helper.optionsToQuery(obj).should.have.property('property', 0); + }); it('should throw on array exact filter', () => { const throws = () => { helper.optionsToQuery({ property: { exact: [] } }); @@ -905,6 +909,18 @@ describe('optionsToQuery', () => { }; throws.should.throw(Error); }); + it('should encode \',\'', () => { + const obj = { property: 'hallo, michi' }; + helper.optionsToQuery(obj, null, true).should.have.property('property', 'hallo%2C%20michi'); + }); + it('should encode \',\', exact filter', () => { + const obj = { property: { exact: 'hallo, michi' } }; + helper.optionsToQuery(obj, null, true).should.have.property('property', 'hallo%2C%20michi'); + }); + it('should encode \',\', any filter', () => { + const obj = { property: { any: ['hallo, michi', 'hallo, berni'] } }; + helper.optionsToQuery(obj, null, true).should.have.property('property', 'hallo%2C%20michi,hallo%2C%20berni'); + }); describe('template validation', () => { it('valid, all types', () => { const obj = {