Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add index and array based overrides for createMany and makeMany #185

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ new UserFactory().make({ email: '[email protected]' })
new UserFactory().makeMany(10, { email: '[email protected]' })
```

When making many entities, the details on each instance can be fine-tuned using a callback or an array syntax:
```ts
// each second user will be created with disabled flag set
new UserFactory().makeMany(10, [{ }, { disabled: true }])

// each second user will be created with disabled flag set, using a function syntax. The result will be similar to the above.
new UserFactory().makeMany(10, (index) => ({ disabled: Boolean(index % 2) }))
```

## `create` & `createMany`

the create and createMany method is similar to the make and makeMany method, but at the end the created entity instance gets persisted in the database using TypeORM entity manager.
Expand All @@ -145,6 +154,8 @@ new UserFactory().createMany(10, { email: '[email protected]' })
// using save options
new UserFactory().create({ email: '[email protected]' }, { listeners: false })
new UserFactory().createMany(10, { email: '[email protected]' }, { listeners: false })
new UserFactory().createMany(10, [{}, { disabled: true }])
new UserFactory().createMany(10, (index) => ({ disabled: Boolean(index % 2) }))
```

## `attrs`
Expand Down
22 changes: 13 additions & 9 deletions src/factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { DataSource, SaveOptions } from "typeorm";
import { EagerInstanceAttribute, LazyInstanceAttribute } from "./instanceAttributes";
import { BaseSubfactory } from "./subfactories";
import type { Constructable, FactorizedAttrs } from "./types";
import type { Constructable, FactorizedAttrs, SequenceAttrs } from "./types";

export abstract class Factory<T extends object> {
protected abstract entity: Constructable<T>;
Expand All @@ -25,10 +25,11 @@ export abstract class Factory<T extends object> {
/**
* Make many new entities without persisting it
*/
async makeMany(amount: number, overrideParams: Partial<FactorizedAttrs<T>> = {}): Promise<T[]> {
async makeMany(amount: number, overrideParams: SequenceAttrs<T> = {}): Promise<T[]> {
const list = [];
for (let index = 0; index < amount; index++) {
list[index] = await this.make(overrideParams);
const attrs = await this.getAttrsFromSequence(index, overrideParams);
list[index] = await this.make(attrs);
}
return list;
}
Expand All @@ -53,14 +54,11 @@ export abstract class Factory<T extends object> {
/**
* Create many new entities and persist them
*/
async createMany(
amount: number,
overrideParams: Partial<FactorizedAttrs<T>> = {},
saveOptions?: SaveOptions,
): Promise<T[]> {
async createMany(amount: number, overrideParams: SequenceAttrs<T> = {}, saveOptions?: SaveOptions): Promise<T[]> {
const list = [];
for (let index = 0; index < amount; index++) {
list[index] = await this.create(overrideParams, saveOptions);
const attrs = await this.getAttrsFromSequence(index, overrideParams);
list[index] = await this.create(attrs, saveOptions);
}
return list;
}
Expand Down Expand Up @@ -103,6 +101,12 @@ export abstract class Factory<T extends object> {
);
}

private async getAttrsFromSequence<T>(index: number, params: SequenceAttrs<T>): Promise<Partial<FactorizedAttrs<T>>> {
if (typeof params === "function") return params(index);
if (Array.isArray(params)) return params[index % params.length] ?? {};
return params;
}

private static async resolveValue(value: unknown, shouldPersist: boolean): Promise<unknown> {
if (value instanceof BaseSubfactory) {
return shouldPersist ? value.create() : value.make();
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export type InstanceAttributeCallback<T, V> = (entity: T) => FactorizedAttr<V>;
// Helper types
export type Constructable<T> = new () => T;
export type IsObject<T> = T extends object ? T : never;
export type GetChildAttrs<T> = (index: number) => Partial<FactorizedAttrs<T>>;
export type SequenceAttrs<T> = GetChildAttrs<T> | Partial<FactorizedAttrs<T>> | Partial<FactorizedAttrs<T>>[];
62 changes: 62 additions & 0 deletions test/factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,37 @@ describe(Factory, () => {
expect(entity.id).toBeUndefined();
}
});

test("Should make entities with array based overrideParams", async () => {
const count = 4;
const factory = new UserFactory();
const entitiesMaked = await factory.makeMany(count, [
{ email: "[email protected]" },
{ email: "[email protected]" },
]);

expect(entitiesMaked).toHaveLength(count);

for (let i = 0; i < count; i++) {
const entity = entitiesMaked[i] as User;
expect(entity.id).toBeUndefined();
expect(entity.email).toEqual(["[email protected]", "[email protected]"][i % 2]);
}
});

test("Should make entities with function based overrideParams", async () => {
const count = 4;
const factory = new UserFactory();
const entitiesMaked = await factory.makeMany(count, (index) => ({ email: `${index}@no-reply.bar` }));

expect(entitiesMaked).toHaveLength(count);

for (let i = 0; i < count; i++) {
const entity = entitiesMaked[i] as User;
expect(entity.id).toBeUndefined();
expect(entity.email).toEqual(`${i}@no-reply.bar`);
}
});
});

describe(Factory.prototype.create, () => {
Expand Down Expand Up @@ -324,5 +355,36 @@ describe(Factory, () => {
expect(entity.id).toBeDefined();
}
});

test("Should create entities with array based overrideParams", async () => {
const count = 4;
const factory = new UserFactory();
const entitiesCreated = await factory.createMany(count, [
{ email: "[email protected]" },
{ email: "[email protected]" },
]);

expect(entitiesCreated).toHaveLength(count);

for (let i = 0; i < count; i++) {
const entity = entitiesCreated[i] as User;
expect(entity.id).toBeDefined();
expect(entity.email).toEqual(["[email protected]", "[email protected]"][i % 2]);
}
});

test("Should create entities with function based overrideParams", async () => {
const count = 4;
const factory = new UserFactory();
const entitiesCreated = await factory.createMany(count, (index) => ({ email: `${index}@no-reply.bar` }));

expect(entitiesCreated).toHaveLength(count);

for (let i = 0; i < count; i++) {
const entity = entitiesCreated[i] as User;
expect(entity.id).toBeDefined();
expect(entity.email).toEqual(`${i}@no-reply.bar`);
}
});
});
});