Skip to content

Commit

Permalink
fix: copy a clone of relationship during inheritance
Browse files Browse the repository at this point in the history
FIXES #730
  • Loading branch information
Harminder Virk authored and Harminder Virk committed Oct 25, 2021
1 parent d2f961f commit 53a07df
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 1 deletion.
1 change: 1 addition & 0 deletions adonis-typings/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ declare module '@ioc:Adonis/Lucid/Orm' {
readonly model: ParentModel
relatedModel(): RelatedModel
boot(): void
clone(parent: LucidModel): this

/**
* Get client
Expand Down
6 changes: 5 additions & 1 deletion src/Orm/BaseModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,11 @@ export class BaseModel implements LucidRow {
*/
this.$defineProperty('$relationsDefinitions', new Map(), (value) => {
const relations = new Map<string, RelationshipsContract>()
value.forEach((relation, key) => relations.set(key, relation))
value.forEach((relation, key) => {
const relationClone = relation.clone(this)
relationClone.boot()
relations.set(key, relationClone)
})
return relations
})

Expand Down
7 changes: 7 additions & 0 deletions src/Orm/Relations/BelongsTo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ export class BelongsTo implements BelongsToRelationContract<LucidModel, LucidMod
public model: LucidModel
) {}

/**
* Clone relationship instance
*/
public clone(parent: LucidModel): any {
return new BelongsTo(this.relationName, this.relatedModel, { ...this.options }, parent)
}

/**
* Returns a boolean telling if the related row belongs to the parent
* row or not.
Expand Down
7 changes: 7 additions & 0 deletions src/Orm/Relations/HasMany/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ export class HasMany implements HasManyRelationContract<LucidModel, LucidModel>
return parent[this.localKey] !== undefined && related[this.foreignKey] === parent[this.localKey]
}

/**
* Clone relationship instance
*/
public clone(parent: LucidModel): any {
return new HasMany(this.relationName, this.relatedModel, { ...this.options }, parent)
}

/**
* Boot the relationship and ensure that all keys are in
* place for queries to do their job.
Expand Down
7 changes: 7 additions & 0 deletions src/Orm/Relations/HasManyThrough/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ export class HasManyThrough implements HasManyThroughRelationContract<LucidModel
public model: LucidModel
) {}

/**
* Clone relationship instance
*/
public clone(parent: LucidModel): any {
return new HasManyThrough(this.relationName, this.relatedModel, { ...this.options }, parent)
}

/**
* Returns the alias for the through key
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Orm/Relations/HasOne/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ export class HasOne implements HasOneRelationContract<LucidModel, LucidModel> {
public model: LucidModel
) {}

/**
* Clone relationship instance
*/
public clone(parent: LucidModel): any {
return new HasOne(this.relationName, this.relatedModel, { ...this.options }, parent)
}

/**
* Boot the relationship and ensure that all keys are in
* place for queries to do their job.
Expand Down
7 changes: 7 additions & 0 deletions src/Orm/Relations/ManyToMany/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ export class ManyToMany implements ManyToManyRelationContract<LucidModel, LucidM
return `pivot_${key}`
}

/**
* Clone relationship instance
*/
public clone(parent: LucidModel): any {
return new ManyToMany(this.relationName, this.relatedModel, { ...this.options }, parent)
}

/**
* Boot the relationship and ensure that all keys are in
* place for queries to do their job.
Expand Down
25 changes: 25 additions & 0 deletions test/orm/model-belongs-to.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,31 @@ test.group('Model | BelongsTo | Options', (group) => {

assert.equal(Profile.$getRelation('user')!['foreignKey'], 'userUid')
})

test('clone relationship instance with options', (assert) => {
class User extends BaseModel {
@column({ isPrimary: true })
public id: number
}

class BaseProfile extends BaseModel {
@column({ columnName: 'user_id' })
public userUid: number

@belongsTo(() => User, { foreignKey: 'userUid' })
public user: BelongsTo<typeof User>
}

class Profile extends BaseProfile {}
Profile.boot()

Profile.$getRelation('user')!.boot()
console.log(Profile.$getRelation('user'))

assert.deepEqual(Profile.$getRelation('user')!.relatedModel(), User)
assert.deepEqual(Profile.$getRelation('user')!.model, Profile)
assert.equal(Profile.$getRelation('user')!['foreignKey'], 'userUid')
})
})

test.group('Model | BelongsTo | Set Relations', (group) => {
Expand Down
50 changes: 50 additions & 0 deletions test/orm/model-has-many-through.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,56 @@ test.group('Model | Has Many Through | Options', (group) => {
assert.equal(relation['throughForeignKey'], 'userUid')
assert.equal(relation['throughForeignKeyColumnName'], 'user_uid')
})

test('clone relationship instance with options', (assert) => {
class User extends BaseModel {
@column({ isPrimary: true })
public uid: number

@column()
public countryUid: number
}
User.boot()

class Post extends BaseModel {
@column()
public userUid: number
}
Post.boot()

class BaseCountry extends BaseModel {
@column({ isPrimary: true })
public uid: number

@hasManyThrough([() => Post, () => User], {
throughForeignKey: 'userUid',
throughLocalKey: 'uid',
foreignKey: 'countryUid',
localKey: 'uid',
})
public posts: HasManyThrough<typeof Post>
}

class Country extends BaseCountry {}
Country.boot()

const relation = Country.$getRelation('posts')!
relation.boot()

assert.deepEqual(relation.model, Country)

assert.equal(relation['localKey'], 'uid')
assert.equal(relation['localKeyColumnName'], 'uid')

assert.equal(relation['foreignKey'], 'countryUid')
assert.equal(relation['foreignKeyColumnName'], 'country_uid')

assert.equal(relation['throughLocalKey'], 'uid')
assert.equal(relation['throughLocalKeyColumnName'], 'uid')

assert.equal(relation['throughForeignKey'], 'userUid')
assert.equal(relation['throughForeignKeyColumnName'], 'user_uid')
})
})

test.group('Model | Has Many Through | Set Relations', (group) => {
Expand Down
23 changes: 23 additions & 0 deletions test/orm/model-has-many.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,29 @@ test.group('Model | HasMany | Options', (group) => {

assert.equal(User.$getRelation('posts')!['foreignKey'], 'userUid')
})

test('clone relationship instance with options', (assert) => {
class Post extends BaseModel {
@column({ columnName: 'user_id' })
public userUid: number
}

class BaseUser extends BaseModel {
@column({ isPrimary: true })
public id: number

@hasMany(() => Post, { foreignKey: 'userUid' })
public posts: HasMany<typeof Post>
}

class User extends BaseUser {}

User.boot()
User.$getRelation('posts')!.boot()

assert.deepEqual(User.$getRelation('posts')!.model, User)
assert.equal(User.$getRelation('posts')!['foreignKey'], 'userUid')
})
})

test.group('Model | HasMany | Set Relations', (group) => {
Expand Down
24 changes: 24 additions & 0 deletions test/orm/model-has-one.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,30 @@ test.group('Model | HasOne | Options', (group) => {

assert.equal(User.$getRelation('profile')!['foreignKey'], 'userUid')
})

test('clone relationship instance with options', (assert) => {
class Profile extends BaseModel {
@column({ columnName: 'user_id' })
public userUid: number
}
Profile.boot()

class BaseUser extends BaseModel {
@column({ isPrimary: true })
public id: number

@hasOne(() => Profile, { foreignKey: 'userUid' })
public profile: HasOne<typeof Profile>
}

class User extends BaseUser {}

User.boot()
User.$getRelation('profile')!.boot()

assert.equal(User.$getRelation('profile')!['foreignKey'], 'userUid')
assert.deepEqual(User.$getRelation('posts')!.model, User)
})
})

test.group('Model | HasOne | Set Relations', (group) => {
Expand Down
22 changes: 22 additions & 0 deletions test/orm/model-many-to-many.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,28 @@ test.group('Model | ManyToMany | Options', (group) => {

assert.equal(User.$getRelation('skills')!['pivotRelatedForeignKey'], 'skill_uid')
})

test('clone relationship instance with options', (assert) => {
class Skill extends BaseModel {
@column({ isPrimary: true })
public id: number
}

class BaseUser extends BaseModel {
@column({ isPrimary: true })
public id: number

@manyToMany(() => Skill, { pivotRelatedForeignKey: 'skill_uid' })
public skills: ManyToMany<typeof Skill>
}

class User extends BaseUser {}
User.boot()
User.$getRelation('skills')!.boot()

assert.deepEqual(User.$getRelation('skills')!.model, User)
assert.equal(User.$getRelation('skills')!['pivotRelatedForeignKey'], 'skill_uid')
})
})

test.group('Model | ManyToMany | Set Relations', (group) => {
Expand Down

0 comments on commit 53a07df

Please sign in to comment.