Skip to content

Commit

Permalink
fix: withAll should observe constraints
Browse files Browse the repository at this point in the history
added additional unit tests
updated documentation for clarity
  • Loading branch information
cuebit committed Mar 16, 2020
1 parent 76c0fbc commit f3fdf02
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 44 deletions.
9 changes: 9 additions & 0 deletions docs/guide/data/retrieving.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,15 @@ const user = User.query().with('posts.comments', (query) => {
}).get()
```

Similarly, you may add constraints to wilcard relations. For example, `posts` may have `comments` and `tags`, all of which will be ordered by the `created_at` field.

```js
const user = User.query().with('posts.*', (query) => {
// This constraint will be applied to all relations belonging to `posts`
query.orderBy('created_at', 'desc')
}).get()
```

If you need to add constraints to each relation, you could always nest constraints. This is the most flexible way of defining constraints to the relationships.

```js
Expand Down
4 changes: 2 additions & 2 deletions src/query/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,8 @@ export default class Query<T extends Model = Model> {
/**
* Query all relations.
*/
withAll (): this {
Loader.withAll(this)
withAll (constraint: Contracts.RelationshipConstraint | null = null): this {
Loader.withAll(this, constraint)

return this
}
Expand Down
4 changes: 2 additions & 2 deletions src/query/loaders/Loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class Loader {
static with (query: Query, name: string | string[], constraint: Constraint | null): void {
// If the name of the relation is `*`, we'll load all relationships.
if (name === '*') {
this.withAll(query)
this.withAll(query, constraint)

return
}
Expand All @@ -30,7 +30,7 @@ export default class Loader {
/**
* Set all relationships to be eager loaded with the query.
*/
static withAll (query: Query, constraint: Constraint = () => null): void {
static withAll (query: Query, constraint: Constraint | null): void {
const fields = query.model.getFields()

for (const field in fields) {
Expand Down
132 changes: 92 additions & 40 deletions test/feature/relations/Retrieve_With_NestedConstraints.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,70 @@ import { createStore } from 'test/support/Helpers'
import Model from '@/model/Model'

describe('Feature – Relations – With – Nested Constraints', () => {
it('can apply `with` constraints to nested relationships', async () => {
class User extends Model {
static entity = 'users'
class User extends Model {
static entity = 'users'

// @Attribute
id!: number
// @Attribute
id!: number

// @HasMany(Post, 'user_id')
posts!: Post[]
// @HasMany(Post, 'user_id')
posts!: Post[]

static fields () {
return {
id: this.attr(null),
posts: this.hasMany(Post, 'user_id')
}
static fields () {
return {
id: this.attr(null),
posts: this.hasMany(Post, 'user_id')
}
}
}

class Post extends Model {
static entity = 'posts'
class Post extends Model {
static entity = 'posts'

// @Attribute
id!: number
// @Attribute
id!: number

// @Attribute
user_id!: number
// @Attribute
user_id!: number

// @HasMany(Comment, 'post_id')
comments!: Comment[]
// @HasMany(Comment, 'post_id')
comments!: Comment[]

static fields () {
return {
id: this.attr(null),
user_id: this.attr(null),
comments: this.hasMany(Comment, 'post_id')
}
static fields () {
return {
id: this.attr(null),
user_id: this.attr(null),
comments: this.hasMany(Comment, 'post_id')
}
}
}

class Comment extends Model {
static entity = 'comments'
class Comment extends Model {
static entity = 'comments'

// @Attribute
id!: number
// @Attribute
id!: number

// @Attribute('')
title!: string
// @Attribute('')
title!: string

// @Attribute
user_id!: number
// @Attribute
user_id!: number

static fields () {
return {
id: this.attr(null),
title: this.attr(''),
post_id: this.attr(null)
}
static fields () {
return {
id: this.attr(null),
title: this.attr(''),
post_id: this.attr(null)
}
}
}

beforeEach(() => {
createStore([{ model: User }, { model: Post }, { model: Comment }])
})

it('can apply `with` constraints to nested relations', async () => {
await User.create({ data: { id: 1 } })

await Post.create({ data: { id: 1, user_id: 1 } })
Expand All @@ -85,4 +87,54 @@ describe('Feature – Relations – With – Nested Constraints', () => {
expect(user.posts[0].comments.length).toBe(2)
expect(user.posts[0].comments[0].title).toBe('Title01')
})

it('can apply `withAll` constraints to nested relations', async () => {
await User.create({ data: { id: 1 } })

await Post.create({ data: [{ id: 1, user_id: 1 }, { id: 2, user_id: 1 }] })

await Comment.create({
data: [
{ id: 1, post_id: 1, title: 'Title01' },
{ id: 2, post_id: 1, title: 'Title01' },
{ id: 3, post_id: 1, title: 'Title02' }
]
})

const user = User.query().withAll((query) => {
query.where('id', 2)
}).find(1) as User

expect(user.posts.length).toBe(1)
expect(user.posts[0].comments.length).toEqual(0)
expect(user.posts[0].id).toBe(2)
})

it('can apply constraints to multiple sub relations', async () => {
await User.create({ data: { id: 1 } })

await Post.create({ data: { id: 1, user_id: 1 } })

await Comment.create({
data: [
{ id: 1, post_id: 1, title: 'Beta' },
{ id: 2, post_id: 1, title: 'Cyprus' },
{ id: 3, post_id: 1, title: 'Alpha' }
]
})

const user = User.query().with('posts.*', (query) => {
query.orderBy('title')
}).find(1) as User

const expected = [
{ '$id': '3', id: 3, title: 'Alpha', post_id: 1 },
{ '$id': '1', id: 1, title: 'Beta', post_id: 1 },
{ '$id': '2', id: 2, title: 'Cyprus', post_id: 1 }
]

expect(user.posts.length).toBe(1)
expect(user.posts[0].comments.length).toBe(3)
expect(user.posts[0].comments).toEqual(expected)
})
})

0 comments on commit f3fdf02

Please sign in to comment.