@danielhritcu/zenstack-custom 1.1.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/dist/cli.js ADDED
@@ -0,0 +1,2492 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
4
+
5
+ // src/cli.ts
6
+ import * as fs3 from "fs";
7
+ import * as path from "path";
8
+
9
+ // src/codegen/discover.ts
10
+ import { getTableConfig, getViewConfig } from "drizzle-orm/pg-core";
11
+ import * as fs2 from "fs";
12
+ import * as ts from "typescript";
13
+
14
+ // src/drizzle/define.ts
15
+ import { SQL, sql } from "drizzle-orm";
16
+ import { pgEnum as drizzlePgEnum } from "drizzle-orm/pg-core";
17
+ var ENUM_MAP = Symbol.for("drizzle:EnumMap");
18
+
19
+ // src/codegen/utils.ts
20
+ import * as fs from "fs";
21
+ var APP_SLUG_JS = "appSlug";
22
+ var GENERATED_FILE_BANNER = [
23
+ "//////////////////////////////////////////////////////////////////////////////////////////////",
24
+ "// DO NOT MODIFY THIS FILE //",
25
+ "// Generated by scripts/zen from Drizzle schema. //",
26
+ "//////////////////////////////////////////////////////////////////////////////////////////////",
27
+ "",
28
+ "/* eslint-disable */"
29
+ ];
30
+ function emitGeneratedFileBanner() {
31
+ return [
32
+ ...GENERATED_FILE_BANNER
33
+ ];
34
+ }
35
+ __name(emitGeneratedFileBanner, "emitGeneratedFileBanner");
36
+ function capitalize(s) {
37
+ return s.charAt(0).toUpperCase() + s.slice(1);
38
+ }
39
+ __name(capitalize, "capitalize");
40
+ function toPascalCase(s) {
41
+ return s.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[_\-\s]+/).filter(Boolean).map(capitalize).join("");
42
+ }
43
+ __name(toPascalCase, "toPascalCase");
44
+ function esc(s) {
45
+ return JSON.stringify(s);
46
+ }
47
+ __name(esc, "esc");
48
+ function getDrizzleTableName(table) {
49
+ return table[Symbol.for("drizzle:Name")];
50
+ }
51
+ __name(getDrizzleTableName, "getDrizzleTableName");
52
+ function writeFileIfChanged(filePath, content) {
53
+ if (fs.existsSync(filePath) && fs.readFileSync(filePath, "utf-8") === content) {
54
+ return false;
55
+ }
56
+ fs.writeFileSync(filePath, content, "utf-8");
57
+ return true;
58
+ }
59
+ __name(writeFileIfChanged, "writeFileIfChanged");
60
+
61
+ // src/codegen/discover.ts
62
+ function discoverEnums(allEnums) {
63
+ const enums = /* @__PURE__ */ new Map();
64
+ for (const [exportName, val] of Object.entries(allEnums)) {
65
+ if (typeof val !== "function" || !("enumName" in val)) continue;
66
+ const e = val;
67
+ const pgName = e.enumName;
68
+ const values = e.enumValues;
69
+ const zenstackName = capitalize(exportName.replace(/Enum$/, ""));
70
+ const mapping = e[ENUM_MAP] ?? null;
71
+ enums.set(pgName, {
72
+ pgName,
73
+ zenstackName,
74
+ values,
75
+ mapping,
76
+ mappedName: pgName
77
+ });
78
+ }
79
+ return enums;
80
+ }
81
+ __name(discoverEnums, "discoverEnums");
82
+ function discoverTables(allTables, computedFieldsConfig = {}, derivedModelsConfig = {}) {
83
+ const tables = [];
84
+ const tablesByModel = /* @__PURE__ */ new Map();
85
+ for (const [exportName, _val] of Object.entries(allTables)) {
86
+ const val = _val;
87
+ if (!val || typeof val !== "object") continue;
88
+ const syms = Object.getOwnPropertySymbols(val);
89
+ if (!syms.some((s) => s.toString().includes("IsDrizzleTable"))) continue;
90
+ const sqlName = getDrizzleTableName(val);
91
+ const modelName = exportName;
92
+ const typeName = capitalize(exportName);
93
+ const sqlToJsKey = /* @__PURE__ */ new Map();
94
+ const jsKeySet = /* @__PURE__ */ new Set();
95
+ for (const key of Object.keys(val)) {
96
+ const col = val[key];
97
+ if (col.name && col.columnType) {
98
+ sqlToJsKey.set(col.name, key);
99
+ jsKeySet.add(key);
100
+ }
101
+ }
102
+ const cfg = getTableConfig(val);
103
+ const computedFields = Object.entries(computedFieldsConfig[exportName] ?? {}).map(([name, field]) => {
104
+ if (jsKeySet.has(name)) {
105
+ throw new Error(`Computed field "${exportName}.${name}" collides with an existing column.`);
106
+ }
107
+ return {
108
+ name,
109
+ type: field.type,
110
+ tsType: field.tsType
111
+ };
112
+ });
113
+ tables.push({
114
+ exportName,
115
+ sqlName,
116
+ modelName,
117
+ typeName,
118
+ table: val,
119
+ cfg,
120
+ sqlToJsKey,
121
+ jsKeySet,
122
+ computedFields,
123
+ derivedFrom: null,
124
+ defaultWhere: null,
125
+ narrow: null
126
+ });
127
+ tablesByModel.set(modelName, tables[tables.length - 1]);
128
+ }
129
+ for (const modelName of Object.keys(computedFieldsConfig)) {
130
+ if (!tablesByModel.has(modelName)) {
131
+ throw new Error(`Computed fields declared for unknown table export "${modelName}".`);
132
+ }
133
+ }
134
+ for (const [baseModelName, derivedModels] of Object.entries(derivedModelsConfig)) {
135
+ const baseTable = tablesByModel.get(baseModelName);
136
+ if (!baseTable) {
137
+ throw new Error(`Derived models declared for unknown table export "${baseModelName}".`);
138
+ }
139
+ for (const [derivedModelName, declaration] of Object.entries(derivedModels)) {
140
+ if (tablesByModel.has(derivedModelName)) {
141
+ throw new Error(`Derived model "${derivedModelName}" collides with an existing table or derived model.`);
142
+ }
143
+ const derivedTable = {
144
+ ...baseTable,
145
+ exportName: derivedModelName,
146
+ modelName: derivedModelName,
147
+ typeName: capitalize(derivedModelName),
148
+ computedFields: [
149
+ ...baseTable.computedFields
150
+ ],
151
+ derivedFrom: baseModelName,
152
+ defaultWhere: declaration.where,
153
+ narrow: declaration.narrow ?? null
154
+ };
155
+ tables.push(derivedTable);
156
+ tablesByModel.set(derivedModelName, derivedTable);
157
+ }
158
+ }
159
+ return tables;
160
+ }
161
+ __name(discoverTables, "discoverTables");
162
+ function discoverViews(allViews) {
163
+ const views = [];
164
+ for (const [exportName, val] of Object.entries(allViews)) {
165
+ if (!val || typeof val !== "object") continue;
166
+ const syms = Object.getOwnPropertySymbols(val);
167
+ if (!syms.some((s) => s.toString().includes("IsDrizzleView"))) continue;
168
+ const cfg = getViewConfig(val);
169
+ const sqlName = cfg.name;
170
+ const modelName = exportName;
171
+ const typeName = capitalize(exportName);
172
+ const sqlToJsKey = /* @__PURE__ */ new Map();
173
+ const columns = /* @__PURE__ */ new Map();
174
+ for (const [jsKey, col] of Object.entries(cfg.selectedFields)) {
175
+ const colObj = col;
176
+ if (colObj.name && colObj.columnType) {
177
+ sqlToJsKey.set(colObj.name, jsKey);
178
+ columns.set(jsKey, colObj);
179
+ }
180
+ }
181
+ views.push({
182
+ exportName,
183
+ sqlName,
184
+ modelName,
185
+ typeName,
186
+ columns,
187
+ sqlToJsKey
188
+ });
189
+ }
190
+ return views;
191
+ }
192
+ __name(discoverViews, "discoverViews");
193
+ function extractFKs(table) {
194
+ const cfg = getTableConfig(table);
195
+ return cfg.foreignKeys.map((fk) => {
196
+ const ref = fk.reference();
197
+ return {
198
+ name: fk.getName(),
199
+ localColumns: ref.columns.map((c) => c.name),
200
+ foreignTable: getDrizzleTableName(ref.foreignTable),
201
+ foreignColumns: ref.foreignColumns.map((c) => c.name)
202
+ };
203
+ });
204
+ }
205
+ __name(extractFKs, "extractFKs");
206
+
207
+ // src/codegen/columns.ts
208
+ function mapColumn(jsKey, col, enumMap) {
209
+ const sqlName = col.name;
210
+ const colType = col.columnType;
211
+ const notNull = col.notNull;
212
+ const hasDefault = col.hasDefault;
213
+ const isPrimary = col.primary;
214
+ const isUnique = col.isUnique;
215
+ const generated = col.generated;
216
+ const isArray = colType === "PgArray";
217
+ let type = "String";
218
+ const dbAttrs = [];
219
+ let enumPgName = null;
220
+ let isJsonColumn = false;
221
+ let actualColType = colType;
222
+ let actualCol = col;
223
+ if (isArray && col.baseColumn) {
224
+ actualCol = col.baseColumn;
225
+ actualColType = actualCol.columnType;
226
+ }
227
+ switch (actualColType) {
228
+ case "PgUUID":
229
+ type = "String";
230
+ dbAttrs.push("@db.Uuid");
231
+ break;
232
+ case "PgText":
233
+ type = "String";
234
+ break;
235
+ case "PgVarchar": {
236
+ type = "String";
237
+ const len = actualCol.length;
238
+ if (len) dbAttrs.push(`@db.VarChar(${len})`);
239
+ else dbAttrs.push("@db.VarChar");
240
+ break;
241
+ }
242
+ case "PgBoolean":
243
+ type = "Boolean";
244
+ break;
245
+ case "PgInteger":
246
+ type = "Int";
247
+ break;
248
+ case "PgBigInt53":
249
+ type = "BigInt";
250
+ break;
251
+ case "PgSerial":
252
+ type = "Int";
253
+ break;
254
+ case "PgReal":
255
+ type = "Float";
256
+ dbAttrs.push("@db.Real");
257
+ break;
258
+ case "PgDoublePrecision":
259
+ type = "Float";
260
+ dbAttrs.push("@db.DoublePrecision");
261
+ break;
262
+ case "PgTimestamp": {
263
+ type = "DateTime";
264
+ const wtz = actualCol.withTimezone ?? actualCol.config?.withTimezone;
265
+ if (wtz) dbAttrs.push("@db.Timestamptz(6)");
266
+ else dbAttrs.push("@db.Timestamp(6)");
267
+ break;
268
+ }
269
+ case "PgDate":
270
+ case "PgDateString":
271
+ type = "DateTime";
272
+ dbAttrs.push("@db.Date");
273
+ break;
274
+ case "PgJsonb":
275
+ type = "Json";
276
+ isJsonColumn = true;
277
+ dbAttrs.push("@db.JsonB");
278
+ break;
279
+ case "PgJson":
280
+ type = "Json";
281
+ isJsonColumn = true;
282
+ dbAttrs.push("@db.Json");
283
+ break;
284
+ case "PgEnumColumn": {
285
+ if (isArray) {
286
+ type = "String";
287
+ } else {
288
+ const eName = actualCol.enum?.enumName;
289
+ if (eName && enumMap.has(eName)) {
290
+ type = enumMap.get(eName).zenstackName;
291
+ enumPgName = eName;
292
+ } else {
293
+ type = "String";
294
+ }
295
+ }
296
+ break;
297
+ }
298
+ case "PgCustomColumn": {
299
+ const sqlType = actualCol.sqlName || actualCol.config?.dataType;
300
+ if (sqlType === "json") {
301
+ type = "Json";
302
+ isJsonColumn = true;
303
+ dbAttrs.push("@db.Json");
304
+ } else if (sqlType === "jsonb") {
305
+ type = "Json";
306
+ isJsonColumn = true;
307
+ dbAttrs.push("@db.JsonB");
308
+ } else if (sqlType === "numeric") {
309
+ type = "Decimal";
310
+ } else type = "String";
311
+ break;
312
+ }
313
+ case "PgNumeric":
314
+ type = "Decimal";
315
+ break;
316
+ default:
317
+ console.warn(`Unknown Drizzle column type "${actualColType}" for column "${sqlName}" \u2014 falling back to String`);
318
+ type = "String";
319
+ }
320
+ let defaultExpr = null;
321
+ if (hasDefault) {
322
+ if (isPrimary && actualColType === "PgUUID") {
323
+ defaultExpr = 'ExpressionUtils.call("uuid")';
324
+ } else if (actualColType === "PgBigInt53" && col.generatedIdentity) {
325
+ defaultExpr = 'ExpressionUtils.call("autoincrement")';
326
+ } else if (actualColType === "PgSerial") {
327
+ defaultExpr = 'ExpressionUtils.call("autoincrement")';
328
+ } else if (col.defaultFn) {
329
+ if (type === "DateTime") {
330
+ defaultExpr = 'ExpressionUtils.call("now")';
331
+ } else if (type === "String" && isPrimary) {
332
+ defaultExpr = 'ExpressionUtils.call("uuid")';
333
+ } else {
334
+ defaultExpr = null;
335
+ }
336
+ } else if (col.default !== void 0) {
337
+ const d = col.default;
338
+ if (typeof d === "boolean" || typeof d === "number") {
339
+ defaultExpr = `ExpressionUtils.literal(${d})`;
340
+ } else if (typeof d === "string") {
341
+ defaultExpr = `ExpressionUtils.literal(${esc(d)})`;
342
+ } else if (d && typeof d === "object" && "queryChunks" in d) {
343
+ try {
344
+ const chunks = d.queryChunks || [];
345
+ const sqlStr = chunks.map((c) => typeof c === "string" ? c : c.value?.[0] || "").join("").trim();
346
+ if (sqlStr) {
347
+ defaultExpr = `ExpressionUtils.call("dbgenerated", [ExpressionUtils.literal(${esc(sqlStr)})])`;
348
+ }
349
+ } catch (e) {
350
+ console.warn(`Failed to parse SQL default for column "${sqlName}":`, e);
351
+ }
352
+ } else if (Array.isArray(d) && d.length === 0) {
353
+ defaultExpr = "[] as FieldDefault";
354
+ } else if (typeof d === "object" && d !== null && Object.keys(d).length === 0) {
355
+ defaultExpr = `ExpressionUtils.literal("{}")`;
356
+ }
357
+ }
358
+ }
359
+ return {
360
+ name: jsKey,
361
+ sqlName,
362
+ type,
363
+ isJsonColumn,
364
+ optional: !notNull && !hasDefault,
365
+ array: isArray,
366
+ id: isPrimary,
367
+ unique: isUnique,
368
+ hasDefault,
369
+ dbAttrs,
370
+ defaultExpr,
371
+ enumPgName,
372
+ isGenerated: !!generated
373
+ };
374
+ }
375
+ __name(mapColumn, "mapColumn");
376
+
377
+ // src/codegen/typed-json.ts
378
+ import { toCamelCase } from "drizzle-orm/casing";
379
+ import { ModuleKind, ModuleResolutionKind, Project, ScriptTarget as ScriptTarget2, SyntaxKind } from "ts-morph";
380
+ function unwrapNullableType(type) {
381
+ if (!type.isUnion()) return type;
382
+ const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
383
+ if (nonNull.length !== 1) return type;
384
+ return unwrapNullableType(nonNull[0]);
385
+ }
386
+ __name(unwrapNullableType, "unwrapNullableType");
387
+ function getResolvedArrayInfo(type) {
388
+ const resolvedType = unwrapNullableType(type);
389
+ if (!resolvedType.isArray()) {
390
+ return {
391
+ resolvedType,
392
+ isArray: false
393
+ };
394
+ }
395
+ return {
396
+ resolvedType: resolvedType.getArrayElementTypeOrThrow(),
397
+ isArray: true
398
+ };
399
+ }
400
+ __name(getResolvedArrayInfo, "getResolvedArrayInfo");
401
+ function normalizeTypeText(typeText) {
402
+ let normalized = typeText.replace(/\s+/g, " ").trim();
403
+ normalized = normalized.replace(/\s*\|\s*(?:null|undefined)\s*$/g, "").trim();
404
+ let isArray = false;
405
+ if (normalized.endsWith("[]")) {
406
+ normalized = normalized.slice(0, -2).trim();
407
+ isArray = true;
408
+ }
409
+ if (normalized.startsWith("(") && normalized.endsWith(")")) {
410
+ normalized = normalized.slice(1, -1).trim();
411
+ }
412
+ return {
413
+ baseText: normalized,
414
+ isArray
415
+ };
416
+ }
417
+ __name(normalizeTypeText, "normalizeTypeText");
418
+ function buildTypeDefs(typesPath, tables, views, enumMap) {
419
+ const project = createTypedJsonProject(typesPath, !!views?.length);
420
+ const sf = project.getSourceFileOrThrow(typesPath);
421
+ const typeDefs = /* @__PURE__ */ new Map();
422
+ const fieldToTypeDef = /* @__PURE__ */ new Map();
423
+ const typedJsonFieldMap = /* @__PURE__ */ new Map();
424
+ const exportedTypes = createExportedTypeRegistry(sf);
425
+ const entityBySqlName = /* @__PURE__ */ new Map();
426
+ for (const table of tables) entityBySqlName.set(table.sqlName, table);
427
+ for (const view of views || []) entityBySqlName.set(view.sqlName, view);
428
+ const tableByExportName = new Map(tables.map((table) => [
429
+ table.exportName,
430
+ table
431
+ ]));
432
+ const sourceFiles = [
433
+ "supabase/schema/tables.ts"
434
+ ];
435
+ if (views?.length) sourceFiles.push("supabase/schema/views.ts");
436
+ for (const filePath of sourceFiles) {
437
+ scanFileForTypedColumns({
438
+ sourceFile: project.getSourceFileOrThrow(filePath),
439
+ exportedTypes,
440
+ typeDefs,
441
+ fieldToTypeDef,
442
+ typedJsonFieldMap,
443
+ entityBySqlName,
444
+ tableByExportName,
445
+ enumMap: enumMap || /* @__PURE__ */ new Map()
446
+ });
447
+ }
448
+ return {
449
+ typeDefs,
450
+ fieldToTypeDef,
451
+ typedJsonFields: sortTypedJsonFields([
452
+ ...typedJsonFieldMap.values()
453
+ ])
454
+ };
455
+ }
456
+ __name(buildTypeDefs, "buildTypeDefs");
457
+ function createExportedTypeRegistry(sourceFile) {
458
+ const declarations = /* @__PURE__ */ new Map();
459
+ const resolvedTypes = /* @__PURE__ */ new Map();
460
+ for (const stmt of sourceFile.getStatements()) {
461
+ if (stmt.getKind() === SyntaxKind.TypeAliasDeclaration) {
462
+ const typeAlias = stmt.asKindOrThrow(SyntaxKind.TypeAliasDeclaration);
463
+ if (typeAlias.isExported()) {
464
+ declarations.set(typeAlias.getName(), typeAlias);
465
+ }
466
+ }
467
+ if (stmt.getKind() === SyntaxKind.InterfaceDeclaration) {
468
+ const iface = stmt.asKindOrThrow(SyntaxKind.InterfaceDeclaration);
469
+ if (iface.isExported()) {
470
+ declarations.set(iface.getName(), iface);
471
+ }
472
+ }
473
+ }
474
+ return {
475
+ has(name) {
476
+ return declarations.has(name);
477
+ },
478
+ get(name) {
479
+ if (!declarations.has(name)) return void 0;
480
+ const cachedType = resolvedTypes.get(name);
481
+ if (cachedType) return cachedType;
482
+ const declaration = declarations.get(name);
483
+ if (!declaration) return void 0;
484
+ const resolvedType = declaration.getType();
485
+ resolvedTypes.set(name, resolvedType);
486
+ return resolvedType;
487
+ }
488
+ };
489
+ }
490
+ __name(createExportedTypeRegistry, "createExportedTypeRegistry");
491
+ function createTypedJsonProject(typesPath, includeViews) {
492
+ const project = new Project({
493
+ skipAddingFilesFromTsConfig: true,
494
+ compilerOptions: {
495
+ module: ModuleKind.ESNext,
496
+ moduleResolution: ModuleResolutionKind.Bundler,
497
+ target: ScriptTarget2.ES2022,
498
+ allowJs: false,
499
+ baseUrl: ".",
500
+ paths: {
501
+ "@/*": [
502
+ "src/*"
503
+ ],
504
+ "~/*": [
505
+ "app/*"
506
+ ]
507
+ }
508
+ }
509
+ });
510
+ project.addSourceFileAtPath(typesPath);
511
+ project.addSourceFileAtPath("supabase/schema/tables.ts");
512
+ if (includeViews) {
513
+ project.addSourceFileAtPath("supabase/schema/views.ts");
514
+ }
515
+ return project;
516
+ }
517
+ __name(createTypedJsonProject, "createTypedJsonProject");
518
+ function scanFileForTypedColumns({ sourceFile, exportedTypes, typeDefs, fieldToTypeDef, typedJsonFieldMap, entityBySqlName, tableByExportName, enumMap }) {
519
+ const registerTypedJsonField = /* @__PURE__ */ __name((entitySqlName, columnSqlName, typeDefName, isArray, sourceTypeName) => {
520
+ const entity = entityBySqlName.get(entitySqlName);
521
+ if (!entity) return;
522
+ const fieldName = entity.sqlToJsKey.get(columnSqlName) || columnSqlName;
523
+ const fieldKey = `${entitySqlName}.${fieldName}`;
524
+ fieldToTypeDef.set(fieldKey, {
525
+ typeDefName,
526
+ isArray
527
+ });
528
+ typedJsonFieldMap.set(fieldKey, {
529
+ entitySqlName,
530
+ entityTypeName: entity.typeName,
531
+ fieldName,
532
+ typeDefName,
533
+ isArray,
534
+ sourceTypeName
535
+ });
536
+ }, "registerTypedJsonField");
537
+ for (const access of sourceFile.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {
538
+ if (access.getName() !== "$type") continue;
539
+ const call = access.getParentIfKind(SyntaxKind.CallExpression);
540
+ if (!call || call.getExpression() !== access) continue;
541
+ const typeArg = call.getTypeArguments()[0];
542
+ if (!typeArg) continue;
543
+ const propertyAssignment = call.getFirstAncestorByKind(SyntaxKind.PropertyAssignment);
544
+ if (!propertyAssignment) continue;
545
+ const columnSqlName = propertyAssignment.getName();
546
+ const entitySqlName = getEntitySqlName(call);
547
+ if (!entitySqlName) continue;
548
+ const rawTypeText = typeArg.getText().trim();
549
+ const { baseText, isArray: isArrayFromText } = normalizeTypeText(rawTypeText);
550
+ const rowTypeDefName = resolveWholeRowTypeDefName(baseText, tableByExportName, typeDefs, enumMap);
551
+ if (rowTypeDefName) {
552
+ const isArray2 = isArrayFromText || getResolvedArrayInfo(typeArg.getType()).isArray;
553
+ registerTypedJsonField(entitySqlName, columnSqlName, rowTypeDefName, isArray2);
554
+ continue;
555
+ }
556
+ if (exportedTypes.has(baseText)) {
557
+ const type = exportedTypes.get(baseText);
558
+ if (type && tryBuildTypeDef(baseText, type, typeDefs, exportedTypes)) {
559
+ const isArray2 = isArrayFromText || getResolvedArrayInfo(type).isArray;
560
+ registerTypedJsonField(entitySqlName, columnSqlName, baseText, isArray2, baseText);
561
+ }
562
+ continue;
563
+ }
564
+ const { resolvedType, isArray: isArrayFromType } = getResolvedArrayInfo(typeArg.getType());
565
+ const isArray = isArrayFromType || isArrayFromText;
566
+ const generatedName = `${toPascalCase(entitySqlName)}${toPascalCase(columnSqlName)}`;
567
+ if (tryBuildTypeDef(generatedName, resolvedType, typeDefs, exportedTypes)) {
568
+ registerTypedJsonField(entitySqlName, columnSqlName, generatedName, isArray);
569
+ }
570
+ }
571
+ }
572
+ __name(scanFileForTypedColumns, "scanFileForTypedColumns");
573
+ function getEntitySqlName(call) {
574
+ let node = call.getParent();
575
+ while (node) {
576
+ if (node.getKind() === SyntaxKind.CallExpression) {
577
+ const candidate = node.asKindOrThrow(SyntaxKind.CallExpression);
578
+ const callee = candidate.getExpression().getText();
579
+ if (callee === "pgTable" || callee === "pgView") {
580
+ const firstArg = candidate.getArguments()[0];
581
+ return firstArg ? firstArg.getText().replace(/['"]/g, "") : null;
582
+ }
583
+ }
584
+ node = node.getParent();
585
+ }
586
+ return null;
587
+ }
588
+ __name(getEntitySqlName, "getEntitySqlName");
589
+ function resolveWholeRowTypeDefName(typeText, tableByExportName, typeDefs, enumMap) {
590
+ const wholeRowMatch = typeText.match(/^typeof\s+(?:t\.)?(\w+)\.\$infer(?:Select|Insert)$/);
591
+ if (!wholeRowMatch) return null;
592
+ const refTable = tableByExportName.get(wholeRowMatch[1]);
593
+ if (!refTable) return null;
594
+ const rowTypeDefName = `${refTable.typeName}Row`;
595
+ if (!typeDefs.has(rowTypeDefName)) {
596
+ buildRowTypeDef(rowTypeDefName, refTable, typeDefs, enumMap);
597
+ }
598
+ return typeDefs.has(rowTypeDefName) ? rowTypeDefName : null;
599
+ }
600
+ __name(resolveWholeRowTypeDefName, "resolveWholeRowTypeDefName");
601
+ function buildRowTypeDef(name, table, typeDefs, enumMap) {
602
+ const fields = {};
603
+ for (const jsKey of [
604
+ ...table.sqlToJsKey.values()
605
+ ]) {
606
+ const col = table.table[jsKey];
607
+ if (!col?.columnType) continue;
608
+ const mapped = mapColumn(jsKey, col, enumMap);
609
+ if (mapped.isGenerated) continue;
610
+ if (mapped.sqlName === "$hash") continue;
611
+ let type;
612
+ switch (mapped.type) {
613
+ case "String":
614
+ case "Int":
615
+ case "Float":
616
+ case "Boolean":
617
+ case "DateTime":
618
+ case "Json":
619
+ type = mapped.type;
620
+ break;
621
+ case "BigInt":
622
+ type = "Int";
623
+ break;
624
+ case "Decimal":
625
+ type = "Float";
626
+ break;
627
+ default:
628
+ type = "String";
629
+ break;
630
+ }
631
+ const fieldName = toCamelCase(mapped.name);
632
+ fields[fieldName] = {
633
+ name: fieldName,
634
+ ...fieldName !== mapped.name && {
635
+ rawName: mapped.name
636
+ },
637
+ type,
638
+ ...mapped.optional && {
639
+ optional: true
640
+ },
641
+ ...mapped.array && {
642
+ array: true
643
+ }
644
+ };
645
+ }
646
+ if (Object.keys(fields).length > 0) {
647
+ typeDefs.set(name, {
648
+ name,
649
+ fields
650
+ });
651
+ }
652
+ }
653
+ __name(buildRowTypeDef, "buildRowTypeDef");
654
+ function tryBuildTypeDef(name, type, typeDefs, exportedTypes) {
655
+ if (typeDefs.has(name)) return true;
656
+ if (type.isArray()) {
657
+ return tryBuildTypeDef(name, type.getArrayElementTypeOrThrow(), typeDefs, exportedTypes);
658
+ }
659
+ if (type.isUnion()) {
660
+ const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
661
+ if (nonNull.length === 1) {
662
+ return tryBuildTypeDef(name, nonNull[0], typeDefs, exportedTypes);
663
+ }
664
+ return false;
665
+ }
666
+ if (!type.isObject() || type.getProperties().length === 0) return false;
667
+ if (type.getStringIndexType()) return false;
668
+ if (type.getCallSignatures().length > 0) return false;
669
+ const fields = {};
670
+ for (const prop of type.getProperties()) {
671
+ const propName = prop.getName();
672
+ const declaration = prop.getValueDeclaration();
673
+ if (!declaration) continue;
674
+ const propType = prop.getTypeAtLocation(declaration);
675
+ const fieldName = toCamelCase(propName);
676
+ const mappedField = mapTypeToTypeDef(propName, propType, name, typeDefs, exportedTypes);
677
+ fields[fieldName] = {
678
+ name: fieldName,
679
+ ...fieldName !== propName && {
680
+ rawName: propName
681
+ },
682
+ type: mappedField?.type || "Json",
683
+ ...prop.isOptional() && {
684
+ optional: true
685
+ },
686
+ ...mappedField?.isArray && {
687
+ array: true
688
+ }
689
+ };
690
+ }
691
+ if (Object.keys(fields).length === 0) return false;
692
+ typeDefs.set(name, {
693
+ name,
694
+ fields
695
+ });
696
+ return true;
697
+ }
698
+ __name(tryBuildTypeDef, "tryBuildTypeDef");
699
+ function mapTypeToTypeDef(fieldName, type, parentName, typeDefs, exportedTypes) {
700
+ if (type.isUnion()) {
701
+ const unwrapped = unwrapNullableType(type);
702
+ if (unwrapped !== type) {
703
+ return mapTypeToTypeDef(fieldName, unwrapped, parentName, typeDefs, exportedTypes);
704
+ }
705
+ const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
706
+ if (nonNull.every((member) => member.isStringLiteral() || member.isString())) {
707
+ return {
708
+ type: "String",
709
+ isArray: false
710
+ };
711
+ }
712
+ if (nonNull.every((member) => member.isNumberLiteral() || member.isNumber())) {
713
+ return {
714
+ type: "Float",
715
+ isArray: false
716
+ };
717
+ }
718
+ if (nonNull.every((member) => member.isBooleanLiteral() || member.isBoolean())) {
719
+ return {
720
+ type: "Boolean",
721
+ isArray: false
722
+ };
723
+ }
724
+ return null;
725
+ }
726
+ if (type.isString() || type.isStringLiteral()) return {
727
+ type: "String",
728
+ isArray: false
729
+ };
730
+ if (type.isNumber() || type.isNumberLiteral()) return {
731
+ type: "Float",
732
+ isArray: false
733
+ };
734
+ if (type.isBoolean() || type.isBooleanLiteral()) return {
735
+ type: "Boolean",
736
+ isArray: false
737
+ };
738
+ if (type.getSymbol()?.getName() === "Date") return {
739
+ type: "DateTime",
740
+ isArray: false
741
+ };
742
+ if (type.isArray()) {
743
+ const inner = mapTypeToTypeDef(fieldName, type.getArrayElementTypeOrThrow(), parentName, typeDefs, exportedTypes);
744
+ return inner ? {
745
+ type: inner.type,
746
+ isArray: true
747
+ } : null;
748
+ }
749
+ if (type.isObject() && type.getProperties().length > 0) {
750
+ if (type.getStringIndexType()) return {
751
+ type: "Json",
752
+ isArray: false
753
+ };
754
+ if (type.getCallSignatures().length > 0) return null;
755
+ const symbol = type.getAliasSymbol() || type.getSymbol();
756
+ const knownName = symbol?.getName();
757
+ if (knownName && exportedTypes.has(knownName)) {
758
+ if (tryBuildTypeDef(knownName, type, typeDefs, exportedTypes)) {
759
+ return {
760
+ type: knownName,
761
+ isArray: false
762
+ };
763
+ }
764
+ }
765
+ const subTypeDefName = `${parentName}${toPascalCase(fieldName)}`;
766
+ if (tryBuildTypeDef(subTypeDefName, type, typeDefs, exportedTypes)) {
767
+ return {
768
+ type: subTypeDefName,
769
+ isArray: false
770
+ };
771
+ }
772
+ }
773
+ return null;
774
+ }
775
+ __name(mapTypeToTypeDef, "mapTypeToTypeDef");
776
+ function emitTypeDefsBlock(typeDefs) {
777
+ if (typeDefs.size === 0) return "";
778
+ const lines = [];
779
+ lines.push(" typeDefs = {");
780
+ for (const [name, typeDef] of sortTypeDefs(typeDefs)) {
781
+ lines.push(` ${name}: {`);
782
+ lines.push(` name: ${esc(typeDef.name)},`);
783
+ lines.push(` fields: {`);
784
+ for (const field of Object.values(typeDef.fields)) {
785
+ const parts = [
786
+ `name: ${esc(field.name)}`,
787
+ `type: ${esc(field.type)}`
788
+ ];
789
+ if (field.optional) parts.push("optional: true");
790
+ if (field.array) parts.push("array: true");
791
+ if (field.rawName && field.rawName !== field.name) {
792
+ parts.push(`attributes: [{ name: "@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(field.rawName)}) }] }]`);
793
+ }
794
+ lines.push(` ${field.name}: { ${parts.join(", ")} },`);
795
+ }
796
+ lines.push(" }");
797
+ lines.push(" },");
798
+ }
799
+ lines.push(" } as const;");
800
+ return lines.join("\n");
801
+ }
802
+ __name(emitTypeDefsBlock, "emitTypeDefsBlock");
803
+ function mapTypeDefFieldToTs(field, typeDefs) {
804
+ let tsType;
805
+ switch (field.type) {
806
+ case "String":
807
+ tsType = "string";
808
+ break;
809
+ case "Int":
810
+ case "Float":
811
+ tsType = "number";
812
+ break;
813
+ case "Boolean":
814
+ tsType = "boolean";
815
+ break;
816
+ case "DateTime":
817
+ tsType = "Date";
818
+ break;
819
+ case "Json":
820
+ tsType = "unknown";
821
+ break;
822
+ default:
823
+ tsType = typeDefs.has(field.type) ? `${field.type}JsonShape` : "unknown";
824
+ break;
825
+ }
826
+ return field.array ? `${tsType}[]` : tsType;
827
+ }
828
+ __name(mapTypeDefFieldToTs, "mapTypeDefFieldToTs");
829
+ function getJsonFieldAlias(info) {
830
+ return `${info.entityTypeName}${toPascalCase(info.fieldName)}Json`;
831
+ }
832
+ __name(getJsonFieldAlias, "getJsonFieldAlias");
833
+ function getJsonRawFieldAlias(info) {
834
+ return `${getJsonFieldAlias(info)}Raw`;
835
+ }
836
+ __name(getJsonRawFieldAlias, "getJsonRawFieldAlias");
837
+ function emitJsonNamespaceBlock(typeDefs, typedJsonFields, indent = "") {
838
+ const out = [];
839
+ for (const [name, typeDef] of sortTypeDefs(typeDefs)) {
840
+ out.push(`${indent}export type ${name}JsonShape = {`);
841
+ for (const field of Object.values(typeDef.fields)) {
842
+ const optional = field.optional ? "?" : "";
843
+ out.push(`${indent} ${field.name}${optional}: ${mapTypeDefFieldToTs(field, typeDefs)};`);
844
+ }
845
+ out.push(`${indent}};`);
846
+ out.push("");
847
+ }
848
+ for (const info of typedJsonFields) {
849
+ out.push(`${indent}export type ${getJsonFieldAlias(info)} = ${info.typeDefName}JsonShape;`);
850
+ out.push("");
851
+ }
852
+ if (out.at(-1) === "") {
853
+ out.pop();
854
+ }
855
+ return out;
856
+ }
857
+ __name(emitJsonNamespaceBlock, "emitJsonNamespaceBlock");
858
+ function emitJsonRawNamespaceBlock(typedJsonFields, indent = "") {
859
+ const out = [];
860
+ for (const info of typedJsonFields.filter((field) => field.sourceTypeName)) {
861
+ out.push(`${indent}export type ${getJsonRawFieldAlias(info)} = RawJson.${info.sourceTypeName};`);
862
+ out.push("");
863
+ }
864
+ if (out.at(-1) === "") {
865
+ out.pop();
866
+ }
867
+ return out;
868
+ }
869
+ __name(emitJsonRawNamespaceBlock, "emitJsonRawNamespaceBlock");
870
+ function emitJsonTs(typeDefs, typedJsonFields) {
871
+ const out = [
872
+ ...emitGeneratedFileBanner(),
873
+ ""
874
+ ];
875
+ out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields));
876
+ out.push("");
877
+ return out.join("\n");
878
+ }
879
+ __name(emitJsonTs, "emitJsonTs");
880
+ function emitJsonRawTs(typedJsonFields) {
881
+ const out = [
882
+ ...emitGeneratedFileBanner(),
883
+ "",
884
+ 'import type * as RawJson from "../../supabase/schema/types";',
885
+ ""
886
+ ];
887
+ out.push(...emitJsonRawNamespaceBlock(typedJsonFields));
888
+ out.push("");
889
+ return out.join("\n");
890
+ }
891
+ __name(emitJsonRawTs, "emitJsonRawTs");
892
+ function sortTypeDefs(typeDefs) {
893
+ return [
894
+ ...typeDefs.entries()
895
+ ].sort(([left], [right]) => left.localeCompare(right));
896
+ }
897
+ __name(sortTypeDefs, "sortTypeDefs");
898
+ function sortTypedJsonFields(typedJsonFields) {
899
+ return [
900
+ ...typedJsonFields
901
+ ].sort((left, right) => {
902
+ const leftKey = `${getJsonFieldAlias(left)}:${left.sourceTypeName || ""}`;
903
+ const rightKey = `${getJsonFieldAlias(right)}:${right.sourceTypeName || ""}`;
904
+ return leftKey.localeCompare(rightKey);
905
+ });
906
+ }
907
+ __name(sortTypedJsonFields, "sortTypedJsonFields");
908
+
909
+ // src/codegen/emit.ts
910
+ var DB_ATTR_RE = /@db\.(\w+)(?:\((\d+)\))?/;
911
+ function buildDerivedEnumName(modelName, fieldName) {
912
+ return `${toPascalCase(modelName)}${toPascalCase(fieldName)}`;
913
+ }
914
+ __name(buildDerivedEnumName, "buildDerivedEnumName");
915
+ function inferFieldIsNonNull(defaultWhere, fieldName) {
916
+ if (!defaultWhere) return false;
917
+ const condition = defaultWhere[fieldName];
918
+ if (condition === void 0 || condition === null) return false;
919
+ if (Array.isArray(condition)) return condition.length > 0;
920
+ if (typeof condition !== "object") return true;
921
+ if (Object.prototype.hasOwnProperty.call(condition, "not") && Reflect.get(condition, "not") === null) {
922
+ return true;
923
+ }
924
+ if (Object.prototype.hasOwnProperty.call(condition, "in")) {
925
+ const values = Reflect.get(condition, "in");
926
+ return Array.isArray(values) && values.length > 0;
927
+ }
928
+ return false;
929
+ }
930
+ __name(inferFieldIsNonNull, "inferFieldIsNonNull");
931
+ function applyDerivedFieldOverrides(field, table) {
932
+ if (!table.derivedFrom) return field;
933
+ const narrowedValues = table.narrow?.[field.name];
934
+ return {
935
+ ...field,
936
+ // Keep base enum type — narrowing is handled at runtime by derived-models plugin
937
+ optional: narrowedValues && narrowedValues.length > 0 ? false : field.optional && !inferFieldIsNonNull(table.defaultWhere, field.name)
938
+ };
939
+ }
940
+ __name(applyDerivedFieldOverrides, "applyDerivedFieldOverrides");
941
+ function collectDerivedEnums(tables, enumMap) {
942
+ const derivedEnums = /* @__PURE__ */ new Map();
943
+ const tablesByModel = new Map(tables.map((table) => [
944
+ table.modelName,
945
+ table
946
+ ]));
947
+ for (const table of tables) {
948
+ if (!table.derivedFrom || !table.narrow) continue;
949
+ const baseTable = tablesByModel.get(table.derivedFrom);
950
+ if (!baseTable) continue;
951
+ const baseFields = /* @__PURE__ */ new Map();
952
+ for (const jsKey of baseTable.sqlToJsKey.values()) {
953
+ const column = baseTable.table[jsKey];
954
+ const field = mapColumn(jsKey, column, enumMap);
955
+ baseFields.set(field.name === "$hash" ? "hash" : field.name, field);
956
+ }
957
+ for (const [fieldName, narrowedValues] of Object.entries(table.narrow)) {
958
+ if (!narrowedValues.length) continue;
959
+ const baseField = baseFields.get(fieldName);
960
+ if (!baseField) {
961
+ throw new Error(`Unknown narrowed field "${table.modelName}.${fieldName}".`);
962
+ }
963
+ const baseEnum = [
964
+ ...enumMap.values()
965
+ ].find((info) => info.zenstackName === baseField.type);
966
+ if (!baseEnum) {
967
+ continue;
968
+ }
969
+ const values = narrowedValues.map((value) => String(value));
970
+ for (const value of values) {
971
+ if (!baseEnum.values.includes(value)) {
972
+ throw new Error(`Invalid narrowed enum value "${value}" for "${table.modelName}.${fieldName}".`);
973
+ }
974
+ }
975
+ const enumName = buildDerivedEnumName(table.modelName, fieldName);
976
+ if (derivedEnums.has(enumName)) continue;
977
+ const mapping = baseEnum.mapping ? Object.fromEntries(Object.entries(baseEnum.mapping).filter(([, value]) => values.includes(value))) : Object.fromEntries(values.map((value) => [
978
+ toPascalCase(value).toUpperCase(),
979
+ value
980
+ ]));
981
+ derivedEnums.set(enumName, {
982
+ pgName: `$derived:${enumName}`,
983
+ zenstackName: enumName,
984
+ values,
985
+ mapping,
986
+ mappedName: null
987
+ });
988
+ }
989
+ }
990
+ return derivedEnums;
991
+ }
992
+ __name(collectDerivedEnums, "collectDerivedEnums");
993
+ function emitEnumBlock(info) {
994
+ const lines = [];
995
+ lines.push(` ${info.zenstackName}: {`);
996
+ lines.push(` name: ${esc(info.zenstackName)},`);
997
+ const tuples = info.mapping ? (() => {
998
+ const invertedMap = Object.fromEntries(Object.entries(info.mapping).map(([k, v]) => [
999
+ v,
1000
+ k
1001
+ ]));
1002
+ return info.values.map((v) => {
1003
+ const key = invertedMap[v];
1004
+ if (!key) throw new Error(`Enum "${info.pgName}" value "${v}" not found in mapping.`);
1005
+ return [
1006
+ v,
1007
+ key
1008
+ ];
1009
+ });
1010
+ })() : info.values.map((v) => [
1011
+ v,
1012
+ v
1013
+ ]);
1014
+ const valuesEntries = tuples.map(([value]) => `${esc(value)}: ${esc(value)}`);
1015
+ lines.push(` values: { ${valuesEntries.join(", ")} },`);
1016
+ lines.push(` fields: {`);
1017
+ for (const [v] of tuples) {
1018
+ lines.push(` ${esc(v)}: { name: ${esc(v)} },`);
1019
+ }
1020
+ lines.push(` },`);
1021
+ const mappedName = info.mappedName === void 0 ? info.pgName : info.mappedName;
1022
+ if (mappedName) {
1023
+ lines.push(` attributes: [{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(mappedName)}) }] }]`);
1024
+ }
1025
+ lines.push(` }`);
1026
+ return lines.join("\n");
1027
+ }
1028
+ __name(emitEnumBlock, "emitEnumBlock");
1029
+ function emitFieldBlock(field) {
1030
+ const parts = [];
1031
+ parts.push(`name: ${esc(field.name)}`);
1032
+ parts.push(`type: ${esc(field.type)}`);
1033
+ if (field.optional) parts.push("optional: true");
1034
+ if (field.array) parts.push("array: true");
1035
+ if (field.id) parts.push("id: true");
1036
+ if (field.unique) parts.push("unique: true");
1037
+ const attrs = [];
1038
+ if (field.id) attrs.push('{ name: "@id" }');
1039
+ if (field.unique) attrs.push('{ name: "@unique" }');
1040
+ if (field.name !== field.sqlName) {
1041
+ attrs.push(`{ name: "@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(field.sqlName)}) }] }`);
1042
+ }
1043
+ for (const da of field.dbAttrs) {
1044
+ const match = da.match(DB_ATTR_RE);
1045
+ if (match) {
1046
+ const [, attrName, arg] = match;
1047
+ if (arg) {
1048
+ attrs.push(`{ name: "@db.${attrName}", args: [{ name: "x", value: ExpressionUtils.literal(${arg}) }] }`);
1049
+ } else {
1050
+ attrs.push(`{ name: "@db.${attrName}" }`);
1051
+ }
1052
+ }
1053
+ }
1054
+ if (field.defaultExpr) {
1055
+ const attrValue = field.defaultExpr === "[] as FieldDefault" ? 'ExpressionUtils.literal("[]")' : field.defaultExpr;
1056
+ attrs.push(`{ name: "@default", args: [{ name: "value", value: ${attrValue} }] }`);
1057
+ }
1058
+ if (field.isGenerated) {
1059
+ attrs.push('{ name: "@ignore" }');
1060
+ }
1061
+ if (field.isJsonColumn && field.type !== "Json") {
1062
+ attrs.push('{ name: "@json" }');
1063
+ }
1064
+ if (attrs.length > 0) {
1065
+ parts.push(`attributes: [${attrs.join(", ")}]`);
1066
+ }
1067
+ if (field.defaultExpr) {
1068
+ if (field.defaultExpr.startsWith("ExpressionUtils.literal(")) {
1069
+ const inner = field.defaultExpr.slice("ExpressionUtils.literal(".length, -1);
1070
+ parts.push(`default: ${inner}`);
1071
+ } else {
1072
+ parts.push(`default: ${field.defaultExpr}`);
1073
+ }
1074
+ }
1075
+ return `{ ${parts.join(", ")} }`;
1076
+ }
1077
+ __name(emitFieldBlock, "emitFieldBlock");
1078
+ function emitRelationField(rel, opposite) {
1079
+ const parts = [];
1080
+ parts.push(`name: ${esc(rel.fieldName)}`);
1081
+ parts.push(`type: ${esc(rel.targetModel)}`);
1082
+ if (rel.optional) parts.push("optional: true");
1083
+ if (rel.array) parts.push("array: true");
1084
+ const relParts = [];
1085
+ if (opposite) relParts.push(`opposite: ${esc(opposite)}`);
1086
+ if (rel.relationName) relParts.push(`name: ${esc(rel.relationName)}`);
1087
+ if (rel.fields) relParts.push(`fields: [${rel.fields.map((f) => esc(f)).join(", ")}]`);
1088
+ if (rel.references) relParts.push(`references: [${rel.references.map((r) => esc(r)).join(", ")}]`);
1089
+ if (rel.hasDefault) relParts.push("hasDefault: true");
1090
+ parts.push(`relation: { ${relParts.join(", ")} }`);
1091
+ const attrArgs = [];
1092
+ if (rel.relationName) {
1093
+ attrArgs.push(`{ name: "name", value: ExpressionUtils.literal(${esc(rel.relationName)}) }`);
1094
+ }
1095
+ if (rel.fields) {
1096
+ attrArgs.push(`{ name: "fields", value: ExpressionUtils.array("String", [${rel.fields.map((f) => `ExpressionUtils.field(${esc(f)})`).join(", ")}]) }`);
1097
+ }
1098
+ if (rel.references) {
1099
+ attrArgs.push(`{ name: "references", value: ExpressionUtils.array("String", [${rel.references.map((r) => `ExpressionUtils.field(${esc(r)})`).join(", ")}]) }`);
1100
+ }
1101
+ if (attrArgs.length > 0) {
1102
+ parts.push(`attributes: [{ name: "@relation", args: [${attrArgs.join(", ")}] }]`);
1103
+ }
1104
+ return `{ ${parts.join(", ")} }`;
1105
+ }
1106
+ __name(emitRelationField, "emitRelationField");
1107
+ function emitUnknownLiteral(value) {
1108
+ if (value === null) return "null";
1109
+ if (typeof value === "string") return esc(value);
1110
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
1111
+ if (Array.isArray(value)) {
1112
+ return `[${value.map((item) => emitUnknownLiteral(item)).join(", ")}]`;
1113
+ }
1114
+ if (typeof value === "object") {
1115
+ return `{ ${Object.entries(value).map(([key, item]) => `${JSON.stringify(key)}: ${emitUnknownLiteral(item)}`).join(", ")} }`;
1116
+ }
1117
+ throw new Error(`Unsupported config literal: ${String(value)}`);
1118
+ }
1119
+ __name(emitUnknownLiteral, "emitUnknownLiteral");
1120
+ function emitPluginsBlock(modelRelations, searchDefaults, modelScopes) {
1121
+ const lines = [];
1122
+ lines.push(" plugins = {");
1123
+ lines.push(" virtualRelations: {");
1124
+ for (const [model, relations] of modelRelations) {
1125
+ const virtualRelations = relations.filter((relation) => relation.kind && relation.kind !== "normal");
1126
+ if (virtualRelations.length === 0) continue;
1127
+ lines.push(` ${model}: {`);
1128
+ for (const relation of virtualRelations) {
1129
+ const parts = [
1130
+ `kind: ${esc(relation.kind)}`,
1131
+ `targetModel: ${esc(relation.targetModel)}`
1132
+ ];
1133
+ if (relation.sourceRelation) {
1134
+ parts.push(`relation: ${esc(relation.sourceRelation)}`);
1135
+ }
1136
+ if (relation.throughPath) {
1137
+ parts.push(`path: [${relation.throughPath.map((segment) => esc(segment)).join(", ")}]`);
1138
+ }
1139
+ if (relation.where) {
1140
+ parts.push(`where: ${emitUnknownLiteral(relation.where)}`);
1141
+ }
1142
+ if (relation.single) {
1143
+ parts.push("single: true");
1144
+ }
1145
+ lines.push(` ${relation.fieldName}: { ${parts.join(", ")} },`);
1146
+ }
1147
+ lines.push(" },");
1148
+ }
1149
+ lines.push(" },");
1150
+ lines.push(" searchDefaults: {");
1151
+ for (const [model, profiles] of Object.entries(searchDefaults)) {
1152
+ if (!profiles) continue;
1153
+ lines.push(` ${model}: {`);
1154
+ for (const [profile, declaration] of Object.entries(profiles)) {
1155
+ const parts = [
1156
+ `fields: ${emitUnknownLiteral(declaration.fields)}`
1157
+ ];
1158
+ if (declaration.mode) {
1159
+ parts.push(`mode: ${esc(declaration.mode)}`);
1160
+ }
1161
+ if (declaration.strategy) {
1162
+ parts.push(`strategy: ${esc(declaration.strategy)}`);
1163
+ }
1164
+ lines.push(` ${profile}: { ${parts.join(", ")} },`);
1165
+ }
1166
+ lines.push(" },");
1167
+ }
1168
+ lines.push(" },");
1169
+ if (Object.keys(modelScopes).length > 0) {
1170
+ lines.push(" modelScopes: {");
1171
+ for (const [scopeModel, where] of Object.entries(modelScopes)) {
1172
+ lines.push(` ${scopeModel}: ${emitUnknownLiteral(where)},`);
1173
+ }
1174
+ lines.push(" },");
1175
+ }
1176
+ lines.push(" } as const;");
1177
+ return lines.join("\n");
1178
+ }
1179
+ __name(emitPluginsBlock, "emitPluginsBlock");
1180
+ function applyTypeDefOverride(field, fieldMapping) {
1181
+ if (!fieldMapping) return field;
1182
+ return {
1183
+ ...field,
1184
+ type: fieldMapping.typeDefName,
1185
+ array: fieldMapping.isArray || field.array,
1186
+ dbAttrs: field.dbAttrs.filter((attr) => !attr.startsWith("@db.Json"))
1187
+ };
1188
+ }
1189
+ __name(applyTypeDefOverride, "applyTypeDefOverride");
1190
+ function emitModelBlock(t, enumMap, modelRelations, inverseRelations, fieldToTypeDef) {
1191
+ const out = [];
1192
+ const { cfg } = t;
1193
+ const fields = [];
1194
+ const fieldByName = /* @__PURE__ */ new Map();
1195
+ for (const jsKey of [
1196
+ ...t.sqlToJsKey.values()
1197
+ ]) {
1198
+ const col = t.table[jsKey];
1199
+ const field = mapColumn(jsKey, col, enumMap);
1200
+ if (field.sqlName === "$hash") {
1201
+ field.isGenerated = true;
1202
+ field.name = "hash";
1203
+ }
1204
+ const typedField = applyDerivedFieldOverrides(applyTypeDefOverride(field, fieldToTypeDef?.get(`${t.sqlName}.${jsKey}`)), t);
1205
+ fields.push(typedField);
1206
+ fieldByName.set(typedField.name, typedField);
1207
+ }
1208
+ const fkRels = modelRelations.get(t.modelName) || [];
1209
+ const fkFieldMap = /* @__PURE__ */ new Map();
1210
+ for (const rel of fkRels) {
1211
+ if (rel.fields) {
1212
+ for (const f of rel.fields) {
1213
+ if (!fkFieldMap.has(f)) fkFieldMap.set(f, []);
1214
+ fkFieldMap.get(f).push(rel.fieldName);
1215
+ }
1216
+ }
1217
+ }
1218
+ out.push(` ${t.modelName}: {`);
1219
+ out.push(` name: ${esc(t.modelName)},`);
1220
+ out.push(` fields: {`);
1221
+ for (const field of fields) {
1222
+ const fkFor = fkFieldMap.get(field.name);
1223
+ let block = emitFieldBlock(field);
1224
+ if (fkFor) {
1225
+ block = block.slice(0, -2) + `, foreignKeyFor: [${fkFor.map((f) => esc(f)).join(", ")}] }`;
1226
+ }
1227
+ out.push(` ${field.name}: ${block},`);
1228
+ }
1229
+ for (const rel of fkRels) {
1230
+ const isVirtualOnly = rel.kind === "through" || rel.kind === "filtered" && !rel.fields;
1231
+ const opposite = isVirtualOnly ? "" : rel._opposite || rel.fieldName;
1232
+ const block = emitRelationField(rel, opposite);
1233
+ out.push(` ${rel.fieldName}: ${block},`);
1234
+ }
1235
+ const invRels = inverseRelations.get(t.modelName) || [];
1236
+ for (const rel of invRels) {
1237
+ const opposite = rel._opposite || rel.fieldName;
1238
+ const block = emitRelationField(rel, opposite);
1239
+ out.push(` ${rel.fieldName}: ${block},`);
1240
+ }
1241
+ for (const computedField of t.computedFields) {
1242
+ out.push(` ${computedField.name}: { name: ${esc(computedField.name)}, type: ${esc(computedField.type)}, computed: true, attributes: [{ name: "@computed" }] },`);
1243
+ }
1244
+ out.push(` },`);
1245
+ if (t.computedFields.length > 0) {
1246
+ out.push(` computedFields: {`);
1247
+ for (const computedField of t.computedFields) {
1248
+ out.push(` ${computedField.name}(_context: { modelAlias: ${esc(t.modelName)} }): ${computedField.tsType} { throw new Error("computed stub"); },`);
1249
+ }
1250
+ out.push(` },`);
1251
+ }
1252
+ const modelAttrs = [];
1253
+ modelAttrs.push(`{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(t.sqlName)}) }] }`);
1254
+ for (const uc of cfg.uniqueConstraints) {
1255
+ const ucCols = uc.columns.map((c) => c.name);
1256
+ if (ucCols.length > 1) {
1257
+ modelAttrs.push(`{ name: "@@unique", args: [{ name: "fields", value: ExpressionUtils.array("String", [${ucCols.map((c) => `ExpressionUtils.field(${esc(t.sqlToJsKey.get(c) || c)})`).join(", ")}]) }] }`);
1258
+ }
1259
+ }
1260
+ if (cfg.primaryKeys.length > 0) {
1261
+ for (const pk of cfg.primaryKeys) {
1262
+ const pkCols = pk.columns.map((c) => c.name);
1263
+ modelAttrs.push(`{ name: "@@id", args: [{ name: "fields", value: ExpressionUtils.array("String", [${pkCols.map((c) => `ExpressionUtils.field(${esc(t.sqlToJsKey.get(c) || c)})`).join(", ")}]) }] }`);
1264
+ }
1265
+ }
1266
+ out.push(` attributes: [${modelAttrs.join(", ")}],`);
1267
+ const idCols = cfg.columns.filter((c) => c.primary).map((c) => t.sqlToJsKey.get(c.name) || c.name);
1268
+ if (idCols.length === 0 && cfg.primaryKeys.length > 0) {
1269
+ const pkCols = cfg.primaryKeys[0].columns.map((c) => t.sqlToJsKey.get(c.name) || c.name);
1270
+ out.push(` idFields: [${pkCols.map((c) => esc(c)).join(", ")}],`);
1271
+ } else {
1272
+ out.push(` idFields: [${idCols.map((c) => esc(c)).join(", ")}],`);
1273
+ }
1274
+ const ufEntries = [];
1275
+ const ufKeys = /* @__PURE__ */ new Set();
1276
+ const addUnique = /* @__PURE__ */ __name((cols) => {
1277
+ const key = cols.join("_");
1278
+ if (ufKeys.has(key)) return;
1279
+ ufKeys.add(key);
1280
+ if (cols.length === 1) {
1281
+ ufEntries.push(`${key}: { type: ${esc(fieldByName.get(key)?.type || "String")} }`);
1282
+ } else {
1283
+ const inner = cols.map((c) => `${c}: { type: ${esc(fieldByName.get(c)?.type || "String")} }`).join(", ");
1284
+ ufEntries.push(`${key}: { ${inner} }`);
1285
+ }
1286
+ }, "addUnique");
1287
+ if (idCols.length > 0) {
1288
+ addUnique(idCols);
1289
+ } else if (cfg.primaryKeys.length > 0) {
1290
+ const pkCols = cfg.primaryKeys[0].columns.map((c) => t.sqlToJsKey.get(c.name) || c.name);
1291
+ addUnique(pkCols);
1292
+ }
1293
+ for (const uc of cfg.uniqueConstraints) {
1294
+ addUnique(uc.columns.map((c) => t.sqlToJsKey.get(c.name) || c.name));
1295
+ }
1296
+ for (const f of fields) {
1297
+ if (f.unique) addUnique([
1298
+ f.name
1299
+ ]);
1300
+ }
1301
+ out.push(` uniqueFields: { ${ufEntries.join(", ")} }`);
1302
+ out.push(` },`);
1303
+ return out;
1304
+ }
1305
+ __name(emitModelBlock, "emitModelBlock");
1306
+ function emitViewModelBlock(v, enumMap, fieldToTypeDef) {
1307
+ const out = [];
1308
+ const fields = [];
1309
+ const fieldByName = /* @__PURE__ */ new Map();
1310
+ for (const [jsKey, col] of v.columns) {
1311
+ const field = mapColumn(jsKey, col, enumMap);
1312
+ if (field.sqlName === "$hash") {
1313
+ field.isGenerated = true;
1314
+ field.name = "hash";
1315
+ }
1316
+ const typedField = applyTypeDefOverride(field, fieldToTypeDef?.get(`${v.sqlName}.${jsKey}`));
1317
+ fields.push(typedField);
1318
+ fieldByName.set(typedField.name, typedField);
1319
+ }
1320
+ out.push(` ${v.modelName}: {`);
1321
+ out.push(` name: ${esc(v.modelName)},`);
1322
+ out.push(` isView: true,`);
1323
+ out.push(` fields: {`);
1324
+ for (const field of fields) {
1325
+ const block = emitFieldBlock(field);
1326
+ out.push(` ${field.name}: ${block},`);
1327
+ }
1328
+ out.push(` },`);
1329
+ const modelAttrs = [];
1330
+ modelAttrs.push(`{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(v.sqlName)}) }] }`);
1331
+ out.push(` attributes: [${modelAttrs.join(", ")}],`);
1332
+ const idCols = [];
1333
+ for (const [jsKey, col] of v.columns) {
1334
+ if (col.primary) {
1335
+ const name = jsKey === "$hash" ? "hash" : jsKey;
1336
+ idCols.push(name);
1337
+ }
1338
+ }
1339
+ if (idCols.length === 0 && fields.length > 0) {
1340
+ idCols.push(fields[0].name);
1341
+ }
1342
+ out.push(` idFields: [${idCols.map((c) => esc(c)).join(", ")}],`);
1343
+ const ufEntries = [];
1344
+ if (idCols.length > 0) {
1345
+ const key = idCols.join("_");
1346
+ if (idCols.length === 1) {
1347
+ ufEntries.push(`${key}: { type: ${esc(fieldByName.get(key)?.type || "String")} }`);
1348
+ } else {
1349
+ const inner = idCols.map((c) => `${c}: { type: ${esc(fieldByName.get(c)?.type || "String")} }`).join(", ");
1350
+ ufEntries.push(`${key}: { ${inner} }`);
1351
+ }
1352
+ }
1353
+ for (const f of fields) {
1354
+ if (f.unique && !idCols.includes(f.name)) {
1355
+ const key = f.name;
1356
+ ufEntries.push(`${key}: { type: ${esc(f.type)} }`);
1357
+ }
1358
+ }
1359
+ out.push(` uniqueFields: { ${ufEntries.join(", ")} }`);
1360
+ out.push(` },`);
1361
+ return out;
1362
+ }
1363
+ __name(emitViewModelBlock, "emitViewModelBlock");
1364
+ function emitSchemaTs({ tables, enumMap, modelRelations, inverseRelations, searchDefaults, modelScopes, typeDefs, fieldToTypeDef, views }) {
1365
+ const out = [
1366
+ ...emitGeneratedFileBanner()
1367
+ ];
1368
+ const allEnums = new Map([
1369
+ ...enumMap,
1370
+ ...collectDerivedEnums(tables, enumMap)
1371
+ ]);
1372
+ const hasJsonComputedField = tables.some((table) => table.computedFields.some((field) => field.tsType === "JsonValue"));
1373
+ out.push("");
1374
+ out.push('import { ExpressionUtils, type FieldDefault, type SchemaDef } from "@zenstackhq/schema";');
1375
+ if (hasJsonComputedField) {
1376
+ out.push('import type { JsonValue } from "@zenstackhq/orm";');
1377
+ }
1378
+ out.push("export class SchemaType implements SchemaDef {");
1379
+ out.push(' provider = { type: "postgresql" } as const;');
1380
+ out.push(" models = {");
1381
+ for (const t of tables) {
1382
+ out.push(...emitModelBlock(t, enumMap, modelRelations, inverseRelations, fieldToTypeDef));
1383
+ }
1384
+ if (views) {
1385
+ for (const v of views) {
1386
+ out.push(...emitViewModelBlock(v, enumMap, fieldToTypeDef));
1387
+ }
1388
+ }
1389
+ out.push(" } as const;");
1390
+ if (typeDefs && typeDefs.size > 0) {
1391
+ out.push(emitTypeDefsBlock(typeDefs));
1392
+ }
1393
+ out.push(" enums = {");
1394
+ for (const [, info] of allEnums) {
1395
+ out.push(emitEnumBlock(info) + ",");
1396
+ }
1397
+ out.push(" } as const;");
1398
+ out.push(emitPluginsBlock(modelRelations, searchDefaults, modelScopes ?? {}));
1399
+ out.push("}");
1400
+ out.push("");
1401
+ out.push("export const schema = new SchemaType();");
1402
+ out.push("");
1403
+ return out.join("\n");
1404
+ }
1405
+ __name(emitSchemaTs, "emitSchemaTs");
1406
+ function emitModelsTs(tables, typedJsonFields = []) {
1407
+ const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
1408
+ const out = [
1409
+ ...emitGeneratedFileBanner()
1410
+ ];
1411
+ out.push("");
1412
+ out.push('import type * as $ from "@zenstackhq/orm";');
1413
+ out.push('import type * as Json from "./json";');
1414
+ out.push('import { type SchemaType as Schema } from "./schema";');
1415
+ out.push("");
1416
+ for (const t of tables) {
1417
+ out.push(`export interface ${t.typeName} extends $.ModelResult<Schema, ${esc(t.modelName)}> {}`);
1418
+ out.push(`export namespace ${t.typeName} {`);
1419
+ for (const fieldName of getEntityFieldNames(t)) {
1420
+ const exportName = toPascalCase(fieldName);
1421
+ const jsonAlias = jsonFieldAliases.get(`${t.typeName}.${fieldName}`);
1422
+ if (jsonAlias) {
1423
+ out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
1424
+ } else {
1425
+ out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
1426
+ }
1427
+ }
1428
+ out.push("}");
1429
+ out.push("");
1430
+ }
1431
+ return out.join("\n");
1432
+ }
1433
+ __name(emitModelsTs, "emitModelsTs");
1434
+ function emitViewsTs(views, typedJsonFields = []) {
1435
+ const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
1436
+ const out = [
1437
+ ...emitGeneratedFileBanner()
1438
+ ];
1439
+ out.push("");
1440
+ out.push('import type * as $ from "@zenstackhq/orm";');
1441
+ out.push('import type * as Json from "./json";');
1442
+ out.push('import { type SchemaType as Schema } from "./schema";');
1443
+ out.push("");
1444
+ for (const v of views) {
1445
+ out.push(`export interface ${v.typeName} extends $.ModelResult<Schema, ${esc(v.modelName)}> {}`);
1446
+ out.push(`export namespace ${v.typeName} {`);
1447
+ for (const fieldName of getEntityFieldNames(v)) {
1448
+ const exportName = toPascalCase(fieldName);
1449
+ const jsonAlias = jsonFieldAliases.get(`${v.typeName}.${fieldName}`);
1450
+ if (jsonAlias) {
1451
+ out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
1452
+ } else {
1453
+ out.push(` export type ${exportName} = ${v.typeName}[${esc(fieldName)}];`);
1454
+ }
1455
+ }
1456
+ out.push("}");
1457
+ out.push("");
1458
+ }
1459
+ return out.join("\n");
1460
+ }
1461
+ __name(emitViewsTs, "emitViewsTs");
1462
+ function emitInputTs(tables) {
1463
+ const out = [
1464
+ ...emitGeneratedFileBanner()
1465
+ ];
1466
+ out.push("");
1467
+ out.push('import type * as $ from "@zenstackhq/orm";');
1468
+ out.push('import { type SchemaType as Schema } from "./schema";');
1469
+ out.push("");
1470
+ for (const t of tables) {
1471
+ out.push(`export namespace ${t.typeName} {`);
1472
+ out.push(` export interface FindManyArgs extends $.FindManyArgs<Schema, ${esc(t.modelName)}> {}`);
1473
+ out.push(` export interface FindUniqueArgs extends $.FindUniqueArgs<Schema, ${esc(t.modelName)}> {}`);
1474
+ out.push(` export interface FindFirstArgs extends $.FindFirstArgs<Schema, ${esc(t.modelName)}> {}`);
1475
+ out.push(` export interface ExistsArgs extends $.ExistsArgs<Schema, ${esc(t.modelName)}> {}`);
1476
+ out.push(` export interface CreateArgs extends $.CreateArgs<Schema, ${esc(t.modelName)}> {}`);
1477
+ out.push(` export interface CreateManyArgs extends $.CreateManyArgs<Schema, ${esc(t.modelName)}> {}`);
1478
+ out.push(` export interface CreateManyAndReturnArgs extends $.CreateManyAndReturnArgs<Schema, ${esc(t.modelName)}> {}`);
1479
+ out.push(` export interface UpdateArgs extends $.UpdateArgs<Schema, ${esc(t.modelName)}> {}`);
1480
+ out.push(` export interface UpdateManyArgs extends $.UpdateManyArgs<Schema, ${esc(t.modelName)}> {}`);
1481
+ out.push(` export interface UpdateManyAndReturnArgs extends $.UpdateManyAndReturnArgs<Schema, ${esc(t.modelName)}> {}`);
1482
+ out.push(` export interface UpsertArgs extends $.UpsertArgs<Schema, ${esc(t.modelName)}> {}`);
1483
+ out.push(` export interface DeleteArgs extends $.DeleteArgs<Schema, ${esc(t.modelName)}> {}`);
1484
+ out.push(` export interface DeleteManyArgs extends $.DeleteManyArgs<Schema, ${esc(t.modelName)}> {}`);
1485
+ out.push(` export interface CountArgs extends $.CountArgs<Schema, ${esc(t.modelName)}> {}`);
1486
+ out.push(` export interface AggregateArgs extends $.AggregateArgs<Schema, ${esc(t.modelName)}> {}`);
1487
+ out.push(` export interface GroupByArgs extends $.GroupByArgs<Schema, ${esc(t.modelName)}> {}`);
1488
+ out.push(` export interface WhereInput extends $.WhereInput<Schema, ${esc(t.modelName)}> {}`);
1489
+ out.push(` export interface Select extends $.SelectInput<Schema, ${esc(t.modelName)}> {}`);
1490
+ out.push(` export interface Include extends $.IncludeInput<Schema, ${esc(t.modelName)}> {}`);
1491
+ out.push(` export interface Omit extends $.OmitInput<Schema, ${esc(t.modelName)}> {}`);
1492
+ out.push(` export type GetPayload<Args extends $.SelectIncludeOmit<Schema, ${esc(t.modelName)}, true>, Options extends $.QueryOptions<Schema> = $.QueryOptions<Schema>> = $.SimplifiedPlainResult<Schema, ${esc(t.modelName)}, Args, Options>;`);
1493
+ out.push("}");
1494
+ out.push("");
1495
+ }
1496
+ return out.join("\n");
1497
+ }
1498
+ __name(emitInputTs, "emitInputTs");
1499
+ function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
1500
+ const allEnums = new Map([
1501
+ ...enumMap,
1502
+ ...collectDerivedEnums(tables, enumMap)
1503
+ ]);
1504
+ const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
1505
+ const out = [
1506
+ ...emitGeneratedFileBanner()
1507
+ ];
1508
+ out.push("");
1509
+ out.push('import type * as $ from "@zenstackhq/orm";');
1510
+ out.push('import type * as RawJson from "../../supabase/schema/types";');
1511
+ out.push('import { type SchemaType as Schema } from "./schema";');
1512
+ out.push("");
1513
+ out.push("export namespace Json {");
1514
+ out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields, " "));
1515
+ out.push("}");
1516
+ out.push("");
1517
+ out.push("export namespace JsonRaw {");
1518
+ const jsonRawLines = emitJsonRawNamespaceBlock(typedJsonFields, " ");
1519
+ if (jsonRawLines.length > 0) {
1520
+ out.push(...jsonRawLines);
1521
+ }
1522
+ out.push("}");
1523
+ out.push("");
1524
+ out.push("export namespace Table {");
1525
+ for (const table of tables) {
1526
+ out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " "));
1527
+ out.push("");
1528
+ }
1529
+ out.push("}");
1530
+ out.push("");
1531
+ out.push("export namespace View {");
1532
+ for (const view of views) {
1533
+ out.push(...emitEntityNamespaceBlock(view, view.modelName, jsonFieldAliases, " "));
1534
+ out.push("");
1535
+ }
1536
+ out.push("}");
1537
+ out.push("");
1538
+ out.push("export namespace Input {");
1539
+ for (const table of tables) {
1540
+ out.push(...emitInputNamespaceBlock(table, " "));
1541
+ out.push("");
1542
+ }
1543
+ out.push("}");
1544
+ out.push("");
1545
+ out.push("export namespace ComputedFields {");
1546
+ out.push(" export type All = $.ComputedFieldsOptions<Schema>;");
1547
+ for (const table of tables) {
1548
+ if (table.computedFields.length === 0) continue;
1549
+ out.push(` export type ${table.typeName} = $.ComputedFieldsOptions<Schema>[${esc(table.modelName)}];`);
1550
+ }
1551
+ out.push("}");
1552
+ out.push("");
1553
+ out.push("export namespace Enum {");
1554
+ for (const [, info] of allEnums) {
1555
+ out.push(...emitEnumNamespaceBlock(info, " "));
1556
+ out.push("");
1557
+ }
1558
+ out.push("}");
1559
+ out.push("");
1560
+ return out.join("\n");
1561
+ }
1562
+ __name(emitIndexTs, "emitIndexTs");
1563
+ function emitCompatTs({ tables, views, enumMap, typedJsonFields }) {
1564
+ const out = [
1565
+ ...emitGeneratedFileBanner()
1566
+ ];
1567
+ const jsonAliases = typedJsonFields.map((field) => `${field.entityTypeName}${toPascalCase(field.fieldName)}Json`);
1568
+ const jsonRawAliases = typedJsonFields.filter((field) => field.sourceTypeName).map((field) => `${field.entityTypeName}${toPascalCase(field.fieldName)}JsonRaw`);
1569
+ out.push("");
1570
+ out.push('import type * as $ from "@zenstackhq/orm";');
1571
+ out.push('import * as Db from "./index";');
1572
+ out.push('import type { SchemaType as Schema } from "./schema";');
1573
+ out.push("");
1574
+ out.push("export namespace Models {");
1575
+ for (const table of tables) {
1576
+ out.push(...emitCompatEntityAlias(table, "Table", " "));
1577
+ out.push("");
1578
+ }
1579
+ out.push("}");
1580
+ out.push("");
1581
+ out.push("export namespace Views {");
1582
+ for (const view of views) {
1583
+ out.push(...emitCompatEntityAlias(view, "View", " "));
1584
+ out.push("");
1585
+ }
1586
+ out.push("}");
1587
+ out.push("");
1588
+ out.push("export namespace Input {");
1589
+ for (const table of tables) {
1590
+ out.push(...emitCompatInputAliases(table, " "));
1591
+ out.push("");
1592
+ }
1593
+ out.push("}");
1594
+ out.push("");
1595
+ out.push("export namespace Json {");
1596
+ for (const alias of jsonAliases) {
1597
+ out.push(...emitDeprecatedTypeAlias(alias, `Db.Json.${alias}`, " "));
1598
+ }
1599
+ out.push("}");
1600
+ out.push("");
1601
+ out.push("export namespace JsonRaw {");
1602
+ for (const alias of jsonRawAliases) {
1603
+ out.push(...emitDeprecatedTypeAlias(alias, `Db.JsonRaw.${alias}`, " "));
1604
+ }
1605
+ out.push("}");
1606
+ out.push("");
1607
+ out.push("export namespace Enums {");
1608
+ for (const [, info] of enumMap) {
1609
+ if (!info.mapping) continue;
1610
+ out.push(...emitDeprecatedEnumAliases(info.zenstackName, " "));
1611
+ out.push("");
1612
+ }
1613
+ out.push("}");
1614
+ out.push("");
1615
+ for (const table of tables) {
1616
+ out.push(...emitDeprecatedTypeAlias(table.typeName, `Models.${table.typeName}`));
1617
+ }
1618
+ for (const view of views) {
1619
+ out.push(...emitDeprecatedTypeAlias(view.typeName, `Views.${view.typeName}`));
1620
+ }
1621
+ for (const table of tables) {
1622
+ out.push(...emitCompatInputAliases(table));
1623
+ }
1624
+ for (const alias of jsonAliases) {
1625
+ out.push(...emitDeprecatedTypeAlias(alias, `Json.${alias}`));
1626
+ }
1627
+ for (const alias of jsonRawAliases) {
1628
+ out.push(...emitDeprecatedTypeAlias(alias, `JsonRaw.${alias}`));
1629
+ }
1630
+ for (const [, info] of enumMap) {
1631
+ if (!info.mapping) continue;
1632
+ out.push(...emitDeprecatedEnumAliases(info.zenstackName));
1633
+ out.push("");
1634
+ }
1635
+ return out.join("\n");
1636
+ }
1637
+ __name(emitCompatTs, "emitCompatTs");
1638
+ function emitOrmTypesTs(tables) {
1639
+ const out = [
1640
+ ...emitGeneratedFileBanner()
1641
+ ];
1642
+ out.push("");
1643
+ out.push('import type * as $ from "@zenstackhq/orm";');
1644
+ out.push('import type { SchemaType as Schema } from "./schema";');
1645
+ out.push("");
1646
+ out.push("export type Client = $.ClientContract<Schema>;");
1647
+ out.push("");
1648
+ out.push("export namespace ComputedFields {");
1649
+ out.push(" export type All = $.ComputedFieldsOptions<Schema>;");
1650
+ for (const table of tables) {
1651
+ if (table.computedFields.length === 0) continue;
1652
+ out.push(` export type ${table.typeName} = $.ComputedFieldsOptions<Schema>[${esc(table.modelName)}];`);
1653
+ }
1654
+ out.push("}");
1655
+ out.push("");
1656
+ return out.join("\n");
1657
+ }
1658
+ __name(emitOrmTypesTs, "emitOrmTypesTs");
1659
+ function getEntityFieldNames(entity) {
1660
+ const fieldNames = /* @__PURE__ */ new Set();
1661
+ if ("table" in entity) {
1662
+ for (const jsKey of entity.sqlToJsKey.values()) {
1663
+ fieldNames.add(jsKey === "$hash" ? "hash" : jsKey);
1664
+ }
1665
+ for (const computedField of entity.computedFields) {
1666
+ fieldNames.add(computedField.name);
1667
+ }
1668
+ } else {
1669
+ for (const jsKey of entity.columns.keys()) {
1670
+ fieldNames.add(jsKey === "$hash" ? "hash" : jsKey);
1671
+ }
1672
+ }
1673
+ return [
1674
+ ...fieldNames
1675
+ ];
1676
+ }
1677
+ __name(getEntityFieldNames, "getEntityFieldNames");
1678
+ function createJsonFieldAliasMap(typedJsonFields) {
1679
+ return new Map(typedJsonFields.map((field) => [
1680
+ `${field.entityTypeName}.${field.fieldName}`,
1681
+ `${field.entityTypeName}${toPascalCase(field.fieldName)}Json`
1682
+ ]));
1683
+ }
1684
+ __name(createJsonFieldAliasMap, "createJsonFieldAliasMap");
1685
+ function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent = "") {
1686
+ const out = [];
1687
+ out.push(`${indent}export interface ${entity.typeName} extends $.ModelResult<Schema, ${esc(modelName)}> {}`);
1688
+ out.push(`${indent}export namespace ${entity.typeName} {`);
1689
+ for (const fieldName of getEntityFieldNames(entity)) {
1690
+ const exportName = toPascalCase(fieldName);
1691
+ const jsonAlias = jsonFieldAliases.get(`${entity.typeName}.${fieldName}`);
1692
+ if (jsonAlias) {
1693
+ out.push(`${indent} export interface ${exportName} extends Json.${jsonAlias} {}`);
1694
+ } else {
1695
+ out.push(`${indent} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
1696
+ }
1697
+ }
1698
+ out.push(`${indent}}`);
1699
+ return out;
1700
+ }
1701
+ __name(emitEntityNamespaceBlock, "emitEntityNamespaceBlock");
1702
+ function emitInputNamespaceBlock(table, indent = "") {
1703
+ const out = [];
1704
+ out.push(`${indent}export namespace ${table.typeName} {`);
1705
+ out.push(`${indent} export interface FindManyArgs extends $.FindManyArgs<Schema, ${esc(table.modelName)}> {}`);
1706
+ out.push(`${indent} export interface FindUniqueArgs extends $.FindUniqueArgs<Schema, ${esc(table.modelName)}> {}`);
1707
+ out.push(`${indent} export interface FindFirstArgs extends $.FindFirstArgs<Schema, ${esc(table.modelName)}> {}`);
1708
+ out.push(`${indent} export interface ExistsArgs extends $.ExistsArgs<Schema, ${esc(table.modelName)}> {}`);
1709
+ out.push(`${indent} export interface CreateArgs extends $.CreateArgs<Schema, ${esc(table.modelName)}> {}`);
1710
+ out.push(`${indent} export interface CreateManyArgs extends $.CreateManyArgs<Schema, ${esc(table.modelName)}> {}`);
1711
+ out.push(`${indent} export interface CreateManyAndReturnArgs extends $.CreateManyAndReturnArgs<Schema, ${esc(table.modelName)}> {}`);
1712
+ out.push(`${indent} export interface UpdateArgs extends $.UpdateArgs<Schema, ${esc(table.modelName)}> {}`);
1713
+ out.push(`${indent} export interface UpdateManyArgs extends $.UpdateManyArgs<Schema, ${esc(table.modelName)}> {}`);
1714
+ out.push(`${indent} export interface UpdateManyAndReturnArgs extends $.UpdateManyAndReturnArgs<Schema, ${esc(table.modelName)}> {}`);
1715
+ out.push(`${indent} export interface UpsertArgs extends $.UpsertArgs<Schema, ${esc(table.modelName)}> {}`);
1716
+ out.push(`${indent} export interface DeleteArgs extends $.DeleteArgs<Schema, ${esc(table.modelName)}> {}`);
1717
+ out.push(`${indent} export interface DeleteManyArgs extends $.DeleteManyArgs<Schema, ${esc(table.modelName)}> {}`);
1718
+ out.push(`${indent} export interface CountArgs extends $.CountArgs<Schema, ${esc(table.modelName)}> {}`);
1719
+ out.push(`${indent} export interface AggregateArgs extends $.AggregateArgs<Schema, ${esc(table.modelName)}> {}`);
1720
+ out.push(`${indent} export interface GroupByArgs extends $.GroupByArgs<Schema, ${esc(table.modelName)}> {}`);
1721
+ out.push(`${indent} export interface WhereInput extends $.WhereInput<Schema, ${esc(table.modelName)}> {}`);
1722
+ out.push(`${indent} export interface Select extends $.SelectInput<Schema, ${esc(table.modelName)}> {}`);
1723
+ out.push(`${indent} export interface Include extends $.IncludeInput<Schema, ${esc(table.modelName)}> {}`);
1724
+ out.push(`${indent} export interface Omit extends $.OmitInput<Schema, ${esc(table.modelName)}> {}`);
1725
+ out.push(`${indent} export type GetPayload<Args extends $.SelectIncludeOmit<Schema, ${esc(table.modelName)}, true>, Options extends $.QueryOptions<Schema> = $.QueryOptions<Schema>> = $.SimplifiedPlainResult<Schema, ${esc(table.modelName)}, Args, Options>;`);
1726
+ out.push(`${indent}}`);
1727
+ return out;
1728
+ }
1729
+ __name(emitInputNamespaceBlock, "emitInputNamespaceBlock");
1730
+ function emitEnumNamespaceBlock(info, indent = "") {
1731
+ if (!info.mapping) return [];
1732
+ const out = [];
1733
+ const entries = Object.entries(info.mapping).map(([key, value]) => `${indent} ${key}: ${esc(value)}`).join(",\n");
1734
+ out.push(`${indent}export const ${info.zenstackName} = {`);
1735
+ out.push(entries);
1736
+ out.push(`${indent}} as const;`);
1737
+ out.push(`${indent}export type ${info.zenstackName} = (typeof ${info.zenstackName})[keyof typeof ${info.zenstackName}];`);
1738
+ out.push(`${indent}export type ${info.zenstackName}Key = ${Object.keys(info.mapping).map((key) => esc(key)).join(" | ")};`);
1739
+ out.push(`${indent}export const ${info.zenstackName}Values = Object.values(${info.zenstackName});`);
1740
+ out.push(`${indent}export const ${info.zenstackName}Keys = Object.keys(${info.zenstackName}) as ${info.zenstackName}Key[];`);
1741
+ return out;
1742
+ }
1743
+ __name(emitEnumNamespaceBlock, "emitEnumNamespaceBlock");
1744
+ function emitDeprecatedTypeAlias(name, target, indent = "") {
1745
+ return [
1746
+ `${indent}/** @deprecated Use ${target} instead. */`,
1747
+ `${indent}export type ${name} = ${target};`
1748
+ ];
1749
+ }
1750
+ __name(emitDeprecatedTypeAlias, "emitDeprecatedTypeAlias");
1751
+ function emitDeprecatedValueAlias(name, target, indent = "") {
1752
+ return [
1753
+ `${indent}/** @deprecated Use ${target} instead. */`,
1754
+ `${indent}export const ${name} = ${target};`
1755
+ ];
1756
+ }
1757
+ __name(emitDeprecatedValueAlias, "emitDeprecatedValueAlias");
1758
+ function emitDeprecatedEnumAliases(enumName, indent = "") {
1759
+ return [
1760
+ ...emitDeprecatedValueAlias(enumName, `Db.Enum.${enumName}`, indent),
1761
+ ...emitDeprecatedTypeAlias(enumName, `Db.Enum.${enumName}`, indent),
1762
+ ...emitDeprecatedTypeAlias(`${enumName}Key`, `Db.Enum.${enumName}Key`, indent),
1763
+ ...emitDeprecatedValueAlias(`${enumName}Values`, `Db.Enum.${enumName}Values`, indent),
1764
+ ...emitDeprecatedValueAlias(`${enumName}Keys`, `Db.Enum.${enumName}Keys`, indent)
1765
+ ];
1766
+ }
1767
+ __name(emitDeprecatedEnumAliases, "emitDeprecatedEnumAliases");
1768
+ function emitCompatEntityAlias(entity, namespace, indent = "") {
1769
+ const target = `Db.${namespace}.${entity.typeName}`;
1770
+ const out = [
1771
+ `${indent}/** @deprecated Use ${target} instead. */`
1772
+ ];
1773
+ const legacyFields = [
1774
+ ...entity.sqlToJsKey.entries()
1775
+ ].map(([sqlName, jsName]) => ({
1776
+ sqlName,
1777
+ fieldName: jsName === "$hash" ? "hash" : jsName
1778
+ })).filter(({ sqlName, fieldName }) => sqlName !== "$hash" && sqlName !== fieldName);
1779
+ if (legacyFields.length === 0) {
1780
+ out.push(`${indent}export type ${entity.typeName} = ${target};`);
1781
+ return out;
1782
+ }
1783
+ out.push(`${indent}export type ${entity.typeName} = ${target} & {`);
1784
+ for (const { sqlName, fieldName } of legacyFields) {
1785
+ out.push(`${indent} /** @deprecated Use ${fieldName} instead. */`);
1786
+ out.push(`${indent} ${esc(sqlName)}: ${target}[${esc(fieldName)}];`);
1787
+ }
1788
+ out.push(`${indent}};`);
1789
+ return out;
1790
+ }
1791
+ __name(emitCompatEntityAlias, "emitCompatEntityAlias");
1792
+ function emitCompatInputAliases(table, indent = "") {
1793
+ const target = `Db.Input.${table.typeName}`;
1794
+ return [
1795
+ ...emitDeprecatedTypeAlias(`${table.typeName}FindManyArgs`, `${target}.FindManyArgs`, indent),
1796
+ ...emitDeprecatedTypeAlias(`${table.typeName}FindUniqueArgs`, `${target}.FindUniqueArgs`, indent),
1797
+ ...emitDeprecatedTypeAlias(`${table.typeName}FindFirstArgs`, `${target}.FindFirstArgs`, indent),
1798
+ ...emitDeprecatedTypeAlias(`${table.typeName}ExistsArgs`, `${target}.ExistsArgs`, indent),
1799
+ ...emitDeprecatedTypeAlias(`${table.typeName}CreateArgs`, `${target}.CreateArgs`, indent),
1800
+ ...emitDeprecatedTypeAlias(`${table.typeName}CreateManyArgs`, `${target}.CreateManyArgs`, indent),
1801
+ ...emitDeprecatedTypeAlias(`${table.typeName}CreateManyAndReturnArgs`, `${target}.CreateManyAndReturnArgs`, indent),
1802
+ ...emitDeprecatedTypeAlias(`${table.typeName}UpdateArgs`, `${target}.UpdateArgs`, indent),
1803
+ ...emitDeprecatedTypeAlias(`${table.typeName}UpdateManyArgs`, `${target}.UpdateManyArgs`, indent),
1804
+ ...emitDeprecatedTypeAlias(`${table.typeName}UpdateManyAndReturnArgs`, `${target}.UpdateManyAndReturnArgs`, indent),
1805
+ ...emitDeprecatedTypeAlias(`${table.typeName}UpsertArgs`, `${target}.UpsertArgs`, indent),
1806
+ ...emitDeprecatedTypeAlias(`${table.typeName}DeleteArgs`, `${target}.DeleteArgs`, indent),
1807
+ ...emitDeprecatedTypeAlias(`${table.typeName}DeleteManyArgs`, `${target}.DeleteManyArgs`, indent),
1808
+ ...emitDeprecatedTypeAlias(`${table.typeName}CountArgs`, `${target}.CountArgs`, indent),
1809
+ ...emitDeprecatedTypeAlias(`${table.typeName}AggregateArgs`, `${target}.AggregateArgs`, indent),
1810
+ ...emitDeprecatedTypeAlias(`${table.typeName}GroupByArgs`, `${target}.GroupByArgs`, indent),
1811
+ ...emitDeprecatedTypeAlias(`${table.typeName}WhereInput`, `${target}.WhereInput`, indent),
1812
+ ...emitDeprecatedTypeAlias(`${table.typeName}Select`, `${target}.Select`, indent),
1813
+ ...emitDeprecatedTypeAlias(`${table.typeName}Include`, `${target}.Include`, indent),
1814
+ ...emitDeprecatedTypeAlias(`${table.typeName}Omit`, `${target}.Omit`, indent),
1815
+ `${indent}/** @deprecated Use ${target}.GetPayload instead. */`,
1816
+ `${indent}export type ${table.typeName}GetPayload<Args extends $.SelectIncludeOmit<Schema, ${esc(table.modelName)}, true>, Options extends $.QueryOptions<Schema> = $.QueryOptions<Schema>> = ${target}.GetPayload<Args, Options>;`
1817
+ ];
1818
+ }
1819
+ __name(emitCompatInputAliases, "emitCompatInputAliases");
1820
+ function emitEnumsTs(enumMap) {
1821
+ const out = [
1822
+ ...emitGeneratedFileBanner()
1823
+ ];
1824
+ out.push("");
1825
+ for (const [, info] of enumMap) {
1826
+ if (!info.mapping) continue;
1827
+ const n = info.zenstackName;
1828
+ const entries = Object.entries(info.mapping).map(([k, v]) => ` ${k}: ${esc(v)}`).join(",\n");
1829
+ out.push(`export const ${n} = {
1830
+ ${entries},
1831
+ } as const;`);
1832
+ out.push(`export type ${n} = (typeof ${n})[keyof typeof ${n}];`);
1833
+ out.push(`export type ${n}Key = ${Object.keys(info.mapping).map((k) => esc(k)).join(" | ")};`);
1834
+ out.push(`export const ${n}Values = Object.values(${n});`);
1835
+ out.push(`export const ${n}Keys = Object.keys(${n}) as ${n}Key[];`);
1836
+ out.push("");
1837
+ }
1838
+ return out.join("\n");
1839
+ }
1840
+ __name(emitEnumsTs, "emitEnumsTs");
1841
+
1842
+ // src/codegen/relations.ts
1843
+ function makePhysicalRelationSignature(fields, references, array) {
1844
+ return [
1845
+ array ? "many" : "one",
1846
+ fields?.join(",") || "",
1847
+ references?.join(",") || ""
1848
+ ].join("|");
1849
+ }
1850
+ __name(makePhysicalRelationSignature, "makePhysicalRelationSignature");
1851
+ function makePhysicalFKSignature(sourceTable, targetTable, fk) {
1852
+ return makePhysicalRelationSignature(fk.localColumns.map((column) => sourceTable.sqlToJsKey.get(column) || column), fk.foreignColumns.map((column) => targetTable.sqlToJsKey.get(column) || column), false);
1853
+ }
1854
+ __name(makePhysicalFKSignature, "makePhysicalFKSignature");
1855
+ function assertNoRelationFieldCollision(table, sourceRelations, fieldName) {
1856
+ if (table.jsKeySet.has(fieldName)) {
1857
+ throw new Error(`Relation "${table.exportName}.${fieldName}" collides with an existing field. Rename the FK key in tables.ts or choose a different relation key in relations.ts.`);
1858
+ }
1859
+ if (sourceRelations.some((relation) => relation.fieldName === fieldName)) {
1860
+ throw new Error(`Relation "${table.exportName}.${fieldName}" collides with another relation field. Use a unique key in relations.ts.`);
1861
+ }
1862
+ }
1863
+ __name(assertNoRelationFieldCollision, "assertNoRelationFieldCollision");
1864
+ function unfoldThroughPath(path2, relationNames = []) {
1865
+ const entries = Object.entries(path2);
1866
+ if (entries.length !== 1) {
1867
+ throw new Error("Through relation path must contain exactly one relation per level.");
1868
+ }
1869
+ const entry = entries[0];
1870
+ const [relationName, next] = entry;
1871
+ relationNames.push(relationName);
1872
+ if (next === true) {
1873
+ return relationNames;
1874
+ }
1875
+ return unfoldThroughPath(next, relationNames);
1876
+ }
1877
+ __name(unfoldThroughPath, "unfoldThroughPath");
1878
+ function unfoldRelationSelector(relation) {
1879
+ const entries = Object.entries(relation);
1880
+ if (entries.length !== 1) {
1881
+ throw new Error("Filtered relation selector must contain exactly one relation.");
1882
+ }
1883
+ const entry = entries[0];
1884
+ const [relationName, enabled] = entry;
1885
+ if (enabled !== true) {
1886
+ throw new Error("Filtered relation selector values must be true.");
1887
+ }
1888
+ return relationName;
1889
+ }
1890
+ __name(unfoldRelationSelector, "unfoldRelationSelector");
1891
+ function buildRelations(tables, relationTargets = {}, filteredRelations = {}, throughRelations = {}, fkRelations = {}) {
1892
+ const baseTables = tables.filter((table) => !table.derivedFrom);
1893
+ const sqlToBaseTable = /* @__PURE__ */ new Map();
1894
+ const modelToTable = /* @__PURE__ */ new Map();
1895
+ for (const table of tables) {
1896
+ modelToTable.set(table.modelName, table);
1897
+ if (!table.derivedFrom) {
1898
+ sqlToBaseTable.set(table.sqlName, table);
1899
+ }
1900
+ }
1901
+ const fksByTable = /* @__PURE__ */ new Map();
1902
+ for (const table of baseTables) {
1903
+ fksByTable.set(table.modelName, extractFKs(table.table));
1904
+ }
1905
+ const modelRelations = /* @__PURE__ */ new Map();
1906
+ for (const table of tables) {
1907
+ modelRelations.set(table.modelName, []);
1908
+ }
1909
+ for (const [modelName, relations] of Object.entries(fkRelations)) {
1910
+ const sourceTable = modelToTable.get(modelName);
1911
+ if (!sourceTable) continue;
1912
+ const sourceRelations = modelRelations.get(modelName) || [];
1913
+ const colByName = new Map(sourceTable.cfg.columns.map((column) => [
1914
+ column.name,
1915
+ column
1916
+ ]));
1917
+ for (const [relName, fkInfo] of Object.entries(relations)) {
1918
+ const targetTable = modelToTable.get(fkInfo.targetExportName) ?? sqlToBaseTable.get(fkInfo.targetExportName);
1919
+ if (!targetTable) continue;
1920
+ const targetModelOverride = relationTargets[modelName]?.[relName];
1921
+ const fieldName = relName;
1922
+ assertNoRelationFieldCollision(sourceTable, sourceRelations, fieldName);
1923
+ let hasDefaultFK = false;
1924
+ let isOptional = false;
1925
+ const jsToSql = new Map([
1926
+ ...sourceTable.sqlToJsKey.entries()
1927
+ ].map(([sql2, js]) => [
1928
+ js,
1929
+ sql2
1930
+ ]));
1931
+ for (const jsKey of fkInfo.fields) {
1932
+ const sqlName = jsToSql.get(jsKey) ?? jsKey;
1933
+ const localColumn = colByName.get(sqlName);
1934
+ if (localColumn?.hasDefault) hasDefaultFK = true;
1935
+ if (!localColumn?.notNull) isOptional = true;
1936
+ }
1937
+ sourceRelations.push({
1938
+ fieldName,
1939
+ targetModel: targetModelOverride ?? fkInfo.targetExportName,
1940
+ optional: isOptional,
1941
+ array: false,
1942
+ relationName: fkInfo.relationName,
1943
+ fields: fkInfo.fields,
1944
+ references: fkInfo.references,
1945
+ hasDefault: hasDefaultFK
1946
+ });
1947
+ }
1948
+ modelRelations.set(modelName, sourceRelations);
1949
+ }
1950
+ for (const table of tables) {
1951
+ if (!table.derivedFrom) continue;
1952
+ const baseRelations = modelRelations.get(table.derivedFrom) || [];
1953
+ modelRelations.set(table.modelName, baseRelations.map((relation) => ({
1954
+ ...relation,
1955
+ _opposite: void 0
1956
+ })));
1957
+ }
1958
+ for (const table of baseTables) {
1959
+ const sourceRelations = modelRelations.get(table.modelName) || [];
1960
+ const relationsByTarget = /* @__PURE__ */ new Map();
1961
+ for (const relation of sourceRelations) {
1962
+ if (relation.kind && relation.kind !== "normal") continue;
1963
+ const group = relationsByTarget.get(relation.targetModel) || [];
1964
+ group.push(relation);
1965
+ relationsByTarget.set(relation.targetModel, group);
1966
+ }
1967
+ for (const [targetModel, relations] of relationsByTarget) {
1968
+ if (relations.length <= 1) continue;
1969
+ for (const relation of relations) {
1970
+ if (relation.relationName) continue;
1971
+ throw new Error(`Ambiguous relations for "${table.exportName}" -> "${targetModel}". Add explicit relationName values in supabase/schema/relations.ts.`);
1972
+ }
1973
+ }
1974
+ const declaredFKRelations = new Set(sourceRelations.filter((relation) => !relation.array && relation.fields && relation.references).map((relation) => makePhysicalRelationSignature(relation.fields, relation.references, relation.array)));
1975
+ for (const fk of fksByTable.get(table.modelName) || []) {
1976
+ const targetTable = sqlToBaseTable.get(fk.foreignTable);
1977
+ if (!targetTable) continue;
1978
+ const signature = makePhysicalFKSignature(table, targetTable, fk);
1979
+ if (declaredFKRelations.has(signature)) continue;
1980
+ throw new Error(`Missing explicit relation in supabase/schema/relations.ts for "${table.exportName}": [${fk.localColumns.join(", ")}] -> ${targetTable.exportName}([${fk.foreignColumns.join(", ")}]).`);
1981
+ }
1982
+ }
1983
+ const forwardByTarget = /* @__PURE__ */ new Map();
1984
+ for (const sourceTable of tables) {
1985
+ for (const relation of modelRelations.get(sourceTable.modelName) || []) {
1986
+ if (relation.kind && relation.kind !== "normal") continue;
1987
+ const group = forwardByTarget.get(relation.targetModel) || [];
1988
+ group.push({
1989
+ source: sourceTable,
1990
+ relation
1991
+ });
1992
+ forwardByTarget.set(relation.targetModel, group);
1993
+ }
1994
+ }
1995
+ const inverseRelations = /* @__PURE__ */ new Map();
1996
+ for (const table of tables) {
1997
+ const inverses = [];
1998
+ const existingNames = new Set((modelRelations.get(table.modelName) || []).map((relation) => relation.fieldName));
1999
+ for (const { source: sourceTable, relation } of forwardByTarget.get(table.modelName) || []) {
2000
+ const sourceExport = sourceTable.exportName || sourceTable.sqlName;
2001
+ let fieldName = sourceExport.endsWith("s") ? sourceExport : sourceExport + "s";
2002
+ if (existingNames.has(fieldName)) {
2003
+ const explicitRelation = (modelRelations.get(table.modelName) || []).find((item) => item.fieldName === fieldName);
2004
+ if (explicitRelation) {
2005
+ relation._opposite = fieldName;
2006
+ continue;
2007
+ }
2008
+ const mainField = relation.fields?.find((field) => field !== APP_SLUG_JS) || relation.fields?.[0] || relation.fieldName;
2009
+ fieldName = sourceExport + "By" + capitalize(mainField);
2010
+ }
2011
+ inverses.push({
2012
+ fieldName,
2013
+ targetModel: sourceTable.modelName,
2014
+ optional: false,
2015
+ array: true,
2016
+ relationName: relation.relationName,
2017
+ fields: null,
2018
+ references: null,
2019
+ hasDefault: false,
2020
+ _opposite: relation.fieldName
2021
+ });
2022
+ relation._opposite = fieldName;
2023
+ existingNames.add(fieldName);
2024
+ }
2025
+ inverseRelations.set(table.modelName, inverses);
2026
+ }
2027
+ const getAvailableRelations = /* @__PURE__ */ __name((modelName) => [
2028
+ ...modelRelations.get(modelName) || [],
2029
+ ...inverseRelations.get(modelName) || []
2030
+ ], "getAvailableRelations");
2031
+ for (const [modelName, declarations] of Object.entries(filteredRelations)) {
2032
+ const sourceTable = modelToTable.get(modelName);
2033
+ if (!sourceTable) {
2034
+ throw new Error(`Filtered relations declared for unknown model "${modelName}".`);
2035
+ }
2036
+ const sourceRelations = modelRelations.get(modelName) || [];
2037
+ const availableRelations = getAvailableRelations(modelName);
2038
+ for (const [fieldName, declaration] of Object.entries(declarations)) {
2039
+ const sourceRelation = unfoldRelationSelector(declaration.relation);
2040
+ const existingFk = sourceRelations.find((r) => r.fieldName === fieldName);
2041
+ if (existingFk && sourceRelation === fieldName) {
2042
+ existingFk.kind = "filtered";
2043
+ existingFk.sourceRelation = sourceRelation;
2044
+ existingFk.where = declaration.where;
2045
+ existingFk.single = declaration.single;
2046
+ continue;
2047
+ }
2048
+ assertNoRelationFieldCollision(sourceTable, [
2049
+ ...sourceRelations,
2050
+ ...inverseRelations.get(modelName) || []
2051
+ ], fieldName);
2052
+ const baseRelation = availableRelations.find((relation) => relation.fieldName === sourceRelation);
2053
+ if (!baseRelation) {
2054
+ throw new Error(`Filtered relation "${modelName}.${fieldName}" references unknown relation "${sourceRelation}".`);
2055
+ }
2056
+ sourceRelations.push({
2057
+ fieldName,
2058
+ targetModel: baseRelation.targetModel,
2059
+ optional: declaration.single ? true : baseRelation.optional,
2060
+ array: declaration.single ? false : baseRelation.array,
2061
+ relationName: null,
2062
+ fields: baseRelation.fields,
2063
+ references: baseRelation.references,
2064
+ hasDefault: false,
2065
+ kind: "filtered",
2066
+ sourceRelation,
2067
+ where: declaration.where,
2068
+ single: declaration.single
2069
+ });
2070
+ }
2071
+ modelRelations.set(modelName, sourceRelations);
2072
+ }
2073
+ for (const [modelName, declarations] of Object.entries(throughRelations)) {
2074
+ const sourceTable = modelToTable.get(modelName);
2075
+ if (!sourceTable) {
2076
+ throw new Error(`Through relations declared for unknown model "${modelName}".`);
2077
+ }
2078
+ const sourceRelations = modelRelations.get(modelName) || [];
2079
+ for (const [fieldName, declaration] of Object.entries(declarations)) {
2080
+ assertNoRelationFieldCollision(sourceTable, [
2081
+ ...sourceRelations,
2082
+ ...inverseRelations.get(modelName) || []
2083
+ ], fieldName);
2084
+ const throughPath = unfoldThroughPath(declaration.path);
2085
+ let currentModel = modelName;
2086
+ let targetRelation;
2087
+ let isMany = false;
2088
+ for (const relationName of throughPath) {
2089
+ const relation = getAvailableRelations(currentModel).find((item) => item.fieldName === relationName);
2090
+ if (!relation) {
2091
+ throw new Error(`Through relation "${modelName}.${fieldName}" references unknown relation "${currentModel}.${relationName}".`);
2092
+ }
2093
+ targetRelation = relation;
2094
+ currentModel = relation.targetModel;
2095
+ if (relation.array) {
2096
+ isMany = true;
2097
+ }
2098
+ }
2099
+ if (!targetRelation) {
2100
+ throw new Error(`Through relation "${modelName}.${fieldName}" is missing a target path.`);
2101
+ }
2102
+ sourceRelations.push({
2103
+ fieldName,
2104
+ targetModel: targetRelation.targetModel,
2105
+ optional: !isMany,
2106
+ array: isMany,
2107
+ relationName: null,
2108
+ fields: null,
2109
+ references: null,
2110
+ hasDefault: false,
2111
+ kind: "through",
2112
+ throughPath
2113
+ });
2114
+ }
2115
+ modelRelations.set(modelName, sourceRelations);
2116
+ }
2117
+ return {
2118
+ modelRelations,
2119
+ inverseRelations
2120
+ };
2121
+ }
2122
+ __name(buildRelations, "buildRelations");
2123
+
2124
+ // src/codegen/resolve.ts
2125
+ import { getTableConfig as getTableConfig2 } from "drizzle-orm/pg-core";
2126
+ var COMPUTED_TYPE_MAP = {
2127
+ json: {
2128
+ type: "Json",
2129
+ tsType: "JsonValue"
2130
+ },
2131
+ string: {
2132
+ type: "String",
2133
+ tsType: "string"
2134
+ },
2135
+ text: {
2136
+ type: "String",
2137
+ tsType: "string"
2138
+ },
2139
+ int: {
2140
+ type: "Int",
2141
+ tsType: "number"
2142
+ },
2143
+ float: {
2144
+ type: "Float",
2145
+ tsType: "number"
2146
+ },
2147
+ bool: {
2148
+ type: "Boolean",
2149
+ tsType: "boolean"
2150
+ },
2151
+ boolean: {
2152
+ type: "Boolean",
2153
+ tsType: "boolean"
2154
+ },
2155
+ dateTime: {
2156
+ type: "DateTime",
2157
+ tsType: "Date"
2158
+ }
2159
+ };
2160
+ function resolveColumn(tables, column) {
2161
+ for (const table of Object.values(tables)) {
2162
+ for (const key of Object.keys(table)) {
2163
+ if (table[key] === column) return {
2164
+ table,
2165
+ jsKey: key
2166
+ };
2167
+ }
2168
+ }
2169
+ const sqlName = column.name;
2170
+ for (const table of Object.values(tables)) {
2171
+ for (const key of Object.keys(table)) {
2172
+ const col = table[key];
2173
+ if (col && typeof col === "object" && "name" in col && col.name === sqlName) {
2174
+ return {
2175
+ table,
2176
+ jsKey: key
2177
+ };
2178
+ }
2179
+ }
2180
+ }
2181
+ return void 0;
2182
+ }
2183
+ __name(resolveColumn, "resolveColumn");
2184
+ function findExportNameForTable(tables, target) {
2185
+ for (const [exportName, table] of Object.entries(tables)) {
2186
+ if (table === target) return exportName;
2187
+ }
2188
+ const targetSqlName = getTableConfig2(target).name;
2189
+ for (const [exportName, table] of Object.entries(tables)) {
2190
+ if (getTableConfig2(table).name === targetSqlName) return exportName;
2191
+ }
2192
+ throw new Error(`Could not find export name for table "${targetSqlName}"`);
2193
+ }
2194
+ __name(findExportNameForTable, "findExportNameForTable");
2195
+ function sqlNameToExportName(tables, sqlName) {
2196
+ for (const [exportName, table] of Object.entries(tables)) {
2197
+ if (getTableConfig2(table).name === sqlName) return exportName;
2198
+ }
2199
+ throw new Error(`No table export found with SQL name "${sqlName}"`);
2200
+ }
2201
+ __name(sqlNameToExportName, "sqlNameToExportName");
2202
+ function findDerivedNameForDescriptor(derived, descriptor) {
2203
+ for (const [name, desc] of Object.entries(derived)) {
2204
+ if (desc === descriptor) return name;
2205
+ }
2206
+ throw new Error(`Could not find derived model name for descriptor with base "${descriptor.baseName}"`);
2207
+ }
2208
+ __name(findDerivedNameForDescriptor, "findDerivedNameForDescriptor");
2209
+ function convertSearchFields(tables, fields) {
2210
+ const result = {};
2211
+ for (const field of fields) {
2212
+ if ("name" in field && typeof field.name === "string") {
2213
+ const resolved = resolveColumn(tables, field);
2214
+ if (!resolved) throw new Error(`Could not resolve column "${field.name}"`);
2215
+ result[resolved.jsKey] = true;
2216
+ } else {
2217
+ for (const [relation, nested] of Object.entries(field)) {
2218
+ result[relation] = convertSearchFields(tables, nested);
2219
+ }
2220
+ }
2221
+ }
2222
+ return result;
2223
+ }
2224
+ __name(convertSearchFields, "convertSearchFields");
2225
+ function convertSearchProfile(tables, _modelTable, profile) {
2226
+ return {
2227
+ fields: convertSearchFields(tables, profile.fields)
2228
+ };
2229
+ }
2230
+ __name(convertSearchProfile, "convertSearchProfile");
2231
+ function resolveConfig(config) {
2232
+ const { tables, derived, models } = config;
2233
+ const globalDefaultWhere = config.default?.where;
2234
+ const computedFields = {};
2235
+ const derivedModels = {};
2236
+ const filteredRelations = {};
2237
+ const searchDefaults = {};
2238
+ const throughRelations = {};
2239
+ const relationTargets = {};
2240
+ const modelScopes = {};
2241
+ const derivedFieldsMap = {};
2242
+ const validationSchemas = {};
2243
+ const fkRelations = {};
2244
+ for (const [derivedName, desc] of Object.entries(derived)) {
2245
+ const baseExportName = sqlNameToExportName(tables, desc.baseName);
2246
+ if (!derivedModels[baseExportName]) {
2247
+ derivedModels[baseExportName] = {};
2248
+ }
2249
+ derivedModels[baseExportName][derivedName] = {
2250
+ where: desc.where,
2251
+ ...desc.narrow ? {
2252
+ narrow: desc.narrow
2253
+ } : {}
2254
+ };
2255
+ }
2256
+ for (const [modelName, modelConfig] of Object.entries(models)) {
2257
+ if (modelConfig.computed && typeof modelConfig.computed !== "function") {
2258
+ const resolvedComputed = {};
2259
+ for (const [fieldName, decl] of Object.entries(modelConfig.computed)) {
2260
+ if (typeof decl === "function") {
2261
+ resolvedComputed[fieldName] = COMPUTED_TYPE_MAP["json"];
2262
+ } else {
2263
+ const declObj = decl;
2264
+ const typeKey = declObj.type?.toLowerCase() ?? "json";
2265
+ resolvedComputed[fieldName] = COMPUTED_TYPE_MAP[typeKey] ?? COMPUTED_TYPE_MAP["json"];
2266
+ }
2267
+ }
2268
+ computedFields[modelName] = resolvedComputed;
2269
+ }
2270
+ if (modelConfig.relations) {
2271
+ for (const [relName, rel] of Object.entries(modelConfig.relations)) {
2272
+ if (rel.kind === "one") {
2273
+ const oneRel = rel;
2274
+ const targetTable = "__brand" in oneRel.target ? oneRel.target.base : oneRel.target;
2275
+ const targetExportName = findExportNameForTable(tables, targetTable);
2276
+ const resolvedFields = oneRel.fields.map((col) => {
2277
+ const resolved = resolveColumn(tables, col);
2278
+ return resolved?.jsKey ?? col.name;
2279
+ });
2280
+ const resolvedRefs = oneRel.references.map((col) => {
2281
+ const resolved = resolveColumn(tables, col);
2282
+ return resolved?.jsKey ?? col.name;
2283
+ });
2284
+ if (oneRel.where) {
2285
+ if (!fkRelations[modelName]) {
2286
+ fkRelations[modelName] = {};
2287
+ }
2288
+ fkRelations[modelName][relName] = {
2289
+ targetExportName,
2290
+ fields: resolvedFields,
2291
+ references: resolvedRefs,
2292
+ relationName: oneRel.relationName ?? null
2293
+ };
2294
+ if (!filteredRelations[modelName]) {
2295
+ filteredRelations[modelName] = {};
2296
+ }
2297
+ filteredRelations[modelName][relName] = {
2298
+ relation: {
2299
+ [relName]: true
2300
+ },
2301
+ where: oneRel.where,
2302
+ single: true
2303
+ };
2304
+ } else {
2305
+ if (!fkRelations[modelName]) {
2306
+ fkRelations[modelName] = {};
2307
+ }
2308
+ fkRelations[modelName][relName] = {
2309
+ targetExportName,
2310
+ fields: resolvedFields,
2311
+ references: resolvedRefs,
2312
+ relationName: oneRel.relationName ?? null
2313
+ };
2314
+ }
2315
+ if ("__brand" in oneRel.target && oneRel.target.__brand === "derived") {
2316
+ const descriptor = oneRel.target;
2317
+ const derivedName = findDerivedNameForDescriptor(derived, descriptor);
2318
+ const baseExportName = sqlNameToExportName(tables, descriptor.baseName);
2319
+ if (!derivedModels[baseExportName]) {
2320
+ derivedModels[baseExportName] = {};
2321
+ }
2322
+ const derivedEntry = derivedModels[baseExportName][derivedName];
2323
+ if (derivedEntry) {
2324
+ if (!derivedEntry.relations) {
2325
+ derivedEntry.relations = {};
2326
+ }
2327
+ if (!derivedEntry.relations[modelName]) {
2328
+ derivedEntry.relations[modelName] = {};
2329
+ }
2330
+ derivedEntry.relations[modelName][relName] = true;
2331
+ }
2332
+ if (!relationTargets[modelName]) {
2333
+ relationTargets[modelName] = {};
2334
+ }
2335
+ relationTargets[modelName][relName] = derivedName;
2336
+ }
2337
+ } else if (rel.kind === "many") {
2338
+ const manyRel = rel;
2339
+ const targetExportName = findExportNameForTable(tables, manyRel.target);
2340
+ if (!filteredRelations[modelName]) {
2341
+ filteredRelations[modelName] = {};
2342
+ }
2343
+ filteredRelations[modelName][relName] = {
2344
+ relation: {
2345
+ [targetExportName]: true
2346
+ },
2347
+ ...manyRel.where ? {
2348
+ where: manyRel.where
2349
+ } : {},
2350
+ ...manyRel.single ? {
2351
+ single: true
2352
+ } : {}
2353
+ };
2354
+ } else if (rel.kind === "through") {
2355
+ const throughRel = rel;
2356
+ if (!throughRelations[modelName]) {
2357
+ throughRelations[modelName] = {};
2358
+ }
2359
+ throughRelations[modelName][relName] = {
2360
+ path: throughRel.path
2361
+ };
2362
+ }
2363
+ }
2364
+ }
2365
+ if (modelConfig.defaultWhere) {
2366
+ modelScopes[modelName] = modelConfig.defaultWhere;
2367
+ } else if (globalDefaultWhere) {
2368
+ modelScopes[modelName] = globalDefaultWhere;
2369
+ }
2370
+ if (modelConfig.derived) {
2371
+ derivedFieldsMap[modelName] = modelConfig.derived;
2372
+ }
2373
+ if (modelConfig.validate) {
2374
+ validationSchemas[modelName] = modelConfig.validate;
2375
+ }
2376
+ if (modelConfig.search) {
2377
+ const modelSearchDefaults = {};
2378
+ for (const [profileName, profile] of Object.entries(modelConfig.search)) {
2379
+ modelSearchDefaults[profileName] = convertSearchProfile(tables, modelConfig.table, profile);
2380
+ }
2381
+ searchDefaults[modelName] = modelSearchDefaults;
2382
+ }
2383
+ }
2384
+ return {
2385
+ defaultWhere: globalDefaultWhere,
2386
+ computedFields,
2387
+ derivedModels,
2388
+ filteredRelations,
2389
+ searchDefaults,
2390
+ throughRelations,
2391
+ relationTargets,
2392
+ modelScopes,
2393
+ derivedFields: derivedFieldsMap,
2394
+ validationSchemas,
2395
+ fkRelations
2396
+ };
2397
+ }
2398
+ __name(resolveConfig, "resolveConfig");
2399
+
2400
+ // src/cli.ts
2401
+ async function runCodegen(config) {
2402
+ const resolved = resolveConfig(config);
2403
+ const outDir = path.resolve(process.cwd(), config.schema.output);
2404
+ const enumMap = discoverEnums(config.schema.enums);
2405
+ const tables = discoverTables(config.tables, resolved.computedFields, resolved.derivedModels);
2406
+ const views = config.schema.views ? discoverViews(config.schema.views) : [];
2407
+ const typesPath = config.schema.types ? typeof config.schema.types === "string" ? config.schema.types : void 0 : void 0;
2408
+ let typeDefs = /* @__PURE__ */ new Map();
2409
+ let fieldToTypeDef = /* @__PURE__ */ new Map();
2410
+ let typedJsonFields = [];
2411
+ if (typesPath) {
2412
+ const artifacts = buildTypeDefs(typesPath, tables, views.length > 0 ? views : void 0, enumMap);
2413
+ typeDefs = artifacts.typeDefs;
2414
+ fieldToTypeDef = artifacts.fieldToTypeDef;
2415
+ typedJsonFields = artifacts.typedJsonFields;
2416
+ }
2417
+ const { modelRelations, inverseRelations } = buildRelations(tables, resolved.relationTargets, resolved.filteredRelations, resolved.throughRelations, resolved.fkRelations);
2418
+ const schemaContent = emitSchemaTs({
2419
+ tables,
2420
+ enumMap,
2421
+ modelRelations,
2422
+ inverseRelations,
2423
+ searchDefaults: resolved.searchDefaults,
2424
+ modelScopes: resolved.modelScopes,
2425
+ typeDefs,
2426
+ fieldToTypeDef,
2427
+ views
2428
+ });
2429
+ const indexContent = emitIndexTs({
2430
+ tables,
2431
+ views,
2432
+ enumMap,
2433
+ typeDefs,
2434
+ typedJsonFields
2435
+ });
2436
+ const compatContent = emitCompatTs({
2437
+ tables,
2438
+ views,
2439
+ enumMap,
2440
+ typedJsonFields
2441
+ });
2442
+ const ormTypesContent = emitOrmTypesTs(tables);
2443
+ const modelsContent = emitModelsTs(tables, typedJsonFields);
2444
+ const inputContent = emitInputTs(tables);
2445
+ const enumsContent = emitEnumsTs(enumMap);
2446
+ const jsonContent = emitJsonTs(typeDefs, typedJsonFields);
2447
+ const viewsContent = views.length > 0 ? emitViewsTs(views, typedJsonFields) : null;
2448
+ const jsonRawContent = typedJsonFields.some((f) => f.sourceTypeName) ? emitJsonRawTs(typedJsonFields) : null;
2449
+ fs3.mkdirSync(outDir, {
2450
+ recursive: true
2451
+ });
2452
+ writeFileIfChanged(path.join(outDir, "schema.ts"), schemaContent);
2453
+ writeFileIfChanged(path.join(outDir, "index.ts"), indexContent);
2454
+ writeFileIfChanged(path.join(outDir, "compat.ts"), compatContent);
2455
+ writeFileIfChanged(path.join(outDir, "orm-types.ts"), ormTypesContent);
2456
+ writeFileIfChanged(path.join(outDir, "models.ts"), modelsContent);
2457
+ writeFileIfChanged(path.join(outDir, "input.ts"), inputContent);
2458
+ writeFileIfChanged(path.join(outDir, "enums.ts"), enumsContent);
2459
+ writeFileIfChanged(path.join(outDir, "json.ts"), jsonContent);
2460
+ if (viewsContent) {
2461
+ writeFileIfChanged(path.join(outDir, "views.ts"), viewsContent);
2462
+ }
2463
+ if (jsonRawContent) {
2464
+ writeFileIfChanged(path.join(outDir, "json-raw.ts"), jsonRawContent);
2465
+ }
2466
+ console.log(`Generated schema files in ${outDir}`);
2467
+ }
2468
+ __name(runCodegen, "runCodegen");
2469
+ async function main() {
2470
+ const subcommand = process.argv[2];
2471
+ const filePath = process.argv[3];
2472
+ if (subcommand !== "generate" || !filePath) {
2473
+ console.error("Usage: zenstack-custom generate <config-file>");
2474
+ process.exit(1);
2475
+ }
2476
+ const resolvedPath = path.resolve(process.cwd(), filePath);
2477
+ const mod = await import(resolvedPath);
2478
+ const config = mod.default ?? mod;
2479
+ await runCodegen(config);
2480
+ }
2481
+ __name(main, "main");
2482
+ var isCLI = process.argv[1]?.endsWith("cli.js") || process.argv[1]?.endsWith("cli.cjs");
2483
+ if (isCLI) {
2484
+ main().catch((err) => {
2485
+ console.error(err);
2486
+ process.exit(1);
2487
+ });
2488
+ }
2489
+ export {
2490
+ runCodegen
2491
+ };
2492
+ //# sourceMappingURL=cli.js.map