Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: url with query params #506

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 16 additions & 3 deletions addon/utils/build-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,24 @@ export function buildOperationUrl<M extends Model>(
return baseUrl;
}

if (baseUrl.charAt(baseUrl.length - 1) === '/') {
return `${baseUrl}${path}`;
let url;
const [baseUrlNoQueries, baseQueries] = baseUrl.split('?');
const [pathNoQueries, pathQueries] = path.split('?');

if (baseUrlNoQueries.charAt(baseUrl.length - 1) === '/') {
url = `${baseUrlNoQueries}${pathNoQueries}`;
} else {
return `${baseUrl}/${path}`;
url = `${baseUrlNoQueries}/${pathNoQueries}`;
}

if (baseQueries || pathQueries) {
const baseSearchParams = new URLSearchParams(baseQueries);
const pathSearchParams = new URLSearchParams(pathQueries);
for (const [k, v] of pathSearchParams) { baseSearchParams.append(k, v) };
url = `${url}?${baseSearchParams.toString()}`;
}

return url;
}

export default buildOperationUrl;
32 changes: 32 additions & 0 deletions tests/acceptance/index-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,36 @@ module('Acceptance | index2', hooks => {

(assert as any).dom(`[data-test-fruit-name="Completely Eaten apple"]`).exists();
});

test('query params', async function(assert) {
await visit('/');
assert.expect(9);

this.server.get('/vegatables/:id/info', (request) => {
assert.equal(request.params.id, '1', 'request made to the right URL');
assert.equal(request.queryParams.vegatableId, '1', 'request made with the right query params');
assert.equal(request.queryParams.vegatable, 'potato', 'request made with the right buildURL query params');
return [200, {}, '{"status": "ok"}'];
});

this.server.get('/vegatables/:id/moreInfo', (request) => {
assert.equal(request.params.id, '2', 'request made to the right URL');
assert.equal(request.queryParams.vegatableId, '2', 'request made with the right query params');
assert.equal(request.queryParams.vegatable, 'carrot', 'request made with the right buildURL query params');
assert.equal(request.queryParams.more, 'true', 'request made with the right path query params');
return [200, {}, '{"status": "ok"}'];
});

this.server.get('/vegatables/allInfo', (request) => {
assert.equal(request.queryParams.vegatable, 'potato', 'request made with the right buildURL query params');
assert.equal(request.queryParams.less, 'false', 'request made with the right path query params');
return [200, {}, '{"status": "ok"}'];
});

await click('#potato .info-instance-button');

await click('#carrot .more-info-instance-button');

await click('.all-vegatables .all-info-button');
});
});
8 changes: 8 additions & 0 deletions tests/dummy/app/adapters/vegatable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ApplicationAdapter from './application';

export default class VegatableAdapter extends ApplicationAdapter {
public buildURL(modelName: string, id: string|[string]|object, snapshot: object, requestType: string, query: object) {
const url = super.buildURL(modelName, id, snapshot, requestType, query);
return `${url}?${modelName}=${snapshot.attr('name')}`;
}
}
9 changes: 9 additions & 0 deletions tests/dummy/app/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export default Controller.extend({
},
juiceAllFruit(fruit) {
Fruit.juiceAll({ was_eaten: true });
},
vegatableInfo(vegatable) {
vegatable.info({ vegatableId: vegatable.id });
},
vegatableMoreInfo(vegatable) {
vegatable.moreInfo({ vegatableId: vegatable.id });
},
allInfoVegatables(vegatable) {
vegatable.allInfo();
}
}
// END-SNIPPET
Expand Down
15 changes: 15 additions & 0 deletions tests/dummy/app/models/vegatable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// BEGIN-SNIPPET vegatable-model
import DS from 'ember-data';
import { collectionAction, memberAction } from 'ember-api-actions';

const { attr, Model } = DS;

const Vegatable = Model.extend({
name: attr('string'),
info: memberAction({ path: 'info', type: 'get' }),
moreInfo: memberAction({ path: 'moreInfo?more=true', type: 'get' }),
allInfo: collectionAction({ path: 'allInfo?less=false', type: 'get' }),
});

export default Vegatable;
// END-SNIPPET
54 changes: 47 additions & 7 deletions tests/dummy/app/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Pretender from 'pretender';

const { testing } = Ember;

const LEGACY_PAYLOAD = {
const LEGACY_FRUIT_PAYLOAD = {
fruit: [
{
id: 1,
Expand All @@ -26,7 +26,20 @@ const LEGACY_PAYLOAD = {
]
};

const PAYLOAD = {
const LEGACY_VEGATABLE_PAYLOAD = {
vegatable: [
{
id: 1,
name: 'potato',
},
{
id: 2,
name: 'carrot',
}
]
}

const FRUIT_PAYLOAD = {
data: [
{
type: 'fruit',
Expand Down Expand Up @@ -55,23 +68,50 @@ const PAYLOAD = {
attributes: {
name: 'grape'
}
},
]
};

const VEGATABLE_PAYLOAD = {
data: [
{
type: 'vegatable',
id: 1,
attributes: {
name: 'potato'
}
},
{
type: 'vegatable',
id: 2,
attributes: {
name: 'carrot'
}
}
]
};




export default Route.extend({
server: undefined as any,
requests: [] as any[],
currentModel: undefined as any,
model() {
let arr: any = [];
this.store.pushPayload('fruit', !this.store.peekAll ? LEGACY_PAYLOAD : PAYLOAD);
let fruitArr: any = [];
let vegatableArr: any = [];
this.store.pushPayload('fruit', !this.store.peekAll ? LEGACY_FRUIT_PAYLOAD : FRUIT_PAYLOAD);
this.store.pushPayload('vegatable', !this.store.peekAll ? LEGACY_VEGATABLE_PAYLOAD : VEGATABLE_PAYLOAD);
if (!this.store.peekAll) {
arr = [1, 2, 3, 4].map(id => (this.store as any).getById('fruit', id));
fruitArr = [1, 2, 3, 4].map(id => (this.store as any).getById('fruit', id));
vegatableArr = [1, 2].map(id => (this.store as any).getById('vegatable', id));
} else {
arr = this.store.peekAll('fruit');
fruitArr = this.store.peekAll('fruit');
vegatableArr = this.store.peekAll('vegatable');
}
return A(arr);

return { fruit: A(fruitArr), vegatable: A(vegatableArr) };
},

beforeModel() {
Expand Down
49 changes: 42 additions & 7 deletions tests/dummy/app/templates/index.hbs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<div class="row">
<div class="col m6 s12">
<h4>API actions on an individual resource</h4>
{{#each model as |fruit|}}

<h5>Fruit</h5>
{{#each model.fruit as |fruit|}}
<p class="fruit-thing" id={{fruit.name}}>
{{#x-btn
class="ripen-instance-button yellow"
click=(action "ripenFruit" fruit)
}}
Ripen
{{/x-btn}}
{{/x-btn}}
{{#x-btn
class="info-instance-button indigo white-text"
click=(action "fruitInfo" fruit)
Expand All @@ -23,34 +25,67 @@
{{#x-btn class="eat-instance-button yellow" click=(action "eatFruit" fruit)}}Eat{{/x-btn}}
</p>
{{/each}}

<h5>Vegatable</h5>
{{#each model.vegatable as |vegatable|}}
<p class="vegatable-thing" id={{vegatable.name}}>
{{#x-btn
class="info-instance-button indigo white-text"
click=(action "vegatableInfo" vegatable)
}}
Info
{{/x-btn}}
</p>

<p class="vegatable-thing" id={{vegatable.name}}>
{{#x-btn
class="more-info-instance-button yellow white-text"
click=(action "vegatableMoreInfo" vegatable)
}}
More Info
{{/x-btn}}
</p>
{{/each}}

<h4>API action on a collection of resources</h4>
<p class="all-vegatables">
{{content.vegatable.constructor.modelName}}
{{#x-btn
class="all-info-button indigo white-text"
click=(action "allInfoVegatables"
(first-in-array (or content.vegatable model.vegatable)))
}}
All Info
{{/x-btn}}
</p>

<p class="all-fruit">
{{content.constructor.modelName}}
{{content.fruit.constructor.modelName}}
{{#x-btn
class="ripen-type-button yellow"
click=(action "ripenAllFruit" (first-in-array (or content model)))
click=(action "ripenAllFruit" (first-in-array (or content.fruit model.fruit)))
}}
Ripen All
{{/x-btn}}
{{#x-btn
class="fresh-type-button indigo white-text"
click=(action "getAllFreshFruit"
(first-in-array (or content model)))
(first-in-array (or content.fruit model.fruit)))
}}
Get Fresh
{{/x-btn}}
{{#x-btn
class="fresh-type-button indigo white-text"
click=(action "juiceAllFruit"
(first-in-array (or content model)))
(first-in-array (or content.fruit model.fruit)))
}}
Juice Everything
{{/x-btn}}

{{#x-btn
class="eat-all-button indigo white-text"
click=(action "eatAll"
(first-in-array (or content model)))
(first-in-array (or content.fruit model.fruit)))
}}
Eat all
{{/x-btn}}
Expand Down