Skip to content

Commit 380d684

Browse files
committed
fix: persist belongs to before persisting the parent model
1 parent daab588 commit 380d684

File tree

5 files changed

+67
-6
lines changed

5 files changed

+67
-6
lines changed

src/Factory/FactoryBuilder.ts

+37-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
3333
callback?: (factory: any) => void,
3434
}[] = []
3535

36+
/**
37+
* Belongs to relationships are treated different, since they are
38+
* persisted before the parent model
39+
*/
40+
private withBelongsToRelations: {
41+
name: string,
42+
count?: number,
43+
callback?: (factory: any) => void,
44+
}[] = []
45+
3646
/**
3747
* The current index. Updated by `makeMany` and `createMany`
3848
*/
@@ -151,8 +161,14 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
151161
/**
152162
* Makes and persists relationship instances
153163
*/
154-
public async createRelations (modelInstance: LucidRow, ctx: FactoryContextContract) {
155-
for (let { name, count, callback } of this.withRelations) {
164+
private async createRelations (
165+
modelInstance: LucidRow,
166+
ctx: FactoryContextContract,
167+
cycle: 'before' | 'after',
168+
) {
169+
const relationships = cycle === 'before' ? this.withBelongsToRelations : this.withRelations
170+
171+
for (let { name, count, callback } of relationships) {
156172
const relation = this.model.getRelation(name)
157173
await relation.useCtx(ctx).create(modelInstance, callback, count)
158174
}
@@ -170,8 +186,15 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
170186
/**
171187
* Load relationship
172188
*/
173-
public with (relation: string, count?: number, callback?: (factory: never) => void): this {
174-
this.withRelations.push({ name: relation, count, callback })
189+
public with (name: string, count?: number, callback?: (factory: never) => void): this {
190+
const relation = this.model.getRelation(name)
191+
192+
if (relation.relation.type === 'belongsTo') {
193+
this.withBelongsToRelations.push({ name, count, callback })
194+
return this
195+
}
196+
197+
this.withRelations.push({ name, count, callback })
175198
return this
176199
}
177200

@@ -250,16 +273,24 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
250273
await this.model.hooks.exec('before', 'create', this, modelInstance, ctx)
251274

252275
try {
276+
modelInstance.$trx = ctx.$trx
277+
278+
/**
279+
* Create belongs to relationships before calling the save method. Even though
280+
* we can update the foriegn key after the initial insert call, we avoid it
281+
* for cases, where FK is a not nullable.
282+
*/
283+
await this.createRelations(modelInstance, ctx, 'before')
284+
253285
/**
254286
* Persist model instance
255287
*/
256-
modelInstance.$trx = ctx.$trx
257288
await modelInstance.save()
258289

259290
/**
260291
* Create relationships.
261292
*/
262-
await this.createRelations(modelInstance, ctx)
293+
await this.createRelations(modelInstance, ctx, 'after')
263294

264295
/**
265296
* Fire after hook before the transaction is committed, so that

test/factory/belongs-to-spec.ts

+7
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,13 @@ test.group('Factory | BelongTo | create', (group) => {
269269
assert.instanceOf(profile.user, User)
270270
assert.isTrue(profile.user.$isPersisted)
271271
assert.equal(profile.user.id, profile.userId)
272+
273+
const users = await db.from('users').select('*')
274+
const profiles = await db.from('profiles').select('*')
275+
276+
assert.lengthOf(profiles, 1)
277+
assert.lengthOf(users, 1)
278+
assert.equal(profiles[0].user_id, users[0].id)
272279
})
273280

274281
test('pass custom attributes to the relationship', async (assert) => {

test/factory/has-many.spec.ts

+7
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ test.group('Factory | HasMany | create', (group) => {
255255
assert.instanceOf(user.posts[0], Post)
256256
assert.isTrue(user.posts[0].$isPersisted)
257257
assert.equal(user.posts[0].userId, user.id)
258+
259+
const users = await db.from('users').select('*')
260+
const posts = await db.from('posts').select('*')
261+
262+
assert.lengthOf(posts, 1)
263+
assert.lengthOf(users, 1)
264+
assert.equal(posts[0].user_id, users[0].id)
258265
})
259266

260267
test('pass custom attributes to relationship', async (assert) => {

test/factory/has-one.spec.ts

+7
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ test.group('Factory | HasOne | create', (group) => {
206206
assert.instanceOf(user.profile, Profile)
207207
assert.isTrue(user.profile.$isPersisted)
208208
assert.equal(user.profile.userId, user.id)
209+
210+
const users = await db.from('users').select('*')
211+
const profiles = await db.from('profiles').select('*')
212+
213+
assert.lengthOf(profiles, 1)
214+
assert.lengthOf(users, 1)
215+
assert.equal(profiles[0].user_id, users[0].id)
209216
})
210217

211218
test('pass custom attributes to relationship', async (assert) => {

test/factory/many-to-many.spec.ts

+9
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,15 @@ test.group('Factory | ManyToMany | create', (group) => {
272272
user_id: user.id,
273273
skill_id: user.skills[0].id,
274274
})
275+
276+
const users = await db.from('users').select('*')
277+
const skills = await db.from('skills').select('*')
278+
const skillUsers = await db.from('skill_user').select('*')
279+
280+
assert.lengthOf(skills, 1)
281+
assert.lengthOf(users, 1)
282+
assert.equal(skillUsers[0].user_id, users[0].id)
283+
assert.equal(skillUsers[0].skill_id, skills[0].id)
275284
})
276285

277286
test('pass custom attributes', async (assert) => {

0 commit comments

Comments
 (0)