vue-api-query
Advanced tools
Comparing version
{ | ||
"name": "vue-api-query", | ||
"version": "1.5.2", | ||
"version": "1.6.0", | ||
"description": "💎 Elegant and simple way to build requests for REST API", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
@@ -520,3 +520,87 @@ <p align="center"> | ||
You can also apply a model instance to a nested object by setting the key and the model in `relations` method. | ||
If the backend responds with: | ||
```js | ||
// response from API for /posts/1 | ||
{ | ||
title: 'My title' | ||
body: 'Some text here', | ||
user: { | ||
firstName: 'John', | ||
lastName: 'Doe' | ||
} | ||
} | ||
``` | ||
We just need to set `user` to User model: | ||
**/models/Post.js** | ||
```js | ||
class Post extends Model { | ||
relations () { | ||
return { | ||
// Apply User model to `user` object | ||
user: User | ||
} | ||
} | ||
} | ||
``` | ||
It also works for collections. So if the backend responds with: | ||
```js | ||
// response from API for /comments | ||
{ | ||
text: 'Some text here', | ||
user: { | ||
firstName: 'John', | ||
lastName: 'Doe' | ||
}, | ||
replies: [ | ||
{ | ||
text: 'A reply here', | ||
user: { | ||
firstName: 'Joe', | ||
lastName: 'Doe' | ||
} | ||
}, | ||
{ | ||
text: 'Another reply here', | ||
user: { | ||
firstName: 'Mary', | ||
lastName: 'Doe' | ||
}, | ||
replies: [ | ||
{ | ||
text: 'Yes, this is the reply of the reply!', | ||
user: { | ||
firstName: 'Max', | ||
lastName: 'Doe' | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
Then we just need to set `user` to User model and `replies` to Comment model: | ||
**/models/Comment.js** | ||
```js | ||
class Comment extends Model { | ||
relations () { | ||
return { | ||
// Apply User model to `user` object | ||
user: User, | ||
// Apply Comment model to each object of `replies` array | ||
replies: Comment | ||
} | ||
} | ||
} | ||
``` | ||
# Pagination | ||
@@ -523,0 +607,0 @@ |
@@ -13,2 +13,3 @@ import Builder from './Builder'; | ||
Object.assign(this, ...attributes) | ||
this._applyRelations(this) | ||
} | ||
@@ -127,2 +128,6 @@ | ||
relations () { | ||
return {} | ||
} | ||
/** | ||
@@ -231,2 +236,44 @@ * Helpers | ||
_applyInstance(data, model = this.constructor) { | ||
const item = new model(data) | ||
if(this._fromResource) { | ||
item._from(this._fromResource) | ||
} | ||
return item | ||
} | ||
_applyInstanceCollection(data, model = this.constructor) { | ||
let collection = data.data || data | ||
collection = Array.isArray(collection) ? collection : [collection] | ||
collection = collection.map(c => { | ||
return this._applyInstance(c, model) | ||
}) | ||
return collection | ||
} | ||
_applyRelations(model) { | ||
const relations = model.relations() | ||
for(const relation of Object.keys(relations)) { | ||
if (!model[relation]) { | ||
return; | ||
} | ||
if (Array.isArray(model[relation].data) || Array.isArray(model[relation])) { | ||
const collection = this._applyInstanceCollection(model[relation], relations[relation]) | ||
if (model[relation].data !== undefined) { | ||
model[relation].data = collection | ||
} else { | ||
model[relation] = collection | ||
} | ||
} else { | ||
model[relation] = this._applyInstance(model[relation], relations[relation]) | ||
} | ||
} | ||
} | ||
first() { | ||
@@ -263,9 +310,3 @@ return this.get().then(response => { | ||
}).then(response => { | ||
const item = new this.constructor(response.data) | ||
if (this._fromResource) { | ||
item._from(this._fromResource) | ||
} | ||
return item | ||
return this._applyInstance(response.data) | ||
}) | ||
@@ -281,3 +322,3 @@ } | ||
.find(identifier) | ||
.then(response => new this.constructor(response.data || response)) | ||
.then(response => this._applyInstance(response.data || response)) | ||
} | ||
@@ -294,15 +335,4 @@ | ||
}).then(response => { | ||
let collection = response.data.data || response.data | ||
collection = Array.isArray(collection) ? collection : [collection] | ||
let collection = this._applyInstanceCollection(response.data) | ||
collection = collection.map(c => { | ||
let item = new this.constructor(c) | ||
if (this._fromResource) { | ||
item._from(this._fromResource) | ||
} | ||
return item | ||
}) | ||
if (response.data.data !== undefined) { | ||
@@ -349,4 +379,3 @@ response.data.data = collection | ||
}).then(response => { | ||
let self = Object.assign(this, response.data) | ||
return self | ||
return this._applyInstance(response.data) | ||
}) | ||
@@ -361,4 +390,3 @@ } | ||
}).then(response => { | ||
let self = Object.assign(this, response.data) | ||
return self | ||
return this._applyInstance(response.data) | ||
}) | ||
@@ -386,3 +414,2 @@ } | ||
} | ||
} |
@@ -6,3 +6,11 @@ export const Comments = [ | ||
someId: 'ma018-9ha12', | ||
text: 'Hello' | ||
text: 'Hello', | ||
replies: [ | ||
{ | ||
id: 3, | ||
comment_id: 1, | ||
someId: 'ma020-9ha15', | ||
text: 'Hello', | ||
} | ||
] | ||
}, | ||
@@ -13,4 +21,18 @@ { | ||
someId: 'mw012-7ha19', | ||
text: 'How are you?' | ||
text: 'How are you?', | ||
replies: [ | ||
{ | ||
id: 4, | ||
comment_id: 2, | ||
someId: 'mw023-9ha18', | ||
text: 'Hello', | ||
}, | ||
{ | ||
id: 5, | ||
comment_id: 2, | ||
someId: 'mw035-0ha22', | ||
text: 'Hello', | ||
} | ||
] | ||
} | ||
] | ||
] |
@@ -5,5 +5,8 @@ export const Post = | ||
someId: 'af621-4aa41', | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
} |
@@ -5,6 +5,9 @@ export const Post = { | ||
someId: 'af621-4aa41', | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
} | ||
} |
@@ -5,5 +5,8 @@ export const Posts = [ | ||
someId: 'du761-8bc98', | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
}, | ||
@@ -13,6 +16,9 @@ { | ||
someId: 'pa813-7jx02', | ||
firstname: 'Mary', | ||
lastname: 'Doe', | ||
age: 25 | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'Mary', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
} | ||
] | ||
] |
@@ -6,5 +6,8 @@ export const Posts = { | ||
someId: 'ap319-0nh56', | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
}, | ||
@@ -14,7 +17,10 @@ { | ||
someId: 'by887-0nv66', | ||
firstname: 'Mary', | ||
lastname: 'Doe', | ||
age: 25 | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'Mary', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
} | ||
] | ||
} |
import BaseModel from './BaseModel' | ||
export default class Comment extends BaseModel { | ||
} | ||
relations () { | ||
return { | ||
replies: Comment | ||
} | ||
} | ||
} |
import BaseModel from './BaseModel' | ||
import Comment from './Comment' | ||
import User from './User' | ||
@@ -8,2 +9,8 @@ export default class Post extends BaseModel { | ||
} | ||
} | ||
relations () { | ||
return { | ||
user: User | ||
} | ||
} | ||
} |
@@ -6,5 +6,9 @@ import BaseModel from './BaseModel' | ||
get fullname () { | ||
return `${this.firstname} ${this.lastname}` | ||
} | ||
posts () { | ||
return this.hasMany(Post) | ||
} | ||
} | ||
} |
@@ -12,2 +12,3 @@ import Post from './dummy/models/Post' | ||
import { Comments as commentsResponse } from './dummy/data/comments' | ||
import { Comments as commentsEmbedResponse } from './dummy/data/commentsEmbed' | ||
@@ -52,2 +53,3 @@ describe('Model methods', () => { | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}) | ||
@@ -63,2 +65,3 @@ | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}) | ||
@@ -79,2 +82,3 @@ | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}) | ||
@@ -89,2 +93,3 @@ | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}) | ||
@@ -99,2 +104,3 @@ | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
@@ -110,2 +116,3 @@ }) | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}); | ||
@@ -119,7 +126,14 @@ }) | ||
return [200, {}] | ||
return [200, commentsResponse] | ||
}) | ||
const post = new Post({ id: 1 }) | ||
await post.comments().get() | ||
const comments = await post.comments().get() | ||
comments.forEach(comment => { | ||
expect(comment).toBeInstanceOf(Comment) | ||
comment.replies.forEach(reply => { | ||
expect(reply).toBeInstanceOf(Comment) | ||
}) | ||
}) | ||
}) | ||
@@ -138,6 +152,13 @@ | ||
return [200, {}] | ||
return [200, commentsResponse] | ||
}) | ||
post.comments().get() | ||
const comments = await post.comments().get() | ||
comments.forEach(comment => { | ||
expect(comment).toBeInstanceOf(Comment) | ||
comment.replies.forEach(reply => { | ||
expect(reply).toBeInstanceOf(Comment) | ||
}) | ||
}) | ||
}) | ||
@@ -163,2 +184,21 @@ | ||
test('$get() hits right resource with "data" wrapper (nested object)', async () => { | ||
axiosMock.onGet().reply((config) => { | ||
expect(config.method).toEqual('get') | ||
expect(config.url).toEqual('http://localhost/posts/1/comments') | ||
return [200, commentsEmbedResponse] | ||
}) | ||
const post = new Post({ id: 1 }) | ||
const comments = await post.comments().$get() | ||
comments.forEach(comment => { | ||
expect(comment).toBeInstanceOf(Comment) | ||
comment.replies.data.forEach(reply => { | ||
expect(reply).toBeInstanceOf(Comment) | ||
}) | ||
}) | ||
}) | ||
test('$get() hits right resource (nested object, custom PK)', async () => { | ||
@@ -175,6 +215,13 @@ Post.prototype['primaryKey'] = () => { | ||
return [200, {}] | ||
return [200, commentsResponse] | ||
}) | ||
post.comments().$get() | ||
const comments = await post.comments().$get() | ||
comments.forEach(comment => { | ||
expect(comment).toBeInstanceOf(Comment) | ||
comment.replies.forEach(reply => { | ||
expect(reply).toBeInstanceOf(Comment) | ||
}) | ||
}) | ||
}) | ||
@@ -184,2 +231,12 @@ | ||
let post | ||
const _postResponse = { | ||
id: 1, | ||
title: 'Cool!', | ||
text: 'Lorem Ipsum Dolor', | ||
user: { | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
age: 25 | ||
} | ||
} | ||
@@ -191,8 +248,11 @@ axiosMock.onAny().reply((config) => { | ||
return [200, {}] | ||
return [200, _postResponse] | ||
}) | ||
post = new Post({ title: 'Cool!' }) | ||
await post.save() | ||
post = await post.save() | ||
expect(post).toEqual(_postResponse) | ||
expect(post).toBeInstanceOf(Post) | ||
expect(post.user).toBeInstanceOf(User) | ||
}) | ||
@@ -199,0 +259,0 @@ |
882
10.53%84079
-18.73%28
-12.5%1507
-30.97%