Skip to content

Commit

Permalink
fix: persist belongs to before persisting the parent model
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Jun 20, 2020
1 parent daab588 commit 380d684
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 6 deletions.
43 changes: 37 additions & 6 deletions src/Factory/FactoryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
callback?: (factory: any) => void,
}[] = []

/**
* Belongs to relationships are treated different, since they are
* persisted before the parent model
*/
private withBelongsToRelations: {
name: string,
count?: number,
callback?: (factory: any) => void,
}[] = []

/**
* The current index. Updated by `makeMany` and `createMany`
*/
Expand Down Expand Up @@ -151,8 +161,14 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
/**
* Makes and persists relationship instances
*/
public async createRelations (modelInstance: LucidRow, ctx: FactoryContextContract) {
for (let { name, count, callback } of this.withRelations) {
private async createRelations (
modelInstance: LucidRow,
ctx: FactoryContextContract,
cycle: 'before' | 'after',
) {
const relationships = cycle === 'before' ? this.withBelongsToRelations : this.withRelations

for (let { name, count, callback } of relationships) {
const relation = this.model.getRelation(name)
await relation.useCtx(ctx).create(modelInstance, callback, count)
}
Expand All @@ -170,8 +186,15 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
/**
* Load relationship
*/
public with (relation: string, count?: number, callback?: (factory: never) => void): this {
this.withRelations.push({ name: relation, count, callback })
public with (name: string, count?: number, callback?: (factory: never) => void): this {
const relation = this.model.getRelation(name)

if (relation.relation.type === 'belongsTo') {
this.withBelongsToRelations.push({ name, count, callback })
return this
}

this.withRelations.push({ name, count, callback })
return this
}

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

try {
modelInstance.$trx = ctx.$trx

/**
* Create belongs to relationships before calling the save method. Even though
* we can update the foriegn key after the initial insert call, we avoid it
* for cases, where FK is a not nullable.
*/
await this.createRelations(modelInstance, ctx, 'before')

/**
* Persist model instance
*/
modelInstance.$trx = ctx.$trx
await modelInstance.save()

/**
* Create relationships.
*/
await this.createRelations(modelInstance, ctx)
await this.createRelations(modelInstance, ctx, 'after')

/**
* Fire after hook before the transaction is committed, so that
Expand Down
7 changes: 7 additions & 0 deletions test/factory/belongs-to-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@ test.group('Factory | BelongTo | create', (group) => {
assert.instanceOf(profile.user, User)
assert.isTrue(profile.user.$isPersisted)
assert.equal(profile.user.id, profile.userId)

const users = await db.from('users').select('*')
const profiles = await db.from('profiles').select('*')

assert.lengthOf(profiles, 1)
assert.lengthOf(users, 1)
assert.equal(profiles[0].user_id, users[0].id)
})

test('pass custom attributes to the relationship', async (assert) => {
Expand Down
7 changes: 7 additions & 0 deletions test/factory/has-many.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,13 @@ test.group('Factory | HasMany | create', (group) => {
assert.instanceOf(user.posts[0], Post)
assert.isTrue(user.posts[0].$isPersisted)
assert.equal(user.posts[0].userId, user.id)

const users = await db.from('users').select('*')
const posts = await db.from('posts').select('*')

assert.lengthOf(posts, 1)
assert.lengthOf(users, 1)
assert.equal(posts[0].user_id, users[0].id)
})

test('pass custom attributes to relationship', async (assert) => {
Expand Down
7 changes: 7 additions & 0 deletions test/factory/has-one.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,13 @@ test.group('Factory | HasOne | create', (group) => {
assert.instanceOf(user.profile, Profile)
assert.isTrue(user.profile.$isPersisted)
assert.equal(user.profile.userId, user.id)

const users = await db.from('users').select('*')
const profiles = await db.from('profiles').select('*')

assert.lengthOf(profiles, 1)
assert.lengthOf(users, 1)
assert.equal(profiles[0].user_id, users[0].id)
})

test('pass custom attributes to relationship', async (assert) => {
Expand Down
9 changes: 9 additions & 0 deletions test/factory/many-to-many.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ test.group('Factory | ManyToMany | create', (group) => {
user_id: user.id,
skill_id: user.skills[0].id,
})

const users = await db.from('users').select('*')
const skills = await db.from('skills').select('*')
const skillUsers = await db.from('skill_user').select('*')

assert.lengthOf(skills, 1)
assert.lengthOf(users, 1)
assert.equal(skillUsers[0].user_id, users[0].id)
assert.equal(skillUsers[0].skill_id, skills[0].id)
})

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

0 comments on commit 380d684

Please sign in to comment.