@skmdev/prisma-fixtures 0.1.1 → 1.0.0-rc.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/README.md +219 -51
- package/dist/cli.js +11 -2
- package/dist/contract-fixture-schema.d.ts +8 -0
- package/dist/contract-fixture-schema.js +351 -0
- package/dist/fixture-document.js +4 -2
- package/dist/generator.js +36 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.js +13 -4
- package/dist/prisma-config.js +24 -3
- package/dist/prisma8-client.d.ts +21 -0
- package/dist/prisma8-client.js +184 -0
- package/package.json +4 -2
- package/schema/fixture.schema.json +2 -2
package/README.md
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# @skmdev/prisma-fixtures
|
|
2
2
|
|
|
3
3
|
Load YAML or JSON fixtures into Prisma using named references, generated data and
|
|
4
|
-
processors. The CLI
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Requires Node.js 22.18
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
processors. The CLI supports generated Prisma 7 clients and emitted Prisma 8
|
|
5
|
+
contracts; the API also accepts a client you create.
|
|
6
|
+
|
|
7
|
+
Requires Node.js 22.18+. The retained path uses Prisma 7.10; the Prisma 8 release
|
|
8
|
+
candidate targets `prisma@8.0.0-rc.17`,
|
|
9
|
+
`@prisma/orm-postgres@8.0.0-rc.12` and PostgreSQL 17+. Prisma itself is provided
|
|
10
|
+
by your application, not installed as a runtime dependency of this package.
|
|
11
|
+
Install `@skmdev/prisma-fixtures@1.0.0-rc.1` after it is published to npm `next`,
|
|
12
|
+
or test it before publication through the local tarball workflow below.
|
|
13
|
+
|
|
14
|
+
- [Prisma 7 quick start](#prisma-7-quick-start)
|
|
15
|
+
- [Prisma 8 migration preview](#prisma-8-migration-preview)
|
|
11
16
|
- [Fixture format](#fixture-format)
|
|
12
17
|
- [Processors](#processors)
|
|
13
18
|
- [API and persistence](#api-and-persistence)
|
|
@@ -17,7 +22,7 @@ provided by your application, not installed as a runtime dependency of this pack
|
|
|
17
22
|
- [Compatibility and attribution](#compatibility-and-attribution)
|
|
18
23
|
- [Contributing and releases](CONTRIBUTING.md)
|
|
19
24
|
|
|
20
|
-
##
|
|
25
|
+
## Prisma 7 quick start
|
|
21
26
|
|
|
22
27
|
Start with an existing Prisma 7 application that has:
|
|
23
28
|
|
|
@@ -127,11 +132,141 @@ Migration history and tables preserved by `preserveTables` or Prisma's
|
|
|
127
132
|
See the [framework and runtime examples](examples/README.md) for standalone apps
|
|
128
133
|
with Argon2 password processors and API endpoints. NestJS demonstrates a CommonJS client.
|
|
129
134
|
|
|
135
|
+
## Prisma 8 migration preview
|
|
136
|
+
|
|
137
|
+
Prisma 8 support in this checkout uses separately versioned release candidates:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
npm install @prisma/orm-postgres@8.0.0-rc.12
|
|
141
|
+
npm install --save-dev prisma@8.0.0-rc.17
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
After the fixture RC is published, install its exact version:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
npm install --save-dev @skmdev/prisma-fixtures@1.0.0-rc.1
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`npm install --save-dev @skmdev/prisma-fixtures@next` discovers the current
|
|
151
|
+
prerelease, while the exact version gives reproducible installs. Before
|
|
152
|
+
`1.0.0-rc.1` is published, build the fixture package from this repository. Its
|
|
153
|
+
baseline package version, and therefore the tarball name, remains `0.1.1` until
|
|
154
|
+
the Prepare release action creates the version-bump pull request:
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
# In this repository
|
|
158
|
+
npm ci
|
|
159
|
+
npm pack
|
|
160
|
+
|
|
161
|
+
# In the Prisma application
|
|
162
|
+
npm install --no-save /path/to/skmdev-prisma-fixtures-1.0.0-rc.1.tgz
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
An existing multi-file Prisma 7 schema can be the source for an emitted Prisma 8
|
|
166
|
+
contract. Configure `prisma.config.ts`:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { defineConfig, prisma7Schema } from '@prisma/orm-postgres/config'
|
|
170
|
+
import { definePrismaConfig } from 'prisma/config'
|
|
171
|
+
|
|
172
|
+
export default definePrismaConfig({
|
|
173
|
+
orm: defineConfig({
|
|
174
|
+
contract: prisma7Schema('./prisma/schema'),
|
|
175
|
+
output: './src/generated/prisma',
|
|
176
|
+
db: { connection: process.env.DATABASE_URL },
|
|
177
|
+
}),
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Emit `contract.json` and `contract.d.ts`, then derive the fixture JSON Schema
|
|
182
|
+
offline from that contract:
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
npx prisma contract emit
|
|
186
|
+
npx prisma-fixtures-generator src/generated/prisma/contract.json src/generated/prisma-fixtures
|
|
187
|
+
npx prisma-fixtures --lint --schema src/generated/prisma-fixtures/schema.json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
After creating the database schema with `prisma db init` or your migration
|
|
191
|
+
workflow, load or reset fixtures directly:
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
npx prisma-fixtures
|
|
195
|
+
npx prisma-fixtures --reset
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
With no `client` in `.prisma-fixtures`, the CLI reads the v8 config, loads the
|
|
199
|
+
emitted contract and constructs the PostgreSQL fixture adapter. To select it
|
|
200
|
+
explicitly, point the existing configured-client shape at `contract.json`:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"fixtures": ["./fixtures"],
|
|
205
|
+
"client": {
|
|
206
|
+
"module": "./src/generated/prisma/contract.json",
|
|
207
|
+
"adapter": "pg"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Application routes should use the native Prisma 8 `db.orm` API. Only fixture
|
|
213
|
+
loading needs the compatibility bridge:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import postgres from '@prisma/orm-postgres/runtime'
|
|
217
|
+
import {
|
|
218
|
+
createPrisma8FixtureClient,
|
|
219
|
+
PrismaFixtures,
|
|
220
|
+
} from '@skmdev/prisma-fixtures'
|
|
221
|
+
import type { Contract } from './src/generated/prisma/contract.js'
|
|
222
|
+
import contractJson from './src/generated/prisma/contract.json' with { type: 'json' }
|
|
223
|
+
|
|
224
|
+
const db = postgres<Contract>({
|
|
225
|
+
contractJson,
|
|
226
|
+
url: process.env.DATABASE_URL!,
|
|
227
|
+
})
|
|
228
|
+
const client = createPrisma8FixtureClient(db)
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
await new PrismaFixtures().load(client)
|
|
232
|
+
} finally {
|
|
233
|
+
await client.$disconnect()
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`createPrisma8FixtureClient(db)` exposes the legacy fixture-facing delegates,
|
|
238
|
+
`$transaction` and `$disconnect` on top of the native v8 client. Prisma 8 fixture
|
|
239
|
+
transactions set PostgreSQL's `transaction_timeout`, so this path requires
|
|
240
|
+
PostgreSQL 17 or newer and retains rollback when the configured timeout expires.
|
|
241
|
+
Enable TypeScript's `resolveJsonModule`; use `contract.js` with NodeNext ESM or
|
|
242
|
+
`contract.d` with bundler module resolution for the generated `Contract` type.
|
|
243
|
+
|
|
244
|
+
The v8 bridge decodes scalar fixture values with the contract's PostgreSQL codecs,
|
|
245
|
+
including nested creates, connections and scalar lists. Quote large integers and
|
|
246
|
+
decimals to preserve precision; use base64 strings for binary fields. JSON fields
|
|
247
|
+
remain JSON. Dates use the emitted codec's ISO format: `Temporal.Instant` takes
|
|
248
|
+
a timezone such as `2026-01-02T03:04:05Z`, while `Temporal.PlainDateTime` takes
|
|
249
|
+
`2026-01-02T03:04:05` without a timezone. Processors can also supply the codec's
|
|
250
|
+
native values directly.
|
|
251
|
+
|
|
252
|
+
If your contract uses Temporal codecs and your runtime has no `Temporal`, install
|
|
253
|
+
the application's polyfill and preload it before constructing the client:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
npm install temporal-polyfill@1.0.5
|
|
257
|
+
npx prisma-fixtures --require temporal-polyfill/full/global
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
For programmatic loading, use `import 'temporal-polyfill/full/global'` before
|
|
261
|
+
creating `db`. The fixture package does not install a global polyfill itself.
|
|
262
|
+
|
|
130
263
|
## Fixture format
|
|
131
264
|
|
|
132
|
-
Each `.yml`, `.yaml` or `.json` file describes one entity.
|
|
133
|
-
|
|
134
|
-
|
|
265
|
+
Each `.yml`, `.yaml` or `.json` file describes one entity. Prisma 8 accepts
|
|
266
|
+
namespace-qualified entities such as `public.User`; `User` and `user` are also
|
|
267
|
+
available when that model name is unambiguous across namespaces. Prisma 7 resolves
|
|
268
|
+
`User` and `user` to the `user` delegate. Directory files are sorted; reference
|
|
269
|
+
dependencies determine insert order. Fixture names must be unique across all files.
|
|
135
270
|
|
|
136
271
|
| Feature | Example | Meaning |
|
|
137
272
|
| ------------------------ | -------------------------------- | ------------------------------------------------------------- |
|
|
@@ -346,6 +481,9 @@ seed script, use `try`/`finally` as in the runnable example above.
|
|
|
346
481
|
then loads the fixtures and returns the same record map as `loadFixtures`.
|
|
347
482
|
`FixtureResetOptions` combines `seed`, `refDate` and `preserveTables`. Passing
|
|
348
483
|
the writer as the third argument remains supported.
|
|
484
|
+
- `createPrisma8FixtureClient(db)` adapts a native Prisma 8 PostgreSQL client to
|
|
485
|
+
the fixture delegate, transaction and disconnect interface. Application queries
|
|
486
|
+
continue to use the original native `db`.
|
|
349
487
|
- Package-owned failures are `FixtureError` instances with a stable `code`, safe
|
|
350
488
|
`stage`/source/fixture/path context and the original private `cause` for API
|
|
351
489
|
callers. Opaque provider, hook and database messages are not copied into the
|
|
@@ -372,7 +510,8 @@ const records = await prisma.$transaction(
|
|
|
372
510
|
Cleanup currently supports **PostgreSQL only** and requires `$executeRawUnsafe`.
|
|
373
511
|
It truncates all ordinary/partitioned tables across all non-system schemas in the
|
|
374
512
|
connected database, including implicit join tables. Tables, schema, indexes,
|
|
375
|
-
constraints, sequence values
|
|
513
|
+
constraints, sequence values, `_prisma_migrations` records and Prisma 8's
|
|
514
|
+
`prisma_contract` schema are preserved.
|
|
376
515
|
Each `preserveTables` entry names one existing table as `schema.table`;
|
|
377
516
|
its data and sequence state are also preserved. Unknown tables and
|
|
378
517
|
duplicate or malformed entries fail before truncation.
|
|
@@ -399,17 +538,17 @@ applied. Rollback cannot undo external side effects in templates or processors.
|
|
|
399
538
|
|
|
400
539
|
Run these commands from your project directory:
|
|
401
540
|
|
|
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;
|
|
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
|
|
541
|
+
| Command | Purpose |
|
|
542
|
+
| ------------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
|
543
|
+
| `npx prisma-fixtures init` | Create config and fixture directory without overwriting an existing config |
|
|
544
|
+
| `npx prisma-fixtures` | Load configured fixtures; used directly by v8 and by the v7 seed command |
|
|
545
|
+
| `npx prisma-fixtures ./fixtures --list` | List fixture names and entities without executing code |
|
|
546
|
+
| `npx prisma-fixtures --lint` | Check fixtures without a client or database |
|
|
547
|
+
| `npx prisma-fixtures --clean` | Clear database data without reading fixtures (PostgreSQL only) |
|
|
548
|
+
| `npx prisma-fixtures --reset` | Clear database data, then load fixtures (PostgreSQL only) |
|
|
549
|
+
| `npx prisma-fixtures --seed 42 --refDate 2026-01-01T00:00:00.000Z` | Reproduce generated values and random references |
|
|
550
|
+
| `npx prisma-fixtures --config ./test/.prisma-fixtures` | Use a different config file |
|
|
551
|
+
| `npx prisma-fixtures --help` | Show all options |
|
|
413
552
|
|
|
414
553
|
Use only one of `--clean`, `--reset`, `--list` and `--lint` at a time. Clean and
|
|
415
554
|
reset affect tables beyond those in your fixtures; see [cleanup and reset](#cleanup-and-reset).
|
|
@@ -420,8 +559,8 @@ To reuse an existing directory during setup, run
|
|
|
420
559
|
|
|
421
560
|
### Configuration
|
|
422
561
|
|
|
423
|
-
`.prisma-fixtures` is JSON. Start with the config from
|
|
424
|
-
the options you need:
|
|
562
|
+
`.prisma-fixtures` is JSON. Start with the config from the Prisma 7 quick start
|
|
563
|
+
or Prisma 8 preview and add only the options you need:
|
|
425
564
|
|
|
426
565
|
```json
|
|
427
566
|
{
|
|
@@ -448,28 +587,32 @@ positional paths and CLI flags are relative to the working directory and overrid
|
|
|
448
587
|
matching config fields. Multiple fixture paths form one load and one transaction.
|
|
449
588
|
Discovery checks only the current directory; an explicit `--config` file must exist.
|
|
450
589
|
|
|
451
|
-
When `client` is omitted, `--clean` and `--reset` also preserve
|
|
452
|
-
|
|
453
|
-
`experimental.externalTables` enabled
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
list and never deletes data.
|
|
590
|
+
When `client` is omitted, `--clean` and `--reset` also preserve Prisma 7
|
|
591
|
+
`tables.external` entries from the adjacent config when
|
|
592
|
+
`experimental.externalTables` is enabled. Every Prisma 8 adapter preserves emitted
|
|
593
|
+
contract tables whose control is `external`, `observed` or `tolerated`. This applies
|
|
594
|
+
to CLI clients constructed from inferred or explicit `contract.json` paths and to
|
|
595
|
+
programmatic transactions created by `createPrisma8FixtureClient(db)`. These tables
|
|
596
|
+
are combined with explicit `preserveTables` entries. Ordinary loading ignores the
|
|
597
|
+
preserve list and never deletes data.
|
|
459
598
|
|
|
460
599
|
### Client discovery and overrides
|
|
461
600
|
|
|
462
601
|
For write commands with no explicit `client`, the CLI reads the adjacent Prisma
|
|
463
|
-
config
|
|
464
|
-
|
|
465
|
-
|
|
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).
|
|
602
|
+
config. A Prisma 8 `definePrismaConfig({ orm: ... })` config resolves its emitted
|
|
603
|
+
`contract.json` output and constructs `createPrisma8FixtureClient(db)` with the
|
|
604
|
+
installed `@prisma/orm-postgres` runtime. Run `prisma contract emit` first.
|
|
469
605
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
606
|
+
The retained Prisma 7 path resolves the static `prisma-client` output and uses
|
|
607
|
+
the installed `@prisma/adapter-pg`; run `prisma generate` first. For inferred
|
|
608
|
+
`.ts`/`.cts` v7 clients, the CLI uses compiled output described by `tsconfig.json`
|
|
609
|
+
or the project's installed `ts-node`. Native ESM `.mts` clients work with Node's
|
|
610
|
+
type stripping.
|
|
611
|
+
|
|
612
|
+
An explicit `client` object uses `module`, `adapter: 'pg'` and an optional
|
|
613
|
+
`guard`. `module` can name a v8 `contract.json` or a generated v7 client. A legacy
|
|
614
|
+
module path exporting a client or factory remains supported, and `--client`
|
|
615
|
+
overrides either configured form with that path.
|
|
473
616
|
|
|
474
617
|
| CLI-only option | Purpose |
|
|
475
618
|
| ---------------------------------- | ------------------------------------------------------------------------------------ |
|
|
@@ -493,6 +636,8 @@ in the application's transaction guard.
|
|
|
493
636
|
|
|
494
637
|
The CLI wraps writes in one transaction (60-second timeout; override with
|
|
495
638
|
`--timeout <ms>`) and always disconnects a successfully acquired valid client.
|
|
639
|
+
Prisma 8 enforces this with PostgreSQL 17+'s `transaction_timeout`; Prisma 7 uses
|
|
640
|
+
its client transaction timeout option.
|
|
496
641
|
`--list` and `--lint` skip all hooks, Prisma config loading and client imports;
|
|
497
642
|
`--list` only parses the JSON config and fixture documents.
|
|
498
643
|
Package diagnostics include a stable code and available filename, fixture name
|
|
@@ -527,7 +672,20 @@ such as Prettier.
|
|
|
527
672
|
|
|
528
673
|
### Generate a schema from your Prisma models
|
|
529
674
|
|
|
530
|
-
|
|
675
|
+
For Prisma 8, emit the contract and pass it to the generator's offline contract
|
|
676
|
+
mode:
|
|
677
|
+
|
|
678
|
+
```sh
|
|
679
|
+
npx prisma contract emit
|
|
680
|
+
npx prisma-fixtures-generator src/generated/prisma/contract.json src/generated/prisma-fixtures
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
This writes `src/generated/prisma-fixtures/schema.json`. Contract validation
|
|
684
|
+
fails closed: dictionary fields and unknown codec IDs, including unsupported
|
|
685
|
+
extension-provided codecs, stop generation instead of producing a permissive or
|
|
686
|
+
incorrect schema.
|
|
687
|
+
|
|
688
|
+
For Prisma 7, add the legacy generator block to `prisma/schema.prisma`:
|
|
531
689
|
|
|
532
690
|
```prisma
|
|
533
691
|
generator fixtures {
|
|
@@ -538,8 +696,8 @@ generator fixtures {
|
|
|
538
696
|
|
|
539
697
|
Run `npx prisma generate`. This creates `generated/fixtures/schema.json` from
|
|
540
698
|
Prisma's model and create-input metadata. Output paths are relative to
|
|
541
|
-
`schema.prisma`; regenerate after changing your models.
|
|
542
|
-
|
|
699
|
+
`schema.prisma`; regenerate after changing your models. Neither generator mode
|
|
700
|
+
needs a database connection.
|
|
543
701
|
|
|
544
702
|
Use the same schema for CLI lint by adding `schema` to `.prisma-fixtures`:
|
|
545
703
|
|
|
@@ -556,12 +714,15 @@ Or pass it explicitly:
|
|
|
556
714
|
npx prisma-fixtures ./fixtures --lint --schema ./generated/fixtures/schema.json
|
|
557
715
|
```
|
|
558
716
|
|
|
559
|
-
The generated schema selects fields by `entity
|
|
560
|
-
names
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
717
|
+
The generated schema selects fields by `entity`. Prisma 8 schemas include
|
|
718
|
+
namespace-qualified names such as `public.User`, plus unqualified model and
|
|
719
|
+
delegate aliases when they are unambiguous; Prisma 7 schemas accept model and
|
|
720
|
+
delegate names. The schema checks known fields, scalar types, enums, nullability,
|
|
721
|
+
lists and required create inputs. Both nested relation inputs and direct foreign
|
|
722
|
+
keys are supported. References, Faker, EJS and parameter expressions remain
|
|
723
|
+
dynamic strings; their evaluated types are checked when loading. References and
|
|
724
|
+
records with an `id` (including arrays) are allowed for `connectedFields`
|
|
725
|
+
shorthand.
|
|
565
726
|
|
|
566
727
|
Documents with a `processor` skip model item validation because the processor
|
|
567
728
|
may add, remove or transform fields; their fixture structure is still checked.
|
|
@@ -616,6 +777,13 @@ visited nodes per validated value. No fixture values are logged by the engine.
|
|
|
616
777
|
|
|
617
778
|
## Compatibility and attribution
|
|
618
779
|
|
|
780
|
+
The Prisma 8 release candidate is tested against the exact RC pair documented
|
|
781
|
+
above and PostgreSQL 17+. Prisma 8 CLI and runtime packages have separate version
|
|
782
|
+
numbers. Prisma 7.10 support, its generator RPC and existing client injection
|
|
783
|
+
remain available for legacy consumers. A stable fixture package `1.0.0` requires
|
|
784
|
+
stable Prisma 8 CLI and runtime releases and successful migration verification
|
|
785
|
+
against those stable versions.
|
|
786
|
+
|
|
619
787
|
Legacy Faker aliases `name.firstName`, `name.lastName`, `name.title`,
|
|
620
788
|
`internet.userName` and `random.number` remain supported. This is syntax
|
|
621
789
|
compatibility, not identical random output or complete emulation of every removed
|
package/dist/cli.js
CHANGED
|
@@ -17,6 +17,7 @@ const load_options_1 = require("./load-options");
|
|
|
17
17
|
const prisma_config_1 = require("./prisma-config");
|
|
18
18
|
const fixture_config_1 = require("./fixture-config");
|
|
19
19
|
const index_1 = require("./index");
|
|
20
|
+
const prisma8_client_1 = require("./prisma8-client");
|
|
20
21
|
const help = `Usage: prisma-fixtures [path...] [--client <module>] [options]
|
|
21
22
|
prisma-fixtures init [fixtures-directory]
|
|
22
23
|
|
|
@@ -276,8 +277,16 @@ async function loadClient(config, values) {
|
|
|
276
277
|
if (typeof databaseUrl !== 'string' || !databaseUrl.trim()) {
|
|
277
278
|
throw new Error('DATABASE_URL is required');
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
if (node_path_1.default.extname(clientConfig.module) === '.json') {
|
|
281
|
+
const { default: postgres } = (await import((0, node_url_1.pathToFileURL)(requireFromCwd.resolve('@prisma/orm-postgres/runtime'))
|
|
282
|
+
.href));
|
|
283
|
+
const contractJson = JSON.parse(node_fs_1.default.readFileSync(clientConfig.module, 'utf8'));
|
|
284
|
+
candidate = (0, prisma8_client_1.createPrisma8FixtureClient)(postgres({ contractJson, url: databaseUrl }));
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
const generated = await importGeneratedClient(clientConfig.module, requireFromCwd);
|
|
288
|
+
candidate = createGeneratedClient(generated, requireFromCwd, databaseUrl);
|
|
289
|
+
}
|
|
281
290
|
}
|
|
282
291
|
if (!candidate ||
|
|
283
292
|
typeof candidate !== 'object' ||
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type JsonSchema = Record<string, unknown>;
|
|
2
|
+
type FixtureSchema = JsonSchema & {
|
|
3
|
+
properties: Record<string, JsonSchema>;
|
|
4
|
+
definitions: Record<string, JsonSchema>;
|
|
5
|
+
allOf?: JsonSchema[];
|
|
6
|
+
};
|
|
7
|
+
export declare function buildContractFixtureSchema(value: unknown): FixtureSchema;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildContractFixtureSchema = buildContractFixtureSchema;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const baseFixtureSchema = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(__dirname, '../schema/fixture.schema.json'), 'utf8'));
|
|
10
|
+
const dynamicString = () => ({
|
|
11
|
+
type: 'string',
|
|
12
|
+
pattern: '(?:^@(?!@)|<%|\\{\\{|<\\{|\\(\\$current(?:[+*/-][0-9]+)?\\))',
|
|
13
|
+
});
|
|
14
|
+
const internalRef = (name) => ({
|
|
15
|
+
$ref: `#/definitions/${encodeURIComponent(name.replaceAll('~', '~0').replaceAll('/', '~1'))}`,
|
|
16
|
+
});
|
|
17
|
+
const invalid = (message) => {
|
|
18
|
+
throw new Error(`Invalid Prisma v8 PostgreSQL contract: ${message}`);
|
|
19
|
+
};
|
|
20
|
+
const object = (value, location) => {
|
|
21
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
22
|
+
invalid(`${location} must be an object`);
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
const text = (value, location) => {
|
|
26
|
+
if (typeof value !== 'string' || !value)
|
|
27
|
+
invalid(`${location} must be a non-empty string`);
|
|
28
|
+
return value;
|
|
29
|
+
};
|
|
30
|
+
function buildContractFixtureSchema(value) {
|
|
31
|
+
const contract = contractMetadata(value);
|
|
32
|
+
const schema = structuredClone(baseFixtureSchema);
|
|
33
|
+
const definitions = schema.definitions;
|
|
34
|
+
const aliasOwners = new Map();
|
|
35
|
+
for (const [namespace, entry] of Object.entries(contract.domain.namespaces)) {
|
|
36
|
+
for (const model of Object.keys(object(entry.models, `${namespace}.models`))) {
|
|
37
|
+
const owner = `${namespace}.${model}`;
|
|
38
|
+
for (const alias of new Set([
|
|
39
|
+
owner,
|
|
40
|
+
model,
|
|
41
|
+
model[0].toLowerCase() + model.slice(1),
|
|
42
|
+
])) {
|
|
43
|
+
aliasOwners.set(alias, aliasOwners.has(alias) && aliasOwners.get(alias) !== owner
|
|
44
|
+
? null
|
|
45
|
+
: owner);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const aliases = (namespace, model) => [...aliasOwners]
|
|
50
|
+
.filter(([, owner]) => owner === `${namespace}.${model}`)
|
|
51
|
+
.map(([alias]) => alias);
|
|
52
|
+
const enumValues = (namespace, field) => {
|
|
53
|
+
if (!field.valueSet)
|
|
54
|
+
return undefined;
|
|
55
|
+
const ref = field.valueSet;
|
|
56
|
+
const refNamespace = ref.namespaceId === '__unbound__' ? namespace : ref.namespaceId;
|
|
57
|
+
const values = ref.plane === 'domain' && ref.entityKind === 'enum'
|
|
58
|
+
? contract.domain.namespaces[refNamespace]?.enum?.[ref.entityName]?.members.map(({ value }) => value)
|
|
59
|
+
: ref.plane === 'storage' && ref.entityKind === 'valueSet'
|
|
60
|
+
? contract.storage.namespaces[refNamespace]?.entries.valueSet?.[ref.entityName]?.values
|
|
61
|
+
: undefined;
|
|
62
|
+
if (!values)
|
|
63
|
+
invalid(`field value set ${refNamespace}.${ref.entityName} is invalid`);
|
|
64
|
+
return values;
|
|
65
|
+
};
|
|
66
|
+
const typeSchema = (namespace, value) => {
|
|
67
|
+
const type = object(value, 'field type');
|
|
68
|
+
if (type.kind === 'scalar')
|
|
69
|
+
return scalarSchema(text(type.codecId, 'codecId'));
|
|
70
|
+
if (type.kind === 'valueObject') {
|
|
71
|
+
const name = text(type.name, 'value object name');
|
|
72
|
+
const definitionName = `PrismaContractValueObject_${JSON.stringify([namespace, name])}`;
|
|
73
|
+
if (!(definitionName in definitions)) {
|
|
74
|
+
const valueObject = contract.domain.namespaces[namespace]?.valueObjects?.[name] ??
|
|
75
|
+
invalid(`value object ${namespace}.${name} does not exist`);
|
|
76
|
+
definitions[definitionName] = {};
|
|
77
|
+
definitions[definitionName] = objectSchema(namespace, valueObject.fields, {});
|
|
78
|
+
}
|
|
79
|
+
return internalRef(definitionName);
|
|
80
|
+
}
|
|
81
|
+
if (type.kind === 'union' &&
|
|
82
|
+
Array.isArray(type.members) &&
|
|
83
|
+
type.members.length)
|
|
84
|
+
return {
|
|
85
|
+
anyOf: type.members.map((member) => typeSchema(namespace, member)),
|
|
86
|
+
};
|
|
87
|
+
return invalid('field type kind is invalid');
|
|
88
|
+
};
|
|
89
|
+
const fieldSchema = (namespace, field) => {
|
|
90
|
+
if (typeof field.nullable !== 'boolean')
|
|
91
|
+
invalid('field nullable must be boolean');
|
|
92
|
+
if (field.many !== undefined && field.many !== true)
|
|
93
|
+
invalid('field many must be true when present');
|
|
94
|
+
if (field.dict)
|
|
95
|
+
invalid('dictionary fields are not supported');
|
|
96
|
+
const values = enumValues(namespace, field);
|
|
97
|
+
const value = values ? { enum: values } : typeSchema(namespace, field.type);
|
|
98
|
+
let result = field.many
|
|
99
|
+
? { type: 'array', items: { anyOf: [value, dynamicString()] } }
|
|
100
|
+
: value;
|
|
101
|
+
const acceptsString = values === undefined &&
|
|
102
|
+
!field.many &&
|
|
103
|
+
field.type.kind === 'scalar' &&
|
|
104
|
+
(stringCodec(field.type.codecId) || jsonCodec(field.type.codecId));
|
|
105
|
+
if (!acceptsString)
|
|
106
|
+
result = { anyOf: [result, dynamicString()] };
|
|
107
|
+
if (field.nullable)
|
|
108
|
+
result = { anyOf: [result, { type: 'null' }] };
|
|
109
|
+
return result;
|
|
110
|
+
};
|
|
111
|
+
const connection = () => ({
|
|
112
|
+
allOf: [
|
|
113
|
+
internalRef('safeObject'),
|
|
114
|
+
{
|
|
115
|
+
minProperties: 1,
|
|
116
|
+
propertyNames: { not: { enum: ['connect', 'create'] } },
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
const ensureModel = (namespace, name) => {
|
|
121
|
+
const definitionName = `PrismaContractModel_${JSON.stringify([namespace, name])}`;
|
|
122
|
+
if (definitionName in definitions)
|
|
123
|
+
return definitionName;
|
|
124
|
+
const model = contract.domain.namespaces[namespace]?.models[name];
|
|
125
|
+
if (!model)
|
|
126
|
+
invalid(`relation target ${namespace}.${name} does not exist`);
|
|
127
|
+
definitions[definitionName] = {};
|
|
128
|
+
definitions[definitionName] = objectSchema(namespace, model.fields, model.relations, model, name);
|
|
129
|
+
return definitionName;
|
|
130
|
+
};
|
|
131
|
+
const ensureNestedModel = (sourceNamespace, sourceName, sourceModel, relationName, relation) => {
|
|
132
|
+
const namespace = text(relation.to?.namespace, 'relation namespace');
|
|
133
|
+
const name = text(relation.to?.model, 'relation model');
|
|
134
|
+
const omitted = parentInjectedFields(contract, sourceNamespace, sourceName, sourceModel, relation);
|
|
135
|
+
if (!omitted.length)
|
|
136
|
+
return ensureModel(namespace, name);
|
|
137
|
+
const definitionName = `PrismaContractNested_${JSON.stringify([sourceNamespace, sourceName, relationName])}`;
|
|
138
|
+
if (definitionName in definitions)
|
|
139
|
+
return definitionName;
|
|
140
|
+
const model = contract.domain.namespaces[namespace]?.models[name];
|
|
141
|
+
if (!model)
|
|
142
|
+
invalid(`relation target ${namespace}.${name} does not exist`);
|
|
143
|
+
definitions[definitionName] = {};
|
|
144
|
+
definitions[definitionName] = objectSchema(namespace, model.fields, model.relations, model, name, new Set(omitted));
|
|
145
|
+
return definitionName;
|
|
146
|
+
};
|
|
147
|
+
const relationSchema = (namespace, modelName, model, relationName, relation) => {
|
|
148
|
+
if (!['1:1', 'N:1', '1:N', 'N:M'].includes(relation.cardinality))
|
|
149
|
+
invalid('relation cardinality is invalid');
|
|
150
|
+
const target = internalRef(model && modelName
|
|
151
|
+
? ensureNestedModel(namespace, modelName, model, relationName, relation)
|
|
152
|
+
: ensureModel(text(relation.to?.namespace, 'relation namespace'), text(relation.to?.model, 'relation model')));
|
|
153
|
+
const oneOrMany = (item) => ({
|
|
154
|
+
anyOf: [
|
|
155
|
+
item,
|
|
156
|
+
dynamicString(),
|
|
157
|
+
{ type: 'array', items: { anyOf: [item, dynamicString()] } },
|
|
158
|
+
],
|
|
159
|
+
});
|
|
160
|
+
const selector = connection();
|
|
161
|
+
const alternatives = [
|
|
162
|
+
dynamicString(),
|
|
163
|
+
selector,
|
|
164
|
+
{
|
|
165
|
+
type: 'object',
|
|
166
|
+
additionalProperties: false,
|
|
167
|
+
properties: {
|
|
168
|
+
connect: oneOrMany(selector),
|
|
169
|
+
create: oneOrMany(target),
|
|
170
|
+
},
|
|
171
|
+
oneOf: [{ required: ['connect'] }, { required: ['create'] }],
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
if (relation.cardinality === '1:N' || relation.cardinality === 'N:M')
|
|
175
|
+
alternatives.push({
|
|
176
|
+
type: 'array',
|
|
177
|
+
items: { anyOf: [dynamicString(), selector] },
|
|
178
|
+
});
|
|
179
|
+
if (relation.nullable)
|
|
180
|
+
alternatives.push({ type: 'null' });
|
|
181
|
+
return { anyOf: alternatives };
|
|
182
|
+
};
|
|
183
|
+
function objectSchema(namespace, fields, relations, model, modelName, omittedRequiredFields = new Set()) {
|
|
184
|
+
const properties = Object.fromEntries(Object.entries(object(fields, `${namespace} fields`)).map(([name, field]) => [name, fieldSchema(namespace, field)]));
|
|
185
|
+
const required = Object.entries(fields)
|
|
186
|
+
.filter(([name, field]) => !field.nullable &&
|
|
187
|
+
!omittedRequiredFields.has(name) &&
|
|
188
|
+
!hasDefault(contract, model, name))
|
|
189
|
+
.map(([name]) => name);
|
|
190
|
+
const relationRequirements = [];
|
|
191
|
+
for (const [name, relation] of Object.entries(object(relations, `${namespace} relations`))) {
|
|
192
|
+
properties[name] = relationSchema(namespace, modelName, model, name, relation);
|
|
193
|
+
if (relation.nullable === false &&
|
|
194
|
+
(relation.cardinality === 'N:1' ||
|
|
195
|
+
(relation.cardinality === '1:1' &&
|
|
196
|
+
ownsForeignKey(contract, model, relation)))) {
|
|
197
|
+
const local = relation.on?.localFields.filter((field) => required.includes(field));
|
|
198
|
+
if (local?.length) {
|
|
199
|
+
for (const field of local)
|
|
200
|
+
required.splice(required.indexOf(field), 1);
|
|
201
|
+
relationRequirements.push({
|
|
202
|
+
anyOf: [{ required: local }, { required: [name] }],
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
type: 'object',
|
|
209
|
+
additionalProperties: false,
|
|
210
|
+
properties,
|
|
211
|
+
...(required.length ? { required } : {}),
|
|
212
|
+
...(relationRequirements.length ? { allOf: relationRequirements } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const entityNames = [];
|
|
216
|
+
const conditions = [];
|
|
217
|
+
for (const [namespace, entry] of Object.entries(contract.domain.namespaces)) {
|
|
218
|
+
for (const [name, model] of Object.entries(entry.models)) {
|
|
219
|
+
const modelAliases = aliases(namespace, name);
|
|
220
|
+
const relations = Object.keys(model.relations);
|
|
221
|
+
const scalars = Object.keys(model.fields);
|
|
222
|
+
entityNames.push(...modelAliases);
|
|
223
|
+
conditions.push({
|
|
224
|
+
if: {
|
|
225
|
+
required: ['entity'],
|
|
226
|
+
properties: { entity: { enum: modelAliases } },
|
|
227
|
+
},
|
|
228
|
+
then: {
|
|
229
|
+
properties: {
|
|
230
|
+
connectedFields: relations.length
|
|
231
|
+
? { items: { enum: relations } }
|
|
232
|
+
: { maxItems: 0 },
|
|
233
|
+
deferredFields: scalars.length
|
|
234
|
+
? { items: { enum: scalars } }
|
|
235
|
+
: { maxItems: 0 },
|
|
236
|
+
},
|
|
237
|
+
allOf: [
|
|
238
|
+
{
|
|
239
|
+
if: { not: { required: ['processor'] } },
|
|
240
|
+
then: {
|
|
241
|
+
properties: {
|
|
242
|
+
items: {
|
|
243
|
+
additionalProperties: internalRef(ensureModel(namespace, name)),
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
schema.properties.entity = entityNames.length
|
|
254
|
+
? {
|
|
255
|
+
description: 'Prisma v8 namespace-qualified model or an unambiguous model alias.',
|
|
256
|
+
type: 'string',
|
|
257
|
+
enum: [...new Set(entityNames)],
|
|
258
|
+
}
|
|
259
|
+
: { description: 'No Prisma models are available.', not: {} };
|
|
260
|
+
schema.allOf = [...(schema.allOf ?? []), ...conditions];
|
|
261
|
+
return schema;
|
|
262
|
+
}
|
|
263
|
+
function contractMetadata(value) {
|
|
264
|
+
const root = object(value, 'contract');
|
|
265
|
+
if (root.schemaVersion !== '1')
|
|
266
|
+
invalid('schemaVersion must be "1"');
|
|
267
|
+
if (root.targetFamily !== 'sql' || root.target !== 'postgres')
|
|
268
|
+
invalid('contract must target PostgreSQL');
|
|
269
|
+
const domain = object(root.domain, 'domain');
|
|
270
|
+
const storage = object(root.storage, 'storage');
|
|
271
|
+
object(root.roots, 'roots');
|
|
272
|
+
object(domain.namespaces, 'domain.namespaces');
|
|
273
|
+
object(storage.namespaces, 'storage.namespaces');
|
|
274
|
+
return root;
|
|
275
|
+
}
|
|
276
|
+
function hasDefault(contract, model, name) {
|
|
277
|
+
if (!model)
|
|
278
|
+
return false;
|
|
279
|
+
const field = model.storage.fields[name];
|
|
280
|
+
if (!field)
|
|
281
|
+
return false;
|
|
282
|
+
const column = contract.storage.namespaces[model.storage.namespaceId]?.entries.table[model.storage.table]?.columns[field.column];
|
|
283
|
+
return ((column !== undefined && 'default' in column) ||
|
|
284
|
+
(contract.execution?.mutations.defaults.some(({ ref, onCreate }) => onCreate !== undefined &&
|
|
285
|
+
ref.namespace === model.storage.namespaceId &&
|
|
286
|
+
ref.table === model.storage.table &&
|
|
287
|
+
ref.column === field.column) ??
|
|
288
|
+
false));
|
|
289
|
+
}
|
|
290
|
+
function parentInjectedFields(contract, sourceNamespace, sourceName, sourceModel, relation) {
|
|
291
|
+
if (!relation.on ||
|
|
292
|
+
(relation.cardinality !== '1:N' && relation.cardinality !== '1:1'))
|
|
293
|
+
return [];
|
|
294
|
+
const target = contract.domain.namespaces[relation.to.namespace]?.models[relation.to.model];
|
|
295
|
+
if (!target ||
|
|
296
|
+
!relation.on.localFields.every((field) => field in sourceModel.fields) ||
|
|
297
|
+
!relation.on.targetFields.every((field) => field in target.fields))
|
|
298
|
+
return [];
|
|
299
|
+
const inverse = Object.values(target.relations).find((candidate) => candidate.to.namespace === sourceNamespace &&
|
|
300
|
+
candidate.to.model === sourceName &&
|
|
301
|
+
candidate.on !== undefined &&
|
|
302
|
+
sameFields(candidate.on.localFields, relation.on.targetFields) &&
|
|
303
|
+
sameFields(candidate.on.targetFields, relation.on.localFields) &&
|
|
304
|
+
ownsForeignKey(contract, target, candidate));
|
|
305
|
+
return inverse ? relation.on.targetFields : [];
|
|
306
|
+
}
|
|
307
|
+
function sameFields(left, right) {
|
|
308
|
+
return (left.length === right.length &&
|
|
309
|
+
left.every((field, index) => field === right[index]));
|
|
310
|
+
}
|
|
311
|
+
function ownsForeignKey(contract, model, relation) {
|
|
312
|
+
if (!model || !relation.on)
|
|
313
|
+
return false;
|
|
314
|
+
const sourceColumns = relation.on.localFields.map((field) => model.storage.fields[field]?.column);
|
|
315
|
+
const target = contract.domain.namespaces[relation.to.namespace]?.models[relation.to.model];
|
|
316
|
+
const targetColumns = relation.on.targetFields.map((field) => target?.storage.fields[field]?.column);
|
|
317
|
+
if (!target ||
|
|
318
|
+
sourceColumns.some((column) => column === undefined) ||
|
|
319
|
+
targetColumns.some((column) => column === undefined))
|
|
320
|
+
return false;
|
|
321
|
+
const table = contract.storage.namespaces[model.storage.namespaceId]?.entries.table[model.storage.table];
|
|
322
|
+
return table?.foreignKeys.some(({ source, target: foreignTarget }) => source.namespaceId === model.storage.namespaceId &&
|
|
323
|
+
source.tableName === model.storage.table &&
|
|
324
|
+
sameFields(source.columns, sourceColumns) &&
|
|
325
|
+
foreignTarget.namespaceId === target.storage.namespaceId &&
|
|
326
|
+
foreignTarget.tableName === target.storage.table &&
|
|
327
|
+
sameFields(foreignTarget.columns, targetColumns));
|
|
328
|
+
}
|
|
329
|
+
const jsonCodec = (codecId) => codecId === 'pg/json@1' || codecId === 'pg/jsonb@1';
|
|
330
|
+
const stringCodec = (codecId) => /^(?:pg\/(?:text|enum|char|varchar|bit|varbit|date-(?:string|temporal)|timestamp-(?:string|temporal)|timestamptz-(?:string|temporal|date)|time-(?:string|temporal)|timetz|interval|bytea|uuid|inet|tsquery)|sql\/(?:char|varchar|text))@1$/.test(codecId);
|
|
331
|
+
const scalarSchema = (codecId) => {
|
|
332
|
+
if (jsonCodec(codecId))
|
|
333
|
+
return internalRef('jsonValue');
|
|
334
|
+
if (codecId === 'pg/bool@1')
|
|
335
|
+
return { type: 'boolean' };
|
|
336
|
+
if (/^(?:pg\/(?:int|int2|int4|int8number)|sql\/int)@1$/.test(codecId))
|
|
337
|
+
return { type: 'integer' };
|
|
338
|
+
if (/^pg\/(?:int8|unboundedint)@1$/.test(codecId))
|
|
339
|
+
return {
|
|
340
|
+
anyOf: [{ type: 'integer' }, { type: 'string', pattern: '^-?[0-9]+$' }],
|
|
341
|
+
};
|
|
342
|
+
if (/^(?:pg\/(?:float|float4|float8)|sql\/float)@1$/.test(codecId))
|
|
343
|
+
return { type: 'number' };
|
|
344
|
+
if (codecId === 'pg/numeric@1')
|
|
345
|
+
return { anyOf: [{ type: 'number' }, { type: 'string' }] };
|
|
346
|
+
if (codecId === 'pg/text-array@1')
|
|
347
|
+
return { type: 'array', items: { type: 'string' } };
|
|
348
|
+
if (stringCodec(codecId))
|
|
349
|
+
return { type: 'string' };
|
|
350
|
+
return invalid(`field type codec ${codecId} is not supported`);
|
|
351
|
+
};
|
package/dist/fixture-document.js
CHANGED
|
@@ -295,8 +295,10 @@ function assertFixtureDefinition(value) {
|
|
|
295
295
|
function assertFixtureMetadata(metadata, file) {
|
|
296
296
|
const { entity, parameters, processor, locale, connectedFields, deferredFields, } = metadata;
|
|
297
297
|
if (typeof entity !== 'string' ||
|
|
298
|
-
|
|
299
|
-
|
|
298
|
+
entity.split('.').length > 2 ||
|
|
299
|
+
entity
|
|
300
|
+
.split('.')
|
|
301
|
+
.some((part) => !NAME_PATTERN.test(part) || exports.DANGEROUS_KEYS.has(part)) ||
|
|
300
302
|
!isFixtureRecord(parameters) ||
|
|
301
303
|
(processor !== undefined &&
|
|
302
304
|
(typeof processor !== 'string' || !processor)) ||
|
package/dist/generator.js
CHANGED
|
@@ -5,21 +5,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_module_1 = require("node:module");
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_url_1 = require("node:url");
|
|
9
11
|
const generator_helper_1 = require("@prisma/generator-helper");
|
|
12
|
+
const contract_fixture_schema_1 = require("./contract-fixture-schema");
|
|
10
13
|
const fixture_schema_1 = require("./fixture-schema");
|
|
11
|
-
(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
const writeSchema = (output, schema) => {
|
|
15
|
+
node_fs_1.default.mkdirSync(output, { recursive: true });
|
|
16
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(output, 'schema.json'), `${JSON.stringify(schema, null, 2)}\n`);
|
|
17
|
+
};
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
if (args.length) {
|
|
20
|
+
if (args.length !== 2)
|
|
21
|
+
throw new Error('Usage: prisma-fixtures-generator <contract.json> <output-directory>');
|
|
22
|
+
const [contractPath, output] = args;
|
|
23
|
+
const contract = JSON.parse(node_fs_1.default.readFileSync(contractPath, 'utf8'));
|
|
24
|
+
const consumerRequire = (0, node_module_1.createRequire)(node_path_1.default.join(process.cwd(), 'package.json'));
|
|
25
|
+
const runtime = consumerRequire.resolve('@prisma/orm-postgres/target/runtime');
|
|
26
|
+
void import((0, node_url_1.pathToFileURL)(runtime).href).then(({ PostgresContractSerializer }) => {
|
|
27
|
+
new PostgresContractSerializer().deserializeContract(contract);
|
|
28
|
+
writeSchema(output, (0, contract_fixture_schema_1.buildContractFixtureSchema)(contract));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
(0, generator_helper_1.generatorHandler)({
|
|
33
|
+
onManifest() {
|
|
34
|
+
return {
|
|
35
|
+
prettyName: 'Prisma Fixtures',
|
|
36
|
+
defaultOutput: './generated/fixtures',
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
async onGenerate(options) {
|
|
40
|
+
const output = options.generator.output?.value;
|
|
41
|
+
if (!output)
|
|
42
|
+
throw new Error('Prisma Fixtures generator requires an output path');
|
|
43
|
+
writeSchema(output, (0, fixture_schema_1.buildFixtureSchema)(options.dmmf));
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type FixtureDefinition, readFixtureDocuments } from './fixture-document';
|
|
2
2
|
import { type FixtureCleanupOptions } from './cleanup-options';
|
|
3
3
|
import { type FixtureLoadOptions, type FixtureResetOptions } from './load-options';
|
|
4
|
+
export { createPrisma8FixtureClient } from './prisma8-client';
|
|
4
5
|
export type { FixtureDefinition } from './fixture-document';
|
|
5
6
|
export { FixtureError } from './fixture-error';
|
|
6
7
|
export type { FixtureErrorCode, FixtureErrorContext } from './fixture-error';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PrismaFixtures = exports.readFixtureDefinitions = exports.FixtureError = void 0;
|
|
3
|
+
exports.PrismaFixtures = exports.readFixtureDefinitions = exports.FixtureError = exports.createPrisma8FixtureClient = void 0;
|
|
4
4
|
exports.loadFixtures = loadFixtures;
|
|
5
5
|
exports.cleanFixtures = cleanFixtures;
|
|
6
6
|
exports.resetFixtures = resetFixtures;
|
|
@@ -11,6 +11,9 @@ const cleanup_options_1 = require("./cleanup-options");
|
|
|
11
11
|
const load_options_1 = require("./load-options");
|
|
12
12
|
const fixture_error_1 = require("./fixture-error");
|
|
13
13
|
const fixture_config_1 = require("./fixture-config");
|
|
14
|
+
const prisma8_client_1 = require("./prisma8-client");
|
|
15
|
+
var prisma8_client_2 = require("./prisma8-client");
|
|
16
|
+
Object.defineProperty(exports, "createPrisma8FixtureClient", { enumerable: true, get: function () { return prisma8_client_2.createPrisma8FixtureClient; } });
|
|
14
17
|
var fixture_error_2 = require("./fixture-error");
|
|
15
18
|
Object.defineProperty(exports, "FixtureError", { enumerable: true, get: function () { return fixture_error_2.FixtureError; } });
|
|
16
19
|
exports.readFixtureDefinitions = fixture_document_1.readFixtureDocuments;
|
|
@@ -45,11 +48,17 @@ async function loadFixtures(client, definitions, optionsOrWrite, finalWrite) {
|
|
|
45
48
|
return writeFixtures(fixtures, write);
|
|
46
49
|
}
|
|
47
50
|
async function cleanFixtures(client, options) {
|
|
48
|
-
const { preserveTables = [] } = (0, cleanup_options_1.normalizeCleanupOptions)(options);
|
|
51
|
+
const { preserveTables: requestedTables = [] } = (0, cleanup_options_1.normalizeCleanupOptions)(options);
|
|
49
52
|
if (client === null ||
|
|
50
53
|
(typeof client !== 'object' && typeof client !== 'function')) {
|
|
51
54
|
throw new Error('Invalid fixture cleaner arguments');
|
|
52
55
|
}
|
|
56
|
+
const preserveTables = [
|
|
57
|
+
...new Set([
|
|
58
|
+
...requestedTables,
|
|
59
|
+
...(prisma8_client_1.prisma8PreservedTables.get(client) ?? []),
|
|
60
|
+
]),
|
|
61
|
+
];
|
|
53
62
|
const execute = client.$executeRawUnsafe;
|
|
54
63
|
if (typeof execute !== 'function') {
|
|
55
64
|
throw new Error('Fixture cleaner requires $executeRawUnsafe');
|
|
@@ -86,7 +95,7 @@ BEGIN
|
|
|
86
95
|
FROM pg_catalog.pg_class AS candidate
|
|
87
96
|
JOIN pg_catalog.pg_namespace AS namespace ON namespace.oid = candidate.relnamespace
|
|
88
97
|
WHERE candidate.relkind IN ('r', 'p')
|
|
89
|
-
AND namespace.nspname
|
|
98
|
+
AND namespace.nspname NOT IN ('information_schema', 'prisma_contract')
|
|
90
99
|
AND namespace.nspname !~ '^pg_'
|
|
91
100
|
AND candidate.relname <> '_prisma_migrations'
|
|
92
101
|
AND NOT EXISTS (
|
|
@@ -115,7 +124,7 @@ BEGIN
|
|
|
115
124
|
)
|
|
116
125
|
INTO tables
|
|
117
126
|
FROM pg_catalog.pg_tables
|
|
118
|
-
WHERE schemaname
|
|
127
|
+
WHERE schemaname NOT IN ('information_schema', 'prisma_contract')
|
|
119
128
|
AND schemaname !~ '^pg_'
|
|
120
129
|
AND tablename <> '_prisma_migrations'
|
|
121
130
|
AND NOT EXISTS (
|
package/dist/prisma-config.js
CHANGED
|
@@ -7,17 +7,20 @@ exports.loadPrismaDefaults = loadPrismaDefaults;
|
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_module_1 = require("node:module");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const node_url_1 = require("node:url");
|
|
11
|
+
const prisma8_client_1 = require("./prisma8-client");
|
|
10
12
|
const cleanup_options_1 = require("./cleanup-options");
|
|
11
13
|
async function loadPrismaDefaults(configRoot, requireFromCwd, databaseUrlOverride) {
|
|
12
14
|
const requireFromPrisma = (0, node_module_1.createRequire)(requireFromCwd.resolve('prisma/package.json'));
|
|
13
|
-
const
|
|
15
|
+
const version = requireFromPrisma('./package.json').version;
|
|
14
16
|
const previousUrl = process.env.DATABASE_URL;
|
|
15
17
|
if (databaseUrlOverride !== undefined) {
|
|
16
18
|
process.env.DATABASE_URL = databaseUrlOverride;
|
|
17
19
|
}
|
|
18
|
-
let loaded;
|
|
19
20
|
try {
|
|
20
|
-
|
|
21
|
+
return version.startsWith('8.')
|
|
22
|
+
? await loadPrisma8Defaults(configRoot, requireFromPrisma)
|
|
23
|
+
: await loadPrisma7Defaults(configRoot, requireFromPrisma, requireFromCwd);
|
|
21
24
|
}
|
|
22
25
|
finally {
|
|
23
26
|
if (databaseUrlOverride !== undefined) {
|
|
@@ -27,6 +30,10 @@ async function loadPrismaDefaults(configRoot, requireFromCwd, databaseUrlOverrid
|
|
|
27
30
|
process.env.DATABASE_URL = previousUrl;
|
|
28
31
|
}
|
|
29
32
|
}
|
|
33
|
+
}
|
|
34
|
+
async function loadPrisma7Defaults(configRoot, requireFromPrisma, requireFromCwd) {
|
|
35
|
+
const { loadConfigFromFile } = requireFromPrisma('@prisma/config');
|
|
36
|
+
const loaded = await loadConfigFromFile({ configRoot });
|
|
30
37
|
if (!loaded.resolvedPath || !loaded.config || loaded.error) {
|
|
31
38
|
throw new Error('Prisma config could not be loaded');
|
|
32
39
|
}
|
|
@@ -40,6 +47,20 @@ async function loadPrismaDefaults(configRoot, requireFromCwd, databaseUrlOverrid
|
|
|
40
47
|
}).preserveTables ?? [],
|
|
41
48
|
};
|
|
42
49
|
}
|
|
50
|
+
async function loadPrisma8Defaults(configRoot, requireFromPrisma) {
|
|
51
|
+
const { loadConfigForSections } = (await import((0, node_url_1.pathToFileURL)(requireFromPrisma.resolve('@prisma/orm-toolchain/config-loader')).href));
|
|
52
|
+
const loaded = await loadConfigForSections(node_path_1.default.join(configRoot, 'prisma.config.ts'), ['contract', 'db']);
|
|
53
|
+
const config = loaded.ok ? loaded.value : undefined;
|
|
54
|
+
const output = config?.contract?.output;
|
|
55
|
+
if (!output || config?.extensions?.length) {
|
|
56
|
+
throw new Error('Prisma 8 config requires an emitted contract and a supported runtime');
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
module: output,
|
|
60
|
+
databaseUrl: config?.db?.connection,
|
|
61
|
+
preserveTables: (0, prisma8_client_1.contractPreservedTables)(JSON.parse(node_fs_1.default.readFileSync(output, 'utf8'))),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
43
64
|
function defaultSchema(root) {
|
|
44
65
|
for (const name of ['prisma/schema.prisma', 'schema.prisma']) {
|
|
45
66
|
const file = node_path_1.default.join(root, name);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Data = Record<string, unknown>;
|
|
2
|
+
export declare const prisma8PreservedTables: WeakMap<object, string[]>;
|
|
3
|
+
export declare function contractPreservedTables(value: unknown): string[];
|
|
4
|
+
/** Bridge a native Prisma 8 PostgreSQL client to the fixture API. Requires PostgreSQL 17+. */
|
|
5
|
+
export declare function createPrisma8FixtureClient(client: object): Record<string, {
|
|
6
|
+
create(args: {
|
|
7
|
+
data: Data;
|
|
8
|
+
}): Promise<unknown>;
|
|
9
|
+
update(args: {
|
|
10
|
+
where: Data;
|
|
11
|
+
data: Data;
|
|
12
|
+
}): Promise<unknown>;
|
|
13
|
+
}> & {
|
|
14
|
+
$executeRawUnsafe(sql: string): Promise<unknown>;
|
|
15
|
+
} & {
|
|
16
|
+
$disconnect: () => Promise<void>;
|
|
17
|
+
$transaction<T>(action: (tx: object) => Promise<T>, { timeout }?: {
|
|
18
|
+
timeout?: number | undefined;
|
|
19
|
+
}): Promise<T>;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prisma8PreservedTables = void 0;
|
|
4
|
+
exports.contractPreservedTables = contractPreservedTables;
|
|
5
|
+
exports.createPrisma8FixtureClient = createPrisma8FixtureClient;
|
|
6
|
+
const fixture_document_1 = require("./fixture-document");
|
|
7
|
+
const cleanup_options_1 = require("./cleanup-options");
|
|
8
|
+
// Internal cleanup metadata follows the adapted client and each transaction.
|
|
9
|
+
exports.prisma8PreservedTables = new WeakMap();
|
|
10
|
+
function contractPreservedTables(value) {
|
|
11
|
+
const contract = value;
|
|
12
|
+
const names = [];
|
|
13
|
+
for (const [namespace, entry] of Object.entries(contract.storage?.namespaces ?? {})) {
|
|
14
|
+
for (const [table, metadata] of Object.entries(entry.entries?.table ?? {})) {
|
|
15
|
+
if (metadata.control !== undefined && metadata.control !== 'managed')
|
|
16
|
+
names.push(`${namespace}.${table}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return (0, cleanup_options_1.normalizeCleanupOptions)({ preserveTables: names }).preserveTables ?? [];
|
|
20
|
+
}
|
|
21
|
+
/** Bridge a native Prisma 8 PostgreSQL client to the fixture API. Requires PostgreSQL 17+. */
|
|
22
|
+
function createPrisma8FixtureClient(client) {
|
|
23
|
+
const db = client;
|
|
24
|
+
if (!db ||
|
|
25
|
+
!(0, fixture_document_1.isFixtureRecord)(db.contract?.domain?.namespaces) ||
|
|
26
|
+
!(0, fixture_document_1.isFixtureRecord)(db.orm) ||
|
|
27
|
+
typeof db.transaction !== 'function' ||
|
|
28
|
+
typeof db.close !== 'function' ||
|
|
29
|
+
typeof db.runtime !== 'function' ||
|
|
30
|
+
typeof db.raw?.sql !== 'function') {
|
|
31
|
+
throw new Error('Expected a Prisma 8 PostgreSQL client');
|
|
32
|
+
}
|
|
33
|
+
const namespaces = db.contract.domain.namespaces;
|
|
34
|
+
const preserveTables = contractPreservedTables(db.contract);
|
|
35
|
+
const aliases = new Map();
|
|
36
|
+
for (const [namespace, entry] of Object.entries(namespaces)) {
|
|
37
|
+
for (const name of Object.keys(entry.models)) {
|
|
38
|
+
for (const alias of new Set([
|
|
39
|
+
`${namespace}.${name}`,
|
|
40
|
+
name,
|
|
41
|
+
name[0].toLowerCase() + name.slice(1),
|
|
42
|
+
])) {
|
|
43
|
+
aliases.set(alias, aliases.has(alias) ? null : { namespace, name });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const plan = (sql) => db.raw
|
|
48
|
+
.sql(Object.assign([sql], { raw: [sql] }))
|
|
49
|
+
.affectedCount()
|
|
50
|
+
.build();
|
|
51
|
+
function scalarValue(model, field, value) {
|
|
52
|
+
const metadata = model.fields?.[field];
|
|
53
|
+
const codecId = metadata?.type.codecId;
|
|
54
|
+
if (metadata?.type.kind !== 'scalar' ||
|
|
55
|
+
!codecId ||
|
|
56
|
+
!/^pg\/(?:int8|unboundedint|int8number|numeric|bytea|interval|(?:date|timestamp|timestamptz|time)-temporal|timestamptz-date)@1$/.test(codecId))
|
|
57
|
+
return value;
|
|
58
|
+
const decode = (item) => {
|
|
59
|
+
// Native objects returned by processors/references already have the runtime type.
|
|
60
|
+
if (typeof item !== 'string' && typeof item !== 'number')
|
|
61
|
+
return item;
|
|
62
|
+
if (typeof item === 'number') {
|
|
63
|
+
if (codecId === 'pg/int8number@1')
|
|
64
|
+
return item;
|
|
65
|
+
if (!/^pg\/(?:int8|unboundedint|numeric)@1$/.test(codecId))
|
|
66
|
+
return item;
|
|
67
|
+
if (!Number.isFinite(item) ||
|
|
68
|
+
(codecId !== 'pg/numeric@1' && !Number.isSafeInteger(item)))
|
|
69
|
+
throw new Error('Invalid numeric fixture value');
|
|
70
|
+
item = String(item);
|
|
71
|
+
}
|
|
72
|
+
const storage = model.storage;
|
|
73
|
+
const column = storage?.fields[field]?.column;
|
|
74
|
+
const codec = storage && column
|
|
75
|
+
? db.context.contractCodecs.forColumn(storage.namespaceId, storage.table, column)
|
|
76
|
+
: undefined;
|
|
77
|
+
if (!codec)
|
|
78
|
+
throw new Error('Prisma 8 fixture column codec not found');
|
|
79
|
+
return codec.decodeJson(item);
|
|
80
|
+
};
|
|
81
|
+
return metadata.many && Array.isArray(value)
|
|
82
|
+
? value.map(decode)
|
|
83
|
+
: decode(value);
|
|
84
|
+
}
|
|
85
|
+
function relationData(data, model) {
|
|
86
|
+
return Object.fromEntries(Object.entries(data).map(([field, value]) => {
|
|
87
|
+
const relation = model.relations[field];
|
|
88
|
+
if (!relation)
|
|
89
|
+
return [field, scalarValue(model, field, value)];
|
|
90
|
+
if (!(0, fixture_document_1.isFixtureRecord)(value) ||
|
|
91
|
+
Object.keys(value).length !== 1 ||
|
|
92
|
+
(!Object.hasOwn(value, 'connect') && !Object.hasOwn(value, 'create'))) {
|
|
93
|
+
throw new Error('Prisma 8 fixture relations require connect or create');
|
|
94
|
+
}
|
|
95
|
+
const target = namespaces[relation.to.namespace].models[relation.to.model];
|
|
96
|
+
const operation = Object.hasOwn(value, 'connect') ? 'connect' : 'create';
|
|
97
|
+
const map = (item) => {
|
|
98
|
+
if (!(0, fixture_document_1.isFixtureRecord)(item))
|
|
99
|
+
throw new Error('Invalid fixture relation data');
|
|
100
|
+
return relationData(item, target);
|
|
101
|
+
};
|
|
102
|
+
const input = value[operation];
|
|
103
|
+
const mapped = Array.isArray(input) ? input.map(map) : map(input);
|
|
104
|
+
return [
|
|
105
|
+
field,
|
|
106
|
+
(mutator) => mutator[operation](mapped),
|
|
107
|
+
];
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
function adapt(orm, runtime, check = () => { }) {
|
|
111
|
+
const delegates = Object.create(null);
|
|
112
|
+
const byModel = new Map();
|
|
113
|
+
for (const [alias, model] of aliases) {
|
|
114
|
+
if (!model)
|
|
115
|
+
continue;
|
|
116
|
+
const { namespace, name } = model;
|
|
117
|
+
const qualified = `${namespace}.${name}`;
|
|
118
|
+
let delegate = byModel.get(qualified);
|
|
119
|
+
if (!delegate) {
|
|
120
|
+
const metadata = namespaces[namespace].models[name];
|
|
121
|
+
delegate = {
|
|
122
|
+
async create({ data }) {
|
|
123
|
+
check();
|
|
124
|
+
return orm[namespace][name].create(relationData(data, metadata));
|
|
125
|
+
},
|
|
126
|
+
async update({ where, data }) {
|
|
127
|
+
check();
|
|
128
|
+
return orm[namespace][name]
|
|
129
|
+
.where(relationData(where, metadata))
|
|
130
|
+
.update(relationData(data, metadata));
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
byModel.set(qualified, delegate);
|
|
134
|
+
}
|
|
135
|
+
delegates[alias] = delegate;
|
|
136
|
+
}
|
|
137
|
+
const adapted = Object.assign(delegates, {
|
|
138
|
+
async $executeRawUnsafe(sql) {
|
|
139
|
+
check();
|
|
140
|
+
return runtime.execute(plan(sql));
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
exports.prisma8PreservedTables.set(adapted, preserveTables);
|
|
144
|
+
return adapted;
|
|
145
|
+
}
|
|
146
|
+
return Object.assign(adapt(db.orm, db.runtime()), {
|
|
147
|
+
$disconnect: () => db.close(),
|
|
148
|
+
async $transaction(action, { timeout = 60_000 } = {}) {
|
|
149
|
+
if (!Number.isSafeInteger(timeout) ||
|
|
150
|
+
timeout <= 0 ||
|
|
151
|
+
timeout > 2_147_483_647)
|
|
152
|
+
throw new Error('Invalid transaction timeout');
|
|
153
|
+
return db.transaction(async (tx) => {
|
|
154
|
+
// PostgreSQL rejects this setting before any fixtures on versions older than 17.
|
|
155
|
+
// The database deadline also cancels in-flight queries and rolls back idle callbacks.
|
|
156
|
+
await tx.execute(plan(`SET LOCAL transaction_timeout = '${timeout}ms'`));
|
|
157
|
+
const deadline = Date.now() + timeout;
|
|
158
|
+
let closed = false;
|
|
159
|
+
let timer;
|
|
160
|
+
const check = () => {
|
|
161
|
+
if (closed || Date.now() >= deadline)
|
|
162
|
+
throw new Error('Fixture transaction closed or timed out');
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
const result = await Promise.race([
|
|
166
|
+
Promise.resolve().then(() => action(adapt(tx.orm, tx, check))),
|
|
167
|
+
new Promise((_, reject) => {
|
|
168
|
+
timer = setTimeout(() => {
|
|
169
|
+
closed = true;
|
|
170
|
+
reject(new Error('Fixture transaction timed out'));
|
|
171
|
+
}, timeout);
|
|
172
|
+
}),
|
|
173
|
+
]);
|
|
174
|
+
check();
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
closed = true;
|
|
179
|
+
clearTimeout(timer);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skmdev/prisma-fixtures",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
4
|
"description": "YAML and JSON fixtures with references, templates and processors for Prisma.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "skmdev <skmdev29@gmail.com>",
|
|
@@ -66,10 +66,12 @@
|
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@prisma/adapter-pg": "7.10.0",
|
|
68
68
|
"@prisma/client": "7.10.0",
|
|
69
|
+
"@prisma/orm-postgres": "8.0.0-rc.12",
|
|
70
|
+
"@prisma/prisma7": "7.10.0",
|
|
69
71
|
"@types/ejs": "3.1.5",
|
|
70
72
|
"@types/node": "22.19.15",
|
|
71
73
|
"prettier": "3.8.3",
|
|
72
|
-
"prisma": "
|
|
74
|
+
"prisma": "8.0.0-rc.17",
|
|
73
75
|
"typescript": "5.9.3"
|
|
74
76
|
},
|
|
75
77
|
"overrides": {
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
},
|
|
59
59
|
"definitions": {
|
|
60
60
|
"entityName": {
|
|
61
|
-
"description": "Prisma model/delegate name.",
|
|
61
|
+
"description": "Prisma model/delegate name, optionally namespace-qualified for v8.",
|
|
62
62
|
"type": "string",
|
|
63
|
-
"pattern": "^[A-Za-z][A-Za-z0-9_-]{0,127}$"
|
|
63
|
+
"pattern": "^(?:[A-Za-z][A-Za-z0-9_-]{0,127}\\.)?[A-Za-z][A-Za-z0-9_-]{0,127}$"
|
|
64
64
|
},
|
|
65
65
|
"fieldName": {
|
|
66
66
|
"description": "Prisma relation field name.",
|