Repository: robsontenorio/vue-api-query (js)

Issue:
Calling custom() before save() should trigger a console error
Building the resource URL for the request is done for you by calling `resource()` of the model you are creating the request with.  
This can be overridden with `custom()` for GET requests and `for()` for POST/PUT/PATCH/DELETE requests.

Users of the library often don't realize that `custom()` was made to query records on, for example, `/posts/latest` which is a conceivable resource URL. It is not RESTful to save/delete records on endpoints such as this.

People should be made aware that `for()` needs to be used for saving/deleting records.

The library should output a console error if `save()` is called after `custom()`.

Pull request description:
fix(model): throw an error if operations are used with `custom` 
Throw an error if CRUD or relationship operations are used in in conjunction with the `custom` method.

Fixes #172 

Patch:
diff --git a/src/Model.js b/src/Model.js
index f864731..cc3208a 100644
--- a/src/Model.js
+++ b/src/Model.js
@@ -423,6 +423,10 @@ export default class Model extends StaticModel {
    */
 
   delete() {
+    if (this._customResource) {
+      throw Error("The delete() method cannot be used in conjunction with the custom() method. Use for() instead.")
+    }
+
     if (!this.hasId()) {
       throw new Error('This model has a empty ID.')
     }
@@ -436,6 +440,10 @@ export default class Model extends StaticModel {
   }
 
   save() {
+    if (this._customResource) {
+      throw Error("The save() method cannot be used in conjunction with the custom() method. Use for() instead.")
+    }
+
     return this.hasId() ? this._update() : this._create()
   }
 
@@ -472,6 +480,10 @@ export default class Model extends StaticModel {
    */
 
   attach(params) {
+    if (this._customResource) {
+      throw Error("The attach() method cannot be used in conjunction with the custom() method. Use for() instead.")
+    }
+
     return this.request(
       this._reqConfig({
         method: 'POST',
@@ -482,6 +494,10 @@ export default class Model extends StaticModel {
   }
 
   sync(params) {
+    if (this._customResource) {
+      throw Error("The sync() method cannot be used in conjunction with the custom() method. Use for() instead.")
+    }
+
     return this.request(
       this._reqConfig({
         method: 'PUT',


Test patch:
diff --git a/tests/model.test.js b/tests/model.test.js
index 385970f..368b62f 100644
--- a/tests/model.test.js
+++ b/tests/model.test.js
@@ -960,6 +960,38 @@ describe('Model methods', () => {
     expect(errorModel).toThrow('Arguments to custom() must be strings or instances of Model.')
   })
 
+  test('it throws an error when CRUD and relationship operations are used in conjunction with custom()', () => {
+    errorModel = () => {
+      const post = new Post({ text: 'Hello' }).custom('foo/bar').save()
+    }
+
+    expect(errorModel).toThrow("The save() method cannot be used in conjunction with the custom() method. Use for() instead.")
+
+    errorModel = () => {
+      const post = new Post({ id: 1 }).custom('foo/bar').delete()
+    }
+
+    expect(errorModel).toThrow("The delete() method cannot be used in conjunction with the custom() method. Use for() instead.")
+
+    errorModel = () => {
+      const post = new Post({ id: 1 })
+      const comment = post.comments().custom('foo/bar').attach({
+        text: 'Awesome post!'
+      })
+    }
+
+    expect(errorModel).toThrow("The attach() method cannot be used in conjunction with the custom() method. Use for() instead.")
+
+    errorModel = () => {
+      const post = new Post({ id: 1 })
+      const comment = post.comments().custom('foo/bar').sync({
+        text: 'Awesome post!'
+      })
+    }
+
+    expect(errorModel).toThrow("The sync() method cannot be used in conjunction with the custom() method. Use for() instead.")
+  })
+
   test('save() method makes a PUT request to the correct URL on nested object thas was fetched with find() method', async () => {
     axiosMock.onGet('http://localhost/posts/1/comments/1').reply(200, commentsResponse[0])
     axiosMock.onPut('http://localhost/posts/1/comments/1').reply(200, commentsResponse[0])