Skip to content

Commit cf18192

Browse files
M3psipaxcuebit
andauthored
feat: add withAll and withAllRecursive methods (#94)
Co-authored-by: Cue <[email protected]>
1 parent 6a3ddd9 commit cf18192

File tree

4 files changed

+173
-0
lines changed

4 files changed

+173
-0
lines changed

src/query/Query.ts

+24
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,30 @@ export class Query<M extends Model = Model> {
179179
return this
180180
}
181181

182+
/**
183+
* Set to eager load all top-level relationships. Constraint is set for all relationships.
184+
*/
185+
withAll(callback: EagerLoadConstraint = () => {}): Query<M> {
186+
const fields = this.model.$fields()
187+
188+
for (const name in fields) {
189+
fields[name] instanceof Relation && this.with(name, callback)
190+
}
191+
192+
return this
193+
}
194+
195+
/**
196+
* Set to eager load all relationships recursively.
197+
*/
198+
withAllRecursive(depth: number = 3): Query<M> {
199+
this.withAll((query) => {
200+
depth > 0 && query.withAllRecursive(depth - 1)
201+
})
202+
203+
return this
204+
}
205+
182206
/**
183207
* Get raw elements from the store.
184208
*/

src/repository/Repository.ts

+14
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ export class Repository<M extends Model = Model> {
147147
return this.query().with(name, callback)
148148
}
149149

150+
/**
151+
* Set to eager load all top-level relationships. Constraint is set for all relationships.
152+
*/
153+
withAll(callback?: EagerLoadConstraint): Query<M> {
154+
return this.query().withAll(callback)
155+
}
156+
157+
/**
158+
* Set to eager load all top-level relationships. Constraint is set for all relationships.
159+
*/
160+
withAllRecursive(depth?: number): Query<M> {
161+
return this.query().withAllRecursive(depth)
162+
}
163+
150164
/**
151165
* Get all models from the store.
152166
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import {
2+
assertInstanceOf,
3+
assertModel,
4+
createStore,
5+
fillState
6+
} from 'test/Helpers'
7+
import { Model, Attr, Str, HasMany, BelongsTo } from '@/index'
8+
9+
describe('feature/relations/eager_loads_all', () => {
10+
class User extends Model {
11+
static entity = 'users'
12+
13+
@Attr() id!: number
14+
@Str('') name!: string
15+
}
16+
17+
class Post extends Model {
18+
static entity = 'posts'
19+
20+
@Attr() id!: number
21+
@Attr() userId!: number
22+
@Str('') title!: string
23+
24+
@BelongsTo(() => User, 'userId')
25+
author!: User | null
26+
27+
@HasMany(() => Comment, 'postId')
28+
comments!: Comment[]
29+
}
30+
31+
class Comment extends Model {
32+
static entity = 'comments'
33+
34+
@Attr() id!: number
35+
@Attr() postId!: number
36+
@Str('') content!: string
37+
}
38+
39+
it('eager loads all top level relations', () => {
40+
const store = createStore()
41+
42+
fillState(store, {
43+
users: {
44+
1: { id: 1, name: 'John Doe' }
45+
},
46+
posts: {
47+
1: { id: 1, userId: 1, title: 'Title 01' }
48+
},
49+
comments: {
50+
1: { id: 1, postId: 1, content: 'Content 01' }
51+
}
52+
})
53+
54+
const post = store.$repo(Post).withAll().first()!
55+
56+
expect(post.author).toBeInstanceOf(User)
57+
assertInstanceOf(post.comments, Comment)
58+
assertModel(post, {
59+
id: 1,
60+
userId: 1,
61+
title: 'Title 01',
62+
author: { id: 1, name: 'John Doe' },
63+
comments: [{ id: 1, postId: 1, content: 'Content 01' }]
64+
})
65+
})
66+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { assertModel, createStore, fillState } from 'test/Helpers'
2+
import { Model, Attr, Str, BelongsTo, HasOne } from '@/index'
3+
4+
describe('feature/relations/eager_loads_recursive', () => {
5+
class User extends Model {
6+
static entity = 'users'
7+
8+
@Attr() id!: number
9+
@Str('') name!: string
10+
11+
@HasOne(() => Phone, 'userId')
12+
phone!: Phone
13+
}
14+
15+
class Phone extends Model {
16+
static entity = 'phones'
17+
18+
@Attr() id!: number
19+
@Attr() userId!: number
20+
@Str('') number!: string
21+
22+
@BelongsTo(() => User, 'userId')
23+
user!: User
24+
}
25+
26+
it('eager loads all relations recursively', () => {
27+
const store = createStore()
28+
29+
fillState(store, {
30+
users: {
31+
1: { id: 1, name: 'John Doe' }
32+
},
33+
phones: {
34+
1: { id: 1, userId: 1, number: '123-4567-8912' }
35+
}
36+
})
37+
38+
const user = store.$repo(User).withAllRecursive().first()!
39+
40+
expect(user.phone.user).toBeInstanceOf(User)
41+
expect(user.phone.user.phone).toBeInstanceOf(Phone)
42+
expect(user.phone.user.phone.user).toBeInstanceOf(User)
43+
assertModel(user.phone.user.phone.user, {
44+
id: 1,
45+
name: 'John Doe'
46+
})
47+
})
48+
49+
it('eager loads all relations with a given recursion limit', () => {
50+
const store = createStore()
51+
52+
fillState(store, {
53+
users: {
54+
1: { id: 1, name: 'John Doe' }
55+
},
56+
phones: {
57+
1: { id: 1, userId: 1, number: '123-4567-8912' }
58+
}
59+
})
60+
61+
const user = store.$repo(User).withAllRecursive(1).first()!
62+
63+
expect(user.phone.user).toBeInstanceOf(User)
64+
assertModel(user.phone.user, {
65+
id: 1,
66+
name: 'John Doe'
67+
})
68+
})
69+
})

0 commit comments

Comments
 (0)