@joakimbugge/typeorm-seeder 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +14 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -79,7 +79,7 @@ async function createOneSeed(EntityClass, context) {
|
|
|
79
79
|
const record = instance;
|
|
80
80
|
for (const { propertyKey, factory } of getSeeds(EntityClass)) {
|
|
81
81
|
if (!factory) continue;
|
|
82
|
-
record[propertyKey] = await factory(context);
|
|
82
|
+
record[propertyKey] = await factory(context, instance);
|
|
83
83
|
seededProperties.add(propertyKey);
|
|
84
84
|
}
|
|
85
85
|
for (const embedded of storage.filterEmbeddeds(EntityClass)) {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["registry","DepGraph"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport { getSeeds } from './registry.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManySeedOptions extends SeedContext {\n count: number;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOneSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createManySeed(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOneSeed(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function createSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context?: SeedContext,\n): Promise<T>;\nexport async function createSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function createSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n context: SeedContext = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOneSeed(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const [entity] = await createManySeed(classOrClasses as EntityConstructor<T>, {\n count: 1,\n ...context,\n });\n\n return entity!;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManySeedOptions,\n): Promise<T[]>;\nexport async function createManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, ...context }: CreateManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n return await Promise.all(\n Array.from({ length: count }, () =>\n createOneSeed(classOrClasses as EntityConstructor<T>, context),\n ),\n );\n}\n","import { type DataSource } from 'typeorm';\n\nimport { createManySeed } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\n/** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */\nexport interface SaveManySeedOptions extends SaveSeedOptions {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n * Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.\n */\nexport async function saveSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveSeedOptions,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveSeedOptions,\n): Promise<MapToInstances<T>>;\nexport async function saveSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveSeedOptions,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveManySeed(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveManySeed(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link saveSeed} for each entity.\n */\nexport async function saveManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveManySeedOne(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveManySeedOne(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class.\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveManySeedOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createManySeed(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import { createManySeed, createSeed } from './creator.js';\nimport { saveManySeed, saveSeed } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\nimport type { SaveSeedOptions } from './persist.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: SeedContext): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveSeedOptions): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveSeedOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n createSeed(classes as [...typeof classes], context) as Promise<\n MapToInstances<typeof classes>\n >,\n save: (options: SaveSeedOptions) =>\n saveSeed(classes as [...typeof classes], options) as Promise<\n MapToInstances<typeof classes>\n >,\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(classes as [...typeof classes], { count, ...options }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (context?: SeedContext) => createSeed(EntityClass, context),\n save: (options: SaveSeedOptions) => saveSeed(EntityClass, options),\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(EntityClass, { count, ...context }),\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["registry","DepGraph"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/**\n * Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.\n *\n * Properties are seeded sequentially in declaration order, so any property declared above the\n * current one is already set on `self` and can be read to derive the current value:\n *\n * @example\n * @Seed(() => faker.date.past())\n * beginDate!: Date\n *\n * @Seed((_, self) => faker.date.future({ refDate: (self as MyEntity).beginDate }))\n * endDate!: Date\n */\nexport type SeedFactory<T = unknown> = (\n context: SeedContext,\n self: EntityInstance,\n) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport { getSeeds } from './registry.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManySeedOptions extends SeedContext {\n count: number;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOneSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context, instance);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createManySeed(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOneSeed(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function createSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context?: SeedContext,\n): Promise<T>;\nexport async function createSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function createSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n context: SeedContext = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOneSeed(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const [entity] = await createManySeed(classOrClasses as EntityConstructor<T>, {\n count: 1,\n ...context,\n });\n\n return entity!;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManySeedOptions,\n): Promise<T[]>;\nexport async function createManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, ...context }: CreateManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n return await Promise.all(\n Array.from({ length: count }, () =>\n createOneSeed(classOrClasses as EntityConstructor<T>, context),\n ),\n );\n}\n","import { type DataSource } from 'typeorm';\n\nimport { createManySeed } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\n/** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */\nexport interface SaveManySeedOptions extends SaveSeedOptions {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n * Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.\n */\nexport async function saveSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveSeedOptions,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveSeedOptions,\n): Promise<MapToInstances<T>>;\nexport async function saveSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveSeedOptions,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveManySeed(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveManySeed(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link saveSeed} for each entity.\n */\nexport async function saveManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveManySeedOne(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveManySeedOne(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class.\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveManySeedOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createManySeed(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import { createManySeed, createSeed } from './creator.js';\nimport { saveManySeed, saveSeed } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\nimport type { SaveSeedOptions } from './persist.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: SeedContext): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveSeedOptions): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveSeedOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n createSeed(classes as [...typeof classes], context) as Promise<\n MapToInstances<typeof classes>\n >,\n save: (options: SaveSeedOptions) =>\n saveSeed(classes as [...typeof classes], options) as Promise<\n MapToInstances<typeof classes>\n >,\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(classes as [...typeof classes], { count, ...options }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (context?: SeedContext) => createSeed(EntityClass, context),\n save: (options: SaveSeedOptions) => saveSeed(EntityClass, options),\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(EntityClass, { count, ...context }),\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":";;;;AA0EA,MAAMA,6BAAW,IAAI,KAA4B;;AAGjD,SAAgB,aAAa,QAAkB,OAAwB;CACrE,MAAM,UAAUA,WAAS,IAAI,OAAO,IAAI,EAAE;AAE1C,SAAQ,KAAK,MAAM;AACnB,YAAS,IAAI,QAAQ,QAAQ;;;;;;AAO/B,SAAgB,SAAS,QAA+B;CACtD,MAAM,UAAuB,EAAE;CAC/B,IAAI,UAAoB;AAExB,QAAO,WAAW,YAAY,SAAS,WAAW;EAChD,MAAM,MAAMA,WAAS,IAAI,QAAQ;AAEjC,MAAI,IACF,SAAQ,QAAQ,GAAG,IAAI;AAGzB,YAAU,OAAO,eAAe,QAAQ;;AAG1C,QAAO;;;;ACzDT,SAAgB,KACd,kBACA,SACmB;CACnB,MAAM,UAAU,OAAO,qBAAqB,aAAa,mBAAmB,KAAA;CAC5E,MAAM,QACH,OAAO,qBAAqB,WAAW,mBAAmB,YAAY,EAAE;AAE3E,SAAQ,QAAQ,gBAAgB;AAC9B,eAAa,OAAO,aAAyB;GAAE;GAAa;GAAS,SAAS;GAAM,CAAC;;;;;;ACjCzF,SAAS,aAAa,SAAqC;AACzD,QAAQ,QAA4B,8BAAc,IAAI,KAAK;;;AAI7D,SAAS,aAAa,SAAsB,KAAgC;CAC1E,MAAM,YAAY,aAAa,QAAQ;AAEvC,QAAO;EAAE,GAAG;EAAS,YAAY,IAAI,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC;EAAE;;;AAIjE,SAAS,kBAAkB,QAA8B;CACvD,MAAM,YAAwB,EAAE;CAChC,IAAI,UAAoB;AAExB,QAAO,WAAW,YAAY,SAAS,WAAW;AAChD,YAAU,KAAK,QAAQ;AACvB,YAAU,OAAO,eAAe,QAAQ;;AAG1C,QAAO;;;;;;;;;;;AAYT,eAAe,cACb,aACA,SACY;CACZ,MAAM,WAAW,IAAI,aAAa;CAClC,MAAM,YAAY,aAAa,QAAQ;CACvC,MAAM,eAAe,aAAa,SAAS,YAAY;CACvD,MAAM,WAAA,GAAA,QAAA,yBAAkC;CACxC,MAAM,YAAY,QAAQ,gBAAgB,kBAAkB,YAAY,CAAC;CACzE,MAAM,mCAAmB,IAAI,KAAsB;CACnD,MAAM,SAAS;AAGf,MAAK,MAAM,EAAE,aAAa,aAAa,SAAS,YAAY,EAAE;AAC5D,MAAI,CAAC,QACH;AAGF,SAAO,eAAe,MAAM,QAAQ,SAAS,SAAS;AACtD,mBAAiB,IAAI,YAAY;;AAInC,MAAK,MAAM,YAAY,QAAQ,gBAAgB,YAAY,EAAE;AAC3D,MAAI,iBAAiB,IAAI,SAAS,aAAa,CAC7C;EAGF,MAAM,gBAAgB,SAAS,MAAM;AAErC,MAAI,SAAS,cAAc,CAAC,SAAS,GAAG;AACtC,UAAO,SAAS,gBAAgB,MAAM,cAAc,eAAe,QAAQ;AAC3E,oBAAiB,IAAI,SAAS,aAAa;;;AAS/C,KAAI,QAAQ,cAAc,MACxB,QAAO;AAGT,MAAK,MAAM,EAAE,aAAa,SAAS,aAAa,SAAS,YAAY,EAAE;AACrE,MAAI,WAAW,iBAAiB,IAAI,YAAY,CAC9C;EAGF,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,iBAAiB,OAAO,YAAY,CAAC;AAE9E,MAAI,CAAC,YAAY,OAAO,SAAS,SAAS,WACxC;EAGF,MAAM,eAAgB,SAAS,MAAyB;AAExD,MAAI,UAAU,IAAI,aAAa,CAC7B;AAMF,MAFE,SAAS,iBAAiB,iBAAiB,SAAS,iBAAiB,eAGrE,QAAO,eAAe,MAAM,eAAe,cAAc;GACvD,OAAO,QAAQ,SAAS;GACxB,GAAG;GACJ,CAAC;MAEF,QAAO,eAAe,MAAM,cAAc,cAAc,aAAa;AAGvE,mBAAiB,IAAI,YAAY;;AAGnC,QAAO;;AAkBT,eAAsB,WACpB,gBACA,UAAuB,EAAE,EACM;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,cAAc,KAAK,iBAAiB,CAAC,CAC3F;;CAGH,MAAM,CAAC,UAAU,MAAM,eAAe,gBAAwC;EAC5E,OAAO;EACP,GAAG;EACJ,CAAC;AAEF,QAAO;;AAkBT,eAAsB,eACpB,gBACA,EAAE,OAAO,GAAG,WACuB;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAgC;GAAE,WAAW;GAAO,GAAG;GAAS;AAEtE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAC3C,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,OAAO,QAAQ,cAAc,KAAK,iBAAiB,CAAC,CAAC,CACvF,CACF;;AAGH,QAAO,MAAM,QAAQ,IACnB,MAAM,KAAK,EAAE,QAAQ,OAAO,QAC1B,cAAc,gBAAwC,QAAQ,CAC/D,CACF;;;;;;;;;ACrKH,SAAS,qBAAqB,QAAwB,0BAAU,IAAI,KAAe,EAAc;CAC/F,MAAM,cAAc,OAAO;AAE3B,KAAI,QAAQ,IAAI,YAAY,CAC1B,QAAO,EAAE;AAGX,SAAQ,IAAI,YAAY;CAExB,MAAM,UAAsB,CAAC,YAAY;AAEzC,MAAK,MAAM,SAAS,OAAO,OAAO,OAAO,CACvC,KAAI,MAAM,QAAQ,MAAM;OACjB,MAAM,QAAQ,MACjB,KAAI,QAAQ,OAAO,SAAS,YAAY,KAAK,gBAAgB,OAC3D,SAAQ,KAAK,GAAG,qBAAqB,MAAM,QAAQ,CAAC;YAG/C,SAAS,OAAO,UAAU,YAAY,MAAM,gBAAgB,OACrE,SAAQ,KAAK,GAAG,qBAAqB,OAAyB,QAAQ,CAAC;AAI3E,QAAO;;;;;;;;;;;;AAaT,SAAS,oBAAoB,aAAuB,YAAwC;CAC1F,MAAM,SAAyB,EAAE;AAEjC,KAAI;EACF,MAAM,YAAY,WAAW,YAAY,YAAY,CAAC;AAEtD,OAAK,MAAM,YAAY,WAAW;AAChC,UAAO,KAAK;IAAE;IAAU,UAAU,SAAS;IAAiB,CAAC;AAC7D,YAAS,kBAAkB;;SAEvB;AAIR,QAAO;;;;;;AAOT,SAAS,eAAe,QAA8B;AACpD,MAAK,MAAM,EAAE,UAAU,cAAc,OACnC,UAAS,kBAAkB;;AAoB/B,eAAsB,SACpB,gBACA,SAC+B;AAC/B,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS,OAAO;GAAG;AAEnE,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAC3C,aAAa,KAAK,iBAAiB,CAAC,MAAM,CAAC,YAAY,OAAQ,CAChE,CACF;;CAGH,MAAM,CAAC,UAAU,MAAM,aAAa,gBAAwC;EAC1E,GAAG;EACH,OAAO;EACR,CAAC;AAEF,QAAO;;AAmBT,eAAsB,aACpB,gBACA,SACmC;AACnC,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,mBAAmB;GAAE,WAAW;GAAO,GAAG;GAAS;AAEzD,SAAQ,MAAM,QAAQ,IACnB,eAAuC,KAAK,QAAQ,gBAAgB,KAAK,iBAAiB,CAAC,CAC7F;;AAGH,QAAO,MAAM,gBAAgB,gBAAwC,QAAQ;;;;;;;AAQ/E,eAAe,gBACb,aACA,SACc;CACd,MAAM,EAAE,OAAO,eAAe;AAE9B,KAAI,UAAU,EACZ,QAAO,EAAE;CAGX,MAAM,WAAW,MAAM,eAAe,aAAa,QAAQ;CAE3D,MAAM,0BAAU,IAAI,KAAe;CACnC,MAAM,SAAS,SACZ,SAAS,WAAW,qBAAqB,QAAQ,QAAQ,CAAC,CAC1D,SAAS,QAAQ,oBAAoB,KAAK,WAAW,CAAC;AAEzD,KAAI;AACF,SAAQ,MAAM,WAAW,cAAc,YAAY,CAAC,KAAK,SAAS;WAC1D;AACR,iBAAe,OAAO;;;;;ACnI1B,SAAgB,KACd,gBACyD;AACzD,KAAI,MAAM,QAAQ,eAAe,EAAE;EACjC,MAAM,UAAU;AAEhB,SAAO;GACL,SAAS,YACP,WAAW,SAAgC,QAAQ;GAGrD,OAAO,YACL,SAAS,SAAgC,QAAQ;GAGnD,aAAa,OAAe,YAC1B,eAAe,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGvE,WAAW,OAAe,YACxB,aAAa,SAAgC;IAAE;IAAO,GAAG;IAAS,CAAC;GAGtE;;CAGH,MAAM,cAAc;AAEpB,QAAO;EACL,SAAS,YAA0B,WAAW,aAAa,QAAQ;EACnE,OAAO,YAA6B,SAAS,aAAa,QAAQ;EAClE,aAAa,OAAe,YAC1B,eAAe,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACpD,WAAW,OAAe,YACxB,aAAa,aAAa;GAAE;GAAO,GAAG;GAAS,CAAC;EACnD;;;;AC9FH,MAAM,2BAAW,IAAI,SAA+B;;AAGpD,SAAgB,eAAe,QAAkB,MAAwB;AACvE,UAAS,IAAI,QAAQ,KAAK;;;AAI5B,SAAgB,cAAc,QAA0C;AACtE,QAAO,SAAS,IAAI,OAAO;;;;;;;;;;;;;;;;;;ACyB7B,SAAgB,OAAO,UAAyB,EAAE,EAAkB;AAClE,SAAQ,WAAW;AACjB,iBAAe,QAAQ,EAAE,cAAc,QAAQ,gBAAgB,EAAE,EAAE,CAAC;;;;;;;;;;;ACPxE,SAAS,SAAS,OAAmC;CACnD,MAAM,QAAQ,IAAIC,iBAAAA,UAAsB;CACxC,MAAM,yBAAS,IAAI,KAAyB;CAG5C,MAAM,0BAAU,IAAI,KAAiB;CACrC,MAAM,QAAsB,CAAC,GAAG,MAAM;AAEtC,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,OAAO,MAAM,OAAO;AAE1B,MAAI,QAAQ,IAAI,KAAK,CACnB;AAGF,UAAQ,IAAI,KAAK;AACjB,QAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,SAAO,IAAI,KAAK,MAAM,KAAK;AAE3B,OAAK,MAAM,OAAQ,cAAc,KAAK,EAAE,gBAAgB,EAAE,CACxD,OAAM,KAAK,IAAI;;AAKnB,MAAK,MAAM,QAAQ,QACjB,MAAK,MAAM,OAAQ,cAAc,KAAK,EAAE,gBAAgB,EAAE,CACxD,OAAM,cAAc,KAAK,MAAM,IAAI,KAAK;AAI5C,KAAI;AACF,SAAO,MAAM,cAAc,CAAC,KAAK,SAAS,OAAO,IAAI,KAAK,CAAE;UACrD,KAAK;AACZ,MAAI,OAAO,OAAO,QAAQ,YAAY,eAAe,KAAK;GACxD,MAAM,OAAQ,IAAgC,UAAU,KAAK,MAAM;AACnE,SAAM,IAAI,MAAM,+CAA+C,OAAO;;AAGxE,QAAM;;;;;;;;;;;;;;;;;;;;;AAsBV,eAAsB,WACpB,SACA,UAA6B,EAAE,EAChB;CACf,MAAM,EAAE,UAAU,MAAM,UAAU,SAAS,SAAS,MAAM,GAAG,YAAY;AAEzE,MAAK,MAAM,eAAe,SAAS,QAAQ,EAAE;AAC3C,MAAI,MAAM,OAAO,YAAY,CAC3B;AAGF,MAAI,QACF,SAAQ,IAAI,IAAI,YAAY,KAAK,eAAe;AAGlD,QAAM,WAAW,YAAY;EAE7B,MAAM,QAAQ,KAAK,KAAK;AAExB,MAAI;AACF,SAAM,IAAI,aAAa,CAAC,IAAI,QAAQ;WAC7B,KAAK;GACZ,MAAM,aAAa,KAAK,KAAK,GAAG;AAEhC,OAAI,QACF,SAAQ,MAAM,IAAI,YAAY,KAAK,iBAAiB,WAAW,IAAI;AAGrE,SAAM,UAAU,aAAa,IAAI;AACjC,SAAM;;EAGR,MAAM,aAAa,KAAK,KAAK,GAAG;AAEhC,MAAI,QACF,SAAQ,IAAI,IAAI,YAAY,KAAK,YAAY,WAAW,IAAI;AAG9D,QAAM,UAAU,aAAa,WAAW"}
|
package/dist/index.d.cts
CHANGED
|
@@ -27,8 +27,20 @@ interface SeedContext {
|
|
|
27
27
|
*/
|
|
28
28
|
relations?: boolean;
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.
|
|
32
|
+
*
|
|
33
|
+
* Properties are seeded sequentially in declaration order, so any property declared above the
|
|
34
|
+
* current one is already set on `self` and can be read to derive the current value:
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* @Seed(() => faker.date.past())
|
|
38
|
+
* beginDate!: Date
|
|
39
|
+
*
|
|
40
|
+
* @Seed((_, self) => faker.date.future({ refDate: (self as MyEntity).beginDate }))
|
|
41
|
+
* endDate!: Date
|
|
42
|
+
*/
|
|
43
|
+
type SeedFactory<T = unknown> = (context: SeedContext, self: EntityInstance) => T | Promise<T>;
|
|
32
44
|
/** Options for the `@Seed` decorator. */
|
|
33
45
|
interface SeedOptions {
|
|
34
46
|
/**
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":";;;;KAGY,cAAA;AAAZ;AAAA,KAGY,iBAAA,WAA4B,cAAA,GAAiB,cAAA,cAA4B,CAAA;;UAGpE,WAAA;EANS;AAG1B;;;;;;;;EAaE,UAAA,GAAa,UAAA;EAbyB;;;;;AAGxC;;;EAmBE,SAAA;AAAA
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":";;;;KAGY,cAAA;AAAZ;AAAA,KAGY,iBAAA,WAA4B,cAAA,GAAiB,cAAA,cAA4B,CAAA;;UAGpE,WAAA;EANS;AAG1B;;;;;;;;EAaE,UAAA,GAAa,UAAA;EAbyB;;;;;AAGxC;;;EAmBE,SAAA;AAAA;;;;;AAgBF;;;;;;;;;KAAY,WAAA,iBACV,OAAA,EAAS,WAAA,EACT,IAAA,EAAM,cAAA,KACH,CAAA,GAAI,OAAA,CAAQ,CAAA;;UAGA,WAAA;EALf;;;;EAUA,KAAA;AAAA;AAAA,UAGe,SAAA;EACf,WAAA;EATe;EAWf,OAAA,EAAS,WAAA;EACT,OAAA,EAAS,WAAA;AAAA;AAAA,KAGC,cAAA,oBAAkC,iBAAA,oBAChC,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,iBAAA,YAA6B,CAAA;AAAA,KAGhD,mBAAA,oBAAuC,iBAAA,oBACrC,CAAA,GAAI,CAAA,CAAE,CAAA,UAAW,iBAAA,YAA6B,CAAA;;;;;AAnE5D;;;;;AAGA;;;iBCOgB,IAAA,CAAA,GAAQ,iBAAA;;;;;;;;;;;ADJxB;iBCgBgB,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,iBAAA;;;;;;;;ADmB5C;;;;;;;;;iBCFgB,IAAA,CAAK,OAAA,EAAS,WAAA,GAAc,iBAAA;;iBAE5B,IAAA,CAAK,OAAA,EAAS,WAAA,EAAa,OAAA,EAAS,WAAA,GAAc,iBAAA;;;;UChCjD,eAAA,SAAwB,WAAA;EACvC,UAAA,EAAY,UAAA;AAAA;;UAIG,mBAAA,SAA4B,eAAA;EAC3C,KAAA;AAAA;;;;;iBAsFoB,QAAA,WAAmB,cAAA,CAAA,CACvC,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,eAAA,GACR,OAAA,CAAQ,CAAA;;;;;iBAKW,QAAA,oBAA4B,iBAAA,GAAA,CAChD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,eAAA,GACR,OAAA,CAAQ,cAAA,CAAe,CAAA;;;AF1G1B;;iBEqIsB,YAAA,WAAuB,cAAA,CAAA,CAC3C,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,CAAA;;;;;iBAKW,YAAA,oBAAgC,iBAAA,GAAA,CACpD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,mBAAA,CAAoB,CAAA;;;;UC7IrB,UAAA,WAAqB,cAAA;EHTL;EGWxB,MAAA,CAAO,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,CAAA;EHXf;EGaxB,IAAA,CAAK,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,CAAA;EHV9B;EGYV,UAAA,CAAW,KAAA,UAAe,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,CAAA;EHZ/B;EGc3B,QAAA,CAAS,KAAA,UAAe,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,CAAA;AAAA;;;;;;UAQnD,SAAA,oBAA6B,iBAAA;EHtB8C;EGwBnF,MAAA,CAAO,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,cAAA,CAAe,CAAA;EHxB8B;EG0BpF,IAAA,CAAK,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,cAAA,CAAe,CAAA;EHvB7B;EGyB1B,UAAA,CAAW,KAAA,UAAe,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,mBAAA,CAAoB,CAAA;EHfvD;EGiBvB,QAAA,CAAS,KAAA,UAAe,OAAA,EAAS,eAAA,GAAkB,OAAA,CAAQ,mBAAA,CAAoB,CAAA;AAAA;;;;AHQjF;;;;;;;;;;;;;;;;;;;iBGiBgB,IAAA,WAAe,cAAA,CAAA,CAAgB,WAAA,EAAa,iBAAA,CAAkB,CAAA,IAAK,UAAA,CAAW,CAAA;AAAA,iBAC9E,IAAA,oBAAwB,iBAAA,GAAA,CAAqB,aAAA,MAAmB,CAAA,IAAK,SAAA,CAAU,CAAA;;;;UCnD9E,qBAAA,SAA8B,WAAA;EAC7C,KAAA;AAAA;;;;AJNF;;;;iBIuIsB,UAAA,WAAqB,cAAA,CAAA,CACzC,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,GAAU,WAAA,GACT,OAAA,CAAQ,CAAA;AAAA,iBACW,UAAA,oBAA8B,iBAAA,GAAA,CAClD,aAAA,MAAmB,CAAA,GACnB,OAAA,GAAU,WAAA,GACT,OAAA,CAAQ,cAAA,CAAe,CAAA;;;;;;;;iBA4BJ,cAAA,WAAyB,cAAA,CAAA,CAC7C,WAAA,EAAa,iBAAA,CAAkB,CAAA,GAC/B,OAAA,EAAS,qBAAA,GACR,OAAA,CAAQ,CAAA;AAAA,iBACW,cAAA,oBAAkC,iBAAA,GAAA,CACtD,aAAA,MAAmB,CAAA,GACnB,OAAA,EAAS,qBAAA,GACR,OAAA,CAAQ,mBAAA,CAAoB,CAAA;;;;;AJpL/B;;;;;UKOiB,eAAA;EACf,GAAA,CAAI,OAAA,EAAS,WAAA,GAAc,OAAA;AAAA;;UAIZ,aAAA;ELToE;;;;;EKenF,YAAA,cAA0B,eAAA;AAAA;;;ALZ5B;;;;;;;;;AAmCA;;;iBKNgB,MAAA,CAAO,OAAA,GAAS,aAAA,GAAqB,cAAA;;;;KChCzC,UAAA,aAAuB,eAAA;;UAGlB,iBAAA,SAA0B,WAAA;ENNjB;;AAG1B;;;;EMUE,OAAA;ENVmF;EMYnF,QAAA,IAAY,MAAA,EAAQ,UAAA,YAAsB,OAAA;ENZ0C;EMcpF,OAAA,IAAW,MAAA,EAAQ,UAAA,EAAY,UAAA,oBAA8B,OAAA;ENdvB;EMgBtC,OAAA,IAAW,MAAA,EAAQ,UAAA,EAAY,KAAA,qBAA0B,OAAA;ENhB0B;EMkBnF,IAAA,IAAQ,MAAA,EAAQ,UAAA,eAAyB,OAAA;AAAA;ANf3C;;;;;;;;;AAmCA;;;;;;;;;AAnCA,iBMqFsB,UAAA,CACpB,OAAA,EAAS,UAAA,IACT,OAAA,GAAS,iBAAA,GACR,OAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -27,8 +27,20 @@ interface SeedContext {
|
|
|
27
27
|
*/
|
|
28
28
|
relations?: boolean;
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.
|
|
32
|
+
*
|
|
33
|
+
* Properties are seeded sequentially in declaration order, so any property declared above the
|
|
34
|
+
* current one is already set on `self` and can be read to derive the current value:
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* @Seed(() => faker.date.past())
|
|
38
|
+
* beginDate!: Date
|
|
39
|
+
*
|
|
40
|
+
* @Seed((_, self) => faker.date.future({ refDate: (self as MyEntity).beginDate }))
|
|
41
|
+
* endDate!: Date
|
|
42
|
+
*/
|
|
43
|
+
type SeedFactory<T = unknown> = (context: SeedContext, self: EntityInstance) => T | Promise<T>;
|
|
32
44
|
/** Options for the `@Seed` decorator. */
|
|
33
45
|
interface SeedOptions {
|
|
34
46
|
/**
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":";;;;KAGY,cAAA;AAAZ;AAAA,KAGY,iBAAA,WAA4B,cAAA,GAAiB,cAAA,cAA4B,CAAA;;UAGpE,WAAA;EANS;AAG1B;;;;;;;;EAaE,UAAA,GAAa,UAAA;EAbyB;;;;;AAGxC;;;EAmBE,SAAA;AAAA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seed/creator.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -78,7 +78,7 @@ async function createOneSeed(EntityClass, context) {
|
|
|
78
78
|
const record = instance;
|
|
79
79
|
for (const { propertyKey, factory } of getSeeds(EntityClass)) {
|
|
80
80
|
if (!factory) continue;
|
|
81
|
-
record[propertyKey] = await factory(context);
|
|
81
|
+
record[propertyKey] = await factory(context, instance);
|
|
82
82
|
seededProperties.add(propertyKey);
|
|
83
83
|
}
|
|
84
84
|
for (const embedded of storage.filterEmbeddeds(EntityClass)) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["registry"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */\nexport type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport { getSeeds } from './registry.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManySeedOptions extends SeedContext {\n count: number;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOneSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createManySeed(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOneSeed(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function createSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context?: SeedContext,\n): Promise<T>;\nexport async function createSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function createSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n context: SeedContext = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOneSeed(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const [entity] = await createManySeed(classOrClasses as EntityConstructor<T>, {\n count: 1,\n ...context,\n });\n\n return entity!;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManySeedOptions,\n): Promise<T[]>;\nexport async function createManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, ...context }: CreateManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n return await Promise.all(\n Array.from({ length: count }, () =>\n createOneSeed(classOrClasses as EntityConstructor<T>, context),\n ),\n );\n}\n","import { type DataSource } from 'typeorm';\n\nimport { createManySeed } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\n/** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */\nexport interface SaveManySeedOptions extends SaveSeedOptions {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n * Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.\n */\nexport async function saveSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveSeedOptions,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveSeedOptions,\n): Promise<MapToInstances<T>>;\nexport async function saveSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveSeedOptions,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveManySeed(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveManySeed(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link saveSeed} for each entity.\n */\nexport async function saveManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveManySeedOne(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveManySeedOne(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class.\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveManySeedOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createManySeed(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import { createManySeed, createSeed } from './creator.js';\nimport { saveManySeed, saveSeed } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\nimport type { SaveSeedOptions } from './persist.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: SeedContext): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveSeedOptions): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveSeedOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n createSeed(classes as [...typeof classes], context) as Promise<\n MapToInstances<typeof classes>\n >,\n save: (options: SaveSeedOptions) =>\n saveSeed(classes as [...typeof classes], options) as Promise<\n MapToInstances<typeof classes>\n >,\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(classes as [...typeof classes], { count, ...options }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (context?: SeedContext) => createSeed(EntityClass, context),\n save: (options: SaveSeedOptions) => saveSeed(EntityClass, options),\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(EntityClass, { count, ...context }),\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["registry"],"sources":["../src/seed/registry.ts","../src/seed/decorator.ts","../src/seed/creator.ts","../src/seed/persist.ts","../src/seed/builder.ts","../src/seeder/registry.ts","../src/seeder/decorator.ts","../src/seeder/runner.ts"],"sourcesContent":["import type { DataSource } from 'typeorm';\n\n/** An entity instance — any class-based object managed by TypeORM. */\nexport type EntityInstance = object;\n\n/** A constructor that produces an entity instance. */\nexport type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;\n\n/** Context passed through a seed operation. Available inside factory callbacks and `SeederInterface.run`. */\nexport interface SeedContext {\n /**\n * The TypeORM DataSource. Automatically set by `save`/`saveMany` calls.\n * Also available in factory callbacks — useful for looking up existing\n * entities instead of creating new ones:\n *\n * @example\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\n dataSource?: DataSource;\n /**\n * Set to `false` to skip automatic relation seeding. Scalar and embedded\n * properties are still seeded; only relation properties decorated with a\n * bare `@Seed()` are skipped. Useful when you want to create flat entities\n * and wire relations yourself.\n *\n * @default true\n */\n relations?: boolean;\n}\n\n/**\n * Factory callback passed to `@Seed`. Receives the seed context and the partially built entity.\n *\n * Properties are seeded sequentially in declaration order, so any property declared above the\n * current one is already set on `self` and can be read to derive the current value:\n *\n * @example\n * @Seed(() => faker.date.past())\n * beginDate!: Date\n *\n * @Seed((_, self) => faker.date.future({ refDate: (self as MyEntity).beginDate }))\n * endDate!: Date\n */\nexport type SeedFactory<T = unknown> = (\n context: SeedContext,\n self: EntityInstance,\n) => T | Promise<T>;\n\n/** Options for the `@Seed` decorator. */\nexport interface SeedOptions {\n /**\n * Number of related entities to create. Only meaningful on one-to-many and\n * many-to-many relation properties. Ignored on scalar and single-entity relations.\n */\n count?: number;\n}\n\nexport interface SeedEntry {\n propertyKey: string | symbol;\n /** Undefined when @Seed is used without a factory (i.e. bare relation seed). */\n factory: SeedFactory | undefined;\n options: SeedOptions;\n}\n\nexport type MapToInstances<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never;\n};\n\nexport type MapToInstanceArrays<T extends readonly EntityConstructor[]> = {\n [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never;\n};\n\n// Keyed by the entity class constructor.\nconst registry = new Map<Function, SeedEntry[]>();\n\n/** Registers a seed entry for the given class constructor. Called internally by the `@Seed` decorator. */\nexport function registerSeed(target: Function, entry: SeedEntry): void {\n const entries = registry.get(target) ?? [];\n\n entries.push(entry);\n registry.set(target, entries);\n}\n\n/**\n * Returns all seed entries for the given class, including those inherited from\n * parent classes. Parent entries come first, preserving declaration order.\n */\nexport function getSeeds(target: Function): SeedEntry[] {\n const entries: SeedEntry[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n const own = registry.get(current);\n\n if (own) {\n entries.unshift(...own);\n }\n\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return entries;\n}\n","import { registerSeed } from './registry.js';\nimport type { SeedFactory, SeedOptions } from './registry.js';\n\n/**\n * Marks a relation property for auto-seeding.\n *\n * The related entity class is inferred from TypeORM metadata. One instance is created\n * and recursively seeded (including its own `@Seed` properties).\n *\n * Circular back-references are broken automatically: if the related class is already\n * being seeded higher up in the same call chain, the property is left `undefined`.\n * TypeORM treats `undefined` as \"don't touch this column\" rather than setting it to null.\n */\nexport function Seed(): PropertyDecorator;\n/**\n * Marks a relation property for auto-seeding with options.\n *\n * Use `count` on one-to-many and many-to-many properties to control how many\n * related entities are created. Ignored for one-to-one and many-to-one.\n *\n * @example\n * @Seed({ count: 3 })\n * @OneToMany(() => Book, (b) => b.author)\n * books!: Book[]\n */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/**\n * Marks a property with a factory callback.\n *\n * The factory receives the current {@link SeedContext} and can return any value,\n * including a `Promise`. Use this for scalar properties or when you need full\n * control over how a related entity is resolved.\n *\n * @example\n * @Seed(() => faker.internet.email())\n * email!: string\n *\n * @example\n * // Look up an existing entity instead of creating a new one\n * @Seed(async ({ dataSource }) => dataSource.getRepository(Role).findOneByOrFail({ name: 'admin' }))\n * role!: Role\n */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Marks a property with a factory callback and additional options. */\nexport function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;\nexport function Seed(\n factoryOrOptions?: SeedFactory | SeedOptions,\n options?: SeedOptions,\n): PropertyDecorator {\n const factory = typeof factoryOrOptions === 'function' ? factoryOrOptions : undefined;\n const opts: SeedOptions =\n (typeof factoryOrOptions === 'object' ? factoryOrOptions : options) ?? {};\n\n return (target, propertyKey) => {\n registerSeed(target.constructor as Function, { propertyKey, factory, options: opts });\n };\n}\n","import { getMetadataArgsStorage } from 'typeorm';\nimport { getSeeds } from './registry.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link createManySeed}. Extends {@link SeedContext} with a required instance count. */\nexport interface CreateManySeedOptions extends SeedContext {\n count: number;\n}\n\n// Internal extension of SeedContext — never exposed in the public API.\ninterface InternalContext extends SeedContext {\n _ancestors: Set<Function>;\n}\n\n/** Extracts the ancestor set from an internal context, returning an empty set for external callers. */\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\n/** Returns a new context with `cls` added to the ancestor set, used to detect circular relation chains. */\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\n/** Walks the prototype chain and returns all classes from `target` up to (but not including) `Function.prototype`. */\nfunction getClassHierarchy(target: Function): Function[] {\n const hierarchy: Function[] = [];\n let current: Function = target;\n\n while (current && current !== Function.prototype) {\n hierarchy.push(current);\n current = Object.getPrototypeOf(current) as Function;\n }\n\n return hierarchy;\n}\n\n/**\n * Creates one fully populated instance of `EntityClass` in memory.\n *\n * Runs in three steps:\n * 1. Factory-decorated properties (`@Seed(factory)`) — run first, in declaration order.\n * 2. Embedded types (`@Embedded`) — auto-seeded if the embedded class has any `@Seed` entries.\n * 3. Bare relation decorators (`@Seed()` without a factory) — skipped when `relations` is `false`,\n * and also skipped for any related class already present in the ancestor chain (circular guard).\n */\nasync function createOneSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context: SeedContext,\n): Promise<T> {\n const instance = new EntityClass();\n const ancestors = getAncestors(context);\n const childContext = withAncestor(context, EntityClass);\n const storage = getMetadataArgsStorage();\n const relations = storage.filterRelations(getClassHierarchy(EntityClass));\n const seededProperties = new Set<string | symbol>();\n const record = instance as Record<string | symbol, unknown>;\n\n // Step 1: Run @Seed entries that have an explicit factory.\n for (const { propertyKey, factory } of getSeeds(EntityClass)) {\n if (!factory) {\n continue;\n }\n\n record[propertyKey] = await factory(context, instance);\n seededProperties.add(propertyKey);\n }\n\n // Step 2: Auto-seed TypeORM embedded properties not already covered by Step 1.\n for (const embedded of storage.filterEmbeddeds(EntityClass)) {\n if (seededProperties.has(embedded.propertyName)) {\n continue;\n }\n\n const EmbeddedClass = embedded.type() as EntityConstructor;\n\n if (getSeeds(EmbeddedClass).length > 0) {\n record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);\n seededProperties.add(embedded.propertyName);\n }\n }\n\n // Step 3: Auto-seed @Seed entries without a factory (relation seeds).\n // Uses the ancestor guard to cut circular chains: if the related class is\n // already being seeded higher up in this call chain, the property is left\n // undefined rather than triggering infinite recursion.\n // Skipped entirely when context.relations === false.\n if (context.relations === false) {\n return instance;\n }\n\n for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {\n if (factory || seededProperties.has(propertyKey)) {\n continue;\n }\n\n const relation = relations.find((r) => r.propertyName === String(propertyKey));\n\n if (!relation || typeof relation.type !== 'function') {\n continue;\n }\n\n const RelatedClass = (relation.type as () => Function)() as EntityConstructor;\n\n if (ancestors.has(RelatedClass)) {\n continue;\n }\n\n const isArray =\n relation.relationType === 'one-to-many' || relation.relationType === 'many-to-many';\n\n if (isArray) {\n record[propertyKey] = await createManySeed(RelatedClass, {\n count: options.count ?? 1,\n ...childContext,\n });\n } else {\n record[propertyKey] = await createOneSeed(RelatedClass, childContext);\n }\n\n seededProperties.add(propertyKey);\n }\n\n return instance;\n}\n\n/**\n * Creates one entity instance in memory without persisting it.\n *\n * When passed an array of classes, relation seeding is disabled by default\n * (pass `relations: true` in the context to override). Returns a tuple of\n * instances in the same order as the input array.\n */\nexport async function createSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n context?: SeedContext,\n): Promise<T>;\nexport async function createSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n context?: SeedContext,\n): Promise<MapToInstances<T>>;\nexport async function createSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n context: SeedContext = {},\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => createOneSeed(cls, effectiveContext)),\n )) as EntityInstance[];\n }\n\n const [entity] = await createManySeed(classOrClasses as EntityConstructor<T>, {\n count: 1,\n ...context,\n });\n\n return entity!;\n}\n\n/**\n * Creates multiple entity instances in memory without persisting them.\n *\n * When passed an array of classes, returns a tuple of arrays — one per class — each\n * containing `count` instances. Relation seeding is disabled by default for the\n * array variant; pass `relations: true` in the options to override.\n */\nexport async function createManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: CreateManySeedOptions,\n): Promise<T[]>;\nexport async function createManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: CreateManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function createManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n { count, ...context }: CreateManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveContext: SeedContext = { relations: false, ...context };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext))),\n ),\n )) as EntityInstance[][];\n }\n\n return await Promise.all(\n Array.from({ length: count }, () =>\n createOneSeed(classOrClasses as EntityConstructor<T>, context),\n ),\n );\n}\n","import { type DataSource } from 'typeorm';\n\nimport { createManySeed } from './creator.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\n\n/** Options for {@link saveSeed}. Extends {@link SeedContext} with a required DataSource. */\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\n/** Options for {@link saveManySeed}. Extends {@link SaveSeedOptions} with a required instance count. */\nexport interface SaveManySeedOptions extends SaveSeedOptions {\n count: number;\n}\n\ntype RelationMetadata = DataSource extends { getMetadata(...args: never[]): infer M }\n ? M extends { relations: Array<infer R> }\n ? R\n : never\n : never;\n\ninterface CascadeState {\n relation: RelationMetadata;\n original: boolean;\n}\n\n/**\n * Walks an entity object graph and collects every unique entity class encountered.\n * Used to discover all entity classes that need cascade-insert temporarily enabled\n * before saving so that the full in-memory graph is persisted in one shot.\n */\nfunction collectEntityClasses(entity: EntityInstance, visited = new Set<Function>()): Function[] {\n const EntityClass = entity.constructor as Function;\n\n if (visited.has(EntityClass)) {\n return [];\n }\n\n visited.add(EntityClass);\n\n const classes: Function[] = [EntityClass];\n\n for (const value of Object.values(entity)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item && typeof item === 'object' && item.constructor !== Object) {\n classes.push(...collectEntityClasses(item, visited));\n }\n }\n } else if (value && typeof value === 'object' && value.constructor !== Object) {\n classes.push(...collectEntityClasses(value as EntityInstance, visited));\n }\n }\n\n return classes;\n}\n\n/**\n * Temporarily enables `isCascadeInsert` on every TypeORM relation for the given class.\n * Returns the previous flag values so they can be restored after saving.\n *\n * This is necessary because the seeder builds the full object graph in memory before\n * calling `save()`. Without cascade inserts, TypeORM would only persist the root entity\n * and ignore any nested relations that weren't already configured with `cascade: true`.\n *\n * Classes not registered as TypeORM entities (e.g. embedded value objects) are silently skipped.\n */\nfunction enableCascadeInsert(EntityClass: Function, dataSource: DataSource): CascadeState[] {\n const states: CascadeState[] = [];\n\n try {\n const relations = dataSource.getMetadata(EntityClass).relations;\n\n for (const relation of relations) {\n states.push({ relation, original: relation.isCascadeInsert });\n relation.isCascadeInsert = true;\n }\n } catch {\n // Class is not registered as an entity with this DataSource (e.g. embedded class).\n }\n\n return states;\n}\n\n/**\n * Restores `isCascadeInsert` flags to their original values.\n * Always called in a `finally` block to guarantee cleanup even when saving throws.\n */\nfunction restoreCascade(states: CascadeState[]): void {\n for (const { relation, original } of states) {\n relation.isCascadeInsert = original;\n }\n}\n\n/**\n * Creates and persists a seed entity and all its seeded relations.\n * Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.\n */\nexport async function saveSeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveSeedOptions,\n): Promise<T>;\n/**\n * Creates and persists one instance of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveSeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveSeedOptions,\n): Promise<MapToInstances<T>>;\nexport async function saveSeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveSeedOptions,\n): Promise<T | EntityInstance[]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options, count: 1 };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) =>\n saveManySeed(cls, effectiveOptions).then(([entity]) => entity!),\n ),\n )) as EntityInstance[];\n }\n\n const [entity] = await saveManySeed(classOrClasses as EntityConstructor<T>, {\n ...options,\n count: 1,\n });\n\n return entity!;\n}\n\n/**\n * Creates and persists multiple seed entities of the same class.\n * Applies the same logic as {@link saveSeed} for each entity.\n */\nexport async function saveManySeed<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]>;\n/**\n * Creates and persists multiple instances of each entity class in the array.\n * Relation seeding is disabled by default; pass `relations: true` to override.\n */\nexport async function saveManySeed<T extends readonly EntityConstructor[]>(\n EntityClasses: [...T],\n options: SaveManySeedOptions,\n): Promise<MapToInstanceArrays<T>>;\nexport async function saveManySeed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n options: SaveManySeedOptions,\n): Promise<T[] | EntityInstance[][]> {\n if (Array.isArray(classOrClasses)) {\n const effectiveOptions = { relations: false, ...options };\n\n return (await Promise.all(\n (classOrClasses as EntityConstructor[]).map((cls) => saveManySeedOne(cls, effectiveOptions)),\n )) as EntityInstance[][];\n }\n\n return await saveManySeedOne(classOrClasses as EntityConstructor<T>, options);\n}\n\n/**\n * Creates and persists `count` instances of a single entity class.\n * Enables cascade inserts on every entity class in the object graph before saving,\n * then restores the original flags — regardless of whether the save succeeds or fails.\n */\nasync function saveManySeedOne<T extends EntityInstance>(\n EntityClass: EntityConstructor<T>,\n options: SaveManySeedOptions,\n): Promise<T[]> {\n const { count, dataSource } = options;\n\n if (count === 0) {\n return [];\n }\n\n const entities = await createManySeed(EntityClass, options);\n\n const visited = new Set<Function>();\n const states = entities\n .flatMap((entity) => collectEntityClasses(entity, visited))\n .flatMap((cls) => enableCascadeInsert(cls, dataSource));\n\n try {\n return (await dataSource.getRepository(EntityClass).save(entities)) as T[];\n } finally {\n restoreCascade(states);\n }\n}\n","import { createManySeed, createSeed } from './creator.js';\nimport { saveManySeed, saveSeed } from './persist.js';\nimport type {\n EntityConstructor,\n EntityInstance,\n MapToInstanceArrays,\n MapToInstances,\n SeedContext,\n} from './registry.js';\nimport type { SaveSeedOptions } from './persist.js';\n\n/** Seed builder for a single entity class. Returned by {@link seed} when passed one class. */\ninterface SingleSeed<T extends EntityInstance> {\n /** Creates a single instance in memory without persisting. */\n create(context?: SeedContext): Promise<T>;\n /** Creates and persists a single instance. */\n save(options: SaveSeedOptions): Promise<T>;\n /** Creates multiple instances in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<T[]>;\n /** Creates and persists multiple instances. */\n saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;\n}\n\n/**\n * Seed builder for multiple entity classes. Returned by {@link seed} when passed an array.\n * Each method returns a tuple of instances in the same order as the input array.\n * Relation seeding is disabled by default; pass `relations: true` in the context to enable it.\n */\ninterface MultiSeed<T extends readonly EntityConstructor[]> {\n /** Creates one instance of each class in memory without persisting. */\n create(context?: SeedContext): Promise<MapToInstances<T>>;\n /** Creates and persists one instance of each class. */\n save(options: SaveSeedOptions): Promise<MapToInstances<T>>;\n /** Creates `count` instances of each class in memory without persisting. */\n createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;\n /** Creates and persists `count` instances of each class. */\n saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;\n}\n\n/**\n * Entry point for creating and persisting seed data.\n *\n * Pass a single entity class to get a {@link SingleSeed} builder, or an array of classes\n * to get a {@link MultiSeed} builder that operates on all of them at once.\n *\n * @example\n * // Create one Author in memory (no DB)\n * const author = await seed(Author).create()\n *\n * @example\n * // Persist one Author with all its seeded relations\n * const author = await seed(Author).save({ dataSource })\n *\n * @example\n * // Persist 10 Authors\n * const authors = await seed(Author).saveMany(10, { dataSource })\n *\n * @example\n * // Create multiple entity classes at once (relations disabled by default)\n * const [user, post] = await seed([User, Post]).create()\n */\nexport function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;\nexport function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;\nexport function seed<T extends EntityInstance>(\n classOrClasses: EntityConstructor<T> | readonly EntityConstructor[],\n): SingleSeed<T> | MultiSeed<readonly EntityConstructor[]> {\n if (Array.isArray(classOrClasses)) {\n const classes = classOrClasses as readonly EntityConstructor[];\n\n return {\n create: (context?: SeedContext) =>\n createSeed(classes as [...typeof classes], context) as Promise<\n MapToInstances<typeof classes>\n >,\n save: (options: SaveSeedOptions) =>\n saveSeed(classes as [...typeof classes], options) as Promise<\n MapToInstances<typeof classes>\n >,\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(classes as [...typeof classes], { count, ...context }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(classes as [...typeof classes], { count, ...options }) as Promise<\n MapToInstanceArrays<typeof classes>\n >,\n };\n }\n\n const EntityClass = classOrClasses as EntityConstructor<T>;\n\n return {\n create: (context?: SeedContext) => createSeed(EntityClass, context),\n save: (options: SaveSeedOptions) => saveSeed(EntityClass, options),\n createMany: (count: number, context?: SeedContext) =>\n createManySeed(EntityClass, { count, ...context }),\n saveMany: (count: number, options: SaveSeedOptions) =>\n saveManySeed(EntityClass, { count, ...options }),\n };\n}\n","interface SeederMeta {\n dependencies: Function[];\n}\n\nconst registry = new WeakMap<Function, SeederMeta>();\n\n/** Registers seeder metadata for the given class constructor. Called internally by the `@Seeder` decorator. */\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\n/** Returns the metadata registered for the given seeder class, or `undefined` if not registered. */\nexport function getSeederMeta(target: Function): SeederMeta | undefined {\n return registry.get(target);\n}\n","import { registerSeeder } from './registry.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/**\n * Interface that seeder classes must implement.\n *\n * The `run` method receives the seed context (which includes the DataSource when\n * called via `runSeeders`) and performs the seeding logic — typically by calling\n * `seed().save()` or other seeding utilities.\n */\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\n/** Configuration options for the {@link Seeder} decorator. */\nexport interface SeederOptions {\n /**\n * Seeder classes that must complete before this one runs.\n * Resolved transitively — dependencies of dependencies are included automatically.\n * {@link runSeeders} topologically sorts the full set and detects circular dependencies.\n */\n dependencies?: (new () => SeederInterface)[];\n}\n\n/**\n * Marks a class as a seeder and registers its dependency metadata.\n *\n * Classes decorated with `@Seeder` can be passed to {@link runSeeders}, which resolves\n * all transitive dependencies, sorts them topologically, and executes them in order.\n *\n * @example\n * @Seeder({ dependencies: [UserSeeder] })\n * class PostSeeder implements SeederInterface {\n * async run(ctx: SeedContext) {\n * await seed(Post).saveMany(50, ctx)\n * }\n * }\n */\nexport function Seeder(options: SeederOptions = {}): ClassDecorator {\n return (target) => {\n registerSeeder(target, { dependencies: options.dependencies ?? [] });\n };\n}\n","import { DepGraph } from 'dependency-graph';\nimport { getSeederMeta } from './registry.js';\nimport type { SeederInterface } from './decorator.js';\nimport type { SeedContext } from '../seed/registry.js';\n\n/** Constructor type for a class decorated with `@Seeder`. */\nexport type SeederCtor = new () => SeederInterface;\n\n/** Options for {@link runSeeders}. Extends {@link SeedContext} with lifecycle hooks and logging control. */\nexport interface RunSeedersOptions extends SeedContext {\n /**\n * Enable console logging for each seeder. Set to `false` to silence output,\n * e.g. when using callbacks to handle logging yourself.\n *\n * @default true\n */\n logging?: boolean;\n /** Called before each seeder runs, in execution order. */\n onBefore?: (seeder: SeederCtor) => void | Promise<void>;\n /** Called after each seeder completes successfully, with the time it took in milliseconds. */\n onAfter?: (seeder: SeederCtor, durationMs: number) => void | Promise<void>;\n /** Called when a seeder throws. The error is re-thrown after this callback returns. */\n onError?: (seeder: SeederCtor, error: unknown) => void | Promise<void>;\n /** Called for each seeder before it runs. Return `true` to skip it entirely. */\n skip?: (seeder: SeederCtor) => boolean | Promise<boolean>;\n}\n\n/**\n * Topologically sorts the given seeders and all their transitive dependencies.\n * BFS walks from the roots to collect all nodes, then dependency edges are wired and\n * the graph is sorted so that every dependency precedes the seeders that depend on it.\n * Throws a descriptive error if a circular dependency is detected.\n */\nfunction topoSort(roots: SeederCtor[]): SeederCtor[] {\n const graph = new DepGraph<SeederCtor>();\n const byName = new Map<string, SeederCtor>();\n\n // Collect all nodes transitively via BFS and register them in the graph.\n const visited = new Set<SeederCtor>();\n const queue: SeederCtor[] = [...roots];\n\n while (queue.length > 0) {\n const node = queue.shift()!;\n\n if (visited.has(node)) {\n continue;\n }\n\n visited.add(node);\n graph.addNode(node.name, node);\n byName.set(node.name, node);\n\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n queue.push(dep);\n }\n }\n\n // Wire up the dependency edges.\n for (const node of visited) {\n for (const dep of (getSeederMeta(node)?.dependencies ?? []) as SeederCtor[]) {\n graph.addDependency(node.name, dep.name);\n }\n }\n\n try {\n return graph.overallOrder().map((name) => byName.get(name)!);\n } catch (err) {\n if (err && typeof err === 'object' && 'cyclePath' in err) {\n const path = (err as { cyclePath: string[] }).cyclePath.join(' → ');\n throw new Error(`Circular dependency detected among seeders: ${path}`);\n }\n\n throw err;\n }\n}\n\n/**\n * Runs the given seeders (and all their transitive dependencies) in dependency order.\n *\n * Each seeder is instantiated, its `run` method is called with the context derived\n * from `options`, and lifecycle hooks (`onBefore`, `onAfter`, `onError`) are called\n * around it. Errors are re-thrown after `onError` returns.\n *\n * @example\n * await runSeeders([PostSeeder], { dataSource })\n *\n * @example\n * // With lifecycle hooks and no console output\n * await runSeeders([PostSeeder], {\n * dataSource,\n * logging: false,\n * onAfter: (seeder, ms) => console.log(`${seeder.name} done in ${ms}ms`),\n * })\n */\nexport async function runSeeders(\n seeders: SeederCtor[],\n options: RunSeedersOptions = {},\n): Promise<void> {\n const { logging = true, onBefore, onAfter, onError, skip, ...context } = options;\n\n for (const SeederClass of topoSort(seeders)) {\n if (await skip?.(SeederClass)) {\n continue;\n }\n\n if (logging) {\n console.log(`[${SeederClass.name}] Starting...`);\n }\n\n await onBefore?.(SeederClass);\n\n const start = Date.now();\n\n try {\n await new SeederClass().run(context);\n } catch (err) {\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.error(`[${SeederClass.name}] Failed after ${durationMs}ms`);\n }\n\n await onError?.(SeederClass, err);\n throw err;\n }\n\n const durationMs = Date.now() - start;\n\n if (logging) {\n console.log(`[${SeederClass.name}] Done in ${durationMs}ms`);\n }\n\n await onAfter?.(SeederClass, durationMs);\n }\n}\n"],"mappings":"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"}
|