Skip to content

Commit 12a7aea

Browse files
Merge pull request #45 from Peter-Krebs/master
`custom()` now takes multiple arguments to build resource urls.
2 parents cae0a1a + 9359d0e commit 12a7aea

File tree

4 files changed

+92
-3
lines changed

4 files changed

+92
-3
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,19 @@ let latest = await Post
255255
.first()
256256
```
257257

258+
The `custom()` method can be called with multiple arguments to build
259+
resource endpoints and hierarchies. Simply supply them in the correct order.
260+
Any combination of strings and models is possible.
261+
262+
```js
263+
let user = new User({ id: 1 })
264+
let post = new Post()
265+
266+
// GET /users/1/posts/latest
267+
const result = await Post.custom(user, post, 'latest').get()
268+
```
269+
270+
258271
# Full example
259272

260273
**/models/Post.js**

src/Model.js

+34-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,40 @@ export default class Model extends StaticModel {
4545
return this[this.primaryKey()]
4646
}
4747

48-
custom(resource) {
48+
custom(...args) {
49+
50+
if(args.length === 0) {
51+
throw new Error('The custom() method takes a minimum of one argument.')
52+
}
53+
54+
// It would be unintuitive for users to manage where the '/' has to be for
55+
// multiple arguments. We don't need it for the first argument if it's
56+
// a string, but subsequent string arguments need the '/' at the beginning.
57+
// We handle this implementation detail here to simplify the readme.
58+
let slash = '';
59+
let resource = '';
60+
61+
args.forEach(value => {
62+
switch(true) {
63+
case (typeof value === 'string'):
64+
resource += slash + value.replace(/^\/+/, '');
65+
break;
66+
case (value instanceof Model):
67+
resource += slash + value.resource();
68+
69+
if(value.isValidId(value.getPrimaryKey())) {
70+
resource += '/' + value.getPrimaryKey();
71+
}
72+
break;
73+
default:
74+
throw new Error('Arguments to custom() must be strings or instances of Model.')
75+
}
76+
77+
if( !slash.length ) {
78+
slash = '/';
79+
}
80+
});
81+
4982
this._customResource = resource
5083

5184
return this

src/StaticModel.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ export default class StaticModel {
6767
return self
6868
}
6969

70-
static custom(resource) {
70+
static custom(...args) {
7171
let self = this.instance()
72-
self.custom(resource)
72+
self.custom(...args)
7373

7474
return self
7575
}

tests/model.test.js

+43
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,33 @@ describe('Model methods', () => {
311311
const post = await Post.custom('postz').first()
312312
})
313313

314+
test('custom() gracefully handles accidental / for string arguments', async () => {
315+
316+
axiosMock.onAny().reply((config) => {
317+
expect(config.url).toBe('postz/recent')
318+
319+
return [200, {}]
320+
})
321+
322+
const post = await Post.custom('/postz', 'recent').first()
323+
})
324+
325+
test('custom() called with multiple objects/strings gets the correct resource', async () => {
326+
let user
327+
let comment
328+
329+
axiosMock.onAny().reply((config) => {
330+
expect(config.method).toEqual('get')
331+
expect(config.url).toEqual('users/1/postz/comments')
332+
333+
return [200, {}]
334+
})
335+
336+
user = new User({ id: 1 })
337+
comment = new Comment()
338+
const result = await Comment.custom(user, 'postz', comment).get()
339+
})
340+
314341
test('a request from hasMany() method hits right resource', async () => {
315342
let user
316343
let posts
@@ -469,4 +496,20 @@ describe('Model methods', () => {
469496

470497
expect(errorModel).toThrow('The object referenced on for() method has a invalid id.')
471498
})
499+
500+
test('it throws a error when a custom() parameter is not a valid Model or a string', () => {
501+
502+
errorModel = () => {
503+
const post = new Post({ text: 'Hello' }).custom()
504+
}
505+
506+
expect(errorModel).toThrow('The custom() method takes a minimum of one argument.')
507+
508+
errorModel = () => {
509+
const user = new User({ name: 'Mary' })
510+
const post = new Post({ text: 'Hello' }).custom(user, 'a-string', 42)
511+
}
512+
513+
expect(errorModel).toThrow('Arguments to custom() must be strings or instances of Model.')
514+
})
472515
})

0 commit comments

Comments
 (0)