prisma-laravel-migrate 3.0.4 → 3.0.6
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 +496 -306
- package/dist/cli/cli.js +167 -109
- package/dist/cli/generate.js +20 -24
- package/dist/cli/ts.index.js +12 -0
- package/dist/diff-writer/writer.js +27 -8
- package/dist/generator/modeler/generator.js +2 -1
- package/dist/generator/modeler/relationship/index.js +12 -3
- package/dist/generator/ts/directives.js +76 -0
- package/dist/generator/ts/generator.js +243 -0
- package/dist/generator/ts/index.js +181 -0
- package/dist/generator/ts/printer.js +362 -0
- package/dist/generator/ts/types.js +2 -0
- package/dist/index.js +1 -0
- package/dist/utils/clean.js +2 -2
- package/dist/utils/pretty.js +2 -2
- package/dist/utils/stubResolver.js +35 -14
- package/package.json +1 -1
- package/small.prisma +1 -0
- package/stubs/ts.stub +3 -0
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# Prisma Laravel Migrate
|
|
2
2
|
|
|
3
|
-
A generator plugin that translates your **Prisma schema** into Laravel‑ready
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
A generator plugin that translates your **Prisma schema** into Laravel‑ready
|
|
4
|
+
|
|
5
|
+
* **Database Migrations**
|
|
6
|
+
* **Eloquent Models & PHP Enums**
|
|
7
|
+
* **TypeScript model & enum types**
|
|
8
|
+
|
|
9
|
+
Built in strict TypeScript with fully‑customisable stubs, grouping, smart merge updates, and an optional TS types generator.
|
|
6
10
|
|
|
7
11
|
---
|
|
8
12
|
|
|
@@ -14,7 +18,8 @@ npm install prisma-laravel-migrate --save-dev
|
|
|
14
18
|
```
|
|
15
19
|
|
|
16
20
|
---
|
|
17
|
-
|
|
21
|
+
|
|
22
|
+
## 🛠️ Configuration layers
|
|
18
23
|
|
|
19
24
|
The generators read options in **three tiers (highest → lowest)**:
|
|
20
25
|
|
|
@@ -43,54 +48,97 @@ module.exports = {
|
|
|
43
48
|
output: {
|
|
44
49
|
migrations: "database/migrations",
|
|
45
50
|
models: "app/Models",
|
|
46
|
-
enums: "app/Enums"
|
|
51
|
+
enums: "app/Enums",
|
|
47
52
|
},
|
|
48
53
|
|
|
49
54
|
/* -- per‑generator overrides ------------------------ */
|
|
50
55
|
migrate: {
|
|
51
56
|
groups: "./prisma/migrate-groups.js",
|
|
52
|
-
rules : "./prisma/custom-rules.js"
|
|
57
|
+
rules : "./prisma/custom-rules.js",
|
|
53
58
|
},
|
|
54
59
|
|
|
55
60
|
modeler: {
|
|
56
61
|
groups: [
|
|
57
|
-
{ stubFile: "audit.stub", tables: ["logs","audit_trails"] }
|
|
62
|
+
{ stubFile: "audit.stub", tables: ["logs","audit_trails"] },
|
|
58
63
|
],
|
|
59
64
|
outputEnumDir: "app/Enums",
|
|
60
65
|
overwriteExisting: true,
|
|
61
|
-
allowedPivotExtraFields: ["scope"]
|
|
62
|
-
|
|
66
|
+
allowedPivotExtraFields: ["scope"],
|
|
67
|
+
// use awobaz/compoships for multi-column relations
|
|
68
|
+
awobaz: true,
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* NEW: TypeScript generator (models + enums → TS types)
|
|
73
|
+
*/
|
|
74
|
+
types: {
|
|
75
|
+
// Where generated TS goes (default: "resources/ts/prisma")
|
|
76
|
+
outputDir: "resources/ts/prisma",
|
|
77
|
+
|
|
78
|
+
// Emit .d.ts instead of .ts when true
|
|
79
|
+
declaration: false,
|
|
80
|
+
|
|
81
|
+
// "interface" | "type" for model declarations
|
|
82
|
+
shape: "interface",
|
|
83
|
+
|
|
84
|
+
// Optional module wrapper for the main types file
|
|
85
|
+
// declare module "database/prisma" { ... }
|
|
86
|
+
moduleName: "database/prisma",
|
|
87
|
+
|
|
88
|
+
// Example scalar mapping overrides
|
|
89
|
+
scalarMap: {
|
|
90
|
+
// BigInt: "bigint",
|
|
91
|
+
// Decimal: "string",
|
|
92
|
+
// Json: "unknown",
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// If true: nullable fields become optional properties
|
|
96
|
+
nullableAsOptional: false,
|
|
97
|
+
|
|
98
|
+
// If true: lists become ReadonlyArray<T>
|
|
99
|
+
readonlyArrays: false,
|
|
100
|
+
|
|
101
|
+
// Name decoration for interfaces/types
|
|
102
|
+
namePrefix: "",
|
|
103
|
+
nameSuffix: "",
|
|
104
|
+
},
|
|
63
105
|
};
|
|
64
106
|
```
|
|
65
107
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
108
|
+
> There is also a small section in the codebase labelled
|
|
109
|
+
> **“Related Generator Options (Formatting & Compoships)”** covering:
|
|
110
|
+
>
|
|
111
|
+
> * `prettier` (per‑generator): enables formatting via Prettier for
|
|
112
|
+
> PHP/TS outputs during merge.
|
|
113
|
+
> * `modeler.awobaz`: whether to emit Compoships‑aware relationships
|
|
114
|
+
> (requires `awobaz/compoships` in your Laravel app).
|
|
115
|
+
|
|
116
|
+
---
|
|
69
117
|
|
|
70
118
|
<details>
|
|
71
119
|
<summary>Type reference</summary>
|
|
72
120
|
|
|
73
121
|
```ts
|
|
74
122
|
export interface Rule {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
123
|
+
test(
|
|
124
|
+
def: ColumnDefinition,
|
|
125
|
+
allDefs: ColumnDefinition[],
|
|
126
|
+
dmmf: DMMF.Document,
|
|
127
|
+
): boolean;
|
|
128
|
+
render(
|
|
129
|
+
def: ColumnDefinition,
|
|
130
|
+
allDefs: ColumnDefinition[],
|
|
131
|
+
dmmf: DMMF.Document,
|
|
132
|
+
): Render;
|
|
85
133
|
}
|
|
86
134
|
|
|
87
135
|
/* ------------------------------------------------------------
|
|
88
136
|
* Re-usable stub-group description
|
|
89
137
|
* ---------------------------------------------------------- */
|
|
90
138
|
export interface StubGroupConfig extends FlexibleStubGroup {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
139
|
+
/** Path relative to stubDir/<type>/ (e.g. "auth.stub") */
|
|
140
|
+
stubFile: string;
|
|
141
|
+
tables: string[]; // ["users","accounts",…] or enum names
|
|
94
142
|
}
|
|
95
143
|
|
|
96
144
|
/**
|
|
@@ -98,20 +146,20 @@ export interface StubGroupConfig extends FlexibleStubGroup {
|
|
|
98
146
|
* Supply EITHER `tables` *or* (`include` / `exclude` / `pattern`).
|
|
99
147
|
*/
|
|
100
148
|
interface FlexibleStubGroup {
|
|
101
|
-
|
|
102
|
-
|
|
149
|
+
/** Path relative to stubDir/<type>/, e.g. "auth.stub" */
|
|
150
|
+
stubFile: string;
|
|
103
151
|
|
|
104
|
-
|
|
105
|
-
|
|
152
|
+
/** Old style - explicit white-list */
|
|
153
|
+
tables?: string[];
|
|
106
154
|
|
|
107
|
-
|
|
108
|
-
|
|
155
|
+
/** New style – include list ( '*' means “all tables” ) */
|
|
156
|
+
include?: string[] | '*';
|
|
109
157
|
|
|
110
|
-
|
|
111
|
-
|
|
158
|
+
/** New style – blacklist applied after include / pattern */
|
|
159
|
+
exclude?: string[];
|
|
112
160
|
|
|
113
|
-
|
|
114
|
-
|
|
161
|
+
/** New style – RegExp OR minimatch glob(s) */
|
|
162
|
+
pattern?: RegExp | string | Array<RegExp | string>;
|
|
115
163
|
}
|
|
116
164
|
|
|
117
165
|
|
|
@@ -119,81 +167,124 @@ interface FlexibleStubGroup {
|
|
|
119
167
|
* Per-generator overrides (migration / modeler)
|
|
120
168
|
* ---------------------------------------------------------- */
|
|
121
169
|
export interface LaravelGeneratorConfig {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
170
|
+
tablePrefix?: string;
|
|
171
|
+
tableSuffix?: string;
|
|
172
|
+
|
|
173
|
+
/** Override stubDir only for this generator */
|
|
174
|
+
stubDir?: string;
|
|
175
|
+
|
|
176
|
+
/** Where the generated PHP goes (overrides block) */
|
|
177
|
+
outputDir?: string;
|
|
178
|
+
|
|
179
|
+
overwriteExisting?: boolean;
|
|
180
|
+
/** Allow formatting with prettier */
|
|
181
|
+
prettier?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Stub grouping:
|
|
184
|
+
* • string – path to a JS module exporting StubGroupConfig[]
|
|
185
|
+
* • array – the group definitions themselves
|
|
186
|
+
*/
|
|
187
|
+
groups?: string | StubGroupConfig[];
|
|
188
|
+
|
|
189
|
+
/** Skip file emission for *this* generator only */
|
|
190
|
+
noEmit?: boolean;
|
|
191
|
+
|
|
192
|
+
/** Default namespace for local imports */
|
|
193
|
+
namespace?: "App\\";
|
|
146
194
|
}
|
|
147
195
|
|
|
148
196
|
/* ------------------------------------------------------------
|
|
149
197
|
* Top-level shared config (visible to all generators)
|
|
150
198
|
* ---------------------------------------------------------- */
|
|
151
199
|
export interface LaravelSharedConfig {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
200
|
+
/** Table name decoration */
|
|
201
|
+
tablePrefix?: string;
|
|
202
|
+
tableSuffix?: string;
|
|
203
|
+
|
|
204
|
+
/** Default stub root (migration/, model/, enum/, ts/) */
|
|
205
|
+
stubDir?: string;
|
|
206
|
+
|
|
207
|
+
/** Global “don’t write files” switch */
|
|
208
|
+
noEmit?: boolean;
|
|
209
|
+
|
|
210
|
+
/** Override default output folders (PHP side) */
|
|
211
|
+
output?: {
|
|
212
|
+
migrations?: string;
|
|
213
|
+
models?: string;
|
|
214
|
+
enums?: string;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/** Per-generator fine-tuning */
|
|
218
|
+
migrate?: Partial<MigratorConfigOverride>;
|
|
219
|
+
modeler?: Partial<ModelConfigOverride>;
|
|
220
|
+
|
|
221
|
+
/** NEW: TypeScript generator overrides */
|
|
222
|
+
types?: Partial<TypesConfigOverride>;
|
|
172
223
|
}
|
|
173
224
|
|
|
174
225
|
|
|
175
226
|
/* --- Migrator-specific extra keys ---------------------------------------- */
|
|
176
227
|
export interface MigratorConfigOverride extends LaravelGeneratorConfig {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Custom migration rules:
|
|
230
|
+
* • string – path to JS module exporting Rule[]
|
|
231
|
+
* • Rule[] – rules array inline
|
|
232
|
+
*/
|
|
233
|
+
rules?: string | Rule[];
|
|
234
|
+
stubPath?: string;
|
|
235
|
+
defaultMaps?: DefaultMaps;
|
|
185
236
|
}
|
|
186
237
|
|
|
187
238
|
|
|
188
239
|
export interface ModelConfigOverride extends LaravelGeneratorConfig {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
240
|
+
modelStubPath?: string;
|
|
241
|
+
enumStubPath?: string;
|
|
242
|
+
/** Extra folder for enums (modeler only) */
|
|
243
|
+
outputEnumDir?: string;
|
|
244
|
+
/** use awobaz/compoships */
|
|
245
|
+
awobaz?: boolean;
|
|
246
|
+
/** Extra fields allowed on pivot models */
|
|
247
|
+
allowedPivotExtraFields?: string[];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ------------------------------------------------------------
|
|
251
|
+
* TypeScript generator overrides
|
|
252
|
+
* ---------------------------------------------------------- */
|
|
253
|
+
export interface TypesConfigOverride extends LaravelGeneratorConfig {
|
|
254
|
+
/** Where generated TS types should be written, e.g. "resources/ts/prisma" */
|
|
255
|
+
outputDir?: string;
|
|
256
|
+
|
|
257
|
+
/** Emit `.d.ts` declaration files instead of `.ts` source files. */
|
|
258
|
+
declaration?: boolean; // default: false → .ts
|
|
259
|
+
|
|
260
|
+
/** Use `interface` or `type` for model declarations. */
|
|
261
|
+
shape?: "interface" | "type"; // default: "interface"
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Map Prisma scalar types → TypeScript types.
|
|
265
|
+
* Keys are Prisma scalar names ("Int", "BigInt", "Decimal", "Json", "DateTime", etc.).
|
|
266
|
+
*/
|
|
267
|
+
scalarMap?: Record<string, string>;
|
|
268
|
+
|
|
269
|
+
/** If true, nullable fields become optional: `foo?: string` instead of `foo: string | null`. */
|
|
270
|
+
nullableAsOptional?: boolean;
|
|
271
|
+
|
|
272
|
+
/** If true, lists are emitted as `ReadonlyArray<T>` instead of `T[]`. */
|
|
273
|
+
readonlyArrays?: boolean;
|
|
274
|
+
|
|
275
|
+
/** Optional name decoration for generated types/interfaces. */
|
|
276
|
+
namePrefix?: string;
|
|
277
|
+
nameSuffix?: string;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Optional root module/namespace hint.
|
|
281
|
+
* When set, the main types file is wrapped in:
|
|
282
|
+
* declare module "…" { ... }
|
|
283
|
+
*/
|
|
284
|
+
moduleName?: string;
|
|
285
|
+
|
|
286
|
+
/** Where models should import enums from (default: "./enums"). */
|
|
287
|
+
enumImportFrom?: string;
|
|
197
288
|
}
|
|
198
289
|
```
|
|
199
290
|
|
|
@@ -214,35 +305,47 @@ generator migrate {
|
|
|
214
305
|
generator modeler {
|
|
215
306
|
provider = "prisma-laravel-models"
|
|
216
307
|
stubDir = "./prisma/stubs"
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// NEW: TypeScript types generator
|
|
311
|
+
generator types {
|
|
312
|
+
provider = "prisma-laravel-types"
|
|
313
|
+
stubDir = "./prisma/stubs"
|
|
314
|
+
}
|
|
217
315
|
```
|
|
218
316
|
|
|
219
317
|
### Field Reference
|
|
220
318
|
|
|
221
|
-
| Key
|
|
222
|
-
|
|
|
223
|
-
| `outputDir / output`
|
|
224
|
-
| `outputEnumDir`
|
|
225
|
-
| `stubDir`
|
|
226
|
-
| `tablePrefix`
|
|
227
|
-
| `tableSuffix`
|
|
228
|
-
| `groups`
|
|
229
|
-
| `noEmit`
|
|
319
|
+
| Key | Notes | |
|
|
320
|
+
| -------------------- | ----------------------------------------------------------------------------------------------- | ------ |
|
|
321
|
+
| `outputDir / output` | Destination folder (`outputDir` overrides `output`) — PHP and TS. | |
|
|
322
|
+
| `outputEnumDir` | (modeler) directory for generated PHP enum classes. | |
|
|
323
|
+
| `stubDir` | Root stub folder (`migration/`, `model/`, `enum/`, `ts/`). | |
|
|
324
|
+
| `tablePrefix` | String prepended to every generated **physical** table name. | |
|
|
325
|
+
| `tableSuffix` | String appended to every generated **physical** table name. | |
|
|
326
|
+
| `groups` | JS module *or* inline array that maps stub files to table/model/enum/TS groups. | |
|
|
327
|
+
| `noEmit` | If `true`, generator parses and validates but **does not write** any files (dry-run / CI mode). | |
|
|
328
|
+
| `prettier` | Per-generator toggle for formatting (PHP or TS) before 3‑way merge. | |
|
|
329
|
+
| `awobaz` | (modeler) Emit Compoships‑aware relationships; requires `awobaz/compoships`. | |
|
|
330
|
+
| `scalarMap` | (types) Map Prisma scalars → TS type names. | |
|
|
331
|
+
| `nullableAsOptional` | (types) Emit `foo?: T` for nullable fields instead of `foo: T | null`. |
|
|
332
|
+
| `readonlyArrays` | (types) Emit `ReadonlyArray<T>` instead of `T[]`. | |
|
|
333
|
+
| `moduleName` | (types) Wrap main types output in `declare module "…" {}`. | |
|
|
230
334
|
|
|
231
335
|
---
|
|
232
336
|
|
|
233
|
-
|
|
234
337
|
## 🔀 `groups` – Stub Grouping (v2)
|
|
235
338
|
|
|
236
|
-
A **group** links one stub file to
|
|
339
|
+
A **group** links one stub file to *many* tables (or enums / TS variants).
|
|
237
340
|
From v2 you can keep the old **`tables: [...]`** list **or** use the new, more
|
|
238
341
|
expressive selectors:
|
|
239
342
|
|
|
240
|
-
| Key
|
|
241
|
-
|
|
242
|
-
| `tables`
|
|
243
|
-
| `include`
|
|
244
|
-
| `exclude`
|
|
245
|
-
| `pattern`
|
|
343
|
+
| Key | Type / Example | Meaning |
|
|
344
|
+
| --------- | --------------------------------- | ----------------------------------------------- |
|
|
345
|
+
| `tables` | `["users","accounts"]` | Classic explicit list – **exact names** only |
|
|
346
|
+
| `include` | `["audit_*","logs"]` **or** `"*"` | White‑list using globs or `'*'` (all) |
|
|
347
|
+
| `exclude` | `["*_archive","failed_jobs"]` | Black‑list applied *after* include / pattern |
|
|
348
|
+
| `pattern` | `/^temp_/` or `"report_*"` | `RegExp` **or** glob(s) – match if **any** hits |
|
|
246
349
|
|
|
247
350
|
> Only one of **`tables`** **or** the new selector trio is required.
|
|
248
351
|
|
|
@@ -264,34 +367,36 @@ module.exports = [
|
|
|
264
367
|
// 1. legacy explicit list
|
|
265
368
|
{
|
|
266
369
|
stubFile: "auth.stub", // stubs/migration/auth.stub
|
|
267
|
-
tables: ["users","accounts","password_resets"]
|
|
370
|
+
tables: ["users","accounts","password_resets"],
|
|
268
371
|
},
|
|
269
372
|
|
|
270
373
|
// 2. regex + blacklist
|
|
271
374
|
{
|
|
272
375
|
stubFile: "audit.stub",
|
|
273
376
|
pattern : /^audit_/,
|
|
274
|
-
exclude : ["audit_archive"]
|
|
377
|
+
exclude : ["audit_archive"],
|
|
275
378
|
},
|
|
276
379
|
|
|
277
380
|
// 3. catch‑all
|
|
278
381
|
{
|
|
279
382
|
stubFile: "catch-all.stub",
|
|
280
383
|
include : "*",
|
|
281
|
-
exclude : ["failed_jobs","migrations"]
|
|
282
|
-
}
|
|
384
|
+
exclude : ["failed_jobs","migrations"],
|
|
385
|
+
},
|
|
283
386
|
];
|
|
284
387
|
```
|
|
285
388
|
|
|
286
389
|
### Resolution order
|
|
287
390
|
|
|
288
|
-
1. **Table‑specific** — `stubs/<type>/<table>.stub`
|
|
289
|
-
2. **First matching group** (objects are checked top‑to‑bottom)
|
|
391
|
+
1. **Table‑specific** — `stubs/<type>/<table>.stub`
|
|
392
|
+
2. **First matching group** (objects are checked top‑to‑bottom)
|
|
290
393
|
3. **Default** — `stubs/<type>/index.stub`
|
|
291
394
|
|
|
292
395
|
> If a group’s `stubFile` does not exist it is skipped, so you may leave unused
|
|
293
396
|
> groups in place without breaking the build.
|
|
294
397
|
|
|
398
|
+
---
|
|
399
|
+
|
|
295
400
|
## 📁 Stub Folder Layout
|
|
296
401
|
|
|
297
402
|
```text
|
|
@@ -299,21 +404,26 @@ prisma/stubs/
|
|
|
299
404
|
├── migration/index.stub
|
|
300
405
|
├── model/index.stub
|
|
301
406
|
├── model/simple-model.stub
|
|
302
|
-
|
|
407
|
+
├── enum/index.stub
|
|
408
|
+
└── ts/index.stub
|
|
303
409
|
```
|
|
304
410
|
|
|
305
|
-
Add table‑specific overrides at
|
|
306
|
-
`stubs/<type>/<table>.stub` (e.g. `stubs/model/users.stub`).
|
|
411
|
+
Add table‑specific overrides at
|
|
412
|
+
`stubs/<type>/<table>.stub` (e.g. `stubs/model/users.stub`, `stubs/ts/Account.stub`).
|
|
413
|
+
|
|
414
|
+
* `migration/` and `model/` stubs are **PHP** template literals.
|
|
415
|
+
* `enum/` stubs are **PHP** enum templates.
|
|
416
|
+
* `ts/` stubs are **JavaScript template literals** evaluated by the TS printer.
|
|
307
417
|
|
|
308
418
|
---
|
|
309
419
|
|
|
310
420
|
## 🔧 CLI Commands
|
|
311
421
|
|
|
312
|
-
| Command
|
|
313
|
-
|
|
|
314
|
-
| `init`
|
|
315
|
-
| `customize` | Create per-table stub overrides
|
|
316
|
-
| `gen`
|
|
422
|
+
| Command | Purpose |
|
|
423
|
+
| ----------- | -------------------------------------------------- |
|
|
424
|
+
| `init` | Inject generator blocks & scaffold stubs |
|
|
425
|
+
| `customize` | Create per-table stub overrides |
|
|
426
|
+
| `gen` | Run `prisma generate` then Laravel + TS generators |
|
|
317
427
|
|
|
318
428
|
### init
|
|
319
429
|
|
|
@@ -324,15 +434,18 @@ npx prisma-laravel-cli init --schema=prisma/schema.prisma
|
|
|
324
434
|
### customize
|
|
325
435
|
|
|
326
436
|
```bash
|
|
327
|
-
npx prisma-laravel-cli customize
|
|
437
|
+
npx prisma-laravel-cli customize \
|
|
438
|
+
-t migration,model,ts \
|
|
439
|
+
-n users,accounts \
|
|
440
|
+
--force
|
|
328
441
|
```
|
|
329
442
|
|
|
330
|
-
| Flag
|
|
331
|
-
|
|
|
332
|
-
| `-t, --
|
|
333
|
-
| `-n, --names` | **Required.** Table or enum names (`users,accounts`).
|
|
334
|
-
| `--force`
|
|
335
|
-
| `--config`
|
|
443
|
+
| Flag | Description |
|
|
444
|
+
| ------------- | ---------------------------------------------------------------------------------------------- |
|
|
445
|
+
| `-t, --types` | **Required.** Stub types (`migration`, `model`, `enum`, `ts`). `enum` may not mix with others. |
|
|
446
|
+
| `-n, --names` | **Required.** Table or enum names (`users,accounts`). |
|
|
447
|
+
| `--force` | Overwrite existing stub files. |
|
|
448
|
+
| `--config` | Alternate CLI config path. |
|
|
336
449
|
|
|
337
450
|
### gen
|
|
338
451
|
|
|
@@ -346,17 +459,22 @@ npx prisma-laravel-cli gen --config=prisma/laravel.config.js --skipGenerate
|
|
|
346
459
|
|
|
347
460
|
```js
|
|
348
461
|
module.exports = {
|
|
349
|
-
|
|
462
|
+
migrate: {
|
|
350
463
|
outputDir: "database/migrations",
|
|
351
464
|
stubDir: "prisma/stubs",
|
|
352
|
-
groups: "./prisma/group-stubs.js"
|
|
465
|
+
groups: "./prisma/group-stubs.js",
|
|
353
466
|
},
|
|
354
467
|
modeler: {
|
|
355
468
|
outputDir: "app/Models",
|
|
356
469
|
outputEnumDir: "app/Enums",
|
|
357
470
|
stubDir: "prisma/stubs",
|
|
358
|
-
groups: "./prisma/group-stubs.js"
|
|
359
|
-
}
|
|
471
|
+
groups: "./prisma/group-stubs.js",
|
|
472
|
+
},
|
|
473
|
+
types: {
|
|
474
|
+
outputDir: "resources/ts/prisma",
|
|
475
|
+
stubDir: "prisma/stubs",
|
|
476
|
+
moduleName: "database/prisma",
|
|
477
|
+
},
|
|
360
478
|
};
|
|
361
479
|
```
|
|
362
480
|
|
|
@@ -366,56 +484,67 @@ module.exports = {
|
|
|
366
484
|
|
|
367
485
|
1. Generator builds a **full new file** from your schema & stubs.
|
|
368
486
|
2. Performs a **git‑style 3‑way merge** (using `node-diff3`):
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
487
|
+
|
|
488
|
+
* **base** = last generator output (`.prisma-laravel/backups/...`)
|
|
489
|
+
* **ours** = file on disk (user edits)
|
|
490
|
+
* **theirs** = freshly generated file
|
|
491
|
+
3. Non‑conflicting changes merge automatically; conflicts are wrapped with
|
|
492
|
+
`<<<<<<<`, `=======`, `>>>>>>>`.
|
|
493
|
+
4. New imports are merged, duplicates skipped.
|
|
375
494
|
5. Baseline copy is updated in the backups folder.
|
|
376
495
|
|
|
496
|
+
The same merge pipeline is used for:
|
|
497
|
+
|
|
498
|
+
* PHP migrations (`type: "migrator"` in the diff writer),
|
|
499
|
+
* PHP models/enums (`type: "model"`),
|
|
500
|
+
* TypeScript outputs (`type: "ts"`, using the `typescript` Prettier parser).
|
|
501
|
+
|
|
377
502
|
Delete the marker block **and** set `noEmit = true` to stop updates for a file.
|
|
378
503
|
|
|
379
504
|
---
|
|
380
505
|
|
|
381
506
|
## ✨ Stub Customisation Notes
|
|
382
507
|
|
|
383
|
-
Stubs are **JavaScript template literals**. Escape
|
|
508
|
+
Stubs are **JavaScript template literals**. Escape ` and ${ } if you want them literally.
|
|
384
509
|
|
|
385
|
-
> **Fully custom model stubs**
|
|
510
|
+
> **Fully custom model stubs**
|
|
386
511
|
> If you remove the `${content}` placeholder **and** the marker block, the
|
|
387
|
-
> generator leaves the file untouched.
|
|
512
|
+
> generator leaves the file untouched.
|
|
388
513
|
> Keep the markers if you want automated updates but customised surroundings.
|
|
389
514
|
|
|
390
515
|
---
|
|
391
516
|
|
|
392
517
|
## 📑 Default Stub Templates
|
|
393
518
|
|
|
519
|
+
### PHP Enum `index.stub`
|
|
520
|
+
|
|
394
521
|
<details>
|
|
395
|
-
<summary>Enum <code>index.stub</code
|
|
522
|
+
<summary>Enum <code>index.stub</code> (PHP)</summary>
|
|
396
523
|
|
|
397
524
|
```php
|
|
398
525
|
<?php
|
|
399
526
|
|
|
400
|
-
namespace App
|
|
527
|
+
namespace App\Enums;
|
|
401
528
|
|
|
402
529
|
enum ${enumDef.name}: string
|
|
403
530
|
{
|
|
404
|
-
${enumDef.values.map(v => ` case ${v} = '${v}';`).join('
|
|
531
|
+
${enumDef.values.map(v => ` case ${v} = '${v}';`).join('\n')}
|
|
405
532
|
}
|
|
406
533
|
```
|
|
407
534
|
|
|
408
535
|
</details>
|
|
409
536
|
|
|
537
|
+
### PHP Migration `index.stub`
|
|
538
|
+
|
|
410
539
|
<details>
|
|
411
540
|
<summary>Migration <code>index.stub</code></summary>
|
|
412
541
|
|
|
413
542
|
```php
|
|
414
543
|
<?php
|
|
415
544
|
|
|
416
|
-
use Illuminate
|
|
417
|
-
use Illuminate
|
|
418
|
-
use Illuminate
|
|
545
|
+
use Illuminate\Database\Migrations\Migration;
|
|
546
|
+
use Illuminate\Database\Schema\Blueprint;
|
|
547
|
+
use Illuminate\Support\Facades\Schema;
|
|
419
548
|
|
|
420
549
|
return new class extends Migration
|
|
421
550
|
{
|
|
@@ -435,9 +564,35 @@ return new class extends Migration
|
|
|
435
564
|
|
|
436
565
|
</details>
|
|
437
566
|
|
|
567
|
+
### TypeScript module `index.stub`
|
|
568
|
+
|
|
569
|
+
<details>
|
|
570
|
+
<summary>TS <code>ts/index.stub</code> (module-level)</summary>
|
|
571
|
+
|
|
572
|
+
```ts
|
|
573
|
+
${imports}
|
|
574
|
+
|
|
575
|
+
${body}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
* `imports` → merged import block for all non-stubbed models (including enums).
|
|
579
|
+
* `body` → full `declare module "…" { … }` wrapper generated by the TS printer.
|
|
580
|
+
* `content` (exposed to the stub function) is just the inner interfaces/types
|
|
581
|
+
without the `declare module` wrapper, if you need it for advanced patterns.
|
|
582
|
+
|
|
583
|
+
Per-model TS stubs under `stubs/ts/<Model>.stub` receive:
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
(model, imports, content, body, moduleName) => string
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
and are free to ignore or wrap the default `body` however they like.
|
|
590
|
+
|
|
591
|
+
</details>
|
|
592
|
+
|
|
438
593
|
---
|
|
439
594
|
|
|
440
|
-
## 🏗️ Complex Model Stub Example
|
|
595
|
+
## 🏗️ Complex Model Stub Example (PHP)
|
|
441
596
|
|
|
442
597
|
<details>
|
|
443
598
|
<summary>Expand stub</summary>
|
|
@@ -445,11 +600,11 @@ return new class extends Migration
|
|
|
445
600
|
```php
|
|
446
601
|
<?php
|
|
447
602
|
|
|
448
|
-
namespace App
|
|
603
|
+
namespace App\Models;
|
|
449
604
|
|
|
450
605
|
${model.imports}
|
|
451
|
-
use Illuminate
|
|
452
|
-
use Illuminate
|
|
606
|
+
use Illuminate\Database\Eloquent\Model;
|
|
607
|
+
use Illuminate\Database\Eloquent\Relations\{ BelongsTo, HasMany, BelongsToMany };
|
|
453
608
|
|
|
454
609
|
class ${model.className} extends Model
|
|
455
610
|
{
|
|
@@ -457,25 +612,25 @@ class ${model.className} extends Model
|
|
|
457
612
|
|
|
458
613
|
/* Mass Assignment */
|
|
459
614
|
protected $fillable = [
|
|
460
|
-
${model.properties.filter(p => p.fillable).map(p => ` '${p.name}',`).join('
|
|
615
|
+
${model.properties.filter(p => p.fillable).map(p => ` '${p.name}',`).join('\n')}
|
|
461
616
|
];
|
|
462
617
|
protected $guarded = [
|
|
463
|
-
${(model.guarded ?? []).map(n => ` '${n}',`).join('
|
|
618
|
+
${(model.guarded ?? []).map(n => ` '${n}',`).join('\n')}
|
|
464
619
|
];
|
|
465
620
|
|
|
466
621
|
/* Hidden & Casts */
|
|
467
622
|
protected $hidden = [
|
|
468
|
-
${model.properties.filter(p => p.hidden).map(p => ` '${p.name}',`).join('
|
|
623
|
+
${model.properties.filter(p => p.hidden).map(p => ` '${p.name}',`).join('\n')}
|
|
469
624
|
];
|
|
470
625
|
protected $casts = [
|
|
471
|
-
${model.properties.filter(p => p.cast).map(p => ` '${p.name}' => '${p.cast}',`).join('
|
|
472
|
-
${model.properties.filter(p => p.enumRef).map(p => ` '${p.name}' => ${p.enumRef}::class,`).join('
|
|
626
|
+
${model.properties.filter(p => p.cast).map(p => ` '${p.name}' => '${p.cast}',`).join('\n')}
|
|
627
|
+
${model.properties.filter(p => p.enumRef).map(p => ` '${p.name}' => ${p.enumRef}::class,`).join('\n')}
|
|
473
628
|
];
|
|
474
629
|
|
|
475
630
|
/* Interfaces metadata */
|
|
476
631
|
public array $interfaces = [
|
|
477
632
|
${Object.entries(model.interfaces).map(([k,i]) =>
|
|
478
|
-
` '${k}' => {${i.import ? ` import: '${i.import}',` : ''} type: '${i.type}' },`).join('
|
|
633
|
+
` '${k}' => {${i.import ? ` import: '${i.import}',` : ''} type: '${i.type}' },`).join('\n')}
|
|
479
634
|
];
|
|
480
635
|
// This structure is useful for packages like fumeapp/modeltyper which
|
|
481
636
|
// read interface metadata to build TypeScript helpers.
|
|
@@ -483,9 +638,9 @@ ${Object.entries(model.interfaces).map(([k,i]) =>
|
|
|
483
638
|
/* Relationships */
|
|
484
639
|
${model.relations.map(r => {
|
|
485
640
|
const args = [r.modelClass, r.foreignKey ? `'${r.foreignKey}'` : '', r.localKey ? `'${r.localKey}'` : ''].filter(Boolean).join(', ');
|
|
486
|
-
return ` public function ${r.name}(): ${r.type.charAt(0).toUpperCase()+r.type.slice(1)}
|
|
487
|
-
}).join('
|
|
488
|
-
// Or
|
|
641
|
+
return ` public function ${r.name}(): ${r.type.charAt(0).toUpperCase()+r.type.slice(1)}\n {\n return $this->${r.type}(${args});\n }`;
|
|
642
|
+
}).join('\n\n')}
|
|
643
|
+
// Or
|
|
489
644
|
${relationships}
|
|
490
645
|
|
|
491
646
|
${content}
|
|
@@ -506,7 +661,6 @@ protected $casts = [
|
|
|
506
661
|
|
|
507
662
|
---
|
|
508
663
|
|
|
509
|
-
|
|
510
664
|
## 🧩 Custom Migration Rules
|
|
511
665
|
|
|
512
666
|
Point the generator’s `rules` field to a JS file exporting an **array** of
|
|
@@ -543,7 +697,7 @@ module.exports = [
|
|
|
543
697
|
|
|
544
698
|
**Rule execution order**
|
|
545
699
|
|
|
546
|
-
1. Built‑in rules
|
|
700
|
+
1. Built‑in rules
|
|
547
701
|
2. Custom rules (executed in array order)
|
|
548
702
|
|
|
549
703
|
---
|
|
@@ -568,7 +722,7 @@ export interface ColumnDefinition extends DMMF.Field {
|
|
|
568
722
|
relationship?: {
|
|
569
723
|
on: string;
|
|
570
724
|
references?: string[];
|
|
571
|
-
fields: string[]
|
|
725
|
+
fields: string[];
|
|
572
726
|
onDelete?: string;
|
|
573
727
|
onUpdate?: string;
|
|
574
728
|
};
|
|
@@ -586,9 +740,8 @@ def.migrationType // mapped Laravel builder name
|
|
|
586
740
|
def.isId
|
|
587
741
|
```
|
|
588
742
|
|
|
589
|
-
📝 **Prisma DMMF docs:**
|
|
590
|
-
https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md
|
|
591
|
-
|
|
743
|
+
📝 **Prisma DMMF docs:**
|
|
744
|
+
[https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md](https://github.com/prisma/prisma/blob/main/packages/prisma-schema-wasm/src/__tests__/snapshot/dmmf.md)
|
|
592
745
|
|
|
593
746
|
---
|
|
594
747
|
|
|
@@ -603,6 +756,13 @@ You can attach them either:
|
|
|
603
756
|
|
|
604
757
|
> This document focuses on the **new & updated directives** and how they interact with existing ones like `@fillable`, `@hidden`, `@guarded`, `@cast{…}`, `@type{…}`, `@with`, `@trait:…`, `@extend:…`, `@implements:…`, `@observer:…`, `@factory:…`, `@touch{…}`, `@appends{…}`.
|
|
605
758
|
|
|
759
|
+
The same directives are visible to the **PHP generators** (migrator + modeler)
|
|
760
|
+
**and** to the **TS types generator**, which uses them to:
|
|
761
|
+
|
|
762
|
+
* apply `@type{…}` overrides for TS field types/imports,
|
|
763
|
+
* honour `@with` when deciding whether relation properties are optional, and
|
|
764
|
+
* strip directive noise from generated JSDoc/docblocks.
|
|
765
|
+
|
|
606
766
|
---
|
|
607
767
|
|
|
608
768
|
## What’s New
|
|
@@ -615,18 +775,21 @@ You can attach them either:
|
|
|
615
775
|
|
|
616
776
|
## Summary of Directives
|
|
617
777
|
|
|
618
|
-
| Directive | Scope
|
|
619
|
-
| ------------------------------------------------------------------------------------------- |
|
|
620
|
-
| `@fillable` | Field **or** `@fillable{
|
|
621
|
-
| `@hidden` | Field **or** `@hidden{
|
|
622
|
-
| `@guarded` | Field **or** `@guarded{
|
|
623
|
-
| `@cast{…}` | Field
|
|
624
|
-
| `@type{ import:'…', type:'…' }` | Field
|
|
625
|
-
| `@with` / `@with(a,b,…)` | Field / Model
|
|
626
|
-
| `@trait:…` `@extend:…` `@implements:…` `@observer:…` `@factory:…` `@touch{…}` `@appends{…}` | Model
|
|
627
|
-
|
|
|
628
|
-
|
|
|
629
|
-
|
|
|
778
|
+
| Directive | Scope | Purpose |
|
|
779
|
+
| ------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
780
|
+
| `@fillable` | Field **or** `@fillable{…}` on model | Adds field(s) to `$fillable`. |
|
|
781
|
+
| `@hidden` | Field **or** `@hidden{…}` on model | Adds field(s) to `$hidden`. |
|
|
782
|
+
| `@guarded` | Field **or** `@guarded{…}` on model | Adds field(s) to `$guarded`. |
|
|
783
|
+
| `@cast{…}` | Field | Adds a cast entry to `$casts`. |
|
|
784
|
+
| `@type{ import:'…', type:'…' }` | Field | Exposes a PHP/interface/TS type hint for downstream tooling. |
|
|
785
|
+
| `@with` / `@with(a,b,…)` | Field / Model | Marks relations to eager-load via `$with` and as non‑optional in TS types. |
|
|
786
|
+
| `@trait:…` `@extend:…` `@implements:…` `@observer:…` `@factory:…` `@touch{…}` `@appends{…}` | Model | Class customization & extras (traits, parents, observers, factories, touches, appends). |
|
|
787
|
+
| `@local` | Relation Field | Skip generating that **specific relation method** on the model. Replaces `@ignore`. |
|
|
788
|
+
| `@silent` | Model / Enum | Do **not** emit files for this entity (model + migration / enum). |
|
|
789
|
+
| `@morph(…)` | Model | Declare owner-side polymorphic relations; child-side `morphTo` is auto-detected. |
|
|
790
|
+
| `@pivot` / `@pivot(a,b,…)` | Pivot **model** and/or scalar **fields** | Explicitly mark extra pivot columns to include in generated `withPivot(…)` chains. |
|
|
791
|
+
| `@withTimestamps` | Pivot **model** / relation **field** | Instructs the generator to append `->withTimestamps()` on the relation definition. |
|
|
792
|
+
| `@pivotAlias(name)` | Pivot **model** | Sets the pivot attribute alias; generator should add `->as('name')` on the relation. |
|
|
630
793
|
|
|
631
794
|
> **Syntax options**
|
|
632
795
|
> • Inline: `balance Decimal /// @fillable @cast{decimal:2}`
|
|
@@ -643,10 +806,12 @@ You can attach them either:
|
|
|
643
806
|
> `/// @touch{company,profile}`
|
|
644
807
|
> `/// @appends{full_name,age}`
|
|
645
808
|
|
|
646
|
-
> **Note:** Directives like `@fillable`, `@hidden`, `@guarded`, `@with`, `@touch`, and `@appends`
|
|
647
|
-
>
|
|
648
|
-
>
|
|
649
|
-
>
|
|
809
|
+
> **Note:** Directives like `@fillable`, `@hidden`, `@guarded`, `@with`, `@touch`, and `@appends` support **all** of the following syntaxes:
|
|
810
|
+
>
|
|
811
|
+
> * `/// @fillable{name,balance}`
|
|
812
|
+
> * `/// @fillable(name,balance)`
|
|
813
|
+
> * `/// @fillable: name,balance`
|
|
814
|
+
|
|
650
815
|
---
|
|
651
816
|
|
|
652
817
|
## `@local` — Skip a Single Relation Method (replaces `@ignore`)
|
|
@@ -669,7 +834,7 @@ model Account {
|
|
|
669
834
|
}
|
|
670
835
|
```
|
|
671
836
|
|
|
672
|
-
**Effect:** the `user()` method is *not* written to `Account.php`. If scope includes Migrator, the migration also skips generating the FK/constraint. Other methods remain unaffected.
|
|
837
|
+
**Effect:** the `user()` method is *not* written to `Account.php`. If scope includes Migrator, the migration also skips generating the FK/constraint. Other methods remain unaffected. TS types still include the `user?: User | null` navigation property unless you override it with `@type`.
|
|
673
838
|
|
|
674
839
|
---
|
|
675
840
|
|
|
@@ -693,11 +858,10 @@ model AuditTrail {
|
|
|
693
858
|
}
|
|
694
859
|
```
|
|
695
860
|
|
|
696
|
-
**Effect:** no Eloquent model and/or no migration file are emitted for `AuditTrail` depending on the scope. For enums, no PHP enum is emitted.
|
|
861
|
+
**Effect:** no Eloquent model and/or no migration file are emitted for `AuditTrail` depending on the scope. For enums, no PHP enum is emitted. The TS generator can still expose types for `AuditTrail` if you wish (or you can add an additional TS-side filter later).
|
|
697
862
|
|
|
698
863
|
---
|
|
699
864
|
|
|
700
|
-
|
|
701
865
|
## Polymorphic Relations
|
|
702
866
|
|
|
703
867
|
### Auto-Detected Child Side: `morphTo`
|
|
@@ -713,6 +877,16 @@ public function commentable()
|
|
|
713
877
|
|
|
714
878
|
No directive is required for `morphTo`.
|
|
715
879
|
|
|
880
|
+
On the TS side, the generator also detects these pairs and adds a
|
|
881
|
+
corresponding **appended property** like:
|
|
882
|
+
|
|
883
|
+
```ts
|
|
884
|
+
commentable?: any;
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
which you can refine via `@appends{commentable: Comment}` or project‑specific
|
|
888
|
+
TS overrides.
|
|
889
|
+
|
|
716
890
|
### Owner Side via `@morph(…)`
|
|
717
891
|
|
|
718
892
|
Add one or more `@morph(...)` directives to the **owner model’s** docblock to generate Laravel morph methods. Parentheses and quotes inside `raw:"…"` are supported.
|
|
@@ -755,8 +929,8 @@ model User {
|
|
|
755
929
|
/// Owner: Video → morphToMany(Tag::class, 'taggable', 'taggables')
|
|
756
930
|
/// @morph(name: taggable, type: to many, model: Tag, table:"taggables")
|
|
757
931
|
model Video {
|
|
758
|
-
id
|
|
759
|
-
url
|
|
932
|
+
id Int @id @default(autoincrement())
|
|
933
|
+
url String
|
|
760
934
|
}
|
|
761
935
|
```
|
|
762
936
|
|
|
@@ -806,7 +980,7 @@ model Image {
|
|
|
806
980
|
}
|
|
807
981
|
```
|
|
808
982
|
|
|
809
|
-
**C) Polymorphic M
|
|
983
|
+
**C) Polymorphic M:N (`morphToMany` / `morphedByMany`)**
|
|
810
984
|
|
|
811
985
|
```prisma
|
|
812
986
|
/// @morph(name: taggable, type: to many, model: Tag, table: "taggables")
|
|
@@ -860,64 +1034,53 @@ model Activity {
|
|
|
860
1034
|
}
|
|
861
1035
|
```
|
|
862
1036
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
#### Other Examples
|
|
1037
|
+
---
|
|
866
1038
|
|
|
867
|
-
|
|
1039
|
+
## Other Examples
|
|
868
1040
|
|
|
869
1041
|
```prisma
|
|
870
|
-
|
|
871
1042
|
/// @fillable{name,balance}
|
|
872
1043
|
/// @hidden{secretToken}
|
|
873
1044
|
model Account {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1045
|
+
id Int @id @default(autoincrement())
|
|
1046
|
+
balance Decimal @default(0.0) /// @cast{decimal:2}
|
|
1047
|
+
nickname String /// @fillable @hidden
|
|
1048
|
+
profile Json? /// @type{ import:'@types/forms', type:'ProfileDTO' }
|
|
1049
|
+
company Company? @relation(fields:[companyId], references:[id]) /// @local
|
|
1050
|
+
|
|
1051
|
+
companyId Int?
|
|
1052
|
+
posts Post[] /// @with
|
|
882
1053
|
}
|
|
883
1054
|
|
|
884
|
-
|
|
885
|
-
|
|
886
1055
|
/// @with(posts,comments)
|
|
887
|
-
|
|
888
1056
|
model User {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1057
|
+
id Int @id @default(autoincrement())
|
|
1058
|
+
email String
|
|
1059
|
+
posts Post[]
|
|
1060
|
+
comments Comment[]
|
|
893
1061
|
}
|
|
894
|
-
|
|
895
1062
|
```
|
|
896
1063
|
|
|
897
|
-
**Generated
|
|
1064
|
+
**Generated (PHP, simplified)**
|
|
898
1065
|
|
|
899
1066
|
```php
|
|
900
|
-
|
|
901
1067
|
protected $fillable = ['name','balance','nickname'];
|
|
902
|
-
protected $hidden
|
|
903
|
-
protected $casts
|
|
1068
|
+
protected $hidden = ['secretToken','nickname'];
|
|
1069
|
+
protected $casts = ['balance' => 'decimal:2'];
|
|
904
1070
|
|
|
905
1071
|
public array $interfaces = [
|
|
906
|
-
|
|
1072
|
+
'profile' => { import: '@types/forms', type: 'ProfileDTO' },
|
|
907
1073
|
];
|
|
908
1074
|
|
|
909
1075
|
protected $with = ['posts'];
|
|
910
|
-
|
|
911
1076
|
```
|
|
912
1077
|
|
|
913
|
-
`@local` prevents the `company()` relation method.
|
|
914
|
-
|
|
1078
|
+
`@local` prevents the `company()` relation method.
|
|
915
1079
|
Combine multiple inline directives; they’re processed left‑to‑right.
|
|
916
1080
|
|
|
917
|
-
|
|
1081
|
+
### Example: Combined Directives
|
|
918
1082
|
|
|
919
1083
|
```prisma
|
|
920
|
-
|
|
921
1084
|
/// @fillable{name,balance}
|
|
922
1085
|
/// @hidden{secretToken}
|
|
923
1086
|
/// @guarded{password,apiToken}
|
|
@@ -929,22 +1092,20 @@ Combine multiple inline directives; they’re processed left‑to‑right.
|
|
|
929
1092
|
/// @touch{company}
|
|
930
1093
|
/// @appends{full_name}
|
|
931
1094
|
model User {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1095
|
+
id Int @id @default(autoincrement())
|
|
1096
|
+
email String @unique /// @hidden @fillable
|
|
1097
|
+
password String /// @hidden @guarded
|
|
1098
|
+
balance Decimal @default(0.0) /// @cast{decimal:2}
|
|
1099
|
+
profile Json? /// @type{ import:'@types/forms', type:'ProfileDTO' }
|
|
1100
|
+
company Company? @relation(fields:[companyId], references:[id]) /// @local
|
|
1101
|
+
companyId Int?
|
|
1102
|
+
posts Post[] /// @with
|
|
940
1103
|
}
|
|
941
|
-
|
|
942
1104
|
```
|
|
943
1105
|
|
|
944
1106
|
**Generated output (simplified)**
|
|
945
1107
|
|
|
946
1108
|
```php
|
|
947
|
-
|
|
948
1109
|
use Illuminate\Auth\Authenticatable;
|
|
949
1110
|
use Illuminate\Auth\User;
|
|
950
1111
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
@@ -953,47 +1114,51 @@ use App\Observers\UserObserver;
|
|
|
953
1114
|
|
|
954
1115
|
class User extends User implements AuthenticatableContract
|
|
955
1116
|
{
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1117
|
+
use HasFactory, Authenticatable;
|
|
1118
|
+
|
|
1119
|
+
protected $fillable = ['name','balance','email'];
|
|
1120
|
+
protected $hidden = ['secretToken','password'];
|
|
1121
|
+
protected $guarded = ['password','apiToken'];
|
|
1122
|
+
protected $casts = ['balance' => 'decimal:2'];
|
|
1123
|
+
protected $touches = ['company'];
|
|
1124
|
+
protected $appends = ['full_name'];
|
|
1125
|
+
protected static string $factory = UserFactory::class;
|
|
1126
|
+
|
|
1127
|
+
protected static function boot()
|
|
1128
|
+
{
|
|
1129
|
+
parent::boot();
|
|
1130
|
+
static::observe(UserObserver::class);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
public function getFullNameAttribute()
|
|
1134
|
+
{
|
|
1135
|
+
return $this->attributes['full_name'] ?? null;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
public function posts()
|
|
1139
|
+
{
|
|
1140
|
+
return $this->hasMany(Post::class);
|
|
1141
|
+
}
|
|
981
1142
|
}
|
|
982
1143
|
```
|
|
983
1144
|
|
|
984
1145
|
---
|
|
1146
|
+
|
|
985
1147
|
## Notes & Limitations
|
|
986
1148
|
|
|
987
1149
|
* `@local` is **model-method only**; it does not change the migration. Use `@silent` to suppress a whole model/enum from emission.
|
|
988
1150
|
* Laravel cannot express **composite pivot keys** directly inside `belongsToMany(...)`. If your schema uses composite pivot keys, consider generating a Pivot model or using query/Compoships patterns on the one-to-many sides.
|
|
989
1151
|
* The generator keeps your edits safe via merge markers; conflicts will be surfaced with `<<<<<<<` sections for manual resolution.
|
|
1152
|
+
* TS types are generated from the **same DMMF + directives** as PHP. You can always override a single field type with `@type{…}`.
|
|
1153
|
+
|
|
990
1154
|
---
|
|
991
1155
|
|
|
992
1156
|
## 💡 Tips
|
|
993
1157
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1158
|
+
* Combine `migration` & `model` & `ts` in one `customize` command when table names align.
|
|
1159
|
+
* Use `noEmit: true` for dry‑runs or CI validation.
|
|
1160
|
+
* Escape template chars in stub files.
|
|
1161
|
+
* Keep your Prisma schema as the single source of truth; everything else is generated.
|
|
997
1162
|
|
|
998
1163
|
---
|
|
999
1164
|
|
|
@@ -1005,6 +1170,7 @@ Use the library directly in a script or build tool instead of the CLI.
|
|
|
1005
1170
|
import {
|
|
1006
1171
|
generateLaravelSchema,
|
|
1007
1172
|
generateLaravelModels,
|
|
1173
|
+
generateTypesFromPrisma,
|
|
1008
1174
|
sortMigrations,
|
|
1009
1175
|
} from 'prisma-laravel-migrate';
|
|
1010
1176
|
import { readFileSync, writeFileSync } from 'fs';
|
|
@@ -1017,22 +1183,37 @@ import { getDMMF } from '@prisma/sdk';
|
|
|
1017
1183
|
const dmmf = await getDMMF({ datamodel });
|
|
1018
1184
|
|
|
1019
1185
|
/* 2. Run generators entirely in-memory */
|
|
1020
|
-
const migrations = generateLaravelSchema({
|
|
1186
|
+
const migrations = await generateLaravelSchema({
|
|
1021
1187
|
dmmf,
|
|
1022
1188
|
schemaPath, // ← always pass this
|
|
1023
1189
|
generator : { config: {} } as any,
|
|
1024
1190
|
});
|
|
1025
1191
|
|
|
1026
|
-
const { models, enums } = generateLaravelModels({
|
|
1192
|
+
const { models, enums } = await generateLaravelModels({
|
|
1027
1193
|
dmmf,
|
|
1028
1194
|
schemaPath,
|
|
1029
1195
|
generator : { config: {} } as any,
|
|
1030
1196
|
});
|
|
1031
1197
|
|
|
1198
|
+
const tsResult = await generateTypesFromPrisma({
|
|
1199
|
+
dmmf: dmmf as any,
|
|
1200
|
+
schemaPath,
|
|
1201
|
+
generator: {
|
|
1202
|
+
config: {
|
|
1203
|
+
// types-specific overrides
|
|
1204
|
+
moduleName: 'database/prisma',
|
|
1205
|
+
noEmit: true,
|
|
1206
|
+
},
|
|
1207
|
+
output: { value: 'resources/ts/prisma' },
|
|
1208
|
+
} as any,
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1032
1211
|
/* 3. Inspect or write output */
|
|
1033
1212
|
sortMigrations(migrations).forEach(m => {
|
|
1034
1213
|
writeFileSync(`./out/${m.tableName}.php`, m.statements.join('\n'), 'utf8');
|
|
1035
1214
|
});
|
|
1215
|
+
|
|
1216
|
+
// tsResult.models / tsResult.enums contain TS model/enum definitions
|
|
1036
1217
|
})();
|
|
1037
1218
|
```
|
|
1038
1219
|
|
|
@@ -1058,30 +1239,34 @@ generateLaravelSchema({
|
|
|
1058
1239
|
|
|
1059
1240
|
### Public exports
|
|
1060
1241
|
|
|
1061
|
-
| Export
|
|
1062
|
-
|
|
|
1063
|
-
| `generateLaravelSchema`
|
|
1064
|
-
| `generateLaravelModels`
|
|
1065
|
-
| `
|
|
1066
|
-
| `
|
|
1067
|
-
|
|
|
1242
|
+
| Export | Purpose |
|
|
1243
|
+
| ----------------------------------------------------- | ------------------------------------------------------------- |
|
|
1244
|
+
| `generateLaravelSchema` | Build migration objects (and optionally write files) |
|
|
1245
|
+
| `generateLaravelModels` | Build PHP model + enum definitions |
|
|
1246
|
+
| `generateTypesFromPrisma` | Build TS model + enum definitions, with stub + module support |
|
|
1247
|
+
| `sortMigrations` | Topologically sort migrations by FK dependencies |
|
|
1248
|
+
| `Rule` | Type helper for custom migration shortcuts |
|
|
1249
|
+
| *types* (`column-definition-types`, `laravel-config`) | Full TypeScript typings |
|
|
1068
1250
|
|
|
1069
1251
|
```ts
|
|
1070
1252
|
import {
|
|
1071
1253
|
ColumnDefinition,
|
|
1072
1254
|
LaravelSharedConfig,
|
|
1073
1255
|
MigratorConfigOverride,
|
|
1256
|
+
ModelConfigOverride,
|
|
1257
|
+
TypesConfigOverride,
|
|
1074
1258
|
} from 'prisma-laravel-migrate';
|
|
1075
1259
|
```
|
|
1076
1260
|
|
|
1077
|
-
> **Heads-up:**
|
|
1078
|
-
> `generateLaravelSchema` and `
|
|
1079
|
-
> (honouring
|
|
1261
|
+
> **Heads-up:**
|
|
1262
|
+
> `generateLaravelSchema`, `generateLaravelModels`, and `generateTypesFromPrisma`
|
|
1263
|
+
> **write files by default** (honouring their respective `outputDir` settings).
|
|
1080
1264
|
> If you only want the in-memory objects—e.g. to capture the returned
|
|
1081
|
-
> `migrations`, `models`, or `enums` arrays—set
|
|
1265
|
+
> `migrations`, `models`, `enums`, or TS `models`/`enums` arrays—set
|
|
1082
1266
|
> `noEmit: true` in either
|
|
1083
1267
|
>
|
|
1084
1268
|
> * the per-call `generator.config` object:
|
|
1269
|
+
>
|
|
1085
1270
|
> ```ts
|
|
1086
1271
|
> generateLaravelSchema({
|
|
1087
1272
|
> dmmf,
|
|
@@ -1090,18 +1275,20 @@ import {
|
|
|
1090
1275
|
> });
|
|
1091
1276
|
> ```
|
|
1092
1277
|
> * **or** in `prisma/laravel.config.js`:
|
|
1278
|
+
>
|
|
1093
1279
|
> ```js
|
|
1094
1280
|
> module.exports = {
|
|
1095
1281
|
> migrate: { noEmit: true },
|
|
1096
1282
|
> modeler: { noEmit: true },
|
|
1283
|
+
> types: { noEmit: true },
|
|
1097
1284
|
> };
|
|
1098
1285
|
> ```
|
|
1286
|
+
>
|
|
1099
1287
|
> This prevents any files from being created or overwritten while still
|
|
1100
1288
|
> returning the fully-populated data structures for custom processing.
|
|
1101
1289
|
|
|
1102
1290
|
---
|
|
1103
1291
|
|
|
1104
|
-
|
|
1105
1292
|
# Prisma → Laravel Migration Guide
|
|
1106
1293
|
|
|
1107
1294
|
This document explains **how `prisma‑laravel‑migrate` converts your Prisma schema into
|
|
@@ -1115,21 +1302,21 @@ clean, idiomatic Laravel migrations.
|
|
|
1115
1302
|
The generator first turns every Prisma (or native) scalar into the
|
|
1116
1303
|
corresponding **Laravel schema builder method**.
|
|
1117
1304
|
|
|
1118
|
-
| Native type
|
|
1119
|
-
|
|
1120
|
-
| `Text`
|
|
1121
|
-
| `VarChar`
|
|
1122
|
-
| `Boolean`
|
|
1123
|
-
| `TinyInt`
|
|
1305
|
+
| Native type | Laravel method |
|
|
1306
|
+
| ---------------- | ---------------------- |
|
|
1307
|
+
| `Text` | `text()` |
|
|
1308
|
+
| `VarChar` | `string()` |
|
|
1309
|
+
| `Boolean` | `boolean()` |
|
|
1310
|
+
| `TinyInt` | `tinyInteger()` |
|
|
1124
1311
|
| `UnsignedBigInt` | `unsignedBigInteger()` |
|
|
1125
|
-
| `BigInt`
|
|
1126
|
-
| `Decimal`
|
|
1127
|
-
| `Double`
|
|
1128
|
-
| `DateTime`
|
|
1129
|
-
| `Timestamptz`
|
|
1130
|
-
| `Json`
|
|
1131
|
-
| `Uuid`
|
|
1132
|
-
| `Inet`
|
|
1312
|
+
| `BigInt` | `bigInteger()` |
|
|
1313
|
+
| `Decimal` | `decimal()` |
|
|
1314
|
+
| `Double` | `double()` |
|
|
1315
|
+
| `DateTime` | `timestamp()` |
|
|
1316
|
+
| `Timestamptz` | `timestampsTz()` |
|
|
1317
|
+
| `Json` | `json()` |
|
|
1318
|
+
| `Uuid` | `uuid()` |
|
|
1319
|
+
| `Inet` | `ipAddress()` |
|
|
1133
1320
|
|
|
1134
1321
|
*(See source `migrationTypes.ts` for the full mapping.)*
|
|
1135
1322
|
|
|
@@ -1140,17 +1327,17 @@ corresponding **Laravel schema builder method**.
|
|
|
1140
1327
|
After basic mapping, each column is checked against a **rule set**
|
|
1141
1328
|
so that common Laravel helper methods are used instead of verbose definitions.
|
|
1142
1329
|
|
|
1143
|
-
| Rule
|
|
1144
|
-
|
|
1145
|
-
| **Primary ID**
|
|
1146
|
-
| **Timestamps**
|
|
1147
|
-
| **TimestampsTz**
|
|
1148
|
-
| **Soft‑deletes**
|
|
1149
|
-
| **Soft‑deletesTz**
|
|
1150
|
-
| **Remember token**
|
|
1151
|
-
| **`foreignId`**
|
|
1152
|
-
| **Morphs / NullableMorphs** | `<base>_id` & `<base>_type` combo
|
|
1153
|
-
| **UUID / ULID Morphs**
|
|
1330
|
+
| Rule | Condition in Prisma | Generated code |
|
|
1331
|
+
| --------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------- |
|
|
1332
|
+
| **Primary ID** | `id BigInt @id @default(autoincrement())` | `$table->id();` |
|
|
1333
|
+
| **Timestamps** | `created_at / updated_at` pair (`DateTime` or `Timestamp`) | `$table->timestamps();` |
|
|
1334
|
+
| **TimestampsTz** | Same pair but `DateTimeTz` / tz‑aware types | `$table->timestampsTz();` |
|
|
1335
|
+
| **Soft‑deletes** | `deleted_at DateTime` | `$table->softDeletes();` |
|
|
1336
|
+
| **Soft‑deletesTz** | `deleted_at DateTimeTz` | `$table->softDeletesTz();` |
|
|
1337
|
+
| **Remember token** | `remember_token String?` | `$table->rememberToken();` |
|
|
1338
|
+
| **`foreignId`** | `<col>_id` + `@relation(...)` | `$table->foreignId('…')->constrained();` |
|
|
1339
|
+
| **Morphs / NullableMorphs** | `<base>_id` & `<base>_type` combo | `$table->morphs('base');` / `$table->nullableMorphs('base');` |
|
|
1340
|
+
| **UUID / ULID Morphs** | Same but with `Uuid` / `Ulid` id column | `$table->uuidMorphs()` & friends |
|
|
1154
1341
|
|
|
1155
1342
|
If a rule fires, both columns involved are marked *ignored* so the fallback
|
|
1156
1343
|
builder doesn't emit them twice.
|
|
@@ -1180,7 +1367,7 @@ Foreign‑key references (`@relation`) then add a separate `$table->foreign()` c
|
|
|
1180
1367
|
```prisma
|
|
1181
1368
|
model Post {
|
|
1182
1369
|
id Int @id @default(autoincrement()) // ➜ $table->id()
|
|
1183
|
-
title String
|
|
1370
|
+
title String
|
|
1184
1371
|
body Text
|
|
1185
1372
|
author_id Int
|
|
1186
1373
|
author User @relation(fields:[author_id], references:[id])
|
|
@@ -1223,7 +1410,9 @@ $table->softDeletes();
|
|
|
1223
1410
|
for shortcut rules; non‑standard names fall back to the generic builder.
|
|
1224
1411
|
* Remember to run migrations **after** generating to ensure FK order is correct
|
|
1225
1412
|
(the tool topologically sorts tables to avoid dependency loops).
|
|
1413
|
+
|
|
1226
1414
|
---
|
|
1415
|
+
|
|
1227
1416
|
### Custom `defaultMaps` for `formatDefault`
|
|
1228
1417
|
|
|
1229
1418
|
You can override the built‑in `formatDefault()` logic without forking the package by
|
|
@@ -1264,14 +1453,15 @@ module.exports = {
|
|
|
1264
1453
|
4. Keys are matched *case‑sensitive* to the Prisma default function
|
|
1265
1454
|
(`uuid`, `cuid`, `sequence`, etc.).
|
|
1266
1455
|
|
|
1267
|
-
> **Reference** – full list of Prisma `@@default()` helpers
|
|
1268
|
-
>
|
|
1456
|
+
> **Reference** – full list of Prisma `@@default()` helpers
|
|
1457
|
+
> [https://www.prisma.io/docs/orm/reference/prisma-schema-reference#default](https://www.prisma.io/docs/orm/reference/prisma-schema-reference#default)
|
|
1458
|
+
|
|
1269
1459
|
---
|
|
1270
|
-
Happy scaffolding! 🎉
|
|
1271
1460
|
|
|
1461
|
+
Happy scaffolding! 🎉
|
|
1272
1462
|
|
|
1273
1463
|
---
|
|
1274
1464
|
|
|
1275
1465
|
## 📜 License
|
|
1276
1466
|
|
|
1277
|
-
MIT — Happy scaffolding! 🎉
|
|
1467
|
+
MIT — Happy scaffolding! 🎉
|