@joakimbugge/typeorm-seeder 0.2.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/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/index.cjs +273 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +124 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +124 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +265 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +74 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 typeorm-seeder contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# @joakimbugge/typeorm-seeder
|
|
2
|
+
|
|
3
|
+
Decorator-based entity seeding for TypeORM. Annotate your entity properties with `@Seed()`, then create or persist fully populated entity graphs with a single function call — including relations, embedded types, and circular guards. Organise complex seeding scenarios into `@Seeder` classes with declared dependencies that are automatically ordered and executed for you.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @joakimbugge/typeorm-seeder
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`typeorm` and `reflect-metadata` are peer dependencies and must be installed alongside it.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install typeorm reflect-metadata
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Your `tsconfig.json` must have decorator support enabled:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"compilerOptions": {
|
|
24
|
+
"experimentalDecorators": true,
|
|
25
|
+
"emitDecoratorMetadata": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Decorating entities
|
|
33
|
+
|
|
34
|
+
Use `@Seed()` on any entity property to describe how it should be populated. Plain column properties (scalars) take a factory function; relation properties take the bare decorator (or a `count` option for collections).
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne } from 'typeorm'
|
|
38
|
+
import { faker } from '@faker-js/faker'
|
|
39
|
+
import { Seed } from '@joakimbugge/typeorm-seeder'
|
|
40
|
+
|
|
41
|
+
@Entity()
|
|
42
|
+
class Author {
|
|
43
|
+
@PrimaryGeneratedColumn()
|
|
44
|
+
id!: number
|
|
45
|
+
|
|
46
|
+
@Seed(() => faker.person.fullName())
|
|
47
|
+
@Column()
|
|
48
|
+
name!: string
|
|
49
|
+
|
|
50
|
+
@Seed({ count: 3 })
|
|
51
|
+
@OneToMany(() => Book, (b) => b.author)
|
|
52
|
+
books!: Book[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Entity()
|
|
56
|
+
class Book {
|
|
57
|
+
@PrimaryGeneratedColumn()
|
|
58
|
+
id!: number
|
|
59
|
+
|
|
60
|
+
@Seed(() => faker.lorem.words(4))
|
|
61
|
+
@Column()
|
|
62
|
+
title!: string
|
|
63
|
+
|
|
64
|
+
@Seed()
|
|
65
|
+
@ManyToOne(() => Author, (a) => a.books)
|
|
66
|
+
author!: Author
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> [!IMPORTANT]
|
|
71
|
+
> **How circular relations are handled**
|
|
72
|
+
>
|
|
73
|
+
> When seeding `Author`, its `books` are seeded too. Each `Book` has an `author` relation back to `Author` — but seeding that would loop back to `Author`, which would seed more books, and so on forever.
|
|
74
|
+
>
|
|
75
|
+
> @joakimbugge/typeorm-seeder breaks the cycle at the point where a type would re-enter itself. In the example above, `book.author` is left `undefined` when seeding from `Author`. Seeding a `Book` directly works fine and does populate `book.author` — the cycle only cuts when a type is already being seeded higher up in the same chain.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Seeding entities
|
|
80
|
+
|
|
81
|
+
Call `seed(EntityClass)` to get a builder with four methods: `create`, `createMany`, `save`, and `saveMany`.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { seed } from '@joakimbugge/typeorm-seeder'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Saving
|
|
88
|
+
|
|
89
|
+
`save()` and `saveMany()` create instances and write them to the database in one step. Pass a `DataSource` in the options.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const author = await seed(Author).save({ dataSource })
|
|
93
|
+
// author.id → assigned by the database
|
|
94
|
+
// author.books → 3 persisted Book instances
|
|
95
|
+
|
|
96
|
+
const authors = await seed(Author).saveMany(5, { dataSource })
|
|
97
|
+
// [Author, Author, Author, Author, Author] — each with their own books
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Without saving
|
|
101
|
+
|
|
102
|
+
`create()` and `createMany()` build entity instances without touching the database. Useful for unit tests or for preparing entities before passing them to your own persistence logic.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const author = await seed(Author).create()
|
|
106
|
+
// Plain Author instance — no id, fully populated relations
|
|
107
|
+
|
|
108
|
+
const books = await seed(Book).createMany(10)
|
|
109
|
+
// [Book, Book, …] — each with its own seeded Author
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Multiple entity types at once
|
|
113
|
+
|
|
114
|
+
Pass an array of entity classes to seed one of each:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const [author, book] = await seed([Author, Book]).create()
|
|
118
|
+
const [author, book] = await seed([Author, Book]).save({ dataSource })
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Relation seeding is **disabled by default** in this form — each entity is created independently, so there is no overlap between the `Author` you asked for and the `Author` that would have been auto-created inside `Book`. Pass `relations: true` to override:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const [author, book] = await seed([Author, Book]).save({ dataSource, relations: true })
|
|
125
|
+
// author.books → seeded | book.author → seeded (independently)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`createMany` and `saveMany` return an array per class:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const [authors, books] = await seed([Author, Book]).createMany(3)
|
|
132
|
+
// authors → [Author, Author, Author]
|
|
133
|
+
// books → [Book, Book, Book]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Skipping relations
|
|
137
|
+
|
|
138
|
+
Pass `relations: false` to create a flat entity with no relation properties set — useful when you want to wire relations yourself:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const author = await seed(Author).create({ relations: false })
|
|
142
|
+
// author.books → undefined
|
|
143
|
+
|
|
144
|
+
const book = await seed(Book).save({ dataSource, relations: false })
|
|
145
|
+
// book.author → null in the database
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Passing a DataSource to factories
|
|
149
|
+
|
|
150
|
+
If a factory needs to query the database, the `dataSource` you provide in options is forwarded to every factory via `SeedContext`:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
@Seed(async ({ dataSource }) => {
|
|
154
|
+
const existing = await dataSource!.getRepository(Role).findOneBy({ name: 'admin' })
|
|
155
|
+
return existing!
|
|
156
|
+
})
|
|
157
|
+
@ManyToOne(() => Role)
|
|
158
|
+
role!: Role
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Seeder suites
|
|
164
|
+
|
|
165
|
+
For production seeding scripts or structured test fixtures, organise your seeding logic into `@Seeder` classes. Declare dependencies between seeders and let the library figure out the execution order.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { Seeder, runSeeders, seed } from '@joakimbugge/typeorm-seeder'
|
|
169
|
+
import type { SeederInterface, SeedContext } from '@joakimbugge/typeorm-seeder'
|
|
170
|
+
|
|
171
|
+
@Seeder()
|
|
172
|
+
class UserSeeder implements SeederInterface {
|
|
173
|
+
async run(ctx: SeedContext) {
|
|
174
|
+
await seed(User).saveMany(10, { ...ctx, dataSource: ctx.dataSource! })
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@Seeder({ dependencies: [UserSeeder] })
|
|
179
|
+
class PostSeeder implements SeederInterface {
|
|
180
|
+
async run(ctx: SeedContext) {
|
|
181
|
+
await seed(Post).saveMany(50, { ...ctx, dataSource: ctx.dataSource! })
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Run from your seed script or test setup:
|
|
186
|
+
await runSeeders([PostSeeder], { dataSource })
|
|
187
|
+
// UserSeeder runs first, then PostSeeder
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`runSeeders` accepts the root seeders you want to execute. It collects all transitive dependencies, topologically sorts them, and runs each once in the correct order. Passing the same seeder as both a root and a dependency of another root is safe — it will only run once.
|
|
191
|
+
|
|
192
|
+
Circular dependencies between seeders are detected at runtime and throw an error naming the seeders involved.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## API reference
|
|
197
|
+
|
|
198
|
+
### `@Seed(factory?, options?)`
|
|
199
|
+
|
|
200
|
+
Property decorator. Marks a property for automatic seeding.
|
|
201
|
+
|
|
202
|
+
| Signature | Behaviour |
|
|
203
|
+
|---|---|
|
|
204
|
+
| `@Seed(factory)` | Calls `factory(context)` and assigns the result |
|
|
205
|
+
| `@Seed(factory, options)` | Same, with additional options |
|
|
206
|
+
| `@Seed(options)` | Relation seed with options (e.g. `count`) |
|
|
207
|
+
| `@Seed()` | Bare relation seed — auto-creates one related entity |
|
|
208
|
+
|
|
209
|
+
**`SeedOptions`**
|
|
210
|
+
|
|
211
|
+
| Property | Type | Description |
|
|
212
|
+
|---|---|---|
|
|
213
|
+
| `count` | `number` | Number of related entities to create. Only applies to `one-to-many` and `many-to-many` relations. |
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### `seed(EntityClass)`
|
|
218
|
+
|
|
219
|
+
Returns a builder for creating and persisting seed entities.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
seed(Author).create(context?): Promise<Author>
|
|
223
|
+
seed(Author).createMany(count, context?): Promise<Author[]>
|
|
224
|
+
seed(Author).save(options): Promise<Author>
|
|
225
|
+
seed(Author).saveMany(count, options): Promise<Author[]>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The array form returns a tuple of instances (or arrays of instances for `createMany`/`saveMany`):
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
seed([Author, Book]).create(context?): Promise<[Author, Book]>
|
|
232
|
+
seed([Author, Book]).createMany(count, context?): Promise<[Author[], Book[]]>
|
|
233
|
+
seed([Author, Book]).save(options): Promise<[Author, Book]>
|
|
234
|
+
seed([Author, Book]).saveMany(count, options): Promise<[Author[], Book[]]>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
### `@Seeder(options?)`
|
|
240
|
+
|
|
241
|
+
Class decorator. Registers a class as a seeder and declares its dependencies.
|
|
242
|
+
|
|
243
|
+
**`SeederOptions`**
|
|
244
|
+
|
|
245
|
+
| Property | Type | Description |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| `dependencies` | `SeederInterface[]` | Seeders that must run before this one. |
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
### `runSeeders(seeders, context?)`
|
|
252
|
+
|
|
253
|
+
Topologically sorts and runs the given seeders plus all their transitive dependencies.
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
runSeeders([PostSeeder], { dataSource }): Promise<void>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Throws if a circular dependency is detected.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
### `SeedContext`
|
|
264
|
+
|
|
265
|
+
Passed to factory functions and `SeederInterface.run()`.
|
|
266
|
+
|
|
267
|
+
| Property | Type | Description |
|
|
268
|
+
|---|---|---|
|
|
269
|
+
| `dataSource` | `DataSource?` | Active TypeORM data source. |
|
|
270
|
+
| `relations` | `boolean?` | Set to `false` to skip relation seeding. Defaults to `true`. |
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let typeorm = require("typeorm");
|
|
3
|
+
let dependency_graph = require("dependency-graph");
|
|
4
|
+
//#region src/seed/registry.ts
|
|
5
|
+
const registry$1 = /* @__PURE__ */ new Map();
|
|
6
|
+
function registerSeed(target, entry) {
|
|
7
|
+
const entries = registry$1.get(target) ?? [];
|
|
8
|
+
entries.push(entry);
|
|
9
|
+
registry$1.set(target, entries);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns all seed entries for the given class, including those inherited from
|
|
13
|
+
* parent classes. Parent entries come first, preserving declaration order.
|
|
14
|
+
*/
|
|
15
|
+
function getSeeds(target) {
|
|
16
|
+
const entries = [];
|
|
17
|
+
let current = target;
|
|
18
|
+
while (current && current !== Function.prototype) {
|
|
19
|
+
const own = registry$1.get(current);
|
|
20
|
+
if (own) entries.unshift(...own);
|
|
21
|
+
current = Object.getPrototypeOf(current);
|
|
22
|
+
}
|
|
23
|
+
return entries;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/seed/decorator.ts
|
|
27
|
+
function Seed(factoryOrOptions, options) {
|
|
28
|
+
const factory = typeof factoryOrOptions === "function" ? factoryOrOptions : void 0;
|
|
29
|
+
const opts = (typeof factoryOrOptions === "object" ? factoryOrOptions : options) ?? {};
|
|
30
|
+
return (target, propertyKey) => {
|
|
31
|
+
registerSeed(target.constructor, {
|
|
32
|
+
propertyKey,
|
|
33
|
+
factory,
|
|
34
|
+
options: opts
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/seed/creator.ts
|
|
40
|
+
function getAncestors(context) {
|
|
41
|
+
return context._ancestors ?? /* @__PURE__ */ new Set();
|
|
42
|
+
}
|
|
43
|
+
function withAncestor(context, cls) {
|
|
44
|
+
const ancestors = getAncestors(context);
|
|
45
|
+
return {
|
|
46
|
+
...context,
|
|
47
|
+
_ancestors: new Set([...ancestors, cls])
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function getClassHierarchy(target) {
|
|
51
|
+
const hierarchy = [];
|
|
52
|
+
let current = target;
|
|
53
|
+
while (current && current !== Function.prototype) {
|
|
54
|
+
hierarchy.push(current);
|
|
55
|
+
current = Object.getPrototypeOf(current);
|
|
56
|
+
}
|
|
57
|
+
return hierarchy;
|
|
58
|
+
}
|
|
59
|
+
async function createOneSeed(EntityClass, context) {
|
|
60
|
+
const instance = new EntityClass();
|
|
61
|
+
const ancestors = getAncestors(context);
|
|
62
|
+
const childContext = withAncestor(context, EntityClass);
|
|
63
|
+
const storage = (0, typeorm.getMetadataArgsStorage)();
|
|
64
|
+
const relations = storage.filterRelations(getClassHierarchy(EntityClass));
|
|
65
|
+
const seededProperties = /* @__PURE__ */ new Set();
|
|
66
|
+
const record = instance;
|
|
67
|
+
for (const { propertyKey, factory } of getSeeds(EntityClass)) {
|
|
68
|
+
if (!factory) continue;
|
|
69
|
+
record[propertyKey] = await factory(context);
|
|
70
|
+
seededProperties.add(propertyKey);
|
|
71
|
+
}
|
|
72
|
+
for (const embedded of storage.filterEmbeddeds(EntityClass)) {
|
|
73
|
+
if (seededProperties.has(embedded.propertyName)) continue;
|
|
74
|
+
const EmbeddedClass = embedded.type();
|
|
75
|
+
if (getSeeds(EmbeddedClass).length > 0) {
|
|
76
|
+
record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);
|
|
77
|
+
seededProperties.add(embedded.propertyName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (context.relations === false) return instance;
|
|
81
|
+
for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {
|
|
82
|
+
if (factory || seededProperties.has(propertyKey)) continue;
|
|
83
|
+
const relation = relations.find((r) => r.propertyName === String(propertyKey));
|
|
84
|
+
if (!relation || typeof relation.type !== "function") continue;
|
|
85
|
+
const RelatedClass = relation.type();
|
|
86
|
+
if (ancestors.has(RelatedClass)) continue;
|
|
87
|
+
if (relation.relationType === "one-to-many" || relation.relationType === "many-to-many") record[propertyKey] = await createManySeed(RelatedClass, {
|
|
88
|
+
count: options.count ?? 1,
|
|
89
|
+
...childContext
|
|
90
|
+
});
|
|
91
|
+
else record[propertyKey] = await createOneSeed(RelatedClass, childContext);
|
|
92
|
+
seededProperties.add(propertyKey);
|
|
93
|
+
}
|
|
94
|
+
return instance;
|
|
95
|
+
}
|
|
96
|
+
async function createSeed(classOrClasses, context = {}) {
|
|
97
|
+
if (Array.isArray(classOrClasses)) {
|
|
98
|
+
const effectiveContext = {
|
|
99
|
+
relations: false,
|
|
100
|
+
...context
|
|
101
|
+
};
|
|
102
|
+
return await Promise.all(classOrClasses.map((cls) => createOneSeed(cls, effectiveContext)));
|
|
103
|
+
}
|
|
104
|
+
const [entity] = await createManySeed(classOrClasses, {
|
|
105
|
+
count: 1,
|
|
106
|
+
...context
|
|
107
|
+
});
|
|
108
|
+
return entity;
|
|
109
|
+
}
|
|
110
|
+
async function createManySeed(classOrClasses, { count, ...context }) {
|
|
111
|
+
if (Array.isArray(classOrClasses)) {
|
|
112
|
+
const effectiveContext = {
|
|
113
|
+
relations: false,
|
|
114
|
+
...context
|
|
115
|
+
};
|
|
116
|
+
return await Promise.all(classOrClasses.map((cls) => Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext)))));
|
|
117
|
+
}
|
|
118
|
+
return await Promise.all(Array.from({ length: count }, () => createOneSeed(classOrClasses, context)));
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/seed/persist.ts
|
|
122
|
+
function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
|
|
123
|
+
const EntityClass = entity.constructor;
|
|
124
|
+
if (visited.has(EntityClass)) return [];
|
|
125
|
+
visited.add(EntityClass);
|
|
126
|
+
const classes = [EntityClass];
|
|
127
|
+
for (const value of Object.values(entity)) if (Array.isArray(value)) {
|
|
128
|
+
for (const item of value) if (item && typeof item === "object" && item.constructor !== Object) classes.push(...collectEntityClasses(item, visited));
|
|
129
|
+
} else if (value && typeof value === "object" && value.constructor !== Object) classes.push(...collectEntityClasses(value, visited));
|
|
130
|
+
return classes;
|
|
131
|
+
}
|
|
132
|
+
function enableCascadeInsert(EntityClass, dataSource) {
|
|
133
|
+
const states = [];
|
|
134
|
+
try {
|
|
135
|
+
const relations = dataSource.getMetadata(EntityClass).relations;
|
|
136
|
+
for (const relation of relations) {
|
|
137
|
+
states.push({
|
|
138
|
+
relation,
|
|
139
|
+
original: relation.isCascadeInsert
|
|
140
|
+
});
|
|
141
|
+
relation.isCascadeInsert = true;
|
|
142
|
+
}
|
|
143
|
+
} catch {}
|
|
144
|
+
return states;
|
|
145
|
+
}
|
|
146
|
+
function restoreCascade(states) {
|
|
147
|
+
for (const { relation, original } of states) relation.isCascadeInsert = original;
|
|
148
|
+
}
|
|
149
|
+
async function saveSeed(classOrClasses, options) {
|
|
150
|
+
if (Array.isArray(classOrClasses)) {
|
|
151
|
+
const effectiveOptions = {
|
|
152
|
+
relations: false,
|
|
153
|
+
...options,
|
|
154
|
+
count: 1
|
|
155
|
+
};
|
|
156
|
+
return await Promise.all(classOrClasses.map((cls) => saveManySeed(cls, effectiveOptions).then(([entity]) => entity)));
|
|
157
|
+
}
|
|
158
|
+
const [entity] = await saveManySeed(classOrClasses, {
|
|
159
|
+
...options,
|
|
160
|
+
count: 1
|
|
161
|
+
});
|
|
162
|
+
return entity;
|
|
163
|
+
}
|
|
164
|
+
async function saveManySeed(classOrClasses, options) {
|
|
165
|
+
if (Array.isArray(classOrClasses)) {
|
|
166
|
+
const effectiveOptions = {
|
|
167
|
+
relations: false,
|
|
168
|
+
...options
|
|
169
|
+
};
|
|
170
|
+
return await Promise.all(classOrClasses.map((cls) => saveManySeedOne(cls, effectiveOptions)));
|
|
171
|
+
}
|
|
172
|
+
return await saveManySeedOne(classOrClasses, options);
|
|
173
|
+
}
|
|
174
|
+
async function saveManySeedOne(EntityClass, options) {
|
|
175
|
+
const { count, dataSource } = options;
|
|
176
|
+
if (count === 0) return [];
|
|
177
|
+
const entities = await createManySeed(EntityClass, options);
|
|
178
|
+
const visited = /* @__PURE__ */ new Set();
|
|
179
|
+
const states = entities.flatMap((entity) => collectEntityClasses(entity, visited)).flatMap((cls) => enableCascadeInsert(cls, dataSource));
|
|
180
|
+
try {
|
|
181
|
+
return await dataSource.getRepository(EntityClass).save(entities);
|
|
182
|
+
} finally {
|
|
183
|
+
restoreCascade(states);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/seed/builder.ts
|
|
188
|
+
function seed(classOrClasses) {
|
|
189
|
+
if (Array.isArray(classOrClasses)) {
|
|
190
|
+
const classes = classOrClasses;
|
|
191
|
+
return {
|
|
192
|
+
create: (context) => createSeed(classes, context),
|
|
193
|
+
save: (options) => saveSeed(classes, options),
|
|
194
|
+
createMany: (count, context) => createManySeed(classes, {
|
|
195
|
+
count,
|
|
196
|
+
...context
|
|
197
|
+
}),
|
|
198
|
+
saveMany: (count, options) => saveManySeed(classes, {
|
|
199
|
+
count,
|
|
200
|
+
...options
|
|
201
|
+
})
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const EntityClass = classOrClasses;
|
|
205
|
+
return {
|
|
206
|
+
create: (context) => createSeed(EntityClass, context),
|
|
207
|
+
save: (options) => saveSeed(EntityClass, options),
|
|
208
|
+
createMany: (count, context) => createManySeed(EntityClass, {
|
|
209
|
+
count,
|
|
210
|
+
...context
|
|
211
|
+
}),
|
|
212
|
+
saveMany: (count, options) => saveManySeed(EntityClass, {
|
|
213
|
+
count,
|
|
214
|
+
...options
|
|
215
|
+
})
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/seeder/registry.ts
|
|
220
|
+
const registry = /* @__PURE__ */ new WeakMap();
|
|
221
|
+
function registerSeeder(target, meta) {
|
|
222
|
+
registry.set(target, meta);
|
|
223
|
+
}
|
|
224
|
+
function getSeederMeta(target) {
|
|
225
|
+
return registry.get(target);
|
|
226
|
+
}
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/seeder/decorator.ts
|
|
229
|
+
function Seeder(options = {}) {
|
|
230
|
+
return (target) => {
|
|
231
|
+
registerSeeder(target, { dependencies: options.dependencies ?? [] });
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/seeder/runner.ts
|
|
236
|
+
function topoSort(roots) {
|
|
237
|
+
const graph = new dependency_graph.DepGraph();
|
|
238
|
+
const byName = /* @__PURE__ */ new Map();
|
|
239
|
+
const visited = /* @__PURE__ */ new Set();
|
|
240
|
+
const queue = [...roots];
|
|
241
|
+
while (queue.length > 0) {
|
|
242
|
+
const node = queue.shift();
|
|
243
|
+
if (visited.has(node)) continue;
|
|
244
|
+
visited.add(node);
|
|
245
|
+
graph.addNode(node.name, node);
|
|
246
|
+
byName.set(node.name, node);
|
|
247
|
+
for (const dep of getSeederMeta(node)?.dependencies ?? []) queue.push(dep);
|
|
248
|
+
}
|
|
249
|
+
for (const node of visited) for (const dep of getSeederMeta(node)?.dependencies ?? []) graph.addDependency(node.name, dep.name);
|
|
250
|
+
try {
|
|
251
|
+
return graph.overallOrder().map((name) => byName.get(name));
|
|
252
|
+
} catch (err) {
|
|
253
|
+
if (err && typeof err === "object" && "cyclePath" in err) {
|
|
254
|
+
const path = err.cyclePath.join(" → ");
|
|
255
|
+
throw new Error(`Circular dependency detected among seeders: ${path}`);
|
|
256
|
+
}
|
|
257
|
+
throw err;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async function runSeeders(seeders, context = {}) {
|
|
261
|
+
for (const SeederClass of topoSort(seeders)) await new SeederClass().run(context);
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
exports.Seed = Seed;
|
|
265
|
+
exports.Seeder = Seeder;
|
|
266
|
+
exports.createManySeed = createManySeed;
|
|
267
|
+
exports.createSeed = createSeed;
|
|
268
|
+
exports.runSeeders = runSeeders;
|
|
269
|
+
exports.saveManySeed = saveManySeed;
|
|
270
|
+
exports.saveSeed = saveSeed;
|
|
271
|
+
exports.seed = seed;
|
|
272
|
+
|
|
273
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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\nexport interface SeedContext {\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 passed to @Seed. */\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\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/** Mark a relation property for auto-seeding (creates one related entity). */\nexport function Seed(): PropertyDecorator;\n/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/** Mark a scalar property with a factory callback. */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Mark a scalar property with a factory callback and 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\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\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\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\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\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\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\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\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\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\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\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\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\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\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\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\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\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\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\nexport interface SeederOptions {\n dependencies?: (new () => SeederInterface)[];\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\ntype SeederCtor = new () => SeederInterface;\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\nexport async function runSeeders(seeders: SeederCtor[], context: SeedContext = {}): Promise<void> {\n for (const SeederClass of topoSort(seeders)) {\n await new SeederClass().run(context);\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { DataSource } from "typeorm";
|
|
2
|
+
|
|
3
|
+
//#region src/seed/registry.d.ts
|
|
4
|
+
/** An entity instance — any class-based object managed by TypeORM. */
|
|
5
|
+
type EntityInstance = object;
|
|
6
|
+
/** A constructor that produces an entity instance. */
|
|
7
|
+
type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;
|
|
8
|
+
interface SeedContext {
|
|
9
|
+
dataSource?: DataSource;
|
|
10
|
+
/**
|
|
11
|
+
* Set to `false` to skip automatic relation seeding. Scalar and embedded
|
|
12
|
+
* properties are still seeded; only relation properties decorated with a
|
|
13
|
+
* bare `@Seed()` are skipped. Useful when you want to create flat entities
|
|
14
|
+
* and wire relations yourself.
|
|
15
|
+
*
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
relations?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */
|
|
21
|
+
type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;
|
|
22
|
+
/** Options passed to @Seed. */
|
|
23
|
+
interface SeedOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Number of related entities to create. Only meaningful on one-to-many and
|
|
26
|
+
* many-to-many relation properties. Ignored on scalar and single-entity relations.
|
|
27
|
+
*/
|
|
28
|
+
count?: number;
|
|
29
|
+
}
|
|
30
|
+
interface SeedEntry {
|
|
31
|
+
propertyKey: string | symbol;
|
|
32
|
+
/** Undefined when @Seed is used without a factory (i.e. bare relation seed). */
|
|
33
|
+
factory: SeedFactory | undefined;
|
|
34
|
+
options: SeedOptions;
|
|
35
|
+
}
|
|
36
|
+
type MapToInstances<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never };
|
|
37
|
+
type MapToInstanceArrays<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never };
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/seed/decorator.d.ts
|
|
40
|
+
/** Mark a relation property for auto-seeding (creates one related entity). */
|
|
41
|
+
declare function Seed(): PropertyDecorator;
|
|
42
|
+
/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */
|
|
43
|
+
declare function Seed(options: SeedOptions): PropertyDecorator;
|
|
44
|
+
/** Mark a scalar property with a factory callback. */
|
|
45
|
+
declare function Seed(factory: SeedFactory): PropertyDecorator;
|
|
46
|
+
/** Mark a scalar property with a factory callback and options. */
|
|
47
|
+
declare function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/seed/persist.d.ts
|
|
50
|
+
interface SaveSeedOptions extends SeedContext {
|
|
51
|
+
dataSource: DataSource;
|
|
52
|
+
}
|
|
53
|
+
interface SaveManySeedOptions extends SaveSeedOptions {
|
|
54
|
+
count: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates and persists a seed entity and all its seeded relations.
|
|
58
|
+
* Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.
|
|
59
|
+
*/
|
|
60
|
+
declare function saveSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: SaveSeedOptions): Promise<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Creates and persists one instance of each entity class in the array.
|
|
63
|
+
* Relation seeding is disabled by default; pass `relations: true` to override.
|
|
64
|
+
*/
|
|
65
|
+
declare function saveSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveSeedOptions): Promise<MapToInstances<T>>;
|
|
66
|
+
/**
|
|
67
|
+
* Creates and persists multiple seed entities of the same class.
|
|
68
|
+
* Applies the same logic as {@link saveSeed} for each entity.
|
|
69
|
+
*/
|
|
70
|
+
declare function saveManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: SaveManySeedOptions): Promise<T[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Creates and persists multiple instances of each entity class in the array.
|
|
73
|
+
* Relation seeding is disabled by default; pass `relations: true` to override.
|
|
74
|
+
*/
|
|
75
|
+
declare function saveManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveManySeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/seed/builder.d.ts
|
|
78
|
+
interface SingleSeed<T extends EntityInstance> {
|
|
79
|
+
/** Creates a single instance in memory without persisting. */
|
|
80
|
+
create(context?: SeedContext): Promise<T>;
|
|
81
|
+
/** Creates and persists a single instance. */
|
|
82
|
+
save(options: SaveSeedOptions): Promise<T>;
|
|
83
|
+
/** Creates multiple instances in memory without persisting. */
|
|
84
|
+
createMany(count: number, context?: SeedContext): Promise<T[]>;
|
|
85
|
+
/** Creates and persists multiple instances. */
|
|
86
|
+
saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;
|
|
87
|
+
}
|
|
88
|
+
interface MultiSeed<T extends readonly EntityConstructor[]> {
|
|
89
|
+
/** Creates one instance of each class in memory without persisting. */
|
|
90
|
+
create(context?: SeedContext): Promise<MapToInstances<T>>;
|
|
91
|
+
/** Creates and persists one instance of each class. */
|
|
92
|
+
save(options: SaveSeedOptions): Promise<MapToInstances<T>>;
|
|
93
|
+
/** Creates `count` instances of each class in memory without persisting. */
|
|
94
|
+
createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;
|
|
95
|
+
/** Creates and persists `count` instances of each class. */
|
|
96
|
+
saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
97
|
+
}
|
|
98
|
+
declare function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;
|
|
99
|
+
declare function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/seed/creator.d.ts
|
|
102
|
+
interface CreateManySeedOptions extends SeedContext {
|
|
103
|
+
count: number;
|
|
104
|
+
}
|
|
105
|
+
declare function createSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, context?: SeedContext): Promise<T>;
|
|
106
|
+
declare function createSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], context?: SeedContext): Promise<MapToInstances<T>>;
|
|
107
|
+
declare function createManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: CreateManySeedOptions): Promise<T[]>;
|
|
108
|
+
declare function createManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: CreateManySeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/seeder/decorator.d.ts
|
|
111
|
+
interface SeederInterface {
|
|
112
|
+
run(context: SeedContext): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
interface SeederOptions {
|
|
115
|
+
dependencies?: (new () => SeederInterface)[];
|
|
116
|
+
}
|
|
117
|
+
declare function Seeder(options?: SeederOptions): ClassDecorator;
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/seeder/runner.d.ts
|
|
120
|
+
type SeederCtor = new () => SeederInterface;
|
|
121
|
+
declare function runSeeders(seeders: SeederCtor[], context?: SeedContext): Promise<void>;
|
|
122
|
+
//#endregion
|
|
123
|
+
export { type CreateManySeedOptions, type EntityConstructor, type EntityInstance, type SaveManySeedOptions, type SaveSeedOptions, Seed, type SeedContext, type SeedEntry, type SeedFactory, type SeedOptions, Seeder, type SeederInterface, type SeederOptions, createManySeed, createSeed, runSeeders, saveManySeed, saveSeed, seed };
|
|
124
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +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":"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"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { DataSource } from "typeorm";
|
|
2
|
+
|
|
3
|
+
//#region src/seed/registry.d.ts
|
|
4
|
+
/** An entity instance — any class-based object managed by TypeORM. */
|
|
5
|
+
type EntityInstance = object;
|
|
6
|
+
/** A constructor that produces an entity instance. */
|
|
7
|
+
type EntityConstructor<T extends EntityInstance = EntityInstance> = new () => T;
|
|
8
|
+
interface SeedContext {
|
|
9
|
+
dataSource?: DataSource;
|
|
10
|
+
/**
|
|
11
|
+
* Set to `false` to skip automatic relation seeding. Scalar and embedded
|
|
12
|
+
* properties are still seeded; only relation properties decorated with a
|
|
13
|
+
* bare `@Seed()` are skipped. Useful when you want to create flat entities
|
|
14
|
+
* and wire relations yourself.
|
|
15
|
+
*
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
relations?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Factory callback passed to @Seed. Receives the seeder context, which may include a DataSource. */
|
|
21
|
+
type SeedFactory<T = unknown> = (context: SeedContext) => T | Promise<T>;
|
|
22
|
+
/** Options passed to @Seed. */
|
|
23
|
+
interface SeedOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Number of related entities to create. Only meaningful on one-to-many and
|
|
26
|
+
* many-to-many relation properties. Ignored on scalar and single-entity relations.
|
|
27
|
+
*/
|
|
28
|
+
count?: number;
|
|
29
|
+
}
|
|
30
|
+
interface SeedEntry {
|
|
31
|
+
propertyKey: string | symbol;
|
|
32
|
+
/** Undefined when @Seed is used without a factory (i.e. bare relation seed). */
|
|
33
|
+
factory: SeedFactory | undefined;
|
|
34
|
+
options: SeedOptions;
|
|
35
|
+
}
|
|
36
|
+
type MapToInstances<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I : never };
|
|
37
|
+
type MapToInstanceArrays<T extends readonly EntityConstructor[]> = { [K in keyof T]: T[K] extends EntityConstructor<infer I> ? I[] : never };
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/seed/decorator.d.ts
|
|
40
|
+
/** Mark a relation property for auto-seeding (creates one related entity). */
|
|
41
|
+
declare function Seed(): PropertyDecorator;
|
|
42
|
+
/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */
|
|
43
|
+
declare function Seed(options: SeedOptions): PropertyDecorator;
|
|
44
|
+
/** Mark a scalar property with a factory callback. */
|
|
45
|
+
declare function Seed(factory: SeedFactory): PropertyDecorator;
|
|
46
|
+
/** Mark a scalar property with a factory callback and options. */
|
|
47
|
+
declare function Seed(factory: SeedFactory, options: SeedOptions): PropertyDecorator;
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/seed/persist.d.ts
|
|
50
|
+
interface SaveSeedOptions extends SeedContext {
|
|
51
|
+
dataSource: DataSource;
|
|
52
|
+
}
|
|
53
|
+
interface SaveManySeedOptions extends SaveSeedOptions {
|
|
54
|
+
count: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates and persists a seed entity and all its seeded relations.
|
|
58
|
+
* Delegates to {@link saveManySeed} with `count: 1` and unwraps the result.
|
|
59
|
+
*/
|
|
60
|
+
declare function saveSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: SaveSeedOptions): Promise<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Creates and persists one instance of each entity class in the array.
|
|
63
|
+
* Relation seeding is disabled by default; pass `relations: true` to override.
|
|
64
|
+
*/
|
|
65
|
+
declare function saveSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveSeedOptions): Promise<MapToInstances<T>>;
|
|
66
|
+
/**
|
|
67
|
+
* Creates and persists multiple seed entities of the same class.
|
|
68
|
+
* Applies the same logic as {@link saveSeed} for each entity.
|
|
69
|
+
*/
|
|
70
|
+
declare function saveManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: SaveManySeedOptions): Promise<T[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Creates and persists multiple instances of each entity class in the array.
|
|
73
|
+
* Relation seeding is disabled by default; pass `relations: true` to override.
|
|
74
|
+
*/
|
|
75
|
+
declare function saveManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: SaveManySeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/seed/builder.d.ts
|
|
78
|
+
interface SingleSeed<T extends EntityInstance> {
|
|
79
|
+
/** Creates a single instance in memory without persisting. */
|
|
80
|
+
create(context?: SeedContext): Promise<T>;
|
|
81
|
+
/** Creates and persists a single instance. */
|
|
82
|
+
save(options: SaveSeedOptions): Promise<T>;
|
|
83
|
+
/** Creates multiple instances in memory without persisting. */
|
|
84
|
+
createMany(count: number, context?: SeedContext): Promise<T[]>;
|
|
85
|
+
/** Creates and persists multiple instances. */
|
|
86
|
+
saveMany(count: number, options: SaveSeedOptions): Promise<T[]>;
|
|
87
|
+
}
|
|
88
|
+
interface MultiSeed<T extends readonly EntityConstructor[]> {
|
|
89
|
+
/** Creates one instance of each class in memory without persisting. */
|
|
90
|
+
create(context?: SeedContext): Promise<MapToInstances<T>>;
|
|
91
|
+
/** Creates and persists one instance of each class. */
|
|
92
|
+
save(options: SaveSeedOptions): Promise<MapToInstances<T>>;
|
|
93
|
+
/** Creates `count` instances of each class in memory without persisting. */
|
|
94
|
+
createMany(count: number, context?: SeedContext): Promise<MapToInstanceArrays<T>>;
|
|
95
|
+
/** Creates and persists `count` instances of each class. */
|
|
96
|
+
saveMany(count: number, options: SaveSeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
97
|
+
}
|
|
98
|
+
declare function seed<T extends EntityInstance>(EntityClass: EntityConstructor<T>): SingleSeed<T>;
|
|
99
|
+
declare function seed<T extends readonly EntityConstructor[]>(EntityClasses: [...T]): MultiSeed<T>;
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/seed/creator.d.ts
|
|
102
|
+
interface CreateManySeedOptions extends SeedContext {
|
|
103
|
+
count: number;
|
|
104
|
+
}
|
|
105
|
+
declare function createSeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, context?: SeedContext): Promise<T>;
|
|
106
|
+
declare function createSeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], context?: SeedContext): Promise<MapToInstances<T>>;
|
|
107
|
+
declare function createManySeed<T extends EntityInstance>(EntityClass: EntityConstructor<T>, options: CreateManySeedOptions): Promise<T[]>;
|
|
108
|
+
declare function createManySeed<T extends readonly EntityConstructor[]>(EntityClasses: [...T], options: CreateManySeedOptions): Promise<MapToInstanceArrays<T>>;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/seeder/decorator.d.ts
|
|
111
|
+
interface SeederInterface {
|
|
112
|
+
run(context: SeedContext): Promise<void>;
|
|
113
|
+
}
|
|
114
|
+
interface SeederOptions {
|
|
115
|
+
dependencies?: (new () => SeederInterface)[];
|
|
116
|
+
}
|
|
117
|
+
declare function Seeder(options?: SeederOptions): ClassDecorator;
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/seeder/runner.d.ts
|
|
120
|
+
type SeederCtor = new () => SeederInterface;
|
|
121
|
+
declare function runSeeders(seeders: SeederCtor[], context?: SeedContext): Promise<void>;
|
|
122
|
+
//#endregion
|
|
123
|
+
export { type CreateManySeedOptions, type EntityConstructor, type EntityInstance, type SaveManySeedOptions, type SaveSeedOptions, Seed, type SeedContext, type SeedEntry, type SeedFactory, type SeedOptions, Seeder, type SeederInterface, type SeederOptions, createManySeed, createSeed, runSeeders, saveManySeed, saveSeed, seed };
|
|
124
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +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":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { getMetadataArgsStorage } from "typeorm";
|
|
2
|
+
import { DepGraph } from "dependency-graph";
|
|
3
|
+
//#region src/seed/registry.ts
|
|
4
|
+
const registry$1 = /* @__PURE__ */ new Map();
|
|
5
|
+
function registerSeed(target, entry) {
|
|
6
|
+
const entries = registry$1.get(target) ?? [];
|
|
7
|
+
entries.push(entry);
|
|
8
|
+
registry$1.set(target, entries);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Returns all seed entries for the given class, including those inherited from
|
|
12
|
+
* parent classes. Parent entries come first, preserving declaration order.
|
|
13
|
+
*/
|
|
14
|
+
function getSeeds(target) {
|
|
15
|
+
const entries = [];
|
|
16
|
+
let current = target;
|
|
17
|
+
while (current && current !== Function.prototype) {
|
|
18
|
+
const own = registry$1.get(current);
|
|
19
|
+
if (own) entries.unshift(...own);
|
|
20
|
+
current = Object.getPrototypeOf(current);
|
|
21
|
+
}
|
|
22
|
+
return entries;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/seed/decorator.ts
|
|
26
|
+
function Seed(factoryOrOptions, options) {
|
|
27
|
+
const factory = typeof factoryOrOptions === "function" ? factoryOrOptions : void 0;
|
|
28
|
+
const opts = (typeof factoryOrOptions === "object" ? factoryOrOptions : options) ?? {};
|
|
29
|
+
return (target, propertyKey) => {
|
|
30
|
+
registerSeed(target.constructor, {
|
|
31
|
+
propertyKey,
|
|
32
|
+
factory,
|
|
33
|
+
options: opts
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/seed/creator.ts
|
|
39
|
+
function getAncestors(context) {
|
|
40
|
+
return context._ancestors ?? /* @__PURE__ */ new Set();
|
|
41
|
+
}
|
|
42
|
+
function withAncestor(context, cls) {
|
|
43
|
+
const ancestors = getAncestors(context);
|
|
44
|
+
return {
|
|
45
|
+
...context,
|
|
46
|
+
_ancestors: new Set([...ancestors, cls])
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function getClassHierarchy(target) {
|
|
50
|
+
const hierarchy = [];
|
|
51
|
+
let current = target;
|
|
52
|
+
while (current && current !== Function.prototype) {
|
|
53
|
+
hierarchy.push(current);
|
|
54
|
+
current = Object.getPrototypeOf(current);
|
|
55
|
+
}
|
|
56
|
+
return hierarchy;
|
|
57
|
+
}
|
|
58
|
+
async function createOneSeed(EntityClass, context) {
|
|
59
|
+
const instance = new EntityClass();
|
|
60
|
+
const ancestors = getAncestors(context);
|
|
61
|
+
const childContext = withAncestor(context, EntityClass);
|
|
62
|
+
const storage = getMetadataArgsStorage();
|
|
63
|
+
const relations = storage.filterRelations(getClassHierarchy(EntityClass));
|
|
64
|
+
const seededProperties = /* @__PURE__ */ new Set();
|
|
65
|
+
const record = instance;
|
|
66
|
+
for (const { propertyKey, factory } of getSeeds(EntityClass)) {
|
|
67
|
+
if (!factory) continue;
|
|
68
|
+
record[propertyKey] = await factory(context);
|
|
69
|
+
seededProperties.add(propertyKey);
|
|
70
|
+
}
|
|
71
|
+
for (const embedded of storage.filterEmbeddeds(EntityClass)) {
|
|
72
|
+
if (seededProperties.has(embedded.propertyName)) continue;
|
|
73
|
+
const EmbeddedClass = embedded.type();
|
|
74
|
+
if (getSeeds(EmbeddedClass).length > 0) {
|
|
75
|
+
record[embedded.propertyName] = await createOneSeed(EmbeddedClass, context);
|
|
76
|
+
seededProperties.add(embedded.propertyName);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (context.relations === false) return instance;
|
|
80
|
+
for (const { propertyKey, factory, options } of getSeeds(EntityClass)) {
|
|
81
|
+
if (factory || seededProperties.has(propertyKey)) continue;
|
|
82
|
+
const relation = relations.find((r) => r.propertyName === String(propertyKey));
|
|
83
|
+
if (!relation || typeof relation.type !== "function") continue;
|
|
84
|
+
const RelatedClass = relation.type();
|
|
85
|
+
if (ancestors.has(RelatedClass)) continue;
|
|
86
|
+
if (relation.relationType === "one-to-many" || relation.relationType === "many-to-many") record[propertyKey] = await createManySeed(RelatedClass, {
|
|
87
|
+
count: options.count ?? 1,
|
|
88
|
+
...childContext
|
|
89
|
+
});
|
|
90
|
+
else record[propertyKey] = await createOneSeed(RelatedClass, childContext);
|
|
91
|
+
seededProperties.add(propertyKey);
|
|
92
|
+
}
|
|
93
|
+
return instance;
|
|
94
|
+
}
|
|
95
|
+
async function createSeed(classOrClasses, context = {}) {
|
|
96
|
+
if (Array.isArray(classOrClasses)) {
|
|
97
|
+
const effectiveContext = {
|
|
98
|
+
relations: false,
|
|
99
|
+
...context
|
|
100
|
+
};
|
|
101
|
+
return await Promise.all(classOrClasses.map((cls) => createOneSeed(cls, effectiveContext)));
|
|
102
|
+
}
|
|
103
|
+
const [entity] = await createManySeed(classOrClasses, {
|
|
104
|
+
count: 1,
|
|
105
|
+
...context
|
|
106
|
+
});
|
|
107
|
+
return entity;
|
|
108
|
+
}
|
|
109
|
+
async function createManySeed(classOrClasses, { count, ...context }) {
|
|
110
|
+
if (Array.isArray(classOrClasses)) {
|
|
111
|
+
const effectiveContext = {
|
|
112
|
+
relations: false,
|
|
113
|
+
...context
|
|
114
|
+
};
|
|
115
|
+
return await Promise.all(classOrClasses.map((cls) => Promise.all(Array.from({ length: count }, () => createOneSeed(cls, effectiveContext)))));
|
|
116
|
+
}
|
|
117
|
+
return await Promise.all(Array.from({ length: count }, () => createOneSeed(classOrClasses, context)));
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/seed/persist.ts
|
|
121
|
+
function collectEntityClasses(entity, visited = /* @__PURE__ */ new Set()) {
|
|
122
|
+
const EntityClass = entity.constructor;
|
|
123
|
+
if (visited.has(EntityClass)) return [];
|
|
124
|
+
visited.add(EntityClass);
|
|
125
|
+
const classes = [EntityClass];
|
|
126
|
+
for (const value of Object.values(entity)) if (Array.isArray(value)) {
|
|
127
|
+
for (const item of value) if (item && typeof item === "object" && item.constructor !== Object) classes.push(...collectEntityClasses(item, visited));
|
|
128
|
+
} else if (value && typeof value === "object" && value.constructor !== Object) classes.push(...collectEntityClasses(value, visited));
|
|
129
|
+
return classes;
|
|
130
|
+
}
|
|
131
|
+
function enableCascadeInsert(EntityClass, dataSource) {
|
|
132
|
+
const states = [];
|
|
133
|
+
try {
|
|
134
|
+
const relations = dataSource.getMetadata(EntityClass).relations;
|
|
135
|
+
for (const relation of relations) {
|
|
136
|
+
states.push({
|
|
137
|
+
relation,
|
|
138
|
+
original: relation.isCascadeInsert
|
|
139
|
+
});
|
|
140
|
+
relation.isCascadeInsert = true;
|
|
141
|
+
}
|
|
142
|
+
} catch {}
|
|
143
|
+
return states;
|
|
144
|
+
}
|
|
145
|
+
function restoreCascade(states) {
|
|
146
|
+
for (const { relation, original } of states) relation.isCascadeInsert = original;
|
|
147
|
+
}
|
|
148
|
+
async function saveSeed(classOrClasses, options) {
|
|
149
|
+
if (Array.isArray(classOrClasses)) {
|
|
150
|
+
const effectiveOptions = {
|
|
151
|
+
relations: false,
|
|
152
|
+
...options,
|
|
153
|
+
count: 1
|
|
154
|
+
};
|
|
155
|
+
return await Promise.all(classOrClasses.map((cls) => saveManySeed(cls, effectiveOptions).then(([entity]) => entity)));
|
|
156
|
+
}
|
|
157
|
+
const [entity] = await saveManySeed(classOrClasses, {
|
|
158
|
+
...options,
|
|
159
|
+
count: 1
|
|
160
|
+
});
|
|
161
|
+
return entity;
|
|
162
|
+
}
|
|
163
|
+
async function saveManySeed(classOrClasses, options) {
|
|
164
|
+
if (Array.isArray(classOrClasses)) {
|
|
165
|
+
const effectiveOptions = {
|
|
166
|
+
relations: false,
|
|
167
|
+
...options
|
|
168
|
+
};
|
|
169
|
+
return await Promise.all(classOrClasses.map((cls) => saveManySeedOne(cls, effectiveOptions)));
|
|
170
|
+
}
|
|
171
|
+
return await saveManySeedOne(classOrClasses, options);
|
|
172
|
+
}
|
|
173
|
+
async function saveManySeedOne(EntityClass, options) {
|
|
174
|
+
const { count, dataSource } = options;
|
|
175
|
+
if (count === 0) return [];
|
|
176
|
+
const entities = await createManySeed(EntityClass, options);
|
|
177
|
+
const visited = /* @__PURE__ */ new Set();
|
|
178
|
+
const states = entities.flatMap((entity) => collectEntityClasses(entity, visited)).flatMap((cls) => enableCascadeInsert(cls, dataSource));
|
|
179
|
+
try {
|
|
180
|
+
return await dataSource.getRepository(EntityClass).save(entities);
|
|
181
|
+
} finally {
|
|
182
|
+
restoreCascade(states);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/seed/builder.ts
|
|
187
|
+
function seed(classOrClasses) {
|
|
188
|
+
if (Array.isArray(classOrClasses)) {
|
|
189
|
+
const classes = classOrClasses;
|
|
190
|
+
return {
|
|
191
|
+
create: (context) => createSeed(classes, context),
|
|
192
|
+
save: (options) => saveSeed(classes, options),
|
|
193
|
+
createMany: (count, context) => createManySeed(classes, {
|
|
194
|
+
count,
|
|
195
|
+
...context
|
|
196
|
+
}),
|
|
197
|
+
saveMany: (count, options) => saveManySeed(classes, {
|
|
198
|
+
count,
|
|
199
|
+
...options
|
|
200
|
+
})
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const EntityClass = classOrClasses;
|
|
204
|
+
return {
|
|
205
|
+
create: (context) => createSeed(EntityClass, context),
|
|
206
|
+
save: (options) => saveSeed(EntityClass, options),
|
|
207
|
+
createMany: (count, context) => createManySeed(EntityClass, {
|
|
208
|
+
count,
|
|
209
|
+
...context
|
|
210
|
+
}),
|
|
211
|
+
saveMany: (count, options) => saveManySeed(EntityClass, {
|
|
212
|
+
count,
|
|
213
|
+
...options
|
|
214
|
+
})
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/seeder/registry.ts
|
|
219
|
+
const registry = /* @__PURE__ */ new WeakMap();
|
|
220
|
+
function registerSeeder(target, meta) {
|
|
221
|
+
registry.set(target, meta);
|
|
222
|
+
}
|
|
223
|
+
function getSeederMeta(target) {
|
|
224
|
+
return registry.get(target);
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/seeder/decorator.ts
|
|
228
|
+
function Seeder(options = {}) {
|
|
229
|
+
return (target) => {
|
|
230
|
+
registerSeeder(target, { dependencies: options.dependencies ?? [] });
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/seeder/runner.ts
|
|
235
|
+
function topoSort(roots) {
|
|
236
|
+
const graph = new DepGraph();
|
|
237
|
+
const byName = /* @__PURE__ */ new Map();
|
|
238
|
+
const visited = /* @__PURE__ */ new Set();
|
|
239
|
+
const queue = [...roots];
|
|
240
|
+
while (queue.length > 0) {
|
|
241
|
+
const node = queue.shift();
|
|
242
|
+
if (visited.has(node)) continue;
|
|
243
|
+
visited.add(node);
|
|
244
|
+
graph.addNode(node.name, node);
|
|
245
|
+
byName.set(node.name, node);
|
|
246
|
+
for (const dep of getSeederMeta(node)?.dependencies ?? []) queue.push(dep);
|
|
247
|
+
}
|
|
248
|
+
for (const node of visited) for (const dep of getSeederMeta(node)?.dependencies ?? []) graph.addDependency(node.name, dep.name);
|
|
249
|
+
try {
|
|
250
|
+
return graph.overallOrder().map((name) => byName.get(name));
|
|
251
|
+
} catch (err) {
|
|
252
|
+
if (err && typeof err === "object" && "cyclePath" in err) {
|
|
253
|
+
const path = err.cyclePath.join(" → ");
|
|
254
|
+
throw new Error(`Circular dependency detected among seeders: ${path}`);
|
|
255
|
+
}
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async function runSeeders(seeders, context = {}) {
|
|
260
|
+
for (const SeederClass of topoSort(seeders)) await new SeederClass().run(context);
|
|
261
|
+
}
|
|
262
|
+
//#endregion
|
|
263
|
+
export { Seed, Seeder, createManySeed, createSeed, runSeeders, saveManySeed, saveSeed, seed };
|
|
264
|
+
|
|
265
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +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\nexport interface SeedContext {\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 passed to @Seed. */\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\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/** Mark a relation property for auto-seeding (creates one related entity). */\nexport function Seed(): PropertyDecorator;\n/** Mark a relation property for auto-seeding with options (e.g. count for one-to-many). */\nexport function Seed(options: SeedOptions): PropertyDecorator;\n/** Mark a scalar property with a factory callback. */\nexport function Seed(factory: SeedFactory): PropertyDecorator;\n/** Mark a scalar property with a factory callback and 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\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\nfunction getAncestors(context: SeedContext): Set<Function> {\n return (context as InternalContext)._ancestors ?? new Set();\n}\n\nfunction withAncestor(context: SeedContext, cls: Function): InternalContext {\n const ancestors = getAncestors(context);\n\n return { ...context, _ancestors: new Set([...ancestors, cls]) };\n}\n\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\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\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\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\nexport interface SaveSeedOptions extends SeedContext {\n dataSource: DataSource;\n}\n\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\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\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\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\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\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\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\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\nexport function registerSeeder(target: Function, meta: SeederMeta): void {\n registry.set(target, meta);\n}\n\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\nexport interface SeederInterface {\n run(context: SeedContext): Promise<void>;\n}\n\nexport interface SeederOptions {\n dependencies?: (new () => SeederInterface)[];\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\ntype SeederCtor = new () => SeederInterface;\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\nexport async function runSeeders(seeders: SeederCtor[], context: SeedContext = {}): Promise<void> {\n for (const SeederClass of topoSort(seeders)) {\n await new SeederClass().run(context);\n }\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@joakimbugge/typeorm-seeder",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Decorator-based seeder library for TypeORM",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/joakimbugge/to-seeder.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/joakimbugge/to-seeder#readme",
|
|
10
|
+
"bugs": "https://github.com/joakimbugge/to-seeder/issues",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"default": "./dist/index.mjs"
|
|
20
|
+
},
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./dist/index.d.cts",
|
|
23
|
+
"default": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsdown",
|
|
32
|
+
"prepublishOnly": "npm run build",
|
|
33
|
+
"dev": "tsdown --watch",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"test": "vitest",
|
|
36
|
+
"test:run": "vitest run",
|
|
37
|
+
"lint": "oxlint src tests",
|
|
38
|
+
"lint:fix": "oxlint --fix src tests",
|
|
39
|
+
"fmt": "oxfmt src tests",
|
|
40
|
+
"fmt:check": "oxfmt --check src tests"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"typeorm",
|
|
44
|
+
"seeder",
|
|
45
|
+
"decorator",
|
|
46
|
+
"database",
|
|
47
|
+
"seed"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=16.13.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"reflect-metadata": ">=0.1.0",
|
|
55
|
+
"typeorm": ">=0.3.0"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@faker-js/faker": "^10.4.0",
|
|
59
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
60
|
+
"better-sqlite3": "^12.8.0",
|
|
61
|
+
"lefthook": "^2.1.4",
|
|
62
|
+
"oxfmt": "^0.42.0",
|
|
63
|
+
"oxlint": "^1.57.0",
|
|
64
|
+
"reflect-metadata": "^0.2.2",
|
|
65
|
+
"tsdown": "^0.21.4",
|
|
66
|
+
"tsx": "^4.21.0",
|
|
67
|
+
"typeorm": "1.0.0-beta.1",
|
|
68
|
+
"typescript": "^5.9.3",
|
|
69
|
+
"vitest": "^4.1.1"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"dependency-graph": "^1.0.0"
|
|
73
|
+
}
|
|
74
|
+
}
|