@skmdev/prisma-fixtures 0.1.1
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/NOTICE +29 -0
- package/README.md +631 -0
- package/dist/cleanup-options.d.ts +5 -0
- package/dist/cleanup-options.js +19 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +342 -0
- package/dist/fixture-config.d.ts +14 -0
- package/dist/fixture-config.js +95 -0
- package/dist/fixture-document.d.ts +23 -0
- package/dist/fixture-document.js +349 -0
- package/dist/fixture-error.d.ts +22 -0
- package/dist/fixture-error.js +54 -0
- package/dist/fixture-reference.d.ts +17 -0
- package/dist/fixture-reference.js +234 -0
- package/dist/fixture-schema.d.ts +10 -0
- package/dist/fixture-schema.js +243 -0
- package/dist/fixture-template.d.ts +14 -0
- package/dist/fixture-template.js +239 -0
- package/dist/generator.d.ts +2 -0
- package/dist/generator.js +25 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +257 -0
- package/dist/load-options.d.ts +11 -0
- package/dist/load-options.js +47 -0
- package/dist/prisma-config.d.ts +8 -0
- package/dist/prisma-config.js +111 -0
- package/package.json +83 -0
- package/schema/fixture.schema.json +119 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 skmdev
|
|
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/NOTICE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
This package implements the fixture language described by
|
|
2
|
+
https://github.com/getbigger-io/prisma-fixtures
|
|
3
|
+
Reference revision: bed45fdf82af1002cd51c527d71f5b0b5757884d
|
|
4
|
+
|
|
5
|
+
The implementation has been rewritten for caller-owned Prisma clients, modern
|
|
6
|
+
Faker, bounded validation, asynchronous modules and an explicit public API.
|
|
7
|
+
Upstream copyright and permission notice are retained below.
|
|
8
|
+
|
|
9
|
+
MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2019 Igor Ognichenko
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
# @skmdev/prisma-fixtures
|
|
2
|
+
|
|
3
|
+
Load YAML or JSON fixtures into Prisma using named references, generated data and
|
|
4
|
+
processors. The CLI can initialize a generated Prisma 7 client from your Prisma
|
|
5
|
+
config; the API also accepts a client you create.
|
|
6
|
+
|
|
7
|
+
Requires Node.js 22.18+; tested with Prisma 7.10 and PostgreSQL. Prisma itself is
|
|
8
|
+
provided by your application, not installed as a runtime dependency of this package.
|
|
9
|
+
|
|
10
|
+
- [Quick start](#quick-start)
|
|
11
|
+
- [Fixture format](#fixture-format)
|
|
12
|
+
- [Processors](#processors)
|
|
13
|
+
- [API and persistence](#api-and-persistence)
|
|
14
|
+
- [CLI](#cli)
|
|
15
|
+
- [Fixture linting and editor support](#fixture-linting-and-editor-support)
|
|
16
|
+
- [Trust and limits](#trust-and-limits)
|
|
17
|
+
- [Compatibility and attribution](#compatibility-and-attribution)
|
|
18
|
+
- [Contributing and releases](CONTRIBUTING.md)
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
Start with an existing Prisma 7 application that has:
|
|
23
|
+
|
|
24
|
+
- `prisma`, `@prisma/client` and `@prisma/adapter-pg` installed.
|
|
25
|
+
- A `prisma.config.ts`, a `prisma-client` generator and a PostgreSQL database
|
|
26
|
+
configured through `DATABASE_URL`. See [client discovery](#client-discovery-and-overrides)
|
|
27
|
+
for TypeScript and CommonJS runtime setup.
|
|
28
|
+
- `User` and `Post` models compatible with the following fields, with their
|
|
29
|
+
tables already created by your application's migrations. Fixtures insert data;
|
|
30
|
+
they do not create tables.
|
|
31
|
+
|
|
32
|
+
<details>
|
|
33
|
+
<summary>Minimal User and Post models</summary>
|
|
34
|
+
|
|
35
|
+
```prisma
|
|
36
|
+
model User {
|
|
37
|
+
id Int @id @default(autoincrement())
|
|
38
|
+
email String @unique
|
|
39
|
+
name String
|
|
40
|
+
posts Post[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
model Post {
|
|
44
|
+
id Int @id @default(autoincrement())
|
|
45
|
+
title String
|
|
46
|
+
authorId Int
|
|
47
|
+
author User @relation(fields: [authorId], references: [id])
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
### 1. Install and initialize
|
|
54
|
+
|
|
55
|
+
Run beside your `prisma.config.ts`:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npm install --save-dev @skmdev/prisma-fixtures
|
|
59
|
+
npx prisma-fixtures init
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This creates `.prisma-fixtures` and a fixtures directory. It uses `prisma/fixtures`
|
|
63
|
+
if that directory already exists; otherwise it creates `fixtures`. The examples
|
|
64
|
+
below assume the latter, with this generated config:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"fixtures": ["./fixtures"]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Add fixtures
|
|
73
|
+
|
|
74
|
+
Use the directory recorded in `.prisma-fixtures` for both files.
|
|
75
|
+
Create `fixtures/users.yml`:
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
entity: User
|
|
79
|
+
items:
|
|
80
|
+
user{1..3}:
|
|
81
|
+
email: 'user($current)@example.test'
|
|
82
|
+
name: '{{person.firstName}} {{person.lastName}}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Create `fixtures/posts.yml`:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
entity: Post
|
|
89
|
+
connectedFields: [author]
|
|
90
|
+
items:
|
|
91
|
+
post{1..3}:
|
|
92
|
+
title: 'Post ($current)'
|
|
93
|
+
author: '@user($current)'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 3. Configure and run the seed
|
|
97
|
+
|
|
98
|
+
Add `seed` to `migrations` in your existing `prisma.config.ts`, keeping your other
|
|
99
|
+
settings:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
export default defineConfig({
|
|
103
|
+
// Keep your existing schema, datasource and other settings.
|
|
104
|
+
migrations: { seed: 'prisma-fixtures' },
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
With `DATABASE_URL` available, generate the client, check the fixtures and seed:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npx prisma generate
|
|
112
|
+
npx prisma-fixtures --lint
|
|
113
|
+
npx prisma db seed
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The CLI prints `Loaded 6 fixtures.`: three users, each with one related post,
|
|
117
|
+
committed in one transaction. It reads your Prisma config; no client wrapper is
|
|
118
|
+
needed. For loading from application code, see [API and persistence](#api-and-persistence).
|
|
119
|
+
|
|
120
|
+
Ordinary loading only inserts; it does not upsert or delete. Running this example
|
|
121
|
+
again fails on the unique emails. To clear and reload, use
|
|
122
|
+
`npx prisma db seed -- --reset`. **Reset clears data from all ordinary/partitioned
|
|
123
|
+
tables in non-system schemas, including tables absent from your fixtures.**
|
|
124
|
+
Migration history and tables preserved by `preserveTables` or Prisma's
|
|
125
|
+
`tables.external` remain; see [cleanup and reset](#cleanup-and-reset).
|
|
126
|
+
|
|
127
|
+
See the [framework and runtime examples](examples/README.md) for standalone apps
|
|
128
|
+
with Argon2 password processors and API endpoints. NestJS demonstrates a CommonJS client.
|
|
129
|
+
|
|
130
|
+
## Fixture format
|
|
131
|
+
|
|
132
|
+
Each `.yml`, `.yaml` or `.json` file describes one entity. `User` and `user` both
|
|
133
|
+
resolve to the `user` delegate. Directory files are sorted; reference dependencies
|
|
134
|
+
determine insert order. Fixture names must be unique across all files.
|
|
135
|
+
|
|
136
|
+
| Feature | Example | Meaning |
|
|
137
|
+
| ------------------------ | -------------------------------- | ------------------------------------------------------------- |
|
|
138
|
+
| Inclusive range | `user{1..10}` | Ten independent records |
|
|
139
|
+
| Current index | `user($current)@example.test` | Numeric suffix of the expanded fixture name |
|
|
140
|
+
| Arithmetic | `($current*100)` | One `+`, `-`, `*` or `/` operation with a nonnegative integer |
|
|
141
|
+
| Record reference | `'@user1'` | The saved record |
|
|
142
|
+
| Field reference | `'@user1.id'` | An own field of the saved record |
|
|
143
|
+
| Random reference | `'@user*'` | One existing name with that prefix and a numeric suffix |
|
|
144
|
+
| Bounded random reference | `'@user{1..3}'` | One of user1, user2 or user3; all must exist |
|
|
145
|
+
| Literal `@` | `'@@literal'` | Produces `@literal` |
|
|
146
|
+
| Parameters | `'<{names.admin}>'` | A parameter from this document, converted to text |
|
|
147
|
+
| Faker | `'{{internet.email}}'` | Generated value; a standalone provider preserves its type |
|
|
148
|
+
| EJS | `"<%= ['a', 'b'].join(', ') %>"` | JavaScript template rendered to text |
|
|
149
|
+
|
|
150
|
+
### References and relations
|
|
151
|
+
|
|
152
|
+
Quote references and template expressions in YAML. Arrays and nested objects are
|
|
153
|
+
supported. Random choices are selected once before dependency ordering. Missing
|
|
154
|
+
references and cycles fail before any insert. An absent scalar field can only be
|
|
155
|
+
detected after its referenced record has been saved; use a transaction for atomicity.
|
|
156
|
+
|
|
157
|
+
`connectedFields` converts a saved record into `{ connect: { id } }`, or an array
|
|
158
|
+
into `{ connect: [{ id }, ...] }`. Referenced models need an `id` field for this
|
|
159
|
+
shorthand. For other unique keys use Prisma's explicit nested input:
|
|
160
|
+
|
|
161
|
+
```yaml
|
|
162
|
+
entity: Post
|
|
163
|
+
items:
|
|
164
|
+
post1:
|
|
165
|
+
title: Example
|
|
166
|
+
author:
|
|
167
|
+
connect:
|
|
168
|
+
email: '@user1.email'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Deferred fields
|
|
172
|
+
|
|
173
|
+
For a nullable scalar link that cannot exist until another fixture is created,
|
|
174
|
+
declare `deferredFields`. The loader omits those fields on create, then updates
|
|
175
|
+
the saved rows after all creates. For example, a candidate's optional primary
|
|
176
|
+
resume points to a resume that requires the candidate to exist first:
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
# fixtures/candidates.yml
|
|
180
|
+
entity: Candidate
|
|
181
|
+
deferredFields: [primaryResumeId]
|
|
182
|
+
items:
|
|
183
|
+
candidate1:
|
|
184
|
+
id: can_local_1
|
|
185
|
+
primaryResumeId: rsu_local_1
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
# fixtures/resumes.yml
|
|
190
|
+
entity: Resume
|
|
191
|
+
items:
|
|
192
|
+
resume1:
|
|
193
|
+
id: rsu_local_1
|
|
194
|
+
candidateId: '@candidate1.id'
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The loader creates `candidate1` without `primaryResumeId`, creates `resume1`, then
|
|
198
|
+
sets the candidate's primary resume. Use a fixed ID for the deferred link here:
|
|
199
|
+
`'@resume1.id'` would create a reference cycle because references are still
|
|
200
|
+
resolved before inserts. The models must allow `primaryResumeId` to be omitted
|
|
201
|
+
on create and accept the explicit string IDs shown above.
|
|
202
|
+
|
|
203
|
+
Deferred fields require a saved `id`, a Prisma `update` delegate and the default
|
|
204
|
+
writer. Use a transaction so a failed update rolls back the earlier creates.
|
|
205
|
+
Include an `@updatedAt` field in `deferredFields` when that update must retain a
|
|
206
|
+
specific fixture timestamp.
|
|
207
|
+
|
|
208
|
+
### Parameters and templates
|
|
209
|
+
|
|
210
|
+
Parameters, locale and templates can be combined:
|
|
211
|
+
|
|
212
|
+
```yaml
|
|
213
|
+
entity: User
|
|
214
|
+
locale: en
|
|
215
|
+
parameters:
|
|
216
|
+
names:
|
|
217
|
+
admin: Administrator
|
|
218
|
+
items:
|
|
219
|
+
admin1:
|
|
220
|
+
email: admin@example.test
|
|
221
|
+
name: '<{names.admin}> <%= name %>'
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
EJS receives the normalized fixture (`name`, `entity`, `data`, `parameters`, etc.).
|
|
225
|
+
Expansion order is current-index substitution, EJS, Faker, parameters, references,
|
|
226
|
+
processor, connections, then persistence. Parameters are local to their document.
|
|
227
|
+
`<{process.env.NAME}>` falls back to the environment when no explicit parameter
|
|
228
|
+
with that path exists; missing variables raise an error.
|
|
229
|
+
|
|
230
|
+
Use Faker 10 providers, such as `{{number.int({"min": 1, "max": 10})}}` for a
|
|
231
|
+
number or `{{date.past}}` for a Date. Composed strings preserve surrounding text.
|
|
232
|
+
Locale falls back to English; see [compatibility](#compatibility-and-attribution)
|
|
233
|
+
for legacy provider aliases.
|
|
234
|
+
|
|
235
|
+
### Reproducible data
|
|
236
|
+
|
|
237
|
+
Pass `seed` and `refDate` through the [CLI](#cli) or
|
|
238
|
+
[API](#load-definitions-in-your-own-transaction) to reproduce package-generated
|
|
239
|
+
Faker values, relative dates and random-reference choices.
|
|
240
|
+
|
|
241
|
+
`seed` is an integer from 0 through 4294967295. `refDate` must be a real canonical
|
|
242
|
+
UTC timestamp in `YYYY-MM-DDTHH:mm:ss.sssZ` form. Each load/reset owns its random
|
|
243
|
+
state; global Faker seeding does not affect it. Equal ordered inputs and options
|
|
244
|
+
reproduce package-generated values with the same package/Faker version. Fixture
|
|
245
|
+
order, hooks, environment values and database-generated IDs remain outside that
|
|
246
|
+
guarantee. An explicit Faker provider `refDate` argument overrides the operation
|
|
247
|
+
default.
|
|
248
|
+
|
|
249
|
+
## Processors
|
|
250
|
+
|
|
251
|
+
Set `processor: ./user-processor.mjs` in the fixture document. Paths are relative
|
|
252
|
+
to that document; extensionless paths such as `./user-processor` are also resolved.
|
|
253
|
+
A processor exports a default class with an optional sync or
|
|
254
|
+
async `preProcess(name, object)` hook:
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
export default class UserProcessor {
|
|
258
|
+
async preProcess(name, object) {
|
|
259
|
+
return { ...object, email: object.email.toLowerCase() }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
CommonJS `module.exports = class ...` and `exports.default = class ...` work too.
|
|
265
|
+
Preloaded CommonJS hooks such as `ts-node/register` and `tsconfig-paths/register`
|
|
266
|
+
are honored, including their TypeScript and path-alias handling. Genuine ESM and
|
|
267
|
+
top-level-await modules fall back to native import. TypeScript processors can also
|
|
268
|
+
use Node's native type stripping for supported syntax (for example an ESM `.mts`
|
|
269
|
+
module). Native stripping does not convert ESM imports to CommonJS; match your
|
|
270
|
+
module extension/package configuration or compile your processor first. The hook
|
|
271
|
+
runs once per record after resolving references and before converting connections.
|
|
272
|
+
Return a plain object. No postProcess hook is defined by the upstream processor
|
|
273
|
+
contract.
|
|
274
|
+
|
|
275
|
+
## API and persistence
|
|
276
|
+
|
|
277
|
+
| Entry point | Transaction ownership | Disconnects the client |
|
|
278
|
+
| ------------------------------------------------ | ----------------------------------------------- | ---------------------- |
|
|
279
|
+
| CLI | Automatic, or your configured guard | Yes |
|
|
280
|
+
| `PrismaFixtures.load(client)` | Automatic | No; caller owns it |
|
|
281
|
+
| `loadFixtures`, `cleanFixtures`, `resetFixtures` | Caller; pass a transaction client for atomicity | No; caller owns it |
|
|
282
|
+
|
|
283
|
+
CommonJS callers can use `require('@skmdev/prisma-fixtures')`.
|
|
284
|
+
|
|
285
|
+
### Load from config
|
|
286
|
+
|
|
287
|
+
To load the paths in `.prisma-fixtures` without the CLI, use an existing Prisma
|
|
288
|
+
client (with its adapter already configured):
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
import { PrismaFixtures } from '@skmdev/prisma-fixtures'
|
|
292
|
+
|
|
293
|
+
const fixtures = new PrismaFixtures()
|
|
294
|
+
const records = await fixtures.load(prisma)
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
See the [runnable programmatic example](examples/hono/prisma/seed.mjs) and its
|
|
298
|
+
[setup instructions](examples/hono/README.md).
|
|
299
|
+
|
|
300
|
+
`load()` reads `.prisma-fixtures` from the current directory, applies its `seed`,
|
|
301
|
+
`refDate` and `timeout` settings, and loads in one transaction. The caller keeps
|
|
302
|
+
ownership of the client and disconnects it when finished. A configured `client`
|
|
303
|
+
module is ignored because the client is supplied; guarded client configs require
|
|
304
|
+
the CLI.
|
|
305
|
+
|
|
306
|
+
### Load definitions in your own transaction
|
|
307
|
+
|
|
308
|
+
With your existing `prisma` client, read a file or directory and pass the
|
|
309
|
+
definitions to `loadFixtures`. Returned records are keyed by fixture name:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { loadFixtures, readFixtureDefinitions } from '@skmdev/prisma-fixtures'
|
|
313
|
+
|
|
314
|
+
const definitions = readFixtureDefinitions('./fixtures')
|
|
315
|
+
const records = await prisma.$transaction(
|
|
316
|
+
(tx) =>
|
|
317
|
+
loadFixtures(tx, definitions, {
|
|
318
|
+
seed: 42,
|
|
319
|
+
refDate: '2026-01-01T00:00:00.000Z',
|
|
320
|
+
}),
|
|
321
|
+
{ timeout: 60_000 },
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
console.log(records.user1.id)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Disconnect `prisma` when your application is finished with it. For a standalone
|
|
328
|
+
seed script, use `try`/`finally` as in the runnable example above.
|
|
329
|
+
|
|
330
|
+
### Function reference
|
|
331
|
+
|
|
332
|
+
- `readFixtureDefinitions(path): FixtureDefinition[]` parses without executing
|
|
333
|
+
templates, importing processors or accessing a database.
|
|
334
|
+
- `loadFixtures(client, definitions, options?, writer?): Promise<Record<string, Record<string, unknown>>>`
|
|
335
|
+
validates and loads definitions. `options` accepts `seed` and `refDate`; passing
|
|
336
|
+
the writer directly as the third argument remains supported. It accepts either
|
|
337
|
+
a Prisma client or transaction client and does not disconnect it. Types
|
|
338
|
+
`FixtureDefinition`, `FixtureLoadOptions`, `FixtureWriter` and `FixtureProcessor`
|
|
339
|
+
are exported.
|
|
340
|
+
- The optional `writer(fixture, data)` returns the saved record and replaces the
|
|
341
|
+
default `create({ data })`. Use it to implement application-specific upserts.
|
|
342
|
+
When using a transaction, the writer must use that same transaction client.
|
|
343
|
+
- `cleanFixtures(client, options?)` clears PostgreSQL data, except exact
|
|
344
|
+
`options.preserveTables` entries.
|
|
345
|
+
- `resetFixtures(client, definitions, options?, writer?)` clears the database,
|
|
346
|
+
then loads the fixtures and returns the same record map as `loadFixtures`.
|
|
347
|
+
`FixtureResetOptions` combines `seed`, `refDate` and `preserveTables`. Passing
|
|
348
|
+
the writer as the third argument remains supported.
|
|
349
|
+
- Package-owned failures are `FixtureError` instances with a stable `code`, safe
|
|
350
|
+
`stage`/source/fixture/path context and the original private `cause` for API
|
|
351
|
+
callers. Opaque provider, hook and database messages are not copied into the
|
|
352
|
+
safe message.
|
|
353
|
+
|
|
354
|
+
### Cleanup and reset
|
|
355
|
+
|
|
356
|
+
Default loading inserts records; it never deletes or automatically upserts.
|
|
357
|
+
Repeating a load can create duplicates or raise unique-constraint errors.
|
|
358
|
+
Use a transaction to prevent a failed reset from leaving data deleted:
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
import { resetFixtures } from '@skmdev/prisma-fixtures'
|
|
362
|
+
|
|
363
|
+
const records = await prisma.$transaction(
|
|
364
|
+
(tx) =>
|
|
365
|
+
resetFixtures(tx, definitions, {
|
|
366
|
+
preserveTables: ['public.audit_log'],
|
|
367
|
+
}),
|
|
368
|
+
{ timeout: 60_000 },
|
|
369
|
+
)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Cleanup currently supports **PostgreSQL only** and requires `$executeRawUnsafe`.
|
|
373
|
+
It truncates all ordinary/partitioned tables across all non-system schemas in the
|
|
374
|
+
connected database, including implicit join tables. Tables, schema, indexes,
|
|
375
|
+
constraints, sequence values and `_prisma_migrations` records are preserved.
|
|
376
|
+
Each `preserveTables` entry names one existing table as `schema.table`;
|
|
377
|
+
its data and sequence state are also preserved. Unknown tables and
|
|
378
|
+
duplicate or malformed entries fail before truncation.
|
|
379
|
+
Foreign tables and materialized views are outside this cleanup scope.
|
|
380
|
+
Cleanup refuses inherited/partitioned structures with excluded descendants, so
|
|
381
|
+
truncating a parent cannot reach a preserved table, remote table or migration
|
|
382
|
+
history, and truncating a child cannot change rows visible through a preserved
|
|
383
|
+
ancestor. `RESTRICT` also makes a foreign key from a preserved table to a cleaned
|
|
384
|
+
table fail the cleanup instead of cascading or bypassing triggers.
|
|
385
|
+
The database user needs `TRUNCATE` privileges on every included table.
|
|
386
|
+
|
|
387
|
+
Cleanup needs no fixture definitions and executes no templates or processors.
|
|
388
|
+
Reset prepares templates and random references once and validates the load before
|
|
389
|
+
clearing data; an empty definition list still clears the database. Generated
|
|
390
|
+
values may change on each reset unless fixed generation options are supplied.
|
|
391
|
+
PostgreSQL's
|
|
392
|
+
[`TRUNCATE`](https://www.postgresql.org/docs/current/sql-truncate.html) runs
|
|
393
|
+
transactionally, fires `ON TRUNCATE` triggers and does not fire `ON DELETE` triggers.
|
|
394
|
+
|
|
395
|
+
Without a caller-owned transaction, an error can leave earlier deletes or inserts
|
|
396
|
+
applied. Rollback cannot undo external side effects in templates or processors.
|
|
397
|
+
|
|
398
|
+
## CLI
|
|
399
|
+
|
|
400
|
+
Run these commands from your project directory:
|
|
401
|
+
|
|
402
|
+
| Command | Purpose |
|
|
403
|
+
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
|
|
404
|
+
| `npx prisma-fixtures init` | Create config and fixture directory without overwriting an existing config |
|
|
405
|
+
| `npx prisma-fixtures` | Load configured fixtures; equivalent to the Quick start's `npx prisma db seed` |
|
|
406
|
+
| `npx prisma-fixtures ./fixtures --list` | List fixture names and entities without executing code |
|
|
407
|
+
| `npx prisma-fixtures --lint` | Check fixtures without a client or database |
|
|
408
|
+
| `npx prisma-fixtures --clean` | Clear database data without reading fixtures (PostgreSQL only) |
|
|
409
|
+
| `npx prisma-fixtures --reset` | Clear database data, then load fixtures (PostgreSQL only) |
|
|
410
|
+
| `npx prisma-fixtures --seed 42 --refDate 2026-01-01T00:00:00.000Z` | Reproduce generated values and random references |
|
|
411
|
+
| `npx prisma-fixtures --config ./test/.prisma-fixtures` | Use a different config file |
|
|
412
|
+
| `npx prisma-fixtures --help` | Show all options |
|
|
413
|
+
|
|
414
|
+
Use only one of `--clean`, `--reset`, `--list` and `--lint` at a time. Clean and
|
|
415
|
+
reset affect tables beyond those in your fixtures; see [cleanup and reset](#cleanup-and-reset).
|
|
416
|
+
These destructive modes must be requested on the command line, not saved in config.
|
|
417
|
+
|
|
418
|
+
To reuse an existing directory during setup, run
|
|
419
|
+
`npx prisma-fixtures init ../shared/fixtures`. The directory must already exist.
|
|
420
|
+
|
|
421
|
+
### Configuration
|
|
422
|
+
|
|
423
|
+
`.prisma-fixtures` is JSON. Start with the config from Quick start and add only
|
|
424
|
+
the options you need:
|
|
425
|
+
|
|
426
|
+
```json
|
|
427
|
+
{
|
|
428
|
+
"fixtures": ["./fixtures"],
|
|
429
|
+
"timeout": 60000,
|
|
430
|
+
"seed": 42,
|
|
431
|
+
"refDate": "2026-01-01T00:00:00.000Z",
|
|
432
|
+
"preserveTables": ["public.audit_log"]
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
| Config key | CLI override | Default / purpose |
|
|
437
|
+
| ---------------- | ----------------------- | ---------------------------------------------------------------------------------------- |
|
|
438
|
+
| `fixtures` | Positional paths | No default; nonempty array of paths, required unless using positional paths or `--clean` |
|
|
439
|
+
| `client` | `--client <module>` | Inferred from Prisma config; see client discovery below |
|
|
440
|
+
| `timeout` | `--timeout <ms>` | `60000`; positive integer transaction timeout in milliseconds |
|
|
441
|
+
| `schema` | `--schema <file>` | None; JSON Schema for `--lint` |
|
|
442
|
+
| `seed` | `--seed <integer>` | Random; integer from 0 through 4294967295 |
|
|
443
|
+
| `refDate` | `--refDate <timestamp>` | Current time; canonical UTC timestamp such as `2026-01-01T00:00:00.000Z` |
|
|
444
|
+
| `preserveTables` | Config only | `[]`; exact existing `schema.table` names excluded from clean/reset |
|
|
445
|
+
|
|
446
|
+
Unknown fields are rejected. Config paths are relative to the config file;
|
|
447
|
+
positional paths and CLI flags are relative to the working directory and override
|
|
448
|
+
matching config fields. Multiple fixture paths form one load and one transaction.
|
|
449
|
+
Discovery checks only the current directory; an explicit `--config` file must exist.
|
|
450
|
+
|
|
451
|
+
When `client` is omitted, `--clean` and `--reset` also preserve the PostgreSQL
|
|
452
|
+
tables listed in Prisma's `tables.external` (with
|
|
453
|
+
`experimental.externalTables` enabled). These `schema.table` entries are combined
|
|
454
|
+
with any explicit `preserveTables` entries. For example,
|
|
455
|
+
`tables: { external: ['public.flyway_schema_history'] }` in `prisma.config.ts`
|
|
456
|
+
preserves that table without repeating it in `.prisma-fixtures`. Direct API calls
|
|
457
|
+
still use only the options passed to them. Ordinary loading ignores the preserve
|
|
458
|
+
list and never deletes data.
|
|
459
|
+
|
|
460
|
+
### Client discovery and overrides
|
|
461
|
+
|
|
462
|
+
For write commands with no explicit `client`, the CLI reads the adjacent Prisma
|
|
463
|
+
config's schema and datasource, resolves the static `prisma-client` output path,
|
|
464
|
+
and uses your installed `@prisma/adapter-pg`. Run `prisma generate` first.
|
|
465
|
+
For inferred `.ts`/`.cts` clients, it uses existing compiled output described by
|
|
466
|
+
`tsconfig.json` with `rootDir` and `outDir`, or the project's installed `ts-node`
|
|
467
|
+
when no loader is registered. Native ESM `.mts` clients work with Node's type
|
|
468
|
+
stripping; see the [Hono generator](examples/hono/prisma/schema/00_base.prisma).
|
|
469
|
+
|
|
470
|
+
An explicit `client` can be an object with `module` (generated client path),
|
|
471
|
+
`adapter: 'pg'` and optional `guard`, or a legacy module path exporting a client
|
|
472
|
+
or factory. `--client` overrides either form with a legacy module path.
|
|
473
|
+
|
|
474
|
+
| CLI-only option | Purpose |
|
|
475
|
+
| ---------------------------------- | ------------------------------------------------------------------------------------ |
|
|
476
|
+
| `--databaseUrl <url>` | Override the datasource URL; a legacy client module must export a factory |
|
|
477
|
+
| `--require <module>` | Preload a hook or path alias module; repeatable, resolved from the working directory |
|
|
478
|
+
| `--debug`, `-d` | Include error type/code without fixture values or URLs |
|
|
479
|
+
| `--no-color` | Accepted for compatibility; output is always plain |
|
|
480
|
+
| `--version`, `-v` / `--help`, `-h` | Print version/help without loading config |
|
|
481
|
+
|
|
482
|
+
The inferred client uses Prisma's datasource URL, then `DATABASE_URL` from the
|
|
483
|
+
environment if the config omits it. `--databaseUrl` overrides both. Keep
|
|
484
|
+
credentials out of the JSON config and shell history. The CLI does not
|
|
485
|
+
independently load `.env` files; a `prisma.config.ts` import of `dotenv/config`
|
|
486
|
+
works when Prisma loads that config. Otherwise use `--require dotenv/config`.
|
|
487
|
+
For application-specific safety checks, `client.guard` may name a module exporting
|
|
488
|
+
`fixtureDatabaseUrl(env)` and `fixtureTransaction(client, action, timeout)`.
|
|
489
|
+
Those functions validate the connection before client creation and wrap writes
|
|
490
|
+
in the application's transaction guard.
|
|
491
|
+
|
|
492
|
+
### Transactions and diagnostics
|
|
493
|
+
|
|
494
|
+
The CLI wraps writes in one transaction (60-second timeout; override with
|
|
495
|
+
`--timeout <ms>`) and always disconnects a successfully acquired valid client.
|
|
496
|
+
`--list` and `--lint` skip all hooks, Prisma config loading and client imports;
|
|
497
|
+
`--list` only parses the JSON config and fixture documents.
|
|
498
|
+
Package diagnostics include a stable code and available filename, fixture name
|
|
499
|
+
and JSON Pointer field path. Output is escaped, bounded and omits fixture values,
|
|
500
|
+
URLs and opaque provider/client messages, including with `--debug`. API callers
|
|
501
|
+
can inspect a `FixtureError` cause in their own diagnostic harness.
|
|
502
|
+
|
|
503
|
+
## Fixture linting and editor support
|
|
504
|
+
|
|
505
|
+
```sh
|
|
506
|
+
npx prisma-fixtures --lint
|
|
507
|
+
npx prisma-fixtures ./fixtures --lint
|
|
508
|
+
npx prisma-fixtures --config ./test/.prisma-fixtures --lint
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Lint works without a client or database. It checks YAML/JSON syntax, duplicate
|
|
512
|
+
keys, allowed metadata, fixture shapes/names, ranges, current-index expressions,
|
|
513
|
+
duplicate fixture names across files and input limits. It also validates literal
|
|
514
|
+
fixed, wildcard and bounded references after combining all selected paths, and
|
|
515
|
+
rejects definite self/cross-file dependency cycles. A successful check exits
|
|
516
|
+
with code 0; the first error exits with code 1. YAML syntax diagnostics include
|
|
517
|
+
the filename, line/column and parser error code without printing fixture values.
|
|
518
|
+
`--lint` and `--list` are separate modes; use one at a time.
|
|
519
|
+
|
|
520
|
+
Lint does not execute templates, Faker, environment substitutions, processors,
|
|
521
|
+
preloads or random selection. Dynamic strings and references with several valid
|
|
522
|
+
candidates are counted as unresolved without failing lint or being added as
|
|
523
|
+
definite graph edges; a sole random candidate is a definite edge. Saved-record
|
|
524
|
+
field presence, rendered types, arbitrary hook behavior and database constraints
|
|
525
|
+
remain runtime checks. Formatting is separate: use your existing YAML formatter,
|
|
526
|
+
such as Prettier.
|
|
527
|
+
|
|
528
|
+
### Generate a schema from your Prisma models
|
|
529
|
+
|
|
530
|
+
Add a generator to `prisma/schema.prisma`:
|
|
531
|
+
|
|
532
|
+
```prisma
|
|
533
|
+
generator fixtures {
|
|
534
|
+
provider = "prisma-fixtures-generator"
|
|
535
|
+
output = "../generated/fixtures"
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
Run `npx prisma generate`. This creates `generated/fixtures/schema.json` from
|
|
540
|
+
Prisma's model and create-input metadata. Output paths are relative to
|
|
541
|
+
`schema.prisma`; regenerate after changing your models. No database connection
|
|
542
|
+
is needed for this generator.
|
|
543
|
+
|
|
544
|
+
Use the same schema for CLI lint by adding `schema` to `.prisma-fixtures`:
|
|
545
|
+
|
|
546
|
+
```json
|
|
547
|
+
{
|
|
548
|
+
"fixtures": ["./fixtures"],
|
|
549
|
+
"schema": "./generated/fixtures/schema.json"
|
|
550
|
+
}
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Or pass it explicitly:
|
|
554
|
+
|
|
555
|
+
```sh
|
|
556
|
+
npx prisma-fixtures ./fixtures --lint --schema ./generated/fixtures/schema.json
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
The generated schema selects fields by `entity`, accepts model and delegate
|
|
560
|
+
names, and checks known fields, scalar types, enums, nullability, lists and
|
|
561
|
+
required create inputs. Both nested relation inputs and direct foreign keys are
|
|
562
|
+
supported. References, Faker, EJS and parameter expressions remain dynamic
|
|
563
|
+
strings; their evaluated types are checked when loading. References and records
|
|
564
|
+
with an `id` (including arrays) are allowed for `connectedFields` shorthand.
|
|
565
|
+
|
|
566
|
+
Documents with a `processor` skip model item validation because the processor
|
|
567
|
+
may add, remove or transform fields; their fixture structure is still checked.
|
|
568
|
+
The schema does not reproduce every Prisma runtime rule: native database type
|
|
569
|
+
limits, DateTime/Decimal/Bytes conversions, relation-shorthand correctness,
|
|
570
|
+
uniqueness and reference targets still need runtime validation.
|
|
571
|
+
|
|
572
|
+
### Editor setup
|
|
573
|
+
|
|
574
|
+
The schema comment is optional. Configure a file association once, or use a
|
|
575
|
+
comment in each fixture; you do not need both. For
|
|
576
|
+
[VS Code's Red Hat YAML extension](https://github.com/redhat-developer/vscode-yaml),
|
|
577
|
+
add this to `.vscode/settings.json` in your application:
|
|
578
|
+
|
|
579
|
+
```json
|
|
580
|
+
{
|
|
581
|
+
"yaml.schemas": {
|
|
582
|
+
"./generated/fixtures/schema.json": [
|
|
583
|
+
"fixtures/**/*.yml",
|
|
584
|
+
"fixtures/**/*.yaml"
|
|
585
|
+
]
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Or add a schema comment to each YAML file, with a path relative to that file:
|
|
591
|
+
|
|
592
|
+
```yaml
|
|
593
|
+
# yaml-language-server: $schema=../generated/fixtures/schema.json
|
|
594
|
+
entity: User
|
|
595
|
+
items:
|
|
596
|
+
user1:
|
|
597
|
+
email: user1@example.test
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
If you only need generic fixture metadata checks, the package also includes
|
|
601
|
+
`schema/fixture.schema.json`, exported as `@skmdev/prisma-fixtures/schema.json`.
|
|
602
|
+
Point your editor at `node_modules/@skmdev/prisma-fixtures/schema/fixture.schema.json`
|
|
603
|
+
to use it without generation.
|
|
604
|
+
|
|
605
|
+
The editor schema cannot check cross-file names, the literal dependency graph or
|
|
606
|
+
runtime behavior; run `--lint` in CI as well. This repository's `npm run verify`
|
|
607
|
+
includes `npm run lint:fixtures` for the example fixtures.
|
|
608
|
+
|
|
609
|
+
## Trust and limits
|
|
610
|
+
|
|
611
|
+
Load trusted fixtures only. EJS, processors, preloads and client modules execute
|
|
612
|
+
JavaScript with your process permissions; parsing limits do not sandbox code.
|
|
613
|
+
The parser rejects prototype keys, duplicate names/keys and YAML aliases. Limits:
|
|
614
|
+
100 fixture files, 1 MiB per file, 2,000 expanded records, depth 32 and 50,000
|
|
615
|
+
visited nodes per validated value. No fixture values are logged by the engine.
|
|
616
|
+
|
|
617
|
+
## Compatibility and attribution
|
|
618
|
+
|
|
619
|
+
Legacy Faker aliases `name.firstName`, `name.lastName`, `name.title`,
|
|
620
|
+
`internet.userName` and `random.number` remain supported. This is syntax
|
|
621
|
+
compatibility, not identical random output or complete emulation of every removed
|
|
622
|
+
Faker API. New fixtures should use Faker 10 provider names.
|
|
623
|
+
|
|
624
|
+
The fixture language follows
|
|
625
|
+
[getbigger-io/prisma-fixtures](https://github.com/getbigger-io/prisma-fixtures),
|
|
626
|
+
with modern client injection and validation. This new package does not expose the
|
|
627
|
+
old `Loader`, `Builder`, `Parser`, `Resolver` or `fixturesIterator` class API, or
|
|
628
|
+
instantiate an implicit Prisma client. Replace that setup with the functions
|
|
629
|
+
above. MIT; see [LICENSE](LICENSE) and retained upstream attribution in [NOTICE](NOTICE).
|
|
630
|
+
|
|
631
|
+
Development checks and release instructions are in [CONTRIBUTING.md](CONTRIBUTING.md).
|