Skip to content

Commit 041a866

Browse files
authored
Merge pull request #6 from yapplabs/improvement/url-generation
appendToQueryParam
2 parents f5b5a1e + 36b9244 commit 041a866

File tree

3 files changed

+149
-14
lines changed

3 files changed

+149
-14
lines changed

addon/adapters/ember-data-utils-json-api.js

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import DS from 'ember-data';
22
import { camelize } from '@ember/string';
33
import { isEmpty } from '@ember/utils';
4+
import { appendToQueryParam } from 'ember-data-utils/utils/url';
5+
import { getOwner } from '@ember/application';
46

57
/**
6-
Class to set as your ApplicationAdapter. Extend it for each model
7-
you want to configure explicit filter and include params.
8-
8+
Class to set as your ApplicationAdapter. Extend it for each model
9+
you want to configure explicit filter and include params.
10+
911
```js
1012
// app/adapters/application.js
1113
import { EmberDataUtilsJSONAPIAdapter } from 'ember-data-utils';
@@ -26,20 +28,20 @@ import { isEmpty } from '@ember/utils';
2628
*/
2729
export default DS.JSONAPIAdapter.extend({
2830
/**
29-
List of query param keys that your resource supports filtering on.
30-
Extend your base class for specific models to declare.
31+
List of query param keys that your resource supports filtering on.
32+
Extend your base class for specific models to declare.
3133
@field {Array} supportedFilters
3234
*/
3335
supportedFilters: [], // eslint-disable-line ember/avoid-leaking-state-in-ember-objects
3436

3537
/**
3638
Array of includes to always include when querying a particular model.
37-
Extend your base class for specific models to declare.
38-
39+
Extend your base class for specific models to declare.
40+
3941
@field {Array} include
4042
*/
4143
include: [], // eslint-disable-line ember/avoid-leaking-state-in-ember-objects
42-
44+
4345
/**
4446
* @public
4547
* @method query
@@ -60,9 +62,9 @@ export default DS.JSONAPIAdapter.extend({
6062
* queryRecord and findRecord use buildQuery to add includes to
6163
* api calls. This override adds an adapters configured set of
6264
* default includes
63-
*
65+
*
6466
* @method buildQuery
65-
* @param {object} snapshot
67+
* @param {object} snapshot
6668
* @return {object} Mutated query object
6769
*/
6870
buildQuery(snapshot) {
@@ -77,20 +79,30 @@ export default DS.JSONAPIAdapter.extend({
7779
let combinedUniqueIncludes = [...new Set(existingIncludes.concat(include))];
7880

7981
query.include = combinedUniqueIncludes.join(',');
80-
82+
8183
return query;
8284
},
8385

86+
findHasMany(store, snapshot, url, relationship) {
87+
let adapter = this._adapterForRelationship(relationship.type);
88+
let updatedUrl = appendToQueryParam(url, 'include', adapter.include)
89+
return this._super(store, snapshot, updatedUrl, relationship);
90+
},
91+
92+
_adapterForRelationship(type) {
93+
return getOwner(this).lookup(`adapter:${type}`);
94+
},
95+
8496
/**
8597
* Mutate the `jsonApiQueryParams` object with pagination related keys from `rawQueryParams` object
86-
*
98+
*
8799
* Pagination related keys are `limit`, `since`, and `until`
88-
*
100+
*
89101
* @private
90102
* @method _applyPagination
91103
* @param {Object} jsonApiQueryParams Object of JSONAPI formated query params
92104
* @param {Object} rawQueryParams Original, unformated Object of query params
93-
* @return {Object} Mutated jsonApiQueryParams object with pagination params applied
105+
* @return {Object} Mutated jsonApiQueryParams object with pagination params applied
94106
*/
95107
_applyPagination(jsonApiQueryParams, rawQueryParams) {
96108
['limit', 'since', 'until'].forEach(key => {

addon/utils/url.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { isArray } from '@ember/array';
2+
import { isEmpty } from '@ember/utils';
3+
4+
/**
5+
* @function appendToQueryParam
6+
* @export named
7+
* @param {string} url
8+
*/
9+
export function appendToQueryParam(urlString, param, newValue) {
10+
let url = new URL(urlString);
11+
if (isEmpty(newValue)) {
12+
return url.href;
13+
}
14+
15+
let existingParamValue = url.searchParams.get(param);
16+
let existingValues = existingParamValue ? existingParamValue.split(',') : [];
17+
newValue = isArray(newValue) ? newValue : newValue.split(',');
18+
// Merge the two arrays, filtering out empty values
19+
existingValues = existingValues.concat(newValue).filter(Boolean);
20+
// Remove duplicate content
21+
existingValues = [...new Set(existingValues)]
22+
url.searchParams.set(param, existingValues.join(','));
23+
24+
return url.href;
25+
}

tests/unit/utils/url-test.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { module, test } from 'qunit';
2+
import { appendToQueryParam } from 'ember-data-utils/utils/url';
3+
4+
module('Unit | Utility | url', function() {
5+
6+
test('appendToQueryParam()', function(assert) {
7+
assert.equal(
8+
appendToQueryParam(
9+
'https://www.test.com',
10+
'include',
11+
'profile'
12+
),
13+
'https://www.test.com/?include=profile',
14+
'it adds a new query param'
15+
);
16+
assert.equal(
17+
appendToQueryParam(
18+
'https://www.test.com?include=person',
19+
'include',
20+
'profile'
21+
),
22+
'https://www.test.com/?include=person%2Cprofile',
23+
'it adds to an existing param'
24+
);
25+
assert.equal(
26+
appendToQueryParam(
27+
'https://www.test.com?query=person',
28+
'include',
29+
'profile'
30+
),
31+
'https://www.test.com/?query=person&include=profile',
32+
'it adds a new query param while leaving existing params alone'
33+
);
34+
assert.equal(
35+
appendToQueryParam(
36+
'https://www.test.com',
37+
'include',
38+
['profile', 'pizza']
39+
),
40+
'https://www.test.com/?include=profile%2Cpizza',
41+
'new params can be an array'
42+
);
43+
assert.equal(
44+
appendToQueryParam(
45+
'https://www.test.com?include=party',
46+
'include',
47+
['profile', 'pizza']
48+
),
49+
'https://www.test.com/?include=party%2Cprofile%2Cpizza',
50+
'array params are concatted with existing param values'
51+
);
52+
assert.equal(
53+
appendToQueryParam(
54+
'https://www.test.com?include=party',
55+
'include',
56+
'profile,pizza'
57+
),
58+
'https://www.test.com/?include=party%2Cprofile%2Cpizza',
59+
'params that are strings are added'
60+
);
61+
assert.equal(
62+
appendToQueryParam(
63+
'https://www.test.com?include=party',
64+
'include',
65+
null
66+
),
67+
'https://www.test.com/?include=party',
68+
'null params are ignored'
69+
);
70+
assert.equal(
71+
appendToQueryParam(
72+
'https://www.test.com?include=party',
73+
'include',
74+
[]
75+
),
76+
'https://www.test.com/?include=party',
77+
'empty arrays are ignored'
78+
);
79+
assert.equal(
80+
appendToQueryParam(
81+
'https://www.test.com?include=party',
82+
'include',
83+
['party']
84+
),
85+
'https://www.test.com/?include=party',
86+
'param values are not duplicated'
87+
);
88+
assert.equal(
89+
appendToQueryParam(
90+
'https://www.test.com?include=party',
91+
'include',
92+
'party,pizza'
93+
),
94+
'https://www.test.com/?include=party%2Cpizza',
95+
'param values are not duplicated even if a string'
96+
);
97+
});
98+
});

0 commit comments

Comments
 (0)