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