turbine-orm 0.40.1 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -4
- package/dist/cjs/cli/config.js +3 -0
- package/dist/cjs/cli/index.js +179 -0
- package/dist/cjs/cli/prisma-report.js +216 -0
- package/dist/cjs/cli/prisma-resolve.js +335 -0
- package/dist/cjs/cli/prisma-schema.js +484 -0
- package/dist/cjs/client.js +1 -0
- package/dist/cjs/generate.js +279 -22
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/introspect.js +203 -26
- package/dist/cjs/mssql.js +9 -10
- package/dist/cjs/mysql.js +3 -9
- package/dist/cjs/powdb-introspect.js +5 -10
- package/dist/cjs/powql.js +13 -0
- package/dist/cjs/prisma-compat.js +1147 -0
- package/dist/cjs/query/aggregates.js +67 -7
- package/dist/cjs/query/builder.js +388 -17
- package/dist/cjs/query/compound-unique.js +0 -0
- package/dist/cjs/query/relations.js +7 -5
- package/dist/cjs/query/warn-registry.js +98 -0
- package/dist/cjs/query/writes.js +13 -5
- package/dist/cjs/schema.js +47 -0
- package/dist/cjs/sqlite.js +4 -9
- package/dist/cli/config.d.ts +26 -0
- package/dist/cli/config.js +3 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.js +180 -1
- package/dist/cli/prisma-report.d.ts +19 -0
- package/dist/cli/prisma-report.js +211 -0
- package/dist/cli/prisma-resolve.d.ts +87 -0
- package/dist/cli/prisma-resolve.js +330 -0
- package/dist/cli/prisma-schema.d.ts +116 -0
- package/dist/cli/prisma-schema.js +479 -0
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +18 -2
- package/dist/client.js +1 -0
- package/dist/generate.d.ts +80 -1
- package/dist/generate.js +277 -25
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/introspect.d.ts +92 -2
- package/dist/introspect.js +198 -26
- package/dist/mssql.js +10 -11
- package/dist/mysql.js +4 -10
- package/dist/powdb-introspect.js +5 -10
- package/dist/powql.js +13 -0
- package/dist/prisma-compat.d.ts +281 -0
- package/dist/prisma-compat.js +1143 -0
- package/dist/query/aggregates.js +67 -7
- package/dist/query/builder.d.ts +77 -4
- package/dist/query/builder.js +390 -19
- package/dist/query/compound-unique.d.ts +49 -0
- package/dist/query/compound-unique.js +0 -0
- package/dist/query/deferred.d.ts +18 -0
- package/dist/query/relations.js +7 -5
- package/dist/query/types.d.ts +70 -9
- package/dist/query/warn-registry.d.ts +57 -0
- package/dist/query/warn-registry.js +92 -0
- package/dist/query/writes.js +13 -5
- package/dist/schema.d.ts +75 -0
- package/dist/schema.js +46 -0
- package/dist/sqlite.js +5 -10
- package/package.json +6 -1
package/dist/cjs/generate.js
CHANGED
|
@@ -11,10 +11,15 @@
|
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.generate = generate;
|
|
14
|
+
exports.resolveImportExtension = resolveImportExtension;
|
|
15
|
+
exports.detectTsconfigExtension = detectTsconfigExtension;
|
|
16
|
+
exports.classifyTsconfig = classifyTsconfig;
|
|
17
|
+
exports.stripJsonComments = stripJsonComments;
|
|
14
18
|
exports.generateTypes = generateTypes;
|
|
15
19
|
exports.generateZod = generateZod;
|
|
16
20
|
exports.generateMetadata = generateMetadata;
|
|
17
21
|
exports.generateIndex = generateIndex;
|
|
22
|
+
exports.generatePrismaMap = generatePrismaMap;
|
|
18
23
|
const node_fs_1 = require("node:fs");
|
|
19
24
|
const node_path_1 = require("node:path");
|
|
20
25
|
const schema_js_1 = require("./schema.js");
|
|
@@ -56,29 +61,177 @@ function generate(options) {
|
|
|
56
61
|
throw new Error(`Output directory must be within the project root. Got: ${outDir}`);
|
|
57
62
|
}
|
|
58
63
|
(0, node_fs_1.mkdirSync)(outDir, { recursive: true });
|
|
64
|
+
// F4: keep raw DB column names as field names (opt-in). Pure transform: when
|
|
65
|
+
// the flag is off `withDbFieldNames` is never called and output is unchanged.
|
|
66
|
+
const schema = options.keepColumnNames ? (0, schema_js_1.withDbFieldNames)(options.schema) : options.schema;
|
|
67
|
+
// F3: resolve which extension sibling imports get in index.ts.
|
|
68
|
+
const { ext: importExt, mode: importMode } = resolveImportExtension(outDir, options.importExtension ?? 'auto');
|
|
59
69
|
const files = [];
|
|
60
|
-
const fileOptions = { noTimestamp: options.noTimestamp };
|
|
70
|
+
const fileOptions = { noTimestamp: options.noTimestamp, importExt, importMode };
|
|
61
71
|
// Generate types.ts
|
|
62
|
-
const typesContent = generateTypes(
|
|
72
|
+
const typesContent = generateTypes(schema, fileOptions);
|
|
63
73
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, 'types.ts'), typesContent, 'utf-8');
|
|
64
74
|
files.push('types.ts');
|
|
65
75
|
// Generate metadata.ts
|
|
66
|
-
const metadataContent = generateMetadata(
|
|
76
|
+
const metadataContent = generateMetadata(schema, fileOptions);
|
|
67
77
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, 'metadata.ts'), metadataContent, 'utf-8');
|
|
68
78
|
files.push('metadata.ts');
|
|
69
79
|
// Generate index.ts (configured client)
|
|
70
|
-
const indexContent = generateIndex(
|
|
80
|
+
const indexContent = generateIndex(schema, fileOptions);
|
|
71
81
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, 'index.ts'), indexContent, 'utf-8');
|
|
72
82
|
files.push('index.ts');
|
|
73
83
|
// Generate zod.ts (optional — --zod flag)
|
|
74
84
|
if (options.zod) {
|
|
75
|
-
const zodContent = generateZod(
|
|
85
|
+
const zodContent = generateZod(schema, fileOptions);
|
|
76
86
|
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, 'zod.ts'), zodContent, 'utf-8');
|
|
77
87
|
files.push('zod.ts');
|
|
78
88
|
}
|
|
79
89
|
return { outDir, files };
|
|
80
90
|
}
|
|
81
91
|
// ---------------------------------------------------------------------------
|
|
92
|
+
// Import-extension resolution (F3)
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Resolve the requested {@link GenerateOptions.importExtension} to the concrete
|
|
96
|
+
* extension string used on `index.ts`'s sibling imports plus a human-readable
|
|
97
|
+
* mode label for the generated comment.
|
|
98
|
+
*
|
|
99
|
+
* - `'js'` → `.js`
|
|
100
|
+
* - `'none'` → `''`
|
|
101
|
+
* - `'auto'` → tsconfig-driven ({@link detectTsconfigExtension}); falls back
|
|
102
|
+
* to `.js` (the pre-0.41 default) when detection is uncertain, so NodeNext
|
|
103
|
+
* consumers can never regress.
|
|
104
|
+
*/
|
|
105
|
+
function resolveImportExtension(outDir, requested) {
|
|
106
|
+
if (requested === 'js')
|
|
107
|
+
return { ext: '.js', mode: 'js' };
|
|
108
|
+
if (requested === 'none')
|
|
109
|
+
return { ext: '', mode: 'none' };
|
|
110
|
+
const detected = detectTsconfigExtension((0, node_path_1.resolve)(outDir));
|
|
111
|
+
if (detected === 'js')
|
|
112
|
+
return { ext: '.js', mode: 'auto (nodenext → .js)' };
|
|
113
|
+
if (detected === 'none')
|
|
114
|
+
return { ext: '', mode: 'auto (bundler → no extension)' };
|
|
115
|
+
return { ext: '.js', mode: 'auto (fallback → .js)' };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Walk up from `startDir` to the nearest `tsconfig.json` and classify its module
|
|
119
|
+
* resolution. Does NOT follow `extends` chains (a monorepo whose base config
|
|
120
|
+
* sets `moduleResolution` needs the explicit flag). Returns:
|
|
121
|
+
* - `'js'`: `module`/`moduleResolution` is `node16`/`nodenext`;
|
|
122
|
+
* - `'none'`: both fields present and neither is node16/nodenext (bundler,
|
|
123
|
+
* node, node10, classic, esnext, commonjs, preserve);
|
|
124
|
+
* - `null`: no tsconfig found, unparseable, or the fields are absent
|
|
125
|
+
* (possibly hidden behind `extends`) → caller falls back to `.js`.
|
|
126
|
+
*/
|
|
127
|
+
function detectTsconfigExtension(startDir) {
|
|
128
|
+
let dir = startDir;
|
|
129
|
+
for (;;) {
|
|
130
|
+
const candidate = (0, node_path_1.join)(dir, 'tsconfig.json');
|
|
131
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
132
|
+
try {
|
|
133
|
+
return classifyTsconfig((0, node_fs_1.readFileSync)(candidate, 'utf-8'));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const parent = (0, node_path_1.dirname)(dir);
|
|
140
|
+
if (parent === dir)
|
|
141
|
+
return null; // reached the filesystem root
|
|
142
|
+
dir = parent;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Classify a tsconfig's `compilerOptions.module` / `moduleResolution` (see
|
|
147
|
+
* {@link detectTsconfigExtension}). Tolerant of `//` and block comments and
|
|
148
|
+
* trailing commas (real-world tsconfigs use JSONC).
|
|
149
|
+
*/
|
|
150
|
+
function classifyTsconfig(text) {
|
|
151
|
+
let parsed;
|
|
152
|
+
try {
|
|
153
|
+
parsed = JSON.parse(stripJsonComments(text));
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
159
|
+
return null;
|
|
160
|
+
const co = parsed.compilerOptions;
|
|
161
|
+
if (typeof co !== 'object' || co === null)
|
|
162
|
+
return null;
|
|
163
|
+
const opts = co;
|
|
164
|
+
const mod = typeof opts.module === 'string' ? opts.module.toLowerCase() : undefined;
|
|
165
|
+
const modRes = typeof opts.moduleResolution === 'string' ? opts.moduleResolution.toLowerCase() : undefined;
|
|
166
|
+
const isNodeNext = (v) => v === 'node16' || v === 'nodenext';
|
|
167
|
+
if (isNodeNext(mod) || isNodeNext(modRes))
|
|
168
|
+
return 'js';
|
|
169
|
+
if (mod !== undefined && modRes !== undefined)
|
|
170
|
+
return 'none';
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Strip `//` line comments and block comments from JSONC text, leaving anything
|
|
175
|
+
* inside a double-quoted string untouched. Trailing commas are then removed so
|
|
176
|
+
* `JSON.parse` accepts the result.
|
|
177
|
+
*/
|
|
178
|
+
function stripJsonComments(text) {
|
|
179
|
+
let out = '';
|
|
180
|
+
let inString = false;
|
|
181
|
+
let inLine = false;
|
|
182
|
+
let inBlock = false;
|
|
183
|
+
for (let i = 0; i < text.length; i++) {
|
|
184
|
+
const ch = text[i];
|
|
185
|
+
const next = text[i + 1];
|
|
186
|
+
if (inLine) {
|
|
187
|
+
if (ch === '\n') {
|
|
188
|
+
inLine = false;
|
|
189
|
+
out += ch;
|
|
190
|
+
}
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (inBlock) {
|
|
194
|
+
if (ch === '*' && next === '/') {
|
|
195
|
+
inBlock = false;
|
|
196
|
+
i++;
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (inString) {
|
|
201
|
+
out += ch;
|
|
202
|
+
if (ch === '\\') {
|
|
203
|
+
// Preserve the escaped character verbatim.
|
|
204
|
+
if (next !== undefined) {
|
|
205
|
+
out += next;
|
|
206
|
+
i++;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (ch === '"') {
|
|
210
|
+
inString = false;
|
|
211
|
+
}
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (ch === '"') {
|
|
215
|
+
inString = true;
|
|
216
|
+
out += ch;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (ch === '/' && next === '/') {
|
|
220
|
+
inLine = true;
|
|
221
|
+
i++;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (ch === '/' && next === '*') {
|
|
225
|
+
inBlock = true;
|
|
226
|
+
i++;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
out += ch;
|
|
230
|
+
}
|
|
231
|
+
// Drop trailing commas before } or ].
|
|
232
|
+
return out.replace(/,(\s*[}\]])/g, '$1');
|
|
233
|
+
}
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
82
235
|
// types.ts generator
|
|
83
236
|
// ---------------------------------------------------------------------------
|
|
84
237
|
function generatedFileHeader(options) {
|
|
@@ -174,7 +327,7 @@ function generateTypes(schema, options) {
|
|
|
174
327
|
const piiNote = col.pii ? ' (PII: absent unless selected or includePii)' : '';
|
|
175
328
|
const optional = col.pii ? '?' : '';
|
|
176
329
|
lines.push(` /** Column: ${col.name}, ${col.pgType}${pkNote}${nullNote}${piiNote} */`);
|
|
177
|
-
lines.push(` ${col.field}${optional}: ${columnTsType(col, schema.enums)};`);
|
|
330
|
+
lines.push(` ${quoteIfNeeded(col.field)}${optional}: ${columnTsType(col, schema.enums)};`);
|
|
178
331
|
}
|
|
179
332
|
lines.push('}');
|
|
180
333
|
lines.push('');
|
|
@@ -192,10 +345,10 @@ function generateTypes(schema, options) {
|
|
|
192
345
|
if (isOptional) {
|
|
193
346
|
const reason = isPk ? 'auto-generated' : col.hasDefault ? 'has default' : 'nullable';
|
|
194
347
|
lines.push(` /** Optional: ${reason} */`);
|
|
195
|
-
lines.push(` ${col.field}?: ${columnTsType(col, schema.enums)};`);
|
|
348
|
+
lines.push(` ${quoteIfNeeded(col.field)}?: ${columnTsType(col, schema.enums)};`);
|
|
196
349
|
}
|
|
197
350
|
else {
|
|
198
|
-
lines.push(` ${col.field}: ${columnTsType(col, schema.enums)};`);
|
|
351
|
+
lines.push(` ${quoteIfNeeded(col.field)}: ${columnTsType(col, schema.enums)};`);
|
|
199
352
|
}
|
|
200
353
|
}
|
|
201
354
|
lines.push('};');
|
|
@@ -207,7 +360,7 @@ function generateTypes(schema, options) {
|
|
|
207
360
|
lines.push(`/** Input type for updating a row in \`${table.name}\` */`);
|
|
208
361
|
lines.push(`export type ${typeName}Update = {`);
|
|
209
362
|
for (const col of nonPkCols) {
|
|
210
|
-
lines.push(` ${col.field}?: ${updateFieldType(columnTsType(col, schema.enums))};`);
|
|
363
|
+
lines.push(` ${quoteIfNeeded(col.field)}?: ${updateFieldType(columnTsType(col, schema.enums))};`);
|
|
211
364
|
}
|
|
212
365
|
lines.push('};');
|
|
213
366
|
lines.push('');
|
|
@@ -276,15 +429,54 @@ function generateTypes(schema, options) {
|
|
|
276
429
|
}
|
|
277
430
|
}
|
|
278
431
|
if (uniqueSets.length > 0) {
|
|
279
|
-
const
|
|
432
|
+
const memberType = (colName) => {
|
|
433
|
+
const col = table.columns.find((c) => c.name === colName);
|
|
434
|
+
return { field: col?.field ?? colName, tsType: col?.tsType ?? 'unknown' };
|
|
435
|
+
};
|
|
436
|
+
// Flat branches: one object per unique constraint carrying its columns.
|
|
437
|
+
const flatBranches = uniqueSets.map((cols) => {
|
|
280
438
|
const fields = cols.map((colName) => {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
const tsType = col?.tsType ?? 'unknown';
|
|
284
|
-
return `${field}: ${tsType}`;
|
|
439
|
+
const m = memberType(colName);
|
|
440
|
+
return `${quoteIfNeeded(m.field)}: ${m.tsType}`;
|
|
285
441
|
});
|
|
286
442
|
return `{ ${fields.join('; ')} }`;
|
|
287
443
|
});
|
|
444
|
+
// Prisma-style compound-unique SELECTOR branches: a synthetic key
|
|
445
|
+
// (`orgId_userId`) whose value holds the member columns, emitted for every
|
|
446
|
+
// COMPOSITE unique (PK, composite UNIQUE constraint, or composite UNIQUE
|
|
447
|
+
// index). Runtime expansion lives in query/compound-unique.ts.
|
|
448
|
+
const compoundSeen = new Set();
|
|
449
|
+
const compoundSets = [];
|
|
450
|
+
const addCompound = (cols) => {
|
|
451
|
+
if (cols.length < 2)
|
|
452
|
+
return;
|
|
453
|
+
const key = cols.join(',');
|
|
454
|
+
if (compoundSeen.has(key))
|
|
455
|
+
return;
|
|
456
|
+
compoundSeen.add(key);
|
|
457
|
+
compoundSets.push(cols);
|
|
458
|
+
};
|
|
459
|
+
addCompound(table.primaryKey);
|
|
460
|
+
for (const uc of table.uniqueColumns)
|
|
461
|
+
addCompound(uc);
|
|
462
|
+
for (const idx of table.indexes) {
|
|
463
|
+
if (idx.unique && !idx.docPath)
|
|
464
|
+
addCompound(idx.columns);
|
|
465
|
+
}
|
|
466
|
+
const selectorEntries = compoundSets.map((cols) => {
|
|
467
|
+
const members = cols.map(memberType);
|
|
468
|
+
return {
|
|
469
|
+
selectorName: members.map((m) => m.field).join('_'),
|
|
470
|
+
memberType: `{ ${members.map((m) => `${quoteIfNeeded(m.field)}: ${m.tsType}`).join('; ')} }`,
|
|
471
|
+
};
|
|
472
|
+
});
|
|
473
|
+
// Named helper type for annotating a compound selector by hand (Prisma parity).
|
|
474
|
+
if (selectorEntries.length > 0) {
|
|
475
|
+
const cuFields = selectorEntries.map((e) => `${e.selectorName}: ${e.memberType}`);
|
|
476
|
+
lines.push(`export type ${typeName}CompoundUniques = { ${cuFields.join('; ')} };`);
|
|
477
|
+
}
|
|
478
|
+
const selectorBranches = selectorEntries.map((e) => `{ ${e.selectorName}: ${e.memberType} }`);
|
|
479
|
+
const branches = [...flatBranches, ...selectorBranches];
|
|
288
480
|
lines.push(`export type ${typeName}WhereUnique = ${branches.join(' | ')};`);
|
|
289
481
|
lines.push('');
|
|
290
482
|
}
|
|
@@ -414,7 +606,7 @@ function generateZod(schema, options) {
|
|
|
414
606
|
let expr = zodBaseType(col, schema.enums);
|
|
415
607
|
if (col.nullable)
|
|
416
608
|
expr += '.nullable()';
|
|
417
|
-
lines.push(` ${col.field}: ${expr},`);
|
|
609
|
+
lines.push(` ${quoteIfNeeded(col.field)}: ${expr},`);
|
|
418
610
|
}
|
|
419
611
|
lines.push('});');
|
|
420
612
|
lines.push('');
|
|
@@ -431,7 +623,7 @@ function generateZod(schema, options) {
|
|
|
431
623
|
expr += '.nullable()';
|
|
432
624
|
if (col.hasDefault || col.nullable || isPk)
|
|
433
625
|
expr += '.optional()';
|
|
434
|
-
lines.push(` ${col.field}: ${expr},`);
|
|
626
|
+
lines.push(` ${quoteIfNeeded(col.field)}: ${expr},`);
|
|
435
627
|
}
|
|
436
628
|
lines.push('});');
|
|
437
629
|
lines.push('');
|
|
@@ -447,7 +639,7 @@ function generateZod(schema, options) {
|
|
|
447
639
|
if (col.nullable)
|
|
448
640
|
expr += '.nullable()';
|
|
449
641
|
expr += '.optional()';
|
|
450
|
-
lines.push(` ${col.field}: ${expr},`);
|
|
642
|
+
lines.push(` ${quoteIfNeeded(col.field)}: ${expr},`);
|
|
451
643
|
}
|
|
452
644
|
lines.push('});');
|
|
453
645
|
lines.push('');
|
|
@@ -477,7 +669,7 @@ function generateMetadata(schema, options) {
|
|
|
477
669
|
// columnMap
|
|
478
670
|
lines.push(' columnMap: {');
|
|
479
671
|
for (const [field, col] of Object.entries(table.columnMap)) {
|
|
480
|
-
lines.push(` ${field}: '${escSQ(col)}',`);
|
|
672
|
+
lines.push(` ${quoteIfNeeded(field)}: '${escSQ(col)}',`);
|
|
481
673
|
}
|
|
482
674
|
lines.push(' },');
|
|
483
675
|
// reverseColumnMap
|
|
@@ -577,11 +769,17 @@ function generateIndex(schema, options) {
|
|
|
577
769
|
const hasSafeRelations = new Map();
|
|
578
770
|
for (const t of tableEntries)
|
|
579
771
|
hasSafeRelations.set(t.name, typeSafeRelations(t, false).length > 0);
|
|
772
|
+
// F3: sibling-import extension. Defaults to '.js' for direct callers so their
|
|
773
|
+
// output stays byte-stable; `generate()` resolves it (auto / js / none).
|
|
774
|
+
const ext = options?.importExt ?? '.js';
|
|
580
775
|
const lines = [
|
|
581
776
|
...generatedFileHeader(options),
|
|
777
|
+
// Record the resolved import mode for debuggability (only when generate()
|
|
778
|
+
// drove it, so direct generateIndex() callers stay byte-identical).
|
|
779
|
+
...(options?.importMode ? [`// Sibling imports resolved with importExtension: ${options.importMode}.`, ''] : []),
|
|
582
780
|
"import { TurbineClient as BaseTurbineClient, TransactionClient as BaseTransactionClient, QueryInterface } from 'turbine-orm';",
|
|
583
781
|
"import type { TurbineConfig, TransactionOptions, DeferredQuery, PipelineResults } from 'turbine-orm';",
|
|
584
|
-
|
|
782
|
+
`import { SCHEMA } from './metadata${ext}';`,
|
|
585
783
|
];
|
|
586
784
|
// Import all entity types and relations maps
|
|
587
785
|
const typeImports = [];
|
|
@@ -591,7 +789,7 @@ function generateIndex(schema, options) {
|
|
|
591
789
|
typeImports.push(`${entityName(t.name)}Relations`);
|
|
592
790
|
}
|
|
593
791
|
}
|
|
594
|
-
lines.push(`import type { ${typeImports.join(', ')} } from './types
|
|
792
|
+
lines.push(`import type { ${typeImports.join(', ')} } from './types${ext}';`);
|
|
595
793
|
lines.push('');
|
|
596
794
|
// -------------------------------------------------------------------------
|
|
597
795
|
// TypedTransactionClient — same typed table accessors as TurbineClient,
|
|
@@ -702,11 +900,70 @@ function generateIndex(schema, options) {
|
|
|
702
900
|
lines.push('}');
|
|
703
901
|
lines.push('');
|
|
704
902
|
// Re-export everything
|
|
705
|
-
lines.push(
|
|
706
|
-
lines.push(
|
|
903
|
+
lines.push(`export * from './types${ext}';`);
|
|
904
|
+
lines.push(`export { SCHEMA } from './metadata${ext}';`);
|
|
905
|
+
lines.push('');
|
|
906
|
+
return lines.join('\n');
|
|
907
|
+
}
|
|
908
|
+
// ---------------------------------------------------------------------------
|
|
909
|
+
// prisma-map.ts generator
|
|
910
|
+
// ---------------------------------------------------------------------------
|
|
911
|
+
/**
|
|
912
|
+
* Serialize a resolved {@link PrismaCompatMap} into a `prisma-map.ts` module
|
|
913
|
+
* that exports `export const PRISMA_MAP: PrismaCompatMap = {...}`. Written next
|
|
914
|
+
* to the generated client by `turbine migrate-from-prisma`; consumed later by
|
|
915
|
+
* the phase-2 `turbine-orm/prisma-compat` runtime adapter.
|
|
916
|
+
*
|
|
917
|
+
* Deterministic: uses the same reproducible header as the other emitters, so a
|
|
918
|
+
* stable input regenerates byte-identical output under `noTimestamp`.
|
|
919
|
+
*/
|
|
920
|
+
function generatePrismaMap(map, options) {
|
|
921
|
+
const lines = [
|
|
922
|
+
...generatedFileHeader(options),
|
|
923
|
+
"import type { PrismaCompatMap } from 'turbine-orm';",
|
|
924
|
+
'',
|
|
925
|
+
'/**',
|
|
926
|
+
' * Name map from your Prisma schema onto this Turbine client. Every entry was',
|
|
927
|
+
' * resolved against the live database; unresolved items are omitted (see the',
|
|
928
|
+
' * migration report). Pass this to the phase-2 prisma-compat adapter, or read',
|
|
929
|
+
' * it directly for hand-written compatibility wrappers.',
|
|
930
|
+
' */',
|
|
931
|
+
'export const PRISMA_MAP: PrismaCompatMap = {',
|
|
932
|
+
' models: {',
|
|
933
|
+
];
|
|
934
|
+
for (const [modelName, model] of Object.entries(map.models)) {
|
|
935
|
+
lines.push(` ${quoteIfNeeded(modelName)}: {`);
|
|
936
|
+
lines.push(` table: '${escSQ(model.table)}',`);
|
|
937
|
+
lines.push(` accessor: '${escSQ(model.accessor)}',`);
|
|
938
|
+
lines.push(` fields: ${serializeStringRecord(model.fields)},`);
|
|
939
|
+
lines.push(' relations: {');
|
|
940
|
+
for (const [rel, r] of Object.entries(model.relations)) {
|
|
941
|
+
lines.push(` ${quoteIfNeeded(rel)}: { name: '${escSQ(r.name)}', cardinality: '${r.cardinality}' },`);
|
|
942
|
+
}
|
|
943
|
+
lines.push(' },');
|
|
944
|
+
lines.push(` compoundUniques: ${serializeStringArrayRecord(model.compoundUniques)},`);
|
|
945
|
+
lines.push(' },');
|
|
946
|
+
}
|
|
947
|
+
lines.push(' },');
|
|
948
|
+
lines.push(` enums: ${serializeStringRecord(map.enums)},`);
|
|
949
|
+
lines.push('};');
|
|
707
950
|
lines.push('');
|
|
708
951
|
return lines.join('\n');
|
|
709
952
|
}
|
|
953
|
+
/** Serialize a `Record<string, string>` as an inline object literal. */
|
|
954
|
+
function serializeStringRecord(rec) {
|
|
955
|
+
const entries = Object.entries(rec);
|
|
956
|
+
if (entries.length === 0)
|
|
957
|
+
return '{}';
|
|
958
|
+
return `{ ${entries.map(([k, v]) => `${quoteIfNeeded(k)}: '${escSQ(v)}'`).join(', ')} }`;
|
|
959
|
+
}
|
|
960
|
+
/** Serialize a `Record<string, string[]>` as an inline object literal. */
|
|
961
|
+
function serializeStringArrayRecord(rec) {
|
|
962
|
+
const entries = Object.entries(rec);
|
|
963
|
+
if (entries.length === 0)
|
|
964
|
+
return '{}';
|
|
965
|
+
return `{ ${entries.map(([k, v]) => `${quoteIfNeeded(k)}: [${v.map((s) => `'${escSQ(s)}'`).join(', ')}]`).join(', ')} }`;
|
|
966
|
+
}
|
|
710
967
|
// ---------------------------------------------------------------------------
|
|
711
968
|
// Helpers
|
|
712
969
|
// ---------------------------------------------------------------------------
|
package/dist/cjs/index.js
CHANGED
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.
|
|
38
|
-
exports.TypedSqlQuery = exports.buildTypedSql = exports.turbineHttp = exports.defineSeed = exports.schemaToSQLString = exports.schemaToSQL = exports.schemaPush = exports.schemaDiff = exports.DestructivePushRefusal = exports.schemaDefToMetadata = exports.table = exports.isDocFieldIndexDef = exports.defineSchema = exports.column = exports.ColumnBuilder = void 0;
|
|
37
|
+
exports.withDbFieldNames = exports.snakeToPascal = exports.snakeToCamel = exports.singularize = exports.pgTypeToTs = exports.pgArrayType = exports.normalizeKeyColumns = exports.isDateType = exports.camelToSnake = exports.validateChannel = exports.QueryInterface = exports.pipelineSupported = exports.executePipeline = exports.hasRelationFields = exports.executeNestedUpdate = exports.executeNestedCreate = exports.introspect = exports.generate = exports.wrapPgError = exports.ValidationError = exports.UnsupportedFeatureError = exports.UniqueConstraintError = exports.TurbineErrorCode = exports.TurbineError = exports.TimeoutError = exports.setErrorMessageMode = exports.SerializationFailureError = exports.RelationError = exports.ReadOnlyError = exports.PipelineError = exports.OptimisticLockError = exports.NotNullViolationError = exports.NotFoundError = exports.MigrationError = exports.getErrorMessageMode = exports.ForeignKeyError = exports.ExclusionConstraintError = exports.DeadlockError = exports.ConnectionError = exports.CircularRelationError = exports.CheckConstraintError = exports.postgresDialect = exports.withRetry = exports.TurbineClient = exports.TransactionClient = exports.yugabytedb = exports.timescale = exports.postgresql = exports.cockroachdb = exports.alloydb = void 0;
|
|
38
|
+
exports.TypedSqlQuery = exports.buildTypedSql = exports.turbineHttp = exports.defineSeed = exports.schemaToSQLString = exports.schemaToSQL = exports.schemaPush = exports.schemaDiff = exports.DestructivePushRefusal = exports.schemaDefToMetadata = exports.table = exports.isDocFieldIndexDef = exports.defineSchema = exports.column = exports.ColumnBuilder = exports.applyManyToManyRelations = void 0;
|
|
39
39
|
var index_js_1 = require("./adapters/index.js");
|
|
40
40
|
Object.defineProperty(exports, "alloydb", { enumerable: true, get: function () { return index_js_1.alloydb; } });
|
|
41
41
|
Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return index_js_1.cockroachdb; } });
|
|
@@ -105,6 +105,7 @@ Object.defineProperty(exports, "pgTypeToTs", { enumerable: true, get: function (
|
|
|
105
105
|
Object.defineProperty(exports, "singularize", { enumerable: true, get: function () { return schema_js_1.singularize; } });
|
|
106
106
|
Object.defineProperty(exports, "snakeToCamel", { enumerable: true, get: function () { return schema_js_1.snakeToCamel; } });
|
|
107
107
|
Object.defineProperty(exports, "snakeToPascal", { enumerable: true, get: function () { return schema_js_1.snakeToPascal; } });
|
|
108
|
+
Object.defineProperty(exports, "withDbFieldNames", { enumerable: true, get: function () { return schema_js_1.withDbFieldNames; } });
|
|
108
109
|
// Schema builder — define schemas in TypeScript
|
|
109
110
|
var schema_builder_js_1 = require("./schema-builder.js");
|
|
110
111
|
Object.defineProperty(exports, "applyManyToManyRelations", { enumerable: true, get: function () { return schema_builder_js_1.applyManyToManyRelations; } });
|