diff --git a/README.md b/README.md index 9be953b..35cd632 100644 --- a/README.md +++ b/README.md @@ -81,15 +81,13 @@ This is useful when you want to cleanly disconnect from the database after all t ```ts import type { User } from './my-user-interface.js' -const UserFactory = defineFactory>(({ faker }) => ({ - tableName: 'user', - fields: { - email: faker.internet.email(), - referralCode: faker.random.alphaNumeric(6) - }, +const UserFactory = defineFactory>('user', ({ faker }) => ({ + email: faker.internet.email(), + referralCode: faker.random.alphaNumeric(6) })).build() ``` +The first parameter must be the table name. Make sure that you return an object with all the required properties, otherwise the database will raise not null exceptions. ## Using factories @@ -133,13 +131,10 @@ In the above example Factory states allow you to define variations of your factories as states. For example: On a Post factory, you can have different states to represent published and draft posts. ```ts -export const PostFactory = defineFactory>(({ faker }) => ({ - tableName: 'post', - fields: { - title: faker.lorem.sentence(), - content: faker.lorem.paragraphs(4), - status: 'DRAFT', - } +export const PostFactory = defineFactory>('post', ({ faker }) => ({ + title: faker.lorem.sentence(), + content: faker.lorem.paragraphs(4), + status: 'DRAFT', })) .state('published', (attributes) => ({ status: 'PUBLISHED', // 👈 @@ -159,26 +154,20 @@ await PostFactory.createMany(3) Model factories makes it super simple to work with relationships. Consider the following example: ```ts -export const PostFactory = defineFactory>(({ faker }) => ({ - tableName: 'post', - fields: { - title: faker.lorem.sentence(), - content: faker.lorem.paragraphs(4), - status: 'DRAFT', - } +export const PostFactory = defineFactory>('post', ({ faker }) => ({ + title: faker.lorem.sentence(), + content: faker.lorem.paragraphs(4), + status: 'DRAFT', })) .state('published', (attributes) => ({ status: 'PUBLISHED', // 👈 })) .build() -export const UserFactory = defineFactory>(({ faker }) => ({ - tableName: 'user', - fields: { - username: faker.internet.userName(), - email: faker.internet.email(), - password: faker.internet.password(), - } +export const UserFactory = defineFactory>('user', ({ faker }) => ({ + username: faker.internet.userName(), + email: faker.internet.email(), + password: faker.internet.password(), })) .hasMany('posts', { foreignKey: 'user_id', localKey: 'id', factory: () => PostFactory }) // 👈 .build() diff --git a/packages/core/src/builder/builder.ts b/packages/core/src/builder/builder.ts index cbb2e46..e310cf7 100644 --- a/packages/core/src/builder/builder.ts +++ b/packages/core/src/builder/builder.ts @@ -131,16 +131,12 @@ export class Builder< */ public async createMany(count: number): Promise { this.ensureFactoryConnectionIsSet(factorioConfig.knex) - let models: Record[] = [] - const { tableName } = this.factory.callback({ faker }) /** * Generate fields for each row by calling the factory callback */ - for (let i = 0; i < count; i++) { - models.push(this.factory.callback({ faker }).fields) - } + models = Array.from({ length: count }).map(() => this.factory.callback({ faker })) /** * Apply merge attributes @@ -167,7 +163,7 @@ export class Builder< */ const res = await factorioConfig .knex!.insert(decamelizeKeys(models)) - .into(tableName) + .into(this.factory.tableName) .returning('*') /** diff --git a/packages/core/src/contracts.ts b/packages/core/src/contracts.ts index dda4668..8e01878 100644 --- a/packages/core/src/contracts.ts +++ b/packages/core/src/contracts.ts @@ -9,10 +9,7 @@ type Optional = Pick, K> & Omit * Callback that must be passed to the `defineFactory` function. */ export type DefineFactoryCallback = (args: { faker: typeof faker }) => { - tableName: string - fields: { - [K in keyof T]: T[K] | (() => T[K] | Promise) - } + [K in keyof T]: T[K] | (() => T[K] | Promise) } /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2238dce..adf5c99 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -7,6 +7,12 @@ export { defineFactorioConfig } /** * Define a new factory. */ -export function defineFactory>(cb: DefineFactoryCallback) { - return new FactoryModel(cb) as Omit, 'callback' | 'states' | 'relations'> +export function defineFactory>( + table: string, + cb: DefineFactoryCallback +) { + return new FactoryModel(table, cb) as Omit< + FactoryModel, + 'callback' | 'states' | 'relations' + > } diff --git a/packages/core/src/model.ts b/packages/core/src/model.ts index 3c0a3a9..976a159 100644 --- a/packages/core/src/model.ts +++ b/packages/core/src/model.ts @@ -1,4 +1,3 @@ -import { faker } from '@faker-js/faker' import { Builder } from './builder/builder' import { RelationType } from './contracts' import type { @@ -24,15 +23,19 @@ export class FactoryModel, States extends stri */ public relations: Record = {} - constructor(callback: DefineFactoryCallback) { + /** + * The SQL table name for the model. + */ + public tableName: string + + constructor(tableName: string, callback: DefineFactoryCallback) { + this.tableName = tableName this.callback = callback } private addRelation(name: string, type: RelationType, meta: RelationshipMetaOptions) { - const { tableName } = this.callback({ faker }) - this.relations[name] = { - foreignKey: `${tableName}_id`, + foreignKey: `${this.tableName}_id`, localKey: 'id', ...meta, type, diff --git a/tests-helpers/setup.ts b/tests-helpers/setup.ts index f03f00e..7b7681c 100644 --- a/tests-helpers/setup.ts +++ b/tests-helpers/setup.ts @@ -1,26 +1,21 @@ import { defineFactory } from '@julr/factorio' -export const ProfileFactory = defineFactory(({ faker }) => ({ - tableName: 'profile', - fields: { - age: faker.datatype.number(), - email: faker.internet.email(), - }, +export const ProfileFactory = defineFactory('profile', ({ faker }) => ({ + age: faker.datatype.number(), + email: faker.internet.email(), })) .state('old', () => ({ age: '150' })) .state('admin', () => ({ email: 'admin@admin.com' })) .build() -export const PostFactory = defineFactory(({ faker }) => ({ - tableName: 'post', - fields: { title: faker.lorem.sentence() }, +export const PostFactory = defineFactory('post', ({ faker }) => ({ + title: faker.lorem.sentence(), })) .state('nodeArticle', () => ({ title: 'NodeJS' })) .build() -export const UserFactory = defineFactory(({ faker }) => ({ - tableName: 'user', - fields: { id: faker.datatype.number() }, +export const UserFactory = defineFactory('user', ({ faker }) => ({ + id: faker.datatype.number(), })) .state('easyPassword', () => ({ password: 'easy' })) .state('easyEmail', () => ({ email: 'easy@easy.com' })) @@ -28,14 +23,12 @@ export const UserFactory = defineFactory(({ faker }) => ({ .hasMany('posts', { foreignKey: 'user_id', localKey: 'id', factory: () => PostFactory }) .build() -export const AdminFactory = defineFactory(({ faker }) => ({ - tableName: 'admin', - fields: { id: faker.datatype.number() }, +export const AdminFactory = defineFactory('admin', ({ faker }) => ({ + id: faker.datatype.number(), })).build() -export const AccountFactory = defineFactory(({ faker }) => ({ - tableName: 'account', - fields: { name: faker.commerce.productName() }, +export const AccountFactory = defineFactory('account', ({ faker }) => ({ + name: faker.commerce.productName(), })) .belongsTo('user', { foreignKey: 'user_id', localKey: 'id', factory: () => UserFactory }) .belongsTo('admin', { foreignKey: 'admin_id', localKey: 'id', factory: () => AdminFactory }) diff --git a/tests/core.spec.ts b/tests/core.spec.ts index c730546..4e57490 100644 --- a/tests/core.spec.ts +++ b/tests/core.spec.ts @@ -4,9 +4,9 @@ import { defineFactory } from '@julr/factorio' import { DatabaseUtils } from '@julr/japa-database-plugin' import { setupDb } from '../tests-helpers/db.js' -const UserFactory = defineFactory(({ faker }) => ({ - tableName: 'user', - fields: { email: faker.internet.email(), password: faker.random.alphaNumeric(6) }, +const UserFactory = defineFactory('user', ({ faker }) => ({ + email: faker.internet.email(), + password: faker.random.alphaNumeric(6), })).build() test.group('factorio', (group) => { @@ -61,20 +61,14 @@ test.group('factorio', (group) => { }) test('create entity with nested inline relationship', async ({ expect, database }) => { - const userFactory = defineFactory(({ faker }) => ({ - tableName: 'user', - fields: { - email: faker.internet.email(), - password: faker.random.alphaNumeric(6), - }, + const userFactory = defineFactory('user', ({ faker }) => ({ + email: faker.internet.email(), + password: faker.random.alphaNumeric(6), })).build() - const postFactory = defineFactory(({ faker }) => ({ - tableName: 'post', - fields: { - title: faker.company.bs(), - userId: () => userFactory.create(), - }, + const postFactory = defineFactory('post', ({ faker }) => ({ + title: faker.company.bs(), + userId: () => userFactory.create(), })).build() const post = await postFactory.create() @@ -85,12 +79,9 @@ test.group('factorio', (group) => { }) test('factory with state', async ({ database }) => { - const userFactory = defineFactory(({ faker }) => ({ - tableName: 'user', - fields: { - email: 'bonjour', - password: faker.random.alphaNumeric(6), - }, + const userFactory = defineFactory('user', ({ faker }) => ({ + email: 'bonjour', + password: faker.random.alphaNumeric(6), })) .state('businessUser', (attributes) => ({ email: 'business@admin.com', diff --git a/tests/has_many.spec.ts b/tests/has_many.spec.ts index ef61d3c..28b9caa 100644 --- a/tests/has_many.spec.ts +++ b/tests/has_many.spec.ts @@ -81,19 +81,13 @@ test.group('HasMany', (group) => { }) test('auto detect foreign and primary keys', async ({ database }) => { - const postFactory = defineFactory(({ faker }) => ({ - tableName: 'post', - fields: { - title: faker.company.bs(), - }, + const postFactory = defineFactory('post', ({ faker }) => ({ + title: faker.company.bs(), })).build() - const userFactory = defineFactory(({ faker }) => ({ - tableName: 'user', - fields: { - email: faker.internet.email(), - password: faker.random.alphaNumeric(6), - }, + const userFactory = defineFactory('user', ({ faker }) => ({ + email: faker.internet.email(), + password: faker.random.alphaNumeric(6), })) .hasMany('post', { factory: () => postFactory }) .build()