Skip to content

Commit

Permalink
feat: add support for recursively merging attributes from factories
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed May 19, 2022
1 parent 0ecf89a commit 8f708b3
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 5 deletions.
11 changes: 11 additions & 0 deletions adonis-typings/factory.ts
Expand Up @@ -150,6 +150,11 @@ declare module '@ioc:Adonis/Lucid/Factory' {
*/
relation: RelationshipsContract

/**
* Merge attributes with the relationship and its children
*/
merge(attributes: any): this

/**
* Define custom pivot attributes for many to many
* relationship
Expand Down Expand Up @@ -236,6 +241,12 @@ declare module '@ioc:Adonis/Lucid/Factory' {
*/
merge(attributes: OneOrMany<ExtractFactoryAttributes<FactoryModel>>): this

/**
* Merge custom set of attributes with the correct factory builder
* model and all of its relationships as well
*/
mergeRecursive(attributes: any): this

/**
* Define custom runtime context. This method is usually called by
* the relationships to ensure a single context is used by the
Expand Down
39 changes: 35 additions & 4 deletions src/Factory/FactoryBuilder.ts
Expand Up @@ -61,6 +61,11 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
*/
private attributes: any = {}

/**
* Custom attributes to pass to relationship merge methods
*/
private recursiveAttributes: any = {}

/**
* States to apply. One state can be applied only once and hence
* a set is used.
Expand Down Expand Up @@ -114,7 +119,15 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
* Returns attributes to merge for a given index
*/
private getMergeAttributes(index: number) {
return Array.isArray(this.attributes) ? this.attributes[index] : this.attributes
const attributes = Array.isArray(this.attributes) ? this.attributes[index] : this.attributes
const recursiveAttributes = Array.isArray(this.recursiveAttributes)
? this.recursiveAttributes[index]
: this.recursiveAttributes

return {
...recursiveAttributes,
...attributes,
}
}

/**
Expand Down Expand Up @@ -200,12 +213,18 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
private async makeRelations(modelInstance: LucidRow, ctx: FactoryContextContract) {
for (let { name, count, callback } of this.withBelongsToRelations) {
const relation = this.factory.getRelation(name)
await relation.useCtx(ctx).make(modelInstance, callback, count)
await relation
.useCtx(ctx)
.merge(this.recursiveAttributes)
.make(modelInstance, callback, count)
}

for (let { name, count, callback } of this.withRelations) {
const relation = this.factory.getRelation(name)
await relation.useCtx(ctx).make(modelInstance, callback, count)
await relation
.useCtx(ctx)
.merge(this.recursiveAttributes)
.make(modelInstance, callback, count)
}
}

Expand All @@ -221,7 +240,10 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra

for (let { name, count, callback } of relationships) {
const relation = this.factory.getRelation(name)
await relation.useCtx(ctx).create(modelInstance, callback, count)
await relation
.useCtx(ctx)
.merge(this.recursiveAttributes)
.create(modelInstance, callback, count)
}
}

Expand Down Expand Up @@ -329,6 +351,15 @@ export class FactoryBuilder implements FactoryBuilderContract<FactoryModelContra
return this
}

/**
* Merge custom set of attributes with the correct factory builder
* model and all of its relationships as well
*/
public mergeRecursive(attributes: any): this {
this.recursiveAttributes = attributes
return this
}

/**
* Define pivot attributes when persisting a many to many
* relationship. Results in a noop, when not called
Expand Down
3 changes: 3 additions & 0 deletions src/Factory/FactoryModel.ts
Expand Up @@ -235,6 +235,9 @@ export class FactoryModel<Model extends LucidModel> implements FactoryModelContr
merge(attributes) {
return this.query().merge(attributes)
},
mergeRecursive(attributes) {
return this.query().mergeRecursive(attributes)
},
useCtx(ctx) {
return this.query().useCtx(ctx)
},
Expand Down
11 changes: 10 additions & 1 deletion src/Factory/Relations/Base.ts
Expand Up @@ -21,6 +21,7 @@ import {
*/
export abstract class BaseRelation {
protected ctx: FactoryContextContract
private attributes: any = {}

constructor(
private factory: () => FactoryBuilderQueryContract<FactoryModelContract<LucidModel>>
Expand All @@ -35,10 +36,18 @@ export abstract class BaseRelation {
callback(builder)
}

builder.useCtx(this.ctx)
builder.useCtx(this.ctx).mergeRecursive(this.attributes)
return builder
}

/**
* Merge attributes with the relationship and its children
*/
public merge(attributes: any) {
this.attributes = attributes
return this
}

/**
* Use custom ctx. This must always be called by the factory, otherwise
* `make` and `create` calls will fail.
Expand Down
3 changes: 3 additions & 0 deletions test-helpers/index.ts
Expand Up @@ -157,6 +157,7 @@ export async function setup(destroyDb: boolean = true) {
await db.schema.createTable('users', (table) => {
table.increments()
table.integer('country_id')
table.integer('tenant_id').nullable()
table.string('username').unique()
table.string('email').unique()
table.integer('points').defaultTo(0)
Expand Down Expand Up @@ -232,6 +233,7 @@ export async function setup(destroyDb: boolean = true) {
await db.schema.createTable('posts', (table) => {
table.increments()
table.integer('user_id')
table.integer('tenant_id').nullable()
table.string('title').notNullable()
table.boolean('is_published').defaultTo(false)
table.timestamps()
Expand All @@ -242,6 +244,7 @@ export async function setup(destroyDb: boolean = true) {
if (!hasComments) {
await db.schema.createTable('comments', (table) => {
table.increments()
table.integer('tenant_id').nullable()
table.integer('post_id')
table.string('body')
table.timestamps()
Expand Down

0 comments on commit 8f708b3

Please sign in to comment.