From cd02b06f9e7da522ddd7f8cb4efd2a4ee2f4a3a4 Mon Sep 17 00:00:00 2001 From: Julien Date: Tue, 20 Sep 2022 23:20:22 +0200 Subject: [PATCH] feat: add custom casing strategy --- README.md | 21 ++++++++++++++++++++- packages/core/src/builder/builder.ts | 8 +++----- packages/core/src/config.ts | 5 +++++ packages/core/src/contracts.ts | 21 +++++++++++++++++++++ packages/core/src/utils.ts | 14 ++++++++++++++ 5 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/utils.ts diff --git a/README.md b/README.md index 35cd632..f9cba9f 100644 --- a/README.md +++ b/README.md @@ -43,13 +43,15 @@ Integrations for some test runners are available below : - [Japa](./packages/japa-plugin/) - [Vitest](./packages/vitest-plugin/) ( 🚧 Coming soon ) -## Defining database connection +## Defining configuration and database connection Before running your tests, you must initialize Factorio with your database configuration. This must be done **BEFORE** creating models via Factorio. In general, you can use the setup files system provided by the test runners. ```ts +import { defineFactorioConfig } from '@julr/factorio' + const disconnect = defineFactorioConfig({ // Can also specify a locale for faker locale: 'fr', @@ -76,6 +78,23 @@ This is useful when you want to cleanly disconnect from the database after all t > **Note**: You don't need to do this manually if you are using a test runner integration. +### Casing Strategy +You can also define a specific casing strategy. By default, Factorio convert all keys to `snake_case` before inserting the models into the database. And before returning the model, it converts all keys to `camelCase`. + +```ts +import { defineFactorioConfig } from '@julr/factorio' + +defineFactorioConfig({ + casing: { + // Convert all keys to snake_case before inserting into the database + insert: 'snake', + + // Convert all keys to camelCase before returning the models + return: 'camel', + } +}) +``` + ## Creating factories ```ts diff --git a/packages/core/src/builder/builder.ts b/packages/core/src/builder/builder.ts index e310cf7..94eb696 100644 --- a/packages/core/src/builder/builder.ts +++ b/packages/core/src/builder/builder.ts @@ -1,15 +1,13 @@ import { faker } from '@faker-js/faker' import defu from 'defu' -import humps from 'humps' import { factorioConfig } from '../config' +import { convertCase } from '../utils' import { RelationshipBuilder } from './relationship_builder' import { StatesManager } from './states_manager' import type { FactoryModel } from '../model' import type { FactoryExtractGeneric, WithCallback } from '../contracts' import type { Knex } from 'knex' -const { camelizeKeys, decamelizeKeys } = humps - export class Builder< Factory extends FactoryModel, Model extends Record = FactoryExtractGeneric, @@ -162,7 +160,7 @@ export class Builder< * Insert rows */ const res = await factorioConfig - .knex!.insert(decamelizeKeys(models)) + .knex!.insert(convertCase(models, factorioConfig.casing.insert)) .into(this.factory.tableName) .returning('*') @@ -178,6 +176,6 @@ export class Builder< this.resetBuilder() - return finalModels.map((model) => camelizeKeys(model)) as Model[] + return finalModels.map((model) => convertCase(model, factorioConfig.casing.return)) as Model[] } } diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 52712f5..57b41ce 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -9,6 +9,10 @@ import type { FactorioConfig } from './contracts' */ export const factorioConfig = { knex: null as Knex | null, + casing: { + insert: 'snake', + return: 'camel', + } as NonNullable, } /** @@ -20,6 +24,7 @@ export const defineFactorioConfig = (options: FactorioConfig & { locale?: Usable faker.locale = options.locale || faker.locale factorioConfig.knex = knex(options.database) + factorioConfig.casing = options.casing || factorioConfig.casing return () => { if (factorioConfig.knex) { diff --git a/packages/core/src/contracts.ts b/packages/core/src/contracts.ts index 8e01878..cde2212 100644 --- a/packages/core/src/contracts.ts +++ b/packages/core/src/contracts.ts @@ -5,6 +5,8 @@ import type { Knex } from 'knex' type Optional = Pick, K> & Omit +export type CasingStrategy = 'camel' | 'snake' | 'none' + /** * Callback that must be passed to the `defineFactory` function. */ @@ -22,6 +24,25 @@ export type DefineStateCallback = (attributes: T) => Partial */ export interface FactorioConfig { database: Knex.Config + + /** + * Configure the casing conversion for the database operations + */ + casing?: { + /** + * Casing to which the keys will be converted before inserting into the database + * + * Default: `snake` + */ + insert: CasingStrategy + + /** + * Casing to which the keys will be converted before returning + * + * Default: `camel` + */ + return: CasingStrategy + } } /** diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts new file mode 100644 index 0000000..887196c --- /dev/null +++ b/packages/core/src/utils.ts @@ -0,0 +1,14 @@ +import humps from 'humps' +import type { CasingStrategy } from './contracts.js' + +export function convertCase(obj: Record, casing: CasingStrategy) { + if (casing === 'camel') { + return humps.camelizeKeys(obj) + } + + if (casing === 'snake') { + return humps.decamelizeKeys(obj) + } + + return obj +}