diff --git a/src/factory.ts b/src/factory.ts new file mode 100644 index 0000000..42be3f9 --- /dev/null +++ b/src/factory.ts @@ -0,0 +1,49 @@ +import { ResolvedFields, DefaultFieldsResolver, InputFieldsResolver, resolveFields } from './field-resolver.js'; +import { getSequenceCounter, resetSequence } from './sequence.js'; +import { Merge } from './util.js'; + +export interface TypeFactoryDefineOptions< + Type extends Record, + TransientFields extends Record, +> { + defaultFields: DefaultFieldsResolver; +} +export interface TypeFactoryInterface< + Type extends Record, + TransientFields extends Record, + Options extends TypeFactoryDefineOptions, +> { + build(): Promise, ResolvedFields<{}>>, keyof Type>>; + build>( + inputFieldsResolver: T, + ): Promise, ResolvedFields>, keyof Type>>; + resetSequence(): void; +} + +export function defineTypeFactoryInternal< + Type extends Record, + TransientFields extends Record, + Options extends TypeFactoryDefineOptions, +>( + typeFieldNames: readonly (keyof Type)[], + { defaultFields: defaultFieldsResolver }: Options, +): TypeFactoryInterface { + const seqKey = {}; + const getSeq = () => getSequenceCounter(seqKey); + return { + async build>( + inputFieldsResolver?: T, + ): Promise, ResolvedFields>, keyof Type>> { + const seq = getSeq(); + return resolveFields( + typeFieldNames, + seq, + defaultFieldsResolver, + inputFieldsResolver ?? ({} as T), + ); + }, + resetSequence() { + resetSequence(seqKey); + }, + }; +} diff --git a/src/field-resolver.ts b/src/field-resolver.ts index de6509c..1e5dd83 100644 --- a/src/field-resolver.ts +++ b/src/field-resolver.ts @@ -31,12 +31,7 @@ export type DefaultFieldsResolver = { >; }; /** The type of `inputFields` option of `build` method. */ -export type InputFieldsResolver = { - [FieldName in keyof TypeWithTransientFields]?: FieldResolver< - TypeWithTransientFields, - DeepReadonly[FieldName]> - >; -}; +export type InputFieldsResolver = Partial>; // eslint-disable-next-line @typescript-eslint/no-unused-vars export type ResolvedField> = T extends FieldResolver diff --git a/src/index.ts b/src/index.ts index e979e6a..8e48ac1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,6 @@ -import { - type ResolvedFields, - type DefaultFieldsResolver, - type InputFieldsResolver, - resolveFields, - lazy, -} from './field-resolver.js'; -import { getSequenceCounter, resetSequence, resetAllSequence } from './sequence.js'; -import { type Merge } from './util.js'; +import { TypeFactoryDefineOptions, TypeFactoryInterface, defineTypeFactoryInternal } from './factory.js'; +import { lazy } from './field-resolver.js'; +import { resetAllSequence } from './sequence.js'; export { resetAllSequence, lazy }; @@ -32,43 +26,14 @@ const UserFieldNames = ['id', 'firstName', 'lastName', 'fullName'] as const; // ---------- Book ---------- -export interface BookFactoryDefineOptions> { - defaultFields: DefaultFieldsResolver; -} -export interface BookFactoryInterface< +export type BookFactoryDefineOptions> = TypeFactoryDefineOptions< + Book, + TransientFields +>; +export type BookFactoryInterface< TransientFields extends Record, Options extends BookFactoryDefineOptions, -> { - build(): Promise, ResolvedFields<{}>>, keyof Book>>; - build>( - inputFieldsResolver: T, - ): Promise, ResolvedFields>, keyof Book>>; - resetSequence(): void; -} - -function defineBookFactoryInternal< - TransientFields extends Record, - Options extends BookFactoryDefineOptions, ->({ defaultFields: defaultFieldsResolver }: Options): BookFactoryInterface { - const seqKey = {}; - const getSeq = () => getSequenceCounter(seqKey); - return { - async build>( - inputFieldsResolver?: T, - ): Promise, ResolvedFields>, keyof Book>> { - const seq = getSeq(); - return resolveFields( - BookFieldNames, - seq, - defaultFieldsResolver, - inputFieldsResolver ?? ({} as T), - ); - }, - resetSequence() { - resetSequence(seqKey); - }, - }; -} +> = TypeFactoryInterface; /** * Define factory for {@link Book} model. @@ -79,48 +44,19 @@ function defineBookFactoryInternal< export function defineBookFactory>( options: Options, ): BookFactoryInterface<{}, Options> { - return defineBookFactoryInternal(options); + return defineTypeFactoryInternal(BookFieldNames, options); } // ---------- Author ---------- -export interface AuthorFactoryDefineOptions> { - defaultFields: DefaultFieldsResolver; -} -export interface AuthorFactoryInterface< - TransientFields extends Record, - Options extends AuthorFactoryDefineOptions, -> { - build(): Promise, ResolvedFields<{}>>, keyof Author>>; - build>( - inputFieldsResolver: T, - ): Promise, ResolvedFields>, keyof Author>>; - resetSequence(): void; -} - -function defineAuthorFactoryInternal< +export type AuthorFactoryDefineOptions> = TypeFactoryDefineOptions< + Author, + TransientFields +>; +export type AuthorFactoryInterface< TransientFields extends Record, Options extends AuthorFactoryDefineOptions, ->({ defaultFields: defaultFieldsResolver }: Options): AuthorFactoryInterface { - const seqKey = {}; - const getSeq = () => getSequenceCounter(seqKey); - return { - async build>( - inputFieldsResolver?: T, - ): Promise, ResolvedFields>, keyof Author>> { - const seq = getSeq(); - return resolveFields( - AuthorFieldNames, - seq, - defaultFieldsResolver, - inputFieldsResolver ?? ({} as T), - ); - }, - resetSequence() { - resetSequence(seqKey); - }, - }; -} +> = TypeFactoryInterface; /** * Define factory for {@link Author} model. @@ -131,48 +67,19 @@ function defineAuthorFactoryInternal< export function defineAuthorFactory>( options: Options, ): AuthorFactoryInterface<{}, Options> { - return defineAuthorFactoryInternal(options); + return defineTypeFactoryInternal(AuthorFieldNames, options); } // ---------- User ---------- -export interface UserFactoryDefineOptions> { - defaultFields: DefaultFieldsResolver; -} -export interface UserFactoryInterface< +export type UserFactoryDefineOptions> = TypeFactoryDefineOptions< + User, + TransientFields +>; +export type UserFactoryInterface< TransientFields extends Record, Options extends UserFactoryDefineOptions, -> { - build(): Promise, ResolvedFields<{}>>, keyof User>>; - build>( - inputFieldsResolver: T, - ): Promise, ResolvedFields>, keyof User>>; - resetSequence(): void; -} - -function defineUserFactoryInternal< - TransientFields extends Record, - Options extends UserFactoryDefineOptions, ->({ defaultFields: defaultFieldsResolver }: Options): UserFactoryInterface { - const seqKey = {}; - const getSeq = () => getSequenceCounter(seqKey); - return { - async build>( - inputFieldsResolver?: T, - ): Promise, ResolvedFields>, keyof User>> { - const seq = getSeq(); - return resolveFields( - UserFieldNames, - seq, - defaultFieldsResolver, - inputFieldsResolver ?? ({} as T), - ); - }, - resetSequence() { - resetSequence(seqKey); - }, - }; -} +> = TypeFactoryInterface; /** * Define factory for {@link User} model. @@ -183,5 +90,5 @@ function defineUserFactoryInternal< export function defineUserFactory>( options: Options, ): UserFactoryInterface<{}, Options> { - return defineUserFactoryInternal(options); + return defineTypeFactoryInternal(UserFieldNames, options); }