@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/index.cjs
ADDED
|
@@ -0,0 +1,3705 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var src_exports = {};
|
|
33
|
+
__export(src_exports, {
|
|
34
|
+
APP_SLUG_JS: () => APP_SLUG_JS,
|
|
35
|
+
APP_SLUG_SQL: () => APP_SLUG_SQL,
|
|
36
|
+
CustomObject: () => CustomObject,
|
|
37
|
+
ENUM_MAP: () => ENUM_MAP,
|
|
38
|
+
FALSE: () => FALSE,
|
|
39
|
+
GENERATED_FILE_BANNER: () => GENERATED_FILE_BANNER,
|
|
40
|
+
PgCronJob: () => PgCronJob,
|
|
41
|
+
PgExtension: () => PgExtension,
|
|
42
|
+
PgFunction: () => PgFunction,
|
|
43
|
+
PgTrigger: () => PgTrigger,
|
|
44
|
+
TriggerFunction: () => TriggerFunction,
|
|
45
|
+
adaptToLegacyConfig: () => adaptToLegacyConfig,
|
|
46
|
+
appSlugForeignKey: () => appSlugForeignKey,
|
|
47
|
+
assertNoTypedColumnOverrides: () => assertNoTypedColumnOverrides,
|
|
48
|
+
auditColumns: () => auditColumns,
|
|
49
|
+
buildRelations: () => buildRelations,
|
|
50
|
+
buildTypeDefs: () => buildTypeDefs,
|
|
51
|
+
capitalize: () => capitalize,
|
|
52
|
+
categorizeChanges: () => categorizeChanges,
|
|
53
|
+
cleanMeta: () => cleanMeta,
|
|
54
|
+
colAppSlug: () => colAppSlug,
|
|
55
|
+
colCreatedAt: () => colCreatedAt,
|
|
56
|
+
colDeletedAt: () => colDeletedAt,
|
|
57
|
+
colId: () => colId,
|
|
58
|
+
colNumeric: () => colNumeric,
|
|
59
|
+
colTimestamp: () => colTimestamp,
|
|
60
|
+
colUpdatedAt: () => colUpdatedAt,
|
|
61
|
+
collectCustomObjects: () => collectCustomObjects,
|
|
62
|
+
computeHash: () => computeHash,
|
|
63
|
+
currentAppSlug: () => currentAppSlug,
|
|
64
|
+
currentUser: () => currentUser,
|
|
65
|
+
custom: () => custom,
|
|
66
|
+
defaultPolicy: () => defaultPolicy,
|
|
67
|
+
defineConfig: () => defineConfig,
|
|
68
|
+
defineModels: () => defineModels,
|
|
69
|
+
derived: () => derived,
|
|
70
|
+
discoverEnums: () => discoverEnums,
|
|
71
|
+
discoverTables: () => discoverTables,
|
|
72
|
+
discoverViews: () => discoverViews,
|
|
73
|
+
drop: () => drop,
|
|
74
|
+
emitCompatTs: () => emitCompatTs,
|
|
75
|
+
emitEnumBlock: () => emitEnumBlock,
|
|
76
|
+
emitEnumsTs: () => emitEnumsTs,
|
|
77
|
+
emitFieldBlock: () => emitFieldBlock,
|
|
78
|
+
emitGeneratedFileBanner: () => emitGeneratedFileBanner,
|
|
79
|
+
emitIndexTs: () => emitIndexTs,
|
|
80
|
+
emitInputTs: () => emitInputTs,
|
|
81
|
+
emitJsonNamespaceBlock: () => emitJsonNamespaceBlock,
|
|
82
|
+
emitJsonRawNamespaceBlock: () => emitJsonRawNamespaceBlock,
|
|
83
|
+
emitJsonRawTs: () => emitJsonRawTs,
|
|
84
|
+
emitJsonTs: () => emitJsonTs,
|
|
85
|
+
emitModelsTs: () => emitModelsTs,
|
|
86
|
+
emitOrmTypesTs: () => emitOrmTypesTs,
|
|
87
|
+
emitRelationField: () => emitRelationField,
|
|
88
|
+
emitSchemaTs: () => emitSchemaTs,
|
|
89
|
+
emitTypeDefsBlock: () => emitTypeDefsBlock,
|
|
90
|
+
emitViewsTs: () => emitViewsTs,
|
|
91
|
+
esc: () => esc,
|
|
92
|
+
extend: () => extend,
|
|
93
|
+
extractFKs: () => extractFKs,
|
|
94
|
+
fixOrder: () => fixOrder,
|
|
95
|
+
formatChangeSummary: () => formatChangeSummary,
|
|
96
|
+
formatVerboseOutput: () => formatVerboseOutput,
|
|
97
|
+
generate: () => generate,
|
|
98
|
+
generateDropSQL: () => generateDropSQL,
|
|
99
|
+
getDrizzleTableName: () => getDrizzleTableName,
|
|
100
|
+
getLatestSnapshotPath: () => getLatestSnapshotPath,
|
|
101
|
+
hasAppSlug: () => hasAppSlug,
|
|
102
|
+
hasBypassEnabled: () => hasBypassEnabled,
|
|
103
|
+
loadSchemaModules: () => loadSchemaModules,
|
|
104
|
+
many: () => many,
|
|
105
|
+
mapColumn: () => mapColumn,
|
|
106
|
+
model: () => model,
|
|
107
|
+
one: () => one,
|
|
108
|
+
packToSgz: () => packToSgz,
|
|
109
|
+
parseFlags: () => parseFlags,
|
|
110
|
+
pgCron: () => pgCron,
|
|
111
|
+
pgExtension: () => pgExtension,
|
|
112
|
+
pgFunction: () => pgFunction,
|
|
113
|
+
pgOrmEnum: () => pgOrmEnum,
|
|
114
|
+
pgTrigger: () => pgTrigger,
|
|
115
|
+
pgTypes: () => pgTypes,
|
|
116
|
+
readJournal: () => readJournal,
|
|
117
|
+
readSnapshotCustomObjects: () => readSnapshotCustomObjects,
|
|
118
|
+
serializeCustomObject: () => serializeCustomObject,
|
|
119
|
+
simpleDiff: () => simpleDiff,
|
|
120
|
+
syncMeta: () => syncMeta,
|
|
121
|
+
through: () => through,
|
|
122
|
+
toPascalCase: () => toPascalCase,
|
|
123
|
+
toPgEnum: () => toPgEnum,
|
|
124
|
+
uncapitalize: () => uncapitalize,
|
|
125
|
+
unpackFromSgz: () => unpackFromSgz,
|
|
126
|
+
validateOrder: () => validateOrder,
|
|
127
|
+
validateTimestamps: () => validateTimestamps,
|
|
128
|
+
writeFileIfChanged: () => writeFileIfChanged,
|
|
129
|
+
writeSnapshotCustomObjects: () => writeSnapshotCustomObjects
|
|
130
|
+
});
|
|
131
|
+
module.exports = __toCommonJS(src_exports);
|
|
132
|
+
|
|
133
|
+
// src/codegen/config.ts
|
|
134
|
+
function defineConfig(tables, config) {
|
|
135
|
+
const derived2 = config.derived ?? {};
|
|
136
|
+
const orm = {
|
|
137
|
+
...tables
|
|
138
|
+
};
|
|
139
|
+
for (const [name, desc] of Object.entries(derived2)) {
|
|
140
|
+
if (name in tables) {
|
|
141
|
+
throw new Error(`Derived model "${name}" collides with existing table name.`);
|
|
142
|
+
}
|
|
143
|
+
orm[name] = desc;
|
|
144
|
+
}
|
|
145
|
+
const models = config.models(orm);
|
|
146
|
+
return {
|
|
147
|
+
tables,
|
|
148
|
+
schema: config.schema,
|
|
149
|
+
default: config.default,
|
|
150
|
+
derived: derived2,
|
|
151
|
+
models
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
__name(defineConfig, "defineConfig");
|
|
155
|
+
|
|
156
|
+
// src/codegen/dsl/extend.ts
|
|
157
|
+
var import_pg_core = require("drizzle-orm/pg-core");
|
|
158
|
+
function inferNarrow(where) {
|
|
159
|
+
const narrow = {};
|
|
160
|
+
let hasNarrow = false;
|
|
161
|
+
for (const [field, condition] of Object.entries(where)) {
|
|
162
|
+
if (condition && typeof condition === "object" && !Array.isArray(condition)) {
|
|
163
|
+
const cond = condition;
|
|
164
|
+
if ("in" in cond && Array.isArray(cond["in"])) {
|
|
165
|
+
narrow[field] = cond["in"];
|
|
166
|
+
hasNarrow = true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return hasNarrow ? narrow : null;
|
|
171
|
+
}
|
|
172
|
+
__name(inferNarrow, "inferNarrow");
|
|
173
|
+
function derived(base, opts) {
|
|
174
|
+
const cfg = (0, import_pg_core.getTableConfig)(base);
|
|
175
|
+
const descriptor = {
|
|
176
|
+
__brand: "derived",
|
|
177
|
+
base,
|
|
178
|
+
where: opts.where,
|
|
179
|
+
narrow: opts.narrow ?? inferNarrow(opts.where),
|
|
180
|
+
baseName: cfg.name
|
|
181
|
+
};
|
|
182
|
+
return new Proxy(descriptor, {
|
|
183
|
+
get(target, prop, receiver) {
|
|
184
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
185
|
+
return Reflect.get(base, prop);
|
|
186
|
+
},
|
|
187
|
+
has(target, prop) {
|
|
188
|
+
return prop in target || prop in base;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
__name(derived, "derived");
|
|
193
|
+
function extend(tables, derivedModels) {
|
|
194
|
+
for (const key of Object.keys(derivedModels)) {
|
|
195
|
+
if (key in tables) {
|
|
196
|
+
throw new Error(`Derived model "${key}" collides with existing table name. Choose a different name.`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const extended = {
|
|
200
|
+
tables: {
|
|
201
|
+
...tables
|
|
202
|
+
},
|
|
203
|
+
derived: {
|
|
204
|
+
...derivedModels
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
const schemaProps = Object.assign({}, tables, derivedModels, {
|
|
208
|
+
__extended: extended
|
|
209
|
+
});
|
|
210
|
+
const defineModelsFn = /* @__PURE__ */ __name((globalConfig, models) => ({
|
|
211
|
+
schema: extended,
|
|
212
|
+
global: globalConfig,
|
|
213
|
+
models
|
|
214
|
+
}), "defineModelsFn");
|
|
215
|
+
return Object.assign(defineModelsFn, schemaProps);
|
|
216
|
+
}
|
|
217
|
+
__name(extend, "extend");
|
|
218
|
+
|
|
219
|
+
// src/codegen/dsl/relations.ts
|
|
220
|
+
function one(target, opts) {
|
|
221
|
+
return {
|
|
222
|
+
kind: "one",
|
|
223
|
+
target,
|
|
224
|
+
fields: opts.fields,
|
|
225
|
+
references: opts.references,
|
|
226
|
+
...opts.where ? {
|
|
227
|
+
where: opts.where
|
|
228
|
+
} : {},
|
|
229
|
+
...opts.relationName ? {
|
|
230
|
+
relationName: opts.relationName
|
|
231
|
+
} : {}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
__name(one, "one");
|
|
235
|
+
function many(target, opts) {
|
|
236
|
+
return {
|
|
237
|
+
kind: "many",
|
|
238
|
+
target,
|
|
239
|
+
...opts?.where ? {
|
|
240
|
+
where: opts.where
|
|
241
|
+
} : {},
|
|
242
|
+
...opts?.single ? {
|
|
243
|
+
single: true
|
|
244
|
+
} : {}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
__name(many, "many");
|
|
248
|
+
function through(path) {
|
|
249
|
+
return {
|
|
250
|
+
kind: "through",
|
|
251
|
+
path
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
__name(through, "through");
|
|
255
|
+
|
|
256
|
+
// src/codegen/dsl/model.ts
|
|
257
|
+
function model(table, opts) {
|
|
258
|
+
const helpers = {
|
|
259
|
+
one,
|
|
260
|
+
many,
|
|
261
|
+
through
|
|
262
|
+
};
|
|
263
|
+
return {
|
|
264
|
+
table,
|
|
265
|
+
relations: opts.relations?.(helpers),
|
|
266
|
+
computed: opts.computed,
|
|
267
|
+
search: opts.search,
|
|
268
|
+
defaultWhere: opts.defaultWhere,
|
|
269
|
+
derived: opts.derived,
|
|
270
|
+
validate: opts.validate
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
__name(model, "model");
|
|
274
|
+
function defineModels(extendedSchema, globalConfig, models) {
|
|
275
|
+
return {
|
|
276
|
+
schema: extendedSchema.__extended,
|
|
277
|
+
global: globalConfig,
|
|
278
|
+
models
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
__name(defineModels, "defineModels");
|
|
282
|
+
|
|
283
|
+
// src/codegen/dsl/adapter.ts
|
|
284
|
+
var import_pg_core2 = require("drizzle-orm/pg-core");
|
|
285
|
+
var COMPUTED_TYPE_MAP = {
|
|
286
|
+
json: {
|
|
287
|
+
type: "Json",
|
|
288
|
+
tsType: "JsonValue"
|
|
289
|
+
},
|
|
290
|
+
string: {
|
|
291
|
+
type: "String",
|
|
292
|
+
tsType: "string"
|
|
293
|
+
},
|
|
294
|
+
text: {
|
|
295
|
+
type: "String",
|
|
296
|
+
tsType: "string"
|
|
297
|
+
},
|
|
298
|
+
int: {
|
|
299
|
+
type: "Int",
|
|
300
|
+
tsType: "number"
|
|
301
|
+
},
|
|
302
|
+
float: {
|
|
303
|
+
type: "Float",
|
|
304
|
+
tsType: "number"
|
|
305
|
+
},
|
|
306
|
+
bool: {
|
|
307
|
+
type: "Boolean",
|
|
308
|
+
tsType: "boolean"
|
|
309
|
+
},
|
|
310
|
+
boolean: {
|
|
311
|
+
type: "Boolean",
|
|
312
|
+
tsType: "boolean"
|
|
313
|
+
},
|
|
314
|
+
dateTime: {
|
|
315
|
+
type: "DateTime",
|
|
316
|
+
tsType: "Date"
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function resolveColumn(tables, column) {
|
|
320
|
+
for (const table of Object.values(tables)) {
|
|
321
|
+
for (const key of Object.keys(table)) {
|
|
322
|
+
if (table[key] === column) return {
|
|
323
|
+
table,
|
|
324
|
+
jsKey: key
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const sqlName = column.name;
|
|
329
|
+
for (const table of Object.values(tables)) {
|
|
330
|
+
for (const key of Object.keys(table)) {
|
|
331
|
+
const col = table[key];
|
|
332
|
+
if (col && typeof col === "object" && "name" in col && col.name === sqlName) {
|
|
333
|
+
return {
|
|
334
|
+
table,
|
|
335
|
+
jsKey: key
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return void 0;
|
|
341
|
+
}
|
|
342
|
+
__name(resolveColumn, "resolveColumn");
|
|
343
|
+
function findExportNameForTable(tables, target) {
|
|
344
|
+
for (const [exportName, table] of Object.entries(tables)) {
|
|
345
|
+
if (table === target) return exportName;
|
|
346
|
+
}
|
|
347
|
+
const targetSqlName = (0, import_pg_core2.getTableConfig)(target).name;
|
|
348
|
+
for (const [exportName, table] of Object.entries(tables)) {
|
|
349
|
+
if ((0, import_pg_core2.getTableConfig)(table).name === targetSqlName) return exportName;
|
|
350
|
+
}
|
|
351
|
+
throw new Error(`Could not find export name for table "${targetSqlName}"`);
|
|
352
|
+
}
|
|
353
|
+
__name(findExportNameForTable, "findExportNameForTable");
|
|
354
|
+
function sqlNameToExportName(tables, sqlName) {
|
|
355
|
+
for (const [exportName, table] of Object.entries(tables)) {
|
|
356
|
+
if ((0, import_pg_core2.getTableConfig)(table).name === sqlName) return exportName;
|
|
357
|
+
}
|
|
358
|
+
throw new Error(`No table export found with SQL name "${sqlName}"`);
|
|
359
|
+
}
|
|
360
|
+
__name(sqlNameToExportName, "sqlNameToExportName");
|
|
361
|
+
function findDerivedNameForDescriptor(derived2, descriptor) {
|
|
362
|
+
for (const [name, desc] of Object.entries(derived2)) {
|
|
363
|
+
if (desc === descriptor) return name;
|
|
364
|
+
}
|
|
365
|
+
throw new Error(`Could not find derived model name for descriptor with base "${descriptor.baseName}"`);
|
|
366
|
+
}
|
|
367
|
+
__name(findDerivedNameForDescriptor, "findDerivedNameForDescriptor");
|
|
368
|
+
function convertSearchFields(tables, fields) {
|
|
369
|
+
const result = {};
|
|
370
|
+
for (const field of fields) {
|
|
371
|
+
if ("name" in field && typeof field.name === "string") {
|
|
372
|
+
const resolved = resolveColumn(tables, field);
|
|
373
|
+
if (!resolved) throw new Error(`Could not resolve column "${field.name}"`);
|
|
374
|
+
result[resolved.jsKey] = true;
|
|
375
|
+
} else {
|
|
376
|
+
for (const [relation, nested] of Object.entries(field)) {
|
|
377
|
+
result[relation] = convertSearchFields(tables, nested);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
__name(convertSearchFields, "convertSearchFields");
|
|
384
|
+
function convertSearchProfile(tables, _modelTable, profile) {
|
|
385
|
+
return {
|
|
386
|
+
fields: convertSearchFields(tables, profile.fields)
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
__name(convertSearchProfile, "convertSearchProfile");
|
|
390
|
+
function adaptToLegacyConfig(output) {
|
|
391
|
+
const { schema, models } = output;
|
|
392
|
+
const computedFields = {};
|
|
393
|
+
const computedCallbacks = {};
|
|
394
|
+
const derivedModels = {};
|
|
395
|
+
const filteredRelations = {};
|
|
396
|
+
const searchDefaults = {};
|
|
397
|
+
const throughRelations = {};
|
|
398
|
+
const relationTargets = {};
|
|
399
|
+
const modelScopes = {};
|
|
400
|
+
const derivedFields = {};
|
|
401
|
+
const validationSchemas = {};
|
|
402
|
+
const fkRelations = {};
|
|
403
|
+
for (const [derivedName, desc] of Object.entries(schema.derived)) {
|
|
404
|
+
const baseExportName = sqlNameToExportName(schema.tables, desc.baseName);
|
|
405
|
+
if (!derivedModels[baseExportName]) {
|
|
406
|
+
derivedModels[baseExportName] = {};
|
|
407
|
+
}
|
|
408
|
+
derivedModels[baseExportName][derivedName] = {
|
|
409
|
+
where: desc.where,
|
|
410
|
+
...desc.narrow ? {
|
|
411
|
+
narrow: desc.narrow
|
|
412
|
+
} : {}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
for (const [modelName, config] of Object.entries(models)) {
|
|
416
|
+
if (config.computed && typeof config.computed !== "function") {
|
|
417
|
+
const resolvedComputed = {};
|
|
418
|
+
const callbacks = {};
|
|
419
|
+
for (const [fieldName, decl] of Object.entries(config.computed)) {
|
|
420
|
+
if (typeof decl === "function") {
|
|
421
|
+
resolvedComputed[fieldName] = COMPUTED_TYPE_MAP["json"];
|
|
422
|
+
callbacks[fieldName] = decl;
|
|
423
|
+
} else {
|
|
424
|
+
const declObj = decl;
|
|
425
|
+
const typeKey = declObj.type?.toLowerCase() ?? "json";
|
|
426
|
+
resolvedComputed[fieldName] = COMPUTED_TYPE_MAP[typeKey] ?? COMPUTED_TYPE_MAP["json"];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
computedFields[modelName] = resolvedComputed;
|
|
430
|
+
if (Object.keys(callbacks).length > 0) {
|
|
431
|
+
computedCallbacks[modelName] = callbacks;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (config.relations) {
|
|
435
|
+
for (const [relName, rel] of Object.entries(config.relations)) {
|
|
436
|
+
if (rel.kind === "one") {
|
|
437
|
+
const oneRel = rel;
|
|
438
|
+
const targetTable = "__brand" in oneRel.target ? oneRel.target.base : oneRel.target;
|
|
439
|
+
const targetExportName = findExportNameForTable(schema.tables, targetTable);
|
|
440
|
+
const resolvedFields = oneRel.fields.map((col) => {
|
|
441
|
+
const resolved = resolveColumn(schema.tables, col);
|
|
442
|
+
return resolved?.jsKey ?? col.name;
|
|
443
|
+
});
|
|
444
|
+
const resolvedRefs = oneRel.references.map((col) => {
|
|
445
|
+
const resolved = resolveColumn(schema.tables, col);
|
|
446
|
+
return resolved?.jsKey ?? col.name;
|
|
447
|
+
});
|
|
448
|
+
if (oneRel.where) {
|
|
449
|
+
if (!fkRelations[modelName]) {
|
|
450
|
+
fkRelations[modelName] = {};
|
|
451
|
+
}
|
|
452
|
+
fkRelations[modelName][relName] = {
|
|
453
|
+
targetExportName,
|
|
454
|
+
fields: resolvedFields,
|
|
455
|
+
references: resolvedRefs,
|
|
456
|
+
relationName: oneRel.relationName ?? null
|
|
457
|
+
};
|
|
458
|
+
if (!filteredRelations[modelName]) {
|
|
459
|
+
filteredRelations[modelName] = {};
|
|
460
|
+
}
|
|
461
|
+
filteredRelations[modelName][relName] = {
|
|
462
|
+
relation: {
|
|
463
|
+
[relName]: true
|
|
464
|
+
},
|
|
465
|
+
where: oneRel.where,
|
|
466
|
+
single: true
|
|
467
|
+
};
|
|
468
|
+
} else {
|
|
469
|
+
if (!fkRelations[modelName]) {
|
|
470
|
+
fkRelations[modelName] = {};
|
|
471
|
+
}
|
|
472
|
+
fkRelations[modelName][relName] = {
|
|
473
|
+
targetExportName,
|
|
474
|
+
fields: resolvedFields,
|
|
475
|
+
references: resolvedRefs,
|
|
476
|
+
relationName: oneRel.relationName ?? null
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
if ("__brand" in oneRel.target && oneRel.target.__brand === "derived") {
|
|
480
|
+
const descriptor = oneRel.target;
|
|
481
|
+
const derivedName = findDerivedNameForDescriptor(schema.derived, descriptor);
|
|
482
|
+
const baseExportName = sqlNameToExportName(schema.tables, descriptor.baseName);
|
|
483
|
+
if (!derivedModels[baseExportName]) {
|
|
484
|
+
derivedModels[baseExportName] = {};
|
|
485
|
+
}
|
|
486
|
+
const derivedEntry = derivedModels[baseExportName][derivedName];
|
|
487
|
+
if (derivedEntry) {
|
|
488
|
+
if (!derivedEntry.relations) {
|
|
489
|
+
derivedEntry.relations = {};
|
|
490
|
+
}
|
|
491
|
+
if (!derivedEntry.relations[modelName]) {
|
|
492
|
+
derivedEntry.relations[modelName] = {};
|
|
493
|
+
}
|
|
494
|
+
derivedEntry.relations[modelName][relName] = true;
|
|
495
|
+
}
|
|
496
|
+
if (!relationTargets[modelName]) {
|
|
497
|
+
relationTargets[modelName] = {};
|
|
498
|
+
}
|
|
499
|
+
relationTargets[modelName][relName] = derivedName;
|
|
500
|
+
}
|
|
501
|
+
} else if (rel.kind === "many") {
|
|
502
|
+
const manyRel = rel;
|
|
503
|
+
const targetExportName = findExportNameForTable(schema.tables, manyRel.target);
|
|
504
|
+
if (!filteredRelations[modelName]) {
|
|
505
|
+
filteredRelations[modelName] = {};
|
|
506
|
+
}
|
|
507
|
+
filteredRelations[modelName][relName] = {
|
|
508
|
+
relation: {
|
|
509
|
+
[targetExportName]: true
|
|
510
|
+
},
|
|
511
|
+
...manyRel.where ? {
|
|
512
|
+
where: manyRel.where
|
|
513
|
+
} : {},
|
|
514
|
+
...manyRel.single ? {
|
|
515
|
+
single: true
|
|
516
|
+
} : {}
|
|
517
|
+
};
|
|
518
|
+
} else if (rel.kind === "through") {
|
|
519
|
+
const throughRel = rel;
|
|
520
|
+
if (!throughRelations[modelName]) {
|
|
521
|
+
throughRelations[modelName] = {};
|
|
522
|
+
}
|
|
523
|
+
throughRelations[modelName][relName] = {
|
|
524
|
+
path: throughRel.path
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (config.defaultWhere) {
|
|
530
|
+
modelScopes[modelName] = config.defaultWhere;
|
|
531
|
+
} else if (output.global.defaultWhere) {
|
|
532
|
+
modelScopes[modelName] = output.global.defaultWhere;
|
|
533
|
+
}
|
|
534
|
+
if (config.derived) {
|
|
535
|
+
derivedFields[modelName] = config.derived;
|
|
536
|
+
}
|
|
537
|
+
if (config.validate) {
|
|
538
|
+
validationSchemas[modelName] = config.validate;
|
|
539
|
+
}
|
|
540
|
+
if (config.search) {
|
|
541
|
+
const modelSearchDefaults = {};
|
|
542
|
+
for (const [profileName, profile] of Object.entries(config.search)) {
|
|
543
|
+
modelSearchDefaults[profileName] = convertSearchProfile(schema.tables, config.table, profile);
|
|
544
|
+
}
|
|
545
|
+
searchDefaults[modelName] = modelSearchDefaults;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return {
|
|
549
|
+
computedFields,
|
|
550
|
+
computedCallbacks,
|
|
551
|
+
derivedModels,
|
|
552
|
+
filteredRelations,
|
|
553
|
+
searchDefaults,
|
|
554
|
+
throughRelations,
|
|
555
|
+
relationTargets,
|
|
556
|
+
modelScopes,
|
|
557
|
+
derivedFields,
|
|
558
|
+
validationSchemas,
|
|
559
|
+
fkRelations
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
__name(adaptToLegacyConfig, "adaptToLegacyConfig");
|
|
563
|
+
|
|
564
|
+
// src/codegen/utils.ts
|
|
565
|
+
var fs = __toESM(require("fs"), 1);
|
|
566
|
+
var APP_SLUG_SQL = "app_slug";
|
|
567
|
+
var APP_SLUG_JS = "appSlug";
|
|
568
|
+
var GENERATED_FILE_BANNER = [
|
|
569
|
+
"//////////////////////////////////////////////////////////////////////////////////////////////",
|
|
570
|
+
"// DO NOT MODIFY THIS FILE //",
|
|
571
|
+
"// Generated by scripts/zen from Drizzle schema. //",
|
|
572
|
+
"//////////////////////////////////////////////////////////////////////////////////////////////",
|
|
573
|
+
"",
|
|
574
|
+
"/* eslint-disable */"
|
|
575
|
+
];
|
|
576
|
+
function emitGeneratedFileBanner() {
|
|
577
|
+
return [
|
|
578
|
+
...GENERATED_FILE_BANNER
|
|
579
|
+
];
|
|
580
|
+
}
|
|
581
|
+
__name(emitGeneratedFileBanner, "emitGeneratedFileBanner");
|
|
582
|
+
function capitalize(s) {
|
|
583
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
584
|
+
}
|
|
585
|
+
__name(capitalize, "capitalize");
|
|
586
|
+
function toPascalCase(s) {
|
|
587
|
+
return s.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[_\-\s]+/).filter(Boolean).map(capitalize).join("");
|
|
588
|
+
}
|
|
589
|
+
__name(toPascalCase, "toPascalCase");
|
|
590
|
+
function uncapitalize(s) {
|
|
591
|
+
return s.charAt(0).toLowerCase() + s.slice(1);
|
|
592
|
+
}
|
|
593
|
+
__name(uncapitalize, "uncapitalize");
|
|
594
|
+
function esc(s) {
|
|
595
|
+
return JSON.stringify(s);
|
|
596
|
+
}
|
|
597
|
+
__name(esc, "esc");
|
|
598
|
+
function getDrizzleTableName(table) {
|
|
599
|
+
return table[Symbol.for("drizzle:Name")];
|
|
600
|
+
}
|
|
601
|
+
__name(getDrizzleTableName, "getDrizzleTableName");
|
|
602
|
+
function writeFileIfChanged(filePath, content) {
|
|
603
|
+
if (fs.existsSync(filePath) && fs.readFileSync(filePath, "utf-8") === content) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
__name(writeFileIfChanged, "writeFileIfChanged");
|
|
610
|
+
|
|
611
|
+
// src/codegen/columns.ts
|
|
612
|
+
function mapColumn(jsKey, col, enumMap) {
|
|
613
|
+
const sqlName = col.name;
|
|
614
|
+
const colType = col.columnType;
|
|
615
|
+
const notNull = col.notNull;
|
|
616
|
+
const hasDefault = col.hasDefault;
|
|
617
|
+
const isPrimary = col.primary;
|
|
618
|
+
const isUnique = col.isUnique;
|
|
619
|
+
const generated = col.generated;
|
|
620
|
+
const isArray = colType === "PgArray";
|
|
621
|
+
let type = "String";
|
|
622
|
+
const dbAttrs = [];
|
|
623
|
+
let enumPgName = null;
|
|
624
|
+
let isJsonColumn = false;
|
|
625
|
+
let actualColType = colType;
|
|
626
|
+
let actualCol = col;
|
|
627
|
+
if (isArray && col.baseColumn) {
|
|
628
|
+
actualCol = col.baseColumn;
|
|
629
|
+
actualColType = actualCol.columnType;
|
|
630
|
+
}
|
|
631
|
+
switch (actualColType) {
|
|
632
|
+
case "PgUUID":
|
|
633
|
+
type = "String";
|
|
634
|
+
dbAttrs.push("@db.Uuid");
|
|
635
|
+
break;
|
|
636
|
+
case "PgText":
|
|
637
|
+
type = "String";
|
|
638
|
+
break;
|
|
639
|
+
case "PgVarchar": {
|
|
640
|
+
type = "String";
|
|
641
|
+
const len = actualCol.length;
|
|
642
|
+
if (len) dbAttrs.push(`@db.VarChar(${len})`);
|
|
643
|
+
else dbAttrs.push("@db.VarChar");
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
case "PgBoolean":
|
|
647
|
+
type = "Boolean";
|
|
648
|
+
break;
|
|
649
|
+
case "PgInteger":
|
|
650
|
+
type = "Int";
|
|
651
|
+
break;
|
|
652
|
+
case "PgBigInt53":
|
|
653
|
+
type = "BigInt";
|
|
654
|
+
break;
|
|
655
|
+
case "PgSerial":
|
|
656
|
+
type = "Int";
|
|
657
|
+
break;
|
|
658
|
+
case "PgReal":
|
|
659
|
+
type = "Float";
|
|
660
|
+
dbAttrs.push("@db.Real");
|
|
661
|
+
break;
|
|
662
|
+
case "PgDoublePrecision":
|
|
663
|
+
type = "Float";
|
|
664
|
+
dbAttrs.push("@db.DoublePrecision");
|
|
665
|
+
break;
|
|
666
|
+
case "PgTimestamp": {
|
|
667
|
+
type = "DateTime";
|
|
668
|
+
const wtz = actualCol.withTimezone ?? actualCol.config?.withTimezone;
|
|
669
|
+
if (wtz) dbAttrs.push("@db.Timestamptz(6)");
|
|
670
|
+
else dbAttrs.push("@db.Timestamp(6)");
|
|
671
|
+
break;
|
|
672
|
+
}
|
|
673
|
+
case "PgDate":
|
|
674
|
+
case "PgDateString":
|
|
675
|
+
type = "DateTime";
|
|
676
|
+
dbAttrs.push("@db.Date");
|
|
677
|
+
break;
|
|
678
|
+
case "PgJsonb":
|
|
679
|
+
type = "Json";
|
|
680
|
+
isJsonColumn = true;
|
|
681
|
+
dbAttrs.push("@db.JsonB");
|
|
682
|
+
break;
|
|
683
|
+
case "PgJson":
|
|
684
|
+
type = "Json";
|
|
685
|
+
isJsonColumn = true;
|
|
686
|
+
dbAttrs.push("@db.Json");
|
|
687
|
+
break;
|
|
688
|
+
case "PgEnumColumn": {
|
|
689
|
+
if (isArray) {
|
|
690
|
+
type = "String";
|
|
691
|
+
} else {
|
|
692
|
+
const eName = actualCol.enum?.enumName;
|
|
693
|
+
if (eName && enumMap.has(eName)) {
|
|
694
|
+
type = enumMap.get(eName).zenstackName;
|
|
695
|
+
enumPgName = eName;
|
|
696
|
+
} else {
|
|
697
|
+
type = "String";
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
case "PgCustomColumn": {
|
|
703
|
+
const sqlType = actualCol.sqlName || actualCol.config?.dataType;
|
|
704
|
+
if (sqlType === "json") {
|
|
705
|
+
type = "Json";
|
|
706
|
+
isJsonColumn = true;
|
|
707
|
+
dbAttrs.push("@db.Json");
|
|
708
|
+
} else if (sqlType === "jsonb") {
|
|
709
|
+
type = "Json";
|
|
710
|
+
isJsonColumn = true;
|
|
711
|
+
dbAttrs.push("@db.JsonB");
|
|
712
|
+
} else if (sqlType === "numeric") {
|
|
713
|
+
type = "Decimal";
|
|
714
|
+
} else type = "String";
|
|
715
|
+
break;
|
|
716
|
+
}
|
|
717
|
+
case "PgNumeric":
|
|
718
|
+
type = "Decimal";
|
|
719
|
+
break;
|
|
720
|
+
default:
|
|
721
|
+
console.warn(`Unknown Drizzle column type "${actualColType}" for column "${sqlName}" \u2014 falling back to String`);
|
|
722
|
+
type = "String";
|
|
723
|
+
}
|
|
724
|
+
let defaultExpr = null;
|
|
725
|
+
if (hasDefault) {
|
|
726
|
+
if (isPrimary && actualColType === "PgUUID") {
|
|
727
|
+
defaultExpr = 'ExpressionUtils.call("uuid")';
|
|
728
|
+
} else if (actualColType === "PgBigInt53" && col.generatedIdentity) {
|
|
729
|
+
defaultExpr = 'ExpressionUtils.call("autoincrement")';
|
|
730
|
+
} else if (actualColType === "PgSerial") {
|
|
731
|
+
defaultExpr = 'ExpressionUtils.call("autoincrement")';
|
|
732
|
+
} else if (col.defaultFn) {
|
|
733
|
+
if (type === "DateTime") {
|
|
734
|
+
defaultExpr = 'ExpressionUtils.call("now")';
|
|
735
|
+
} else if (type === "String" && isPrimary) {
|
|
736
|
+
defaultExpr = 'ExpressionUtils.call("uuid")';
|
|
737
|
+
} else {
|
|
738
|
+
defaultExpr = null;
|
|
739
|
+
}
|
|
740
|
+
} else if (col.default !== void 0) {
|
|
741
|
+
const d = col.default;
|
|
742
|
+
if (typeof d === "boolean" || typeof d === "number") {
|
|
743
|
+
defaultExpr = `ExpressionUtils.literal(${d})`;
|
|
744
|
+
} else if (typeof d === "string") {
|
|
745
|
+
defaultExpr = `ExpressionUtils.literal(${esc(d)})`;
|
|
746
|
+
} else if (d && typeof d === "object" && "queryChunks" in d) {
|
|
747
|
+
try {
|
|
748
|
+
const chunks = d.queryChunks || [];
|
|
749
|
+
const sqlStr = chunks.map((c) => typeof c === "string" ? c : c.value?.[0] || "").join("").trim();
|
|
750
|
+
if (sqlStr) {
|
|
751
|
+
defaultExpr = `ExpressionUtils.call("dbgenerated", [ExpressionUtils.literal(${esc(sqlStr)})])`;
|
|
752
|
+
}
|
|
753
|
+
} catch (e) {
|
|
754
|
+
console.warn(`Failed to parse SQL default for column "${sqlName}":`, e);
|
|
755
|
+
}
|
|
756
|
+
} else if (Array.isArray(d) && d.length === 0) {
|
|
757
|
+
defaultExpr = "[] as FieldDefault";
|
|
758
|
+
} else if (typeof d === "object" && d !== null && Object.keys(d).length === 0) {
|
|
759
|
+
defaultExpr = `ExpressionUtils.literal("{}")`;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return {
|
|
764
|
+
name: jsKey,
|
|
765
|
+
sqlName,
|
|
766
|
+
type,
|
|
767
|
+
isJsonColumn,
|
|
768
|
+
optional: !notNull && !hasDefault,
|
|
769
|
+
array: isArray,
|
|
770
|
+
id: isPrimary,
|
|
771
|
+
unique: isUnique,
|
|
772
|
+
hasDefault,
|
|
773
|
+
dbAttrs,
|
|
774
|
+
defaultExpr,
|
|
775
|
+
enumPgName,
|
|
776
|
+
isGenerated: !!generated
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
__name(mapColumn, "mapColumn");
|
|
780
|
+
|
|
781
|
+
// src/codegen/discover.ts
|
|
782
|
+
var import_pg_core4 = require("drizzle-orm/pg-core");
|
|
783
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
784
|
+
var ts = __toESM(require("typescript"), 1);
|
|
785
|
+
|
|
786
|
+
// src/drizzle/define.ts
|
|
787
|
+
var import_drizzle_orm = require("drizzle-orm");
|
|
788
|
+
var import_pg_core3 = require("drizzle-orm/pg-core");
|
|
789
|
+
var ENUM_MAP = Symbol.for("drizzle:EnumMap");
|
|
790
|
+
function toPgEnum(record) {
|
|
791
|
+
return Object.values(record);
|
|
792
|
+
}
|
|
793
|
+
__name(toPgEnum, "toPgEnum");
|
|
794
|
+
function pgOrmEnum(name, values) {
|
|
795
|
+
const pgValues = Object.values(values);
|
|
796
|
+
const result = (0, import_pg_core3.pgEnum)(name, pgValues);
|
|
797
|
+
result[ENUM_MAP] = values;
|
|
798
|
+
return result;
|
|
799
|
+
}
|
|
800
|
+
__name(pgOrmEnum, "pgOrmEnum");
|
|
801
|
+
var pgTypes = {
|
|
802
|
+
date: /* @__PURE__ */ __name(() => "date", "date"),
|
|
803
|
+
uuid: /* @__PURE__ */ __name(() => "uuid", "uuid"),
|
|
804
|
+
text: /* @__PURE__ */ __name(() => "text", "text"),
|
|
805
|
+
integer: /* @__PURE__ */ __name(() => "integer", "integer"),
|
|
806
|
+
bigint: /* @__PURE__ */ __name(() => "bigint", "bigint"),
|
|
807
|
+
boolean: /* @__PURE__ */ __name(() => "boolean", "boolean"),
|
|
808
|
+
numeric: /* @__PURE__ */ __name(() => "numeric", "numeric"),
|
|
809
|
+
timestamptz: /* @__PURE__ */ __name(() => "timestamptz", "timestamptz"),
|
|
810
|
+
timestamp: /* @__PURE__ */ __name(() => "timestamp", "timestamp"),
|
|
811
|
+
jsonb: /* @__PURE__ */ __name(() => "jsonb", "jsonb"),
|
|
812
|
+
json: /* @__PURE__ */ __name(() => "json", "json")
|
|
813
|
+
};
|
|
814
|
+
var CustomObject = class extends import_drizzle_orm.SQL {
|
|
815
|
+
static {
|
|
816
|
+
__name(this, "CustomObject");
|
|
817
|
+
}
|
|
818
|
+
name;
|
|
819
|
+
type;
|
|
820
|
+
schema;
|
|
821
|
+
qualifiedName;
|
|
822
|
+
constructor(name, type, schema) {
|
|
823
|
+
const qn = schema ? `${schema}.${name}` : name;
|
|
824
|
+
super(import_drizzle_orm.sql.raw(qn).queryChunks), this.name = name, this.type = type, this.schema = schema;
|
|
825
|
+
this.qualifiedName = qn;
|
|
826
|
+
}
|
|
827
|
+
getSQL() {
|
|
828
|
+
return import_drizzle_orm.sql.raw(this.qualifiedName);
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
var PgFunction = class extends CustomObject {
|
|
832
|
+
static {
|
|
833
|
+
__name(this, "PgFunction");
|
|
834
|
+
}
|
|
835
|
+
opts;
|
|
836
|
+
constructor(name, opts) {
|
|
837
|
+
super(name, "function", opts.schema), this.opts = opts;
|
|
838
|
+
}
|
|
839
|
+
toSQL(dialect) {
|
|
840
|
+
const args = this.opts.args ? Object.entries(this.opts.args(pgTypes)).map(([n, type]) => `${n} ${type}`).join(", ") : "";
|
|
841
|
+
const language = this.opts.language ?? "plpgsql";
|
|
842
|
+
const body = dialect.sqlToQuery(this.opts.body()).sql;
|
|
843
|
+
const lines = [
|
|
844
|
+
`CREATE OR REPLACE FUNCTION ${this.qualifiedName}(${args})`,
|
|
845
|
+
`RETURNS ${this.opts.returns}`,
|
|
846
|
+
`LANGUAGE ${language}`
|
|
847
|
+
];
|
|
848
|
+
if (this.opts.security === "definer") lines.push("SECURITY DEFINER");
|
|
849
|
+
if (this.opts.searchPath) lines.push(`SET search_path = ${this.opts.searchPath}`);
|
|
850
|
+
lines.push(`AS $function$
|
|
851
|
+
${body}
|
|
852
|
+
$function$;`);
|
|
853
|
+
return lines.join("\n");
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
var TriggerFunction = class extends PgFunction {
|
|
857
|
+
static {
|
|
858
|
+
__name(this, "TriggerFunction");
|
|
859
|
+
}
|
|
860
|
+
triggerOpts;
|
|
861
|
+
constructor(name, triggerOpts) {
|
|
862
|
+
super(name, {
|
|
863
|
+
returns: "trigger",
|
|
864
|
+
schema: triggerOpts.schema,
|
|
865
|
+
language: triggerOpts.language,
|
|
866
|
+
security: triggerOpts.security,
|
|
867
|
+
searchPath: triggerOpts.searchPath,
|
|
868
|
+
body: triggerOpts.body
|
|
869
|
+
}), this.triggerOpts = triggerOpts;
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
var PgTrigger = class extends CustomObject {
|
|
873
|
+
static {
|
|
874
|
+
__name(this, "PgTrigger");
|
|
875
|
+
}
|
|
876
|
+
opts;
|
|
877
|
+
tableName;
|
|
878
|
+
constructor(name, opts) {
|
|
879
|
+
super(name, "trigger", opts.schema), this.opts = opts;
|
|
880
|
+
this.tableName = opts.on[Symbol.for("drizzle:Name")];
|
|
881
|
+
}
|
|
882
|
+
toSQL(dialect) {
|
|
883
|
+
const tableName = this.tableName;
|
|
884
|
+
const eventParts = this.opts.events.map((e) => {
|
|
885
|
+
if (typeof e === "string") return e.toUpperCase();
|
|
886
|
+
const cols = e.update.map((c) => c.name).join(", ");
|
|
887
|
+
return `UPDATE OF ${cols}`;
|
|
888
|
+
});
|
|
889
|
+
const lines = [
|
|
890
|
+
`CREATE OR REPLACE TRIGGER ${this.name}`,
|
|
891
|
+
`${this.opts.timing.toUpperCase()} ${eventParts.join(" OR ")}`,
|
|
892
|
+
`ON ${tableName}`,
|
|
893
|
+
`FOR EACH ${this.opts.forEach.toUpperCase()}`
|
|
894
|
+
];
|
|
895
|
+
if (this.opts.condition) {
|
|
896
|
+
const cond = dialect.sqlToQuery(this.opts.condition).sql;
|
|
897
|
+
lines.push(`WHEN (${cond})`);
|
|
898
|
+
}
|
|
899
|
+
lines.push(`EXECUTE FUNCTION ${this.opts.execute.qualifiedName}();`);
|
|
900
|
+
return lines.join("\n");
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
var PgExtension = class extends CustomObject {
|
|
904
|
+
static {
|
|
905
|
+
__name(this, "PgExtension");
|
|
906
|
+
}
|
|
907
|
+
opts;
|
|
908
|
+
constructor(name, opts = {}) {
|
|
909
|
+
super(name, "extension"), this.opts = opts;
|
|
910
|
+
}
|
|
911
|
+
toSQL() {
|
|
912
|
+
const schema = this.opts.schema ? ` SCHEMA ${this.opts.schema}` : "";
|
|
913
|
+
return `CREATE EXTENSION IF NOT EXISTS "${this.name}"${schema};`;
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
function pgExtension(name, opts = {}) {
|
|
917
|
+
return new PgExtension(name, opts);
|
|
918
|
+
}
|
|
919
|
+
__name(pgExtension, "pgExtension");
|
|
920
|
+
var PgCronJob = class extends CustomObject {
|
|
921
|
+
static {
|
|
922
|
+
__name(this, "PgCronJob");
|
|
923
|
+
}
|
|
924
|
+
opts;
|
|
925
|
+
constructor(name, opts) {
|
|
926
|
+
super(name, "cron"), this.opts = opts;
|
|
927
|
+
}
|
|
928
|
+
toSQL(dialect) {
|
|
929
|
+
const cmd = dialect.sqlToQuery(this.opts.command()).sql;
|
|
930
|
+
const escapedName = this.name.replace(/'/g, "''");
|
|
931
|
+
const escapedSchedule = this.opts.schedule.replace(/'/g, "''");
|
|
932
|
+
return `SELECT cron.schedule('${escapedName}', '${escapedSchedule}', $$${cmd}$$);`;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
function pgCron(name, opts) {
|
|
936
|
+
return new PgCronJob(name, opts);
|
|
937
|
+
}
|
|
938
|
+
__name(pgCron, "pgCron");
|
|
939
|
+
function pgFunction(name, opts) {
|
|
940
|
+
if (opts.returns === "trigger" && "triggersOn" in opts) {
|
|
941
|
+
return new TriggerFunction(name, opts);
|
|
942
|
+
}
|
|
943
|
+
return new PgFunction(name, opts);
|
|
944
|
+
}
|
|
945
|
+
__name(pgFunction, "pgFunction");
|
|
946
|
+
function pgTrigger(name, opts) {
|
|
947
|
+
return new PgTrigger(name, opts);
|
|
948
|
+
}
|
|
949
|
+
__name(pgTrigger, "pgTrigger");
|
|
950
|
+
|
|
951
|
+
// src/codegen/discover.ts
|
|
952
|
+
function discoverEnums(allEnums) {
|
|
953
|
+
const enums = /* @__PURE__ */ new Map();
|
|
954
|
+
for (const [exportName, val] of Object.entries(allEnums)) {
|
|
955
|
+
if (typeof val !== "function" || !("enumName" in val)) continue;
|
|
956
|
+
const e = val;
|
|
957
|
+
const pgName = e.enumName;
|
|
958
|
+
const values = e.enumValues;
|
|
959
|
+
const zenstackName = capitalize(exportName.replace(/Enum$/, ""));
|
|
960
|
+
const mapping = e[ENUM_MAP] ?? null;
|
|
961
|
+
enums.set(pgName, {
|
|
962
|
+
pgName,
|
|
963
|
+
zenstackName,
|
|
964
|
+
values,
|
|
965
|
+
mapping,
|
|
966
|
+
mappedName: pgName
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
return enums;
|
|
970
|
+
}
|
|
971
|
+
__name(discoverEnums, "discoverEnums");
|
|
972
|
+
function getColumnsObject(node) {
|
|
973
|
+
if (ts.isObjectLiteralExpression(node)) return node;
|
|
974
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
|
|
975
|
+
if (ts.isObjectLiteralExpression(node.body)) return node.body;
|
|
976
|
+
if (ts.isParenthesizedExpression(node.body) && ts.isObjectLiteralExpression(node.body.expression)) {
|
|
977
|
+
return node.body.expression;
|
|
978
|
+
}
|
|
979
|
+
if (ts.isBlock(node.body)) {
|
|
980
|
+
for (const statement of node.body.statements) {
|
|
981
|
+
if (!ts.isReturnStatement(statement) || !statement.expression) continue;
|
|
982
|
+
if (ts.isObjectLiteralExpression(statement.expression)) return statement.expression;
|
|
983
|
+
if (ts.isParenthesizedExpression(statement.expression) && ts.isObjectLiteralExpression(statement.expression.expression)) {
|
|
984
|
+
return statement.expression.expression;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
__name(getColumnsObject, "getColumnsObject");
|
|
992
|
+
function getColumnBuilderName(node) {
|
|
993
|
+
if (ts.isCallExpression(node)) return getColumnBuilderName(node.expression);
|
|
994
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
995
|
+
if (ts.isIdentifier(node.expression) && node.expression.text === "col") {
|
|
996
|
+
return node.name.text;
|
|
997
|
+
}
|
|
998
|
+
return getColumnBuilderName(node.expression);
|
|
999
|
+
}
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
__name(getColumnBuilderName, "getColumnBuilderName");
|
|
1003
|
+
function assertNoTypedColumnOverrides(tablesFilePath) {
|
|
1004
|
+
const sourceFile = ts.createSourceFile(tablesFilePath, fs2.readFileSync(tablesFilePath, "utf8"), ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
1005
|
+
for (const statement of sourceFile.statements) {
|
|
1006
|
+
if (!ts.isVariableStatement(statement)) continue;
|
|
1007
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
1008
|
+
if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
|
|
1009
|
+
if (!ts.isCallExpression(declaration.initializer)) continue;
|
|
1010
|
+
const columnsArg = declaration.initializer.arguments[1];
|
|
1011
|
+
if (!columnsArg) continue;
|
|
1012
|
+
const columnsObject = getColumnsObject(columnsArg);
|
|
1013
|
+
if (!columnsObject) continue;
|
|
1014
|
+
for (const property of columnsObject.properties) {
|
|
1015
|
+
if (!ts.isPropertyAssignment(property)) continue;
|
|
1016
|
+
const nameNode = property.name;
|
|
1017
|
+
const jsKey = ts.isIdentifier(nameNode) || ts.isStringLiteral(nameNode) ? nameNode.text : null;
|
|
1018
|
+
if (!jsKey) continue;
|
|
1019
|
+
let typedCall = null;
|
|
1020
|
+
const visit = /* @__PURE__ */ __name((node) => {
|
|
1021
|
+
if (typedCall) return;
|
|
1022
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === "$type") {
|
|
1023
|
+
typedCall = node;
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
ts.forEachChild(node, visit);
|
|
1027
|
+
}, "visit");
|
|
1028
|
+
visit(property.initializer);
|
|
1029
|
+
if (!typedCall) continue;
|
|
1030
|
+
const resolvedCall = typedCall;
|
|
1031
|
+
const builderName = getColumnBuilderName(resolvedCall.expression.expression);
|
|
1032
|
+
if (builderName === "json" || builderName === "jsonb" || builderName === "array") continue;
|
|
1033
|
+
const fullText = property.initializer.getText();
|
|
1034
|
+
if (fullText.includes(".array()")) continue;
|
|
1035
|
+
console.warn(`Warning: Column "${declaration.name.text}.${jsKey}" uses $type<...>() on a ${builderName ?? "scalar"} column. Consider using a real enum.`);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
__name(assertNoTypedColumnOverrides, "assertNoTypedColumnOverrides");
|
|
1041
|
+
function discoverTables(allTables, computedFieldsConfig = {}, derivedModelsConfig = {}) {
|
|
1042
|
+
const tables = [];
|
|
1043
|
+
const tablesByModel = /* @__PURE__ */ new Map();
|
|
1044
|
+
for (const [exportName, _val] of Object.entries(allTables)) {
|
|
1045
|
+
const val = _val;
|
|
1046
|
+
if (!val || typeof val !== "object") continue;
|
|
1047
|
+
const syms = Object.getOwnPropertySymbols(val);
|
|
1048
|
+
if (!syms.some((s) => s.toString().includes("IsDrizzleTable"))) continue;
|
|
1049
|
+
const sqlName = getDrizzleTableName(val);
|
|
1050
|
+
const modelName = exportName;
|
|
1051
|
+
const typeName = capitalize(exportName);
|
|
1052
|
+
const sqlToJsKey = /* @__PURE__ */ new Map();
|
|
1053
|
+
const jsKeySet = /* @__PURE__ */ new Set();
|
|
1054
|
+
for (const key of Object.keys(val)) {
|
|
1055
|
+
const col = val[key];
|
|
1056
|
+
if (col.name && col.columnType) {
|
|
1057
|
+
sqlToJsKey.set(col.name, key);
|
|
1058
|
+
jsKeySet.add(key);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
const cfg = (0, import_pg_core4.getTableConfig)(val);
|
|
1062
|
+
const computedFields = Object.entries(computedFieldsConfig[exportName] ?? {}).map(([name, field]) => {
|
|
1063
|
+
if (jsKeySet.has(name)) {
|
|
1064
|
+
throw new Error(`Computed field "${exportName}.${name}" collides with an existing column.`);
|
|
1065
|
+
}
|
|
1066
|
+
return {
|
|
1067
|
+
name,
|
|
1068
|
+
type: field.type,
|
|
1069
|
+
tsType: field.tsType
|
|
1070
|
+
};
|
|
1071
|
+
});
|
|
1072
|
+
tables.push({
|
|
1073
|
+
exportName,
|
|
1074
|
+
sqlName,
|
|
1075
|
+
modelName,
|
|
1076
|
+
typeName,
|
|
1077
|
+
table: val,
|
|
1078
|
+
cfg,
|
|
1079
|
+
sqlToJsKey,
|
|
1080
|
+
jsKeySet,
|
|
1081
|
+
computedFields,
|
|
1082
|
+
derivedFrom: null,
|
|
1083
|
+
defaultWhere: null,
|
|
1084
|
+
narrow: null
|
|
1085
|
+
});
|
|
1086
|
+
tablesByModel.set(modelName, tables[tables.length - 1]);
|
|
1087
|
+
}
|
|
1088
|
+
for (const modelName of Object.keys(computedFieldsConfig)) {
|
|
1089
|
+
if (!tablesByModel.has(modelName)) {
|
|
1090
|
+
throw new Error(`Computed fields declared for unknown table export "${modelName}".`);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
for (const [baseModelName, derivedModels] of Object.entries(derivedModelsConfig)) {
|
|
1094
|
+
const baseTable = tablesByModel.get(baseModelName);
|
|
1095
|
+
if (!baseTable) {
|
|
1096
|
+
throw new Error(`Derived models declared for unknown table export "${baseModelName}".`);
|
|
1097
|
+
}
|
|
1098
|
+
for (const [derivedModelName, declaration] of Object.entries(derivedModels)) {
|
|
1099
|
+
if (tablesByModel.has(derivedModelName)) {
|
|
1100
|
+
throw new Error(`Derived model "${derivedModelName}" collides with an existing table or derived model.`);
|
|
1101
|
+
}
|
|
1102
|
+
const derivedTable = {
|
|
1103
|
+
...baseTable,
|
|
1104
|
+
exportName: derivedModelName,
|
|
1105
|
+
modelName: derivedModelName,
|
|
1106
|
+
typeName: capitalize(derivedModelName),
|
|
1107
|
+
computedFields: [
|
|
1108
|
+
...baseTable.computedFields
|
|
1109
|
+
],
|
|
1110
|
+
derivedFrom: baseModelName,
|
|
1111
|
+
defaultWhere: declaration.where,
|
|
1112
|
+
narrow: declaration.narrow ?? null
|
|
1113
|
+
};
|
|
1114
|
+
tables.push(derivedTable);
|
|
1115
|
+
tablesByModel.set(derivedModelName, derivedTable);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
return tables;
|
|
1119
|
+
}
|
|
1120
|
+
__name(discoverTables, "discoverTables");
|
|
1121
|
+
function discoverViews(allViews) {
|
|
1122
|
+
const views = [];
|
|
1123
|
+
for (const [exportName, val] of Object.entries(allViews)) {
|
|
1124
|
+
if (!val || typeof val !== "object") continue;
|
|
1125
|
+
const syms = Object.getOwnPropertySymbols(val);
|
|
1126
|
+
if (!syms.some((s) => s.toString().includes("IsDrizzleView"))) continue;
|
|
1127
|
+
const cfg = (0, import_pg_core4.getViewConfig)(val);
|
|
1128
|
+
const sqlName = cfg.name;
|
|
1129
|
+
const modelName = exportName;
|
|
1130
|
+
const typeName = capitalize(exportName);
|
|
1131
|
+
const sqlToJsKey = /* @__PURE__ */ new Map();
|
|
1132
|
+
const columns = /* @__PURE__ */ new Map();
|
|
1133
|
+
for (const [jsKey, col] of Object.entries(cfg.selectedFields)) {
|
|
1134
|
+
const colObj = col;
|
|
1135
|
+
if (colObj.name && colObj.columnType) {
|
|
1136
|
+
sqlToJsKey.set(colObj.name, jsKey);
|
|
1137
|
+
columns.set(jsKey, colObj);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
views.push({
|
|
1141
|
+
exportName,
|
|
1142
|
+
sqlName,
|
|
1143
|
+
modelName,
|
|
1144
|
+
typeName,
|
|
1145
|
+
columns,
|
|
1146
|
+
sqlToJsKey
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
return views;
|
|
1150
|
+
}
|
|
1151
|
+
__name(discoverViews, "discoverViews");
|
|
1152
|
+
function extractFKs(table) {
|
|
1153
|
+
const cfg = (0, import_pg_core4.getTableConfig)(table);
|
|
1154
|
+
return cfg.foreignKeys.map((fk) => {
|
|
1155
|
+
const ref = fk.reference();
|
|
1156
|
+
return {
|
|
1157
|
+
name: fk.getName(),
|
|
1158
|
+
localColumns: ref.columns.map((c) => c.name),
|
|
1159
|
+
foreignTable: getDrizzleTableName(ref.foreignTable),
|
|
1160
|
+
foreignColumns: ref.foreignColumns.map((c) => c.name)
|
|
1161
|
+
};
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
__name(extractFKs, "extractFKs");
|
|
1165
|
+
|
|
1166
|
+
// src/codegen/relations.ts
|
|
1167
|
+
function makePhysicalRelationSignature(fields, references, array) {
|
|
1168
|
+
return [
|
|
1169
|
+
array ? "many" : "one",
|
|
1170
|
+
fields?.join(",") || "",
|
|
1171
|
+
references?.join(",") || ""
|
|
1172
|
+
].join("|");
|
|
1173
|
+
}
|
|
1174
|
+
__name(makePhysicalRelationSignature, "makePhysicalRelationSignature");
|
|
1175
|
+
function makePhysicalFKSignature(sourceTable, targetTable, fk) {
|
|
1176
|
+
return makePhysicalRelationSignature(fk.localColumns.map((column) => sourceTable.sqlToJsKey.get(column) || column), fk.foreignColumns.map((column) => targetTable.sqlToJsKey.get(column) || column), false);
|
|
1177
|
+
}
|
|
1178
|
+
__name(makePhysicalFKSignature, "makePhysicalFKSignature");
|
|
1179
|
+
function assertNoRelationFieldCollision(table, sourceRelations, fieldName) {
|
|
1180
|
+
if (table.jsKeySet.has(fieldName)) {
|
|
1181
|
+
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.`);
|
|
1182
|
+
}
|
|
1183
|
+
if (sourceRelations.some((relation) => relation.fieldName === fieldName)) {
|
|
1184
|
+
throw new Error(`Relation "${table.exportName}.${fieldName}" collides with another relation field. Use a unique key in relations.ts.`);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
__name(assertNoRelationFieldCollision, "assertNoRelationFieldCollision");
|
|
1188
|
+
function unfoldThroughPath(path, relationNames = []) {
|
|
1189
|
+
const entries = Object.entries(path);
|
|
1190
|
+
if (entries.length !== 1) {
|
|
1191
|
+
throw new Error("Through relation path must contain exactly one relation per level.");
|
|
1192
|
+
}
|
|
1193
|
+
const entry = entries[0];
|
|
1194
|
+
const [relationName, next] = entry;
|
|
1195
|
+
relationNames.push(relationName);
|
|
1196
|
+
if (next === true) {
|
|
1197
|
+
return relationNames;
|
|
1198
|
+
}
|
|
1199
|
+
return unfoldThroughPath(next, relationNames);
|
|
1200
|
+
}
|
|
1201
|
+
__name(unfoldThroughPath, "unfoldThroughPath");
|
|
1202
|
+
function unfoldRelationSelector(relation) {
|
|
1203
|
+
const entries = Object.entries(relation);
|
|
1204
|
+
if (entries.length !== 1) {
|
|
1205
|
+
throw new Error("Filtered relation selector must contain exactly one relation.");
|
|
1206
|
+
}
|
|
1207
|
+
const entry = entries[0];
|
|
1208
|
+
const [relationName, enabled] = entry;
|
|
1209
|
+
if (enabled !== true) {
|
|
1210
|
+
throw new Error("Filtered relation selector values must be true.");
|
|
1211
|
+
}
|
|
1212
|
+
return relationName;
|
|
1213
|
+
}
|
|
1214
|
+
__name(unfoldRelationSelector, "unfoldRelationSelector");
|
|
1215
|
+
function buildRelations(tables, relationTargets = {}, filteredRelations = {}, throughRelations = {}, fkRelations = {}) {
|
|
1216
|
+
const baseTables = tables.filter((table) => !table.derivedFrom);
|
|
1217
|
+
const sqlToBaseTable = /* @__PURE__ */ new Map();
|
|
1218
|
+
const modelToTable = /* @__PURE__ */ new Map();
|
|
1219
|
+
for (const table of tables) {
|
|
1220
|
+
modelToTable.set(table.modelName, table);
|
|
1221
|
+
if (!table.derivedFrom) {
|
|
1222
|
+
sqlToBaseTable.set(table.sqlName, table);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
const fksByTable = /* @__PURE__ */ new Map();
|
|
1226
|
+
for (const table of baseTables) {
|
|
1227
|
+
fksByTable.set(table.modelName, extractFKs(table.table));
|
|
1228
|
+
}
|
|
1229
|
+
const modelRelations = /* @__PURE__ */ new Map();
|
|
1230
|
+
for (const table of tables) {
|
|
1231
|
+
modelRelations.set(table.modelName, []);
|
|
1232
|
+
}
|
|
1233
|
+
for (const [modelName, relations] of Object.entries(fkRelations)) {
|
|
1234
|
+
const sourceTable = modelToTable.get(modelName);
|
|
1235
|
+
if (!sourceTable) continue;
|
|
1236
|
+
const sourceRelations = modelRelations.get(modelName) || [];
|
|
1237
|
+
const colByName = new Map(sourceTable.cfg.columns.map((column) => [
|
|
1238
|
+
column.name,
|
|
1239
|
+
column
|
|
1240
|
+
]));
|
|
1241
|
+
for (const [relName, fkInfo] of Object.entries(relations)) {
|
|
1242
|
+
const targetTable = modelToTable.get(fkInfo.targetExportName) ?? sqlToBaseTable.get(fkInfo.targetExportName);
|
|
1243
|
+
if (!targetTable) continue;
|
|
1244
|
+
const targetModelOverride = relationTargets[modelName]?.[relName];
|
|
1245
|
+
const fieldName = relName;
|
|
1246
|
+
assertNoRelationFieldCollision(sourceTable, sourceRelations, fieldName);
|
|
1247
|
+
let hasDefaultFK = false;
|
|
1248
|
+
let isOptional = false;
|
|
1249
|
+
const jsToSql = new Map([
|
|
1250
|
+
...sourceTable.sqlToJsKey.entries()
|
|
1251
|
+
].map(([sql4, js]) => [
|
|
1252
|
+
js,
|
|
1253
|
+
sql4
|
|
1254
|
+
]));
|
|
1255
|
+
for (const jsKey of fkInfo.fields) {
|
|
1256
|
+
const sqlName = jsToSql.get(jsKey) ?? jsKey;
|
|
1257
|
+
const localColumn = colByName.get(sqlName);
|
|
1258
|
+
if (localColumn?.hasDefault) hasDefaultFK = true;
|
|
1259
|
+
if (!localColumn?.notNull) isOptional = true;
|
|
1260
|
+
}
|
|
1261
|
+
sourceRelations.push({
|
|
1262
|
+
fieldName,
|
|
1263
|
+
targetModel: targetModelOverride ?? fkInfo.targetExportName,
|
|
1264
|
+
optional: isOptional,
|
|
1265
|
+
array: false,
|
|
1266
|
+
relationName: fkInfo.relationName,
|
|
1267
|
+
fields: fkInfo.fields,
|
|
1268
|
+
references: fkInfo.references,
|
|
1269
|
+
hasDefault: hasDefaultFK
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
modelRelations.set(modelName, sourceRelations);
|
|
1273
|
+
}
|
|
1274
|
+
for (const table of tables) {
|
|
1275
|
+
if (!table.derivedFrom) continue;
|
|
1276
|
+
const baseRelations = modelRelations.get(table.derivedFrom) || [];
|
|
1277
|
+
modelRelations.set(table.modelName, baseRelations.map((relation) => ({
|
|
1278
|
+
...relation,
|
|
1279
|
+
_opposite: void 0
|
|
1280
|
+
})));
|
|
1281
|
+
}
|
|
1282
|
+
for (const table of baseTables) {
|
|
1283
|
+
const sourceRelations = modelRelations.get(table.modelName) || [];
|
|
1284
|
+
const relationsByTarget = /* @__PURE__ */ new Map();
|
|
1285
|
+
for (const relation of sourceRelations) {
|
|
1286
|
+
if (relation.kind && relation.kind !== "normal") continue;
|
|
1287
|
+
const group = relationsByTarget.get(relation.targetModel) || [];
|
|
1288
|
+
group.push(relation);
|
|
1289
|
+
relationsByTarget.set(relation.targetModel, group);
|
|
1290
|
+
}
|
|
1291
|
+
for (const [targetModel, relations] of relationsByTarget) {
|
|
1292
|
+
if (relations.length <= 1) continue;
|
|
1293
|
+
for (const relation of relations) {
|
|
1294
|
+
if (relation.relationName) continue;
|
|
1295
|
+
throw new Error(`Ambiguous relations for "${table.exportName}" -> "${targetModel}". Add explicit relationName values in supabase/schema/relations.ts.`);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
const declaredFKRelations = new Set(sourceRelations.filter((relation) => !relation.array && relation.fields && relation.references).map((relation) => makePhysicalRelationSignature(relation.fields, relation.references, relation.array)));
|
|
1299
|
+
for (const fk of fksByTable.get(table.modelName) || []) {
|
|
1300
|
+
const targetTable = sqlToBaseTable.get(fk.foreignTable);
|
|
1301
|
+
if (!targetTable) continue;
|
|
1302
|
+
const signature = makePhysicalFKSignature(table, targetTable, fk);
|
|
1303
|
+
if (declaredFKRelations.has(signature)) continue;
|
|
1304
|
+
throw new Error(`Missing explicit relation in supabase/schema/relations.ts for "${table.exportName}": [${fk.localColumns.join(", ")}] -> ${targetTable.exportName}([${fk.foreignColumns.join(", ")}]).`);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
const forwardByTarget = /* @__PURE__ */ new Map();
|
|
1308
|
+
for (const sourceTable of tables) {
|
|
1309
|
+
for (const relation of modelRelations.get(sourceTable.modelName) || []) {
|
|
1310
|
+
if (relation.kind && relation.kind !== "normal") continue;
|
|
1311
|
+
const group = forwardByTarget.get(relation.targetModel) || [];
|
|
1312
|
+
group.push({
|
|
1313
|
+
source: sourceTable,
|
|
1314
|
+
relation
|
|
1315
|
+
});
|
|
1316
|
+
forwardByTarget.set(relation.targetModel, group);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
const inverseRelations = /* @__PURE__ */ new Map();
|
|
1320
|
+
for (const table of tables) {
|
|
1321
|
+
const inverses = [];
|
|
1322
|
+
const existingNames = new Set((modelRelations.get(table.modelName) || []).map((relation) => relation.fieldName));
|
|
1323
|
+
for (const { source: sourceTable, relation } of forwardByTarget.get(table.modelName) || []) {
|
|
1324
|
+
const sourceExport = sourceTable.exportName || sourceTable.sqlName;
|
|
1325
|
+
let fieldName = sourceExport.endsWith("s") ? sourceExport : sourceExport + "s";
|
|
1326
|
+
if (existingNames.has(fieldName)) {
|
|
1327
|
+
const explicitRelation = (modelRelations.get(table.modelName) || []).find((item) => item.fieldName === fieldName);
|
|
1328
|
+
if (explicitRelation) {
|
|
1329
|
+
relation._opposite = fieldName;
|
|
1330
|
+
continue;
|
|
1331
|
+
}
|
|
1332
|
+
const mainField = relation.fields?.find((field) => field !== APP_SLUG_JS) || relation.fields?.[0] || relation.fieldName;
|
|
1333
|
+
fieldName = sourceExport + "By" + capitalize(mainField);
|
|
1334
|
+
}
|
|
1335
|
+
inverses.push({
|
|
1336
|
+
fieldName,
|
|
1337
|
+
targetModel: sourceTable.modelName,
|
|
1338
|
+
optional: false,
|
|
1339
|
+
array: true,
|
|
1340
|
+
relationName: relation.relationName,
|
|
1341
|
+
fields: null,
|
|
1342
|
+
references: null,
|
|
1343
|
+
hasDefault: false,
|
|
1344
|
+
_opposite: relation.fieldName
|
|
1345
|
+
});
|
|
1346
|
+
relation._opposite = fieldName;
|
|
1347
|
+
existingNames.add(fieldName);
|
|
1348
|
+
}
|
|
1349
|
+
inverseRelations.set(table.modelName, inverses);
|
|
1350
|
+
}
|
|
1351
|
+
const getAvailableRelations = /* @__PURE__ */ __name((modelName) => [
|
|
1352
|
+
...modelRelations.get(modelName) || [],
|
|
1353
|
+
...inverseRelations.get(modelName) || []
|
|
1354
|
+
], "getAvailableRelations");
|
|
1355
|
+
for (const [modelName, declarations] of Object.entries(filteredRelations)) {
|
|
1356
|
+
const sourceTable = modelToTable.get(modelName);
|
|
1357
|
+
if (!sourceTable) {
|
|
1358
|
+
throw new Error(`Filtered relations declared for unknown model "${modelName}".`);
|
|
1359
|
+
}
|
|
1360
|
+
const sourceRelations = modelRelations.get(modelName) || [];
|
|
1361
|
+
const availableRelations = getAvailableRelations(modelName);
|
|
1362
|
+
for (const [fieldName, declaration] of Object.entries(declarations)) {
|
|
1363
|
+
const sourceRelation = unfoldRelationSelector(declaration.relation);
|
|
1364
|
+
const existingFk = sourceRelations.find((r) => r.fieldName === fieldName);
|
|
1365
|
+
if (existingFk && sourceRelation === fieldName) {
|
|
1366
|
+
existingFk.kind = "filtered";
|
|
1367
|
+
existingFk.sourceRelation = sourceRelation;
|
|
1368
|
+
existingFk.where = declaration.where;
|
|
1369
|
+
existingFk.single = declaration.single;
|
|
1370
|
+
continue;
|
|
1371
|
+
}
|
|
1372
|
+
assertNoRelationFieldCollision(sourceTable, [
|
|
1373
|
+
...sourceRelations,
|
|
1374
|
+
...inverseRelations.get(modelName) || []
|
|
1375
|
+
], fieldName);
|
|
1376
|
+
const baseRelation = availableRelations.find((relation) => relation.fieldName === sourceRelation);
|
|
1377
|
+
if (!baseRelation) {
|
|
1378
|
+
throw new Error(`Filtered relation "${modelName}.${fieldName}" references unknown relation "${sourceRelation}".`);
|
|
1379
|
+
}
|
|
1380
|
+
sourceRelations.push({
|
|
1381
|
+
fieldName,
|
|
1382
|
+
targetModel: baseRelation.targetModel,
|
|
1383
|
+
optional: declaration.single ? true : baseRelation.optional,
|
|
1384
|
+
array: declaration.single ? false : baseRelation.array,
|
|
1385
|
+
relationName: null,
|
|
1386
|
+
fields: baseRelation.fields,
|
|
1387
|
+
references: baseRelation.references,
|
|
1388
|
+
hasDefault: false,
|
|
1389
|
+
kind: "filtered",
|
|
1390
|
+
sourceRelation,
|
|
1391
|
+
where: declaration.where,
|
|
1392
|
+
single: declaration.single
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
modelRelations.set(modelName, sourceRelations);
|
|
1396
|
+
}
|
|
1397
|
+
for (const [modelName, declarations] of Object.entries(throughRelations)) {
|
|
1398
|
+
const sourceTable = modelToTable.get(modelName);
|
|
1399
|
+
if (!sourceTable) {
|
|
1400
|
+
throw new Error(`Through relations declared for unknown model "${modelName}".`);
|
|
1401
|
+
}
|
|
1402
|
+
const sourceRelations = modelRelations.get(modelName) || [];
|
|
1403
|
+
for (const [fieldName, declaration] of Object.entries(declarations)) {
|
|
1404
|
+
assertNoRelationFieldCollision(sourceTable, [
|
|
1405
|
+
...sourceRelations,
|
|
1406
|
+
...inverseRelations.get(modelName) || []
|
|
1407
|
+
], fieldName);
|
|
1408
|
+
const throughPath = unfoldThroughPath(declaration.path);
|
|
1409
|
+
let currentModel = modelName;
|
|
1410
|
+
let targetRelation;
|
|
1411
|
+
let isMany = false;
|
|
1412
|
+
for (const relationName of throughPath) {
|
|
1413
|
+
const relation = getAvailableRelations(currentModel).find((item) => item.fieldName === relationName);
|
|
1414
|
+
if (!relation) {
|
|
1415
|
+
throw new Error(`Through relation "${modelName}.${fieldName}" references unknown relation "${currentModel}.${relationName}".`);
|
|
1416
|
+
}
|
|
1417
|
+
targetRelation = relation;
|
|
1418
|
+
currentModel = relation.targetModel;
|
|
1419
|
+
if (relation.array) {
|
|
1420
|
+
isMany = true;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
if (!targetRelation) {
|
|
1424
|
+
throw new Error(`Through relation "${modelName}.${fieldName}" is missing a target path.`);
|
|
1425
|
+
}
|
|
1426
|
+
sourceRelations.push({
|
|
1427
|
+
fieldName,
|
|
1428
|
+
targetModel: targetRelation.targetModel,
|
|
1429
|
+
optional: !isMany,
|
|
1430
|
+
array: isMany,
|
|
1431
|
+
relationName: null,
|
|
1432
|
+
fields: null,
|
|
1433
|
+
references: null,
|
|
1434
|
+
hasDefault: false,
|
|
1435
|
+
kind: "through",
|
|
1436
|
+
throughPath
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
modelRelations.set(modelName, sourceRelations);
|
|
1440
|
+
}
|
|
1441
|
+
return {
|
|
1442
|
+
modelRelations,
|
|
1443
|
+
inverseRelations
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
__name(buildRelations, "buildRelations");
|
|
1447
|
+
|
|
1448
|
+
// src/codegen/typed-json.ts
|
|
1449
|
+
var import_casing = require("drizzle-orm/casing");
|
|
1450
|
+
var import_ts_morph = require("ts-morph");
|
|
1451
|
+
function unwrapNullableType(type) {
|
|
1452
|
+
if (!type.isUnion()) return type;
|
|
1453
|
+
const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
|
|
1454
|
+
if (nonNull.length !== 1) return type;
|
|
1455
|
+
return unwrapNullableType(nonNull[0]);
|
|
1456
|
+
}
|
|
1457
|
+
__name(unwrapNullableType, "unwrapNullableType");
|
|
1458
|
+
function getResolvedArrayInfo(type) {
|
|
1459
|
+
const resolvedType = unwrapNullableType(type);
|
|
1460
|
+
if (!resolvedType.isArray()) {
|
|
1461
|
+
return {
|
|
1462
|
+
resolvedType,
|
|
1463
|
+
isArray: false
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
return {
|
|
1467
|
+
resolvedType: resolvedType.getArrayElementTypeOrThrow(),
|
|
1468
|
+
isArray: true
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
__name(getResolvedArrayInfo, "getResolvedArrayInfo");
|
|
1472
|
+
function normalizeTypeText(typeText) {
|
|
1473
|
+
let normalized = typeText.replace(/\s+/g, " ").trim();
|
|
1474
|
+
normalized = normalized.replace(/\s*\|\s*(?:null|undefined)\s*$/g, "").trim();
|
|
1475
|
+
let isArray = false;
|
|
1476
|
+
if (normalized.endsWith("[]")) {
|
|
1477
|
+
normalized = normalized.slice(0, -2).trim();
|
|
1478
|
+
isArray = true;
|
|
1479
|
+
}
|
|
1480
|
+
if (normalized.startsWith("(") && normalized.endsWith(")")) {
|
|
1481
|
+
normalized = normalized.slice(1, -1).trim();
|
|
1482
|
+
}
|
|
1483
|
+
return {
|
|
1484
|
+
baseText: normalized,
|
|
1485
|
+
isArray
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
__name(normalizeTypeText, "normalizeTypeText");
|
|
1489
|
+
function buildTypeDefs(typesPath, tables, views, enumMap) {
|
|
1490
|
+
const project = createTypedJsonProject(typesPath, !!views?.length);
|
|
1491
|
+
const sf = project.getSourceFileOrThrow(typesPath);
|
|
1492
|
+
const typeDefs = /* @__PURE__ */ new Map();
|
|
1493
|
+
const fieldToTypeDef = /* @__PURE__ */ new Map();
|
|
1494
|
+
const typedJsonFieldMap = /* @__PURE__ */ new Map();
|
|
1495
|
+
const exportedTypes = createExportedTypeRegistry(sf);
|
|
1496
|
+
const entityBySqlName = /* @__PURE__ */ new Map();
|
|
1497
|
+
for (const table of tables) entityBySqlName.set(table.sqlName, table);
|
|
1498
|
+
for (const view of views || []) entityBySqlName.set(view.sqlName, view);
|
|
1499
|
+
const tableByExportName = new Map(tables.map((table) => [
|
|
1500
|
+
table.exportName,
|
|
1501
|
+
table
|
|
1502
|
+
]));
|
|
1503
|
+
const sourceFiles = [
|
|
1504
|
+
"supabase/schema/tables.ts"
|
|
1505
|
+
];
|
|
1506
|
+
if (views?.length) sourceFiles.push("supabase/schema/views.ts");
|
|
1507
|
+
for (const filePath of sourceFiles) {
|
|
1508
|
+
scanFileForTypedColumns({
|
|
1509
|
+
sourceFile: project.getSourceFileOrThrow(filePath),
|
|
1510
|
+
exportedTypes,
|
|
1511
|
+
typeDefs,
|
|
1512
|
+
fieldToTypeDef,
|
|
1513
|
+
typedJsonFieldMap,
|
|
1514
|
+
entityBySqlName,
|
|
1515
|
+
tableByExportName,
|
|
1516
|
+
enumMap: enumMap || /* @__PURE__ */ new Map()
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
return {
|
|
1520
|
+
typeDefs,
|
|
1521
|
+
fieldToTypeDef,
|
|
1522
|
+
typedJsonFields: sortTypedJsonFields([
|
|
1523
|
+
...typedJsonFieldMap.values()
|
|
1524
|
+
])
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
__name(buildTypeDefs, "buildTypeDefs");
|
|
1528
|
+
function createExportedTypeRegistry(sourceFile) {
|
|
1529
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
1530
|
+
const resolvedTypes = /* @__PURE__ */ new Map();
|
|
1531
|
+
for (const stmt of sourceFile.getStatements()) {
|
|
1532
|
+
if (stmt.getKind() === import_ts_morph.SyntaxKind.TypeAliasDeclaration) {
|
|
1533
|
+
const typeAlias = stmt.asKindOrThrow(import_ts_morph.SyntaxKind.TypeAliasDeclaration);
|
|
1534
|
+
if (typeAlias.isExported()) {
|
|
1535
|
+
declarations.set(typeAlias.getName(), typeAlias);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
if (stmt.getKind() === import_ts_morph.SyntaxKind.InterfaceDeclaration) {
|
|
1539
|
+
const iface = stmt.asKindOrThrow(import_ts_morph.SyntaxKind.InterfaceDeclaration);
|
|
1540
|
+
if (iface.isExported()) {
|
|
1541
|
+
declarations.set(iface.getName(), iface);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return {
|
|
1546
|
+
has(name) {
|
|
1547
|
+
return declarations.has(name);
|
|
1548
|
+
},
|
|
1549
|
+
get(name) {
|
|
1550
|
+
if (!declarations.has(name)) return void 0;
|
|
1551
|
+
const cachedType = resolvedTypes.get(name);
|
|
1552
|
+
if (cachedType) return cachedType;
|
|
1553
|
+
const declaration = declarations.get(name);
|
|
1554
|
+
if (!declaration) return void 0;
|
|
1555
|
+
const resolvedType = declaration.getType();
|
|
1556
|
+
resolvedTypes.set(name, resolvedType);
|
|
1557
|
+
return resolvedType;
|
|
1558
|
+
}
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
__name(createExportedTypeRegistry, "createExportedTypeRegistry");
|
|
1562
|
+
function createTypedJsonProject(typesPath, includeViews) {
|
|
1563
|
+
const project = new import_ts_morph.Project({
|
|
1564
|
+
skipAddingFilesFromTsConfig: true,
|
|
1565
|
+
compilerOptions: {
|
|
1566
|
+
module: import_ts_morph.ModuleKind.ESNext,
|
|
1567
|
+
moduleResolution: import_ts_morph.ModuleResolutionKind.Bundler,
|
|
1568
|
+
target: import_ts_morph.ScriptTarget.ES2022,
|
|
1569
|
+
allowJs: false,
|
|
1570
|
+
baseUrl: ".",
|
|
1571
|
+
paths: {
|
|
1572
|
+
"@/*": [
|
|
1573
|
+
"src/*"
|
|
1574
|
+
],
|
|
1575
|
+
"~/*": [
|
|
1576
|
+
"app/*"
|
|
1577
|
+
]
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
});
|
|
1581
|
+
project.addSourceFileAtPath(typesPath);
|
|
1582
|
+
project.addSourceFileAtPath("supabase/schema/tables.ts");
|
|
1583
|
+
if (includeViews) {
|
|
1584
|
+
project.addSourceFileAtPath("supabase/schema/views.ts");
|
|
1585
|
+
}
|
|
1586
|
+
return project;
|
|
1587
|
+
}
|
|
1588
|
+
__name(createTypedJsonProject, "createTypedJsonProject");
|
|
1589
|
+
function scanFileForTypedColumns({ sourceFile, exportedTypes, typeDefs, fieldToTypeDef, typedJsonFieldMap, entityBySqlName, tableByExportName, enumMap }) {
|
|
1590
|
+
const registerTypedJsonField = /* @__PURE__ */ __name((entitySqlName, columnSqlName, typeDefName, isArray, sourceTypeName) => {
|
|
1591
|
+
const entity = entityBySqlName.get(entitySqlName);
|
|
1592
|
+
if (!entity) return;
|
|
1593
|
+
const fieldName = entity.sqlToJsKey.get(columnSqlName) || columnSqlName;
|
|
1594
|
+
const fieldKey = `${entitySqlName}.${fieldName}`;
|
|
1595
|
+
fieldToTypeDef.set(fieldKey, {
|
|
1596
|
+
typeDefName,
|
|
1597
|
+
isArray
|
|
1598
|
+
});
|
|
1599
|
+
typedJsonFieldMap.set(fieldKey, {
|
|
1600
|
+
entitySqlName,
|
|
1601
|
+
entityTypeName: entity.typeName,
|
|
1602
|
+
fieldName,
|
|
1603
|
+
typeDefName,
|
|
1604
|
+
isArray,
|
|
1605
|
+
sourceTypeName
|
|
1606
|
+
});
|
|
1607
|
+
}, "registerTypedJsonField");
|
|
1608
|
+
for (const access of sourceFile.getDescendantsOfKind(import_ts_morph.SyntaxKind.PropertyAccessExpression)) {
|
|
1609
|
+
if (access.getName() !== "$type") continue;
|
|
1610
|
+
const call = access.getParentIfKind(import_ts_morph.SyntaxKind.CallExpression);
|
|
1611
|
+
if (!call || call.getExpression() !== access) continue;
|
|
1612
|
+
const typeArg = call.getTypeArguments()[0];
|
|
1613
|
+
if (!typeArg) continue;
|
|
1614
|
+
const propertyAssignment = call.getFirstAncestorByKind(import_ts_morph.SyntaxKind.PropertyAssignment);
|
|
1615
|
+
if (!propertyAssignment) continue;
|
|
1616
|
+
const columnSqlName = propertyAssignment.getName();
|
|
1617
|
+
const entitySqlName = getEntitySqlName(call);
|
|
1618
|
+
if (!entitySqlName) continue;
|
|
1619
|
+
const rawTypeText = typeArg.getText().trim();
|
|
1620
|
+
const { baseText, isArray: isArrayFromText } = normalizeTypeText(rawTypeText);
|
|
1621
|
+
const rowTypeDefName = resolveWholeRowTypeDefName(baseText, tableByExportName, typeDefs, enumMap);
|
|
1622
|
+
if (rowTypeDefName) {
|
|
1623
|
+
const isArray2 = isArrayFromText || getResolvedArrayInfo(typeArg.getType()).isArray;
|
|
1624
|
+
registerTypedJsonField(entitySqlName, columnSqlName, rowTypeDefName, isArray2);
|
|
1625
|
+
continue;
|
|
1626
|
+
}
|
|
1627
|
+
if (exportedTypes.has(baseText)) {
|
|
1628
|
+
const type = exportedTypes.get(baseText);
|
|
1629
|
+
if (type && tryBuildTypeDef(baseText, type, typeDefs, exportedTypes)) {
|
|
1630
|
+
const isArray2 = isArrayFromText || getResolvedArrayInfo(type).isArray;
|
|
1631
|
+
registerTypedJsonField(entitySqlName, columnSqlName, baseText, isArray2, baseText);
|
|
1632
|
+
}
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
const { resolvedType, isArray: isArrayFromType } = getResolvedArrayInfo(typeArg.getType());
|
|
1636
|
+
const isArray = isArrayFromType || isArrayFromText;
|
|
1637
|
+
const generatedName = `${toPascalCase(entitySqlName)}${toPascalCase(columnSqlName)}`;
|
|
1638
|
+
if (tryBuildTypeDef(generatedName, resolvedType, typeDefs, exportedTypes)) {
|
|
1639
|
+
registerTypedJsonField(entitySqlName, columnSqlName, generatedName, isArray);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
__name(scanFileForTypedColumns, "scanFileForTypedColumns");
|
|
1644
|
+
function getEntitySqlName(call) {
|
|
1645
|
+
let node = call.getParent();
|
|
1646
|
+
while (node) {
|
|
1647
|
+
if (node.getKind() === import_ts_morph.SyntaxKind.CallExpression) {
|
|
1648
|
+
const candidate = node.asKindOrThrow(import_ts_morph.SyntaxKind.CallExpression);
|
|
1649
|
+
const callee = candidate.getExpression().getText();
|
|
1650
|
+
if (callee === "pgTable" || callee === "pgView") {
|
|
1651
|
+
const firstArg = candidate.getArguments()[0];
|
|
1652
|
+
return firstArg ? firstArg.getText().replace(/['"]/g, "") : null;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
node = node.getParent();
|
|
1656
|
+
}
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
__name(getEntitySqlName, "getEntitySqlName");
|
|
1660
|
+
function resolveWholeRowTypeDefName(typeText, tableByExportName, typeDefs, enumMap) {
|
|
1661
|
+
const wholeRowMatch = typeText.match(/^typeof\s+(?:t\.)?(\w+)\.\$infer(?:Select|Insert)$/);
|
|
1662
|
+
if (!wholeRowMatch) return null;
|
|
1663
|
+
const refTable = tableByExportName.get(wholeRowMatch[1]);
|
|
1664
|
+
if (!refTable) return null;
|
|
1665
|
+
const rowTypeDefName = `${refTable.typeName}Row`;
|
|
1666
|
+
if (!typeDefs.has(rowTypeDefName)) {
|
|
1667
|
+
buildRowTypeDef(rowTypeDefName, refTable, typeDefs, enumMap);
|
|
1668
|
+
}
|
|
1669
|
+
return typeDefs.has(rowTypeDefName) ? rowTypeDefName : null;
|
|
1670
|
+
}
|
|
1671
|
+
__name(resolveWholeRowTypeDefName, "resolveWholeRowTypeDefName");
|
|
1672
|
+
function buildRowTypeDef(name, table, typeDefs, enumMap) {
|
|
1673
|
+
const fields = {};
|
|
1674
|
+
for (const jsKey of [
|
|
1675
|
+
...table.sqlToJsKey.values()
|
|
1676
|
+
]) {
|
|
1677
|
+
const col = table.table[jsKey];
|
|
1678
|
+
if (!col?.columnType) continue;
|
|
1679
|
+
const mapped = mapColumn(jsKey, col, enumMap);
|
|
1680
|
+
if (mapped.isGenerated) continue;
|
|
1681
|
+
if (mapped.sqlName === "$hash") continue;
|
|
1682
|
+
let type;
|
|
1683
|
+
switch (mapped.type) {
|
|
1684
|
+
case "String":
|
|
1685
|
+
case "Int":
|
|
1686
|
+
case "Float":
|
|
1687
|
+
case "Boolean":
|
|
1688
|
+
case "DateTime":
|
|
1689
|
+
case "Json":
|
|
1690
|
+
type = mapped.type;
|
|
1691
|
+
break;
|
|
1692
|
+
case "BigInt":
|
|
1693
|
+
type = "Int";
|
|
1694
|
+
break;
|
|
1695
|
+
case "Decimal":
|
|
1696
|
+
type = "Float";
|
|
1697
|
+
break;
|
|
1698
|
+
default:
|
|
1699
|
+
type = "String";
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
const fieldName = (0, import_casing.toCamelCase)(mapped.name);
|
|
1703
|
+
fields[fieldName] = {
|
|
1704
|
+
name: fieldName,
|
|
1705
|
+
...fieldName !== mapped.name && {
|
|
1706
|
+
rawName: mapped.name
|
|
1707
|
+
},
|
|
1708
|
+
type,
|
|
1709
|
+
...mapped.optional && {
|
|
1710
|
+
optional: true
|
|
1711
|
+
},
|
|
1712
|
+
...mapped.array && {
|
|
1713
|
+
array: true
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
if (Object.keys(fields).length > 0) {
|
|
1718
|
+
typeDefs.set(name, {
|
|
1719
|
+
name,
|
|
1720
|
+
fields
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
__name(buildRowTypeDef, "buildRowTypeDef");
|
|
1725
|
+
function tryBuildTypeDef(name, type, typeDefs, exportedTypes) {
|
|
1726
|
+
if (typeDefs.has(name)) return true;
|
|
1727
|
+
if (type.isArray()) {
|
|
1728
|
+
return tryBuildTypeDef(name, type.getArrayElementTypeOrThrow(), typeDefs, exportedTypes);
|
|
1729
|
+
}
|
|
1730
|
+
if (type.isUnion()) {
|
|
1731
|
+
const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
|
|
1732
|
+
if (nonNull.length === 1) {
|
|
1733
|
+
return tryBuildTypeDef(name, nonNull[0], typeDefs, exportedTypes);
|
|
1734
|
+
}
|
|
1735
|
+
return false;
|
|
1736
|
+
}
|
|
1737
|
+
if (!type.isObject() || type.getProperties().length === 0) return false;
|
|
1738
|
+
if (type.getStringIndexType()) return false;
|
|
1739
|
+
if (type.getCallSignatures().length > 0) return false;
|
|
1740
|
+
const fields = {};
|
|
1741
|
+
for (const prop of type.getProperties()) {
|
|
1742
|
+
const propName = prop.getName();
|
|
1743
|
+
const declaration = prop.getValueDeclaration();
|
|
1744
|
+
if (!declaration) continue;
|
|
1745
|
+
const propType = prop.getTypeAtLocation(declaration);
|
|
1746
|
+
const fieldName = (0, import_casing.toCamelCase)(propName);
|
|
1747
|
+
const mappedField = mapTypeToTypeDef(propName, propType, name, typeDefs, exportedTypes);
|
|
1748
|
+
fields[fieldName] = {
|
|
1749
|
+
name: fieldName,
|
|
1750
|
+
...fieldName !== propName && {
|
|
1751
|
+
rawName: propName
|
|
1752
|
+
},
|
|
1753
|
+
type: mappedField?.type || "Json",
|
|
1754
|
+
...prop.isOptional() && {
|
|
1755
|
+
optional: true
|
|
1756
|
+
},
|
|
1757
|
+
...mappedField?.isArray && {
|
|
1758
|
+
array: true
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
if (Object.keys(fields).length === 0) return false;
|
|
1763
|
+
typeDefs.set(name, {
|
|
1764
|
+
name,
|
|
1765
|
+
fields
|
|
1766
|
+
});
|
|
1767
|
+
return true;
|
|
1768
|
+
}
|
|
1769
|
+
__name(tryBuildTypeDef, "tryBuildTypeDef");
|
|
1770
|
+
function mapTypeToTypeDef(fieldName, type, parentName, typeDefs, exportedTypes) {
|
|
1771
|
+
if (type.isUnion()) {
|
|
1772
|
+
const unwrapped = unwrapNullableType(type);
|
|
1773
|
+
if (unwrapped !== type) {
|
|
1774
|
+
return mapTypeToTypeDef(fieldName, unwrapped, parentName, typeDefs, exportedTypes);
|
|
1775
|
+
}
|
|
1776
|
+
const nonNull = type.getUnionTypes().filter((member) => !member.isNull() && !member.isUndefined());
|
|
1777
|
+
if (nonNull.every((member) => member.isStringLiteral() || member.isString())) {
|
|
1778
|
+
return {
|
|
1779
|
+
type: "String",
|
|
1780
|
+
isArray: false
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
if (nonNull.every((member) => member.isNumberLiteral() || member.isNumber())) {
|
|
1784
|
+
return {
|
|
1785
|
+
type: "Float",
|
|
1786
|
+
isArray: false
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1789
|
+
if (nonNull.every((member) => member.isBooleanLiteral() || member.isBoolean())) {
|
|
1790
|
+
return {
|
|
1791
|
+
type: "Boolean",
|
|
1792
|
+
isArray: false
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
return null;
|
|
1796
|
+
}
|
|
1797
|
+
if (type.isString() || type.isStringLiteral()) return {
|
|
1798
|
+
type: "String",
|
|
1799
|
+
isArray: false
|
|
1800
|
+
};
|
|
1801
|
+
if (type.isNumber() || type.isNumberLiteral()) return {
|
|
1802
|
+
type: "Float",
|
|
1803
|
+
isArray: false
|
|
1804
|
+
};
|
|
1805
|
+
if (type.isBoolean() || type.isBooleanLiteral()) return {
|
|
1806
|
+
type: "Boolean",
|
|
1807
|
+
isArray: false
|
|
1808
|
+
};
|
|
1809
|
+
if (type.getSymbol()?.getName() === "Date") return {
|
|
1810
|
+
type: "DateTime",
|
|
1811
|
+
isArray: false
|
|
1812
|
+
};
|
|
1813
|
+
if (type.isArray()) {
|
|
1814
|
+
const inner = mapTypeToTypeDef(fieldName, type.getArrayElementTypeOrThrow(), parentName, typeDefs, exportedTypes);
|
|
1815
|
+
return inner ? {
|
|
1816
|
+
type: inner.type,
|
|
1817
|
+
isArray: true
|
|
1818
|
+
} : null;
|
|
1819
|
+
}
|
|
1820
|
+
if (type.isObject() && type.getProperties().length > 0) {
|
|
1821
|
+
if (type.getStringIndexType()) return {
|
|
1822
|
+
type: "Json",
|
|
1823
|
+
isArray: false
|
|
1824
|
+
};
|
|
1825
|
+
if (type.getCallSignatures().length > 0) return null;
|
|
1826
|
+
const symbol = type.getAliasSymbol() || type.getSymbol();
|
|
1827
|
+
const knownName = symbol?.getName();
|
|
1828
|
+
if (knownName && exportedTypes.has(knownName)) {
|
|
1829
|
+
if (tryBuildTypeDef(knownName, type, typeDefs, exportedTypes)) {
|
|
1830
|
+
return {
|
|
1831
|
+
type: knownName,
|
|
1832
|
+
isArray: false
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
const subTypeDefName = `${parentName}${toPascalCase(fieldName)}`;
|
|
1837
|
+
if (tryBuildTypeDef(subTypeDefName, type, typeDefs, exportedTypes)) {
|
|
1838
|
+
return {
|
|
1839
|
+
type: subTypeDefName,
|
|
1840
|
+
isArray: false
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
return null;
|
|
1845
|
+
}
|
|
1846
|
+
__name(mapTypeToTypeDef, "mapTypeToTypeDef");
|
|
1847
|
+
function emitTypeDefsBlock(typeDefs) {
|
|
1848
|
+
if (typeDefs.size === 0) return "";
|
|
1849
|
+
const lines = [];
|
|
1850
|
+
lines.push(" typeDefs = {");
|
|
1851
|
+
for (const [name, typeDef] of sortTypeDefs(typeDefs)) {
|
|
1852
|
+
lines.push(` ${name}: {`);
|
|
1853
|
+
lines.push(` name: ${esc(typeDef.name)},`);
|
|
1854
|
+
lines.push(` fields: {`);
|
|
1855
|
+
for (const field of Object.values(typeDef.fields)) {
|
|
1856
|
+
const parts = [
|
|
1857
|
+
`name: ${esc(field.name)}`,
|
|
1858
|
+
`type: ${esc(field.type)}`
|
|
1859
|
+
];
|
|
1860
|
+
if (field.optional) parts.push("optional: true");
|
|
1861
|
+
if (field.array) parts.push("array: true");
|
|
1862
|
+
if (field.rawName && field.rawName !== field.name) {
|
|
1863
|
+
parts.push(`attributes: [{ name: "@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(field.rawName)}) }] }]`);
|
|
1864
|
+
}
|
|
1865
|
+
lines.push(` ${field.name}: { ${parts.join(", ")} },`);
|
|
1866
|
+
}
|
|
1867
|
+
lines.push(" }");
|
|
1868
|
+
lines.push(" },");
|
|
1869
|
+
}
|
|
1870
|
+
lines.push(" } as const;");
|
|
1871
|
+
return lines.join("\n");
|
|
1872
|
+
}
|
|
1873
|
+
__name(emitTypeDefsBlock, "emitTypeDefsBlock");
|
|
1874
|
+
function mapTypeDefFieldToTs(field, typeDefs) {
|
|
1875
|
+
let tsType;
|
|
1876
|
+
switch (field.type) {
|
|
1877
|
+
case "String":
|
|
1878
|
+
tsType = "string";
|
|
1879
|
+
break;
|
|
1880
|
+
case "Int":
|
|
1881
|
+
case "Float":
|
|
1882
|
+
tsType = "number";
|
|
1883
|
+
break;
|
|
1884
|
+
case "Boolean":
|
|
1885
|
+
tsType = "boolean";
|
|
1886
|
+
break;
|
|
1887
|
+
case "DateTime":
|
|
1888
|
+
tsType = "Date";
|
|
1889
|
+
break;
|
|
1890
|
+
case "Json":
|
|
1891
|
+
tsType = "unknown";
|
|
1892
|
+
break;
|
|
1893
|
+
default:
|
|
1894
|
+
tsType = typeDefs.has(field.type) ? `${field.type}JsonShape` : "unknown";
|
|
1895
|
+
break;
|
|
1896
|
+
}
|
|
1897
|
+
return field.array ? `${tsType}[]` : tsType;
|
|
1898
|
+
}
|
|
1899
|
+
__name(mapTypeDefFieldToTs, "mapTypeDefFieldToTs");
|
|
1900
|
+
function getJsonFieldAlias(info) {
|
|
1901
|
+
return `${info.entityTypeName}${toPascalCase(info.fieldName)}Json`;
|
|
1902
|
+
}
|
|
1903
|
+
__name(getJsonFieldAlias, "getJsonFieldAlias");
|
|
1904
|
+
function getJsonRawFieldAlias(info) {
|
|
1905
|
+
return `${getJsonFieldAlias(info)}Raw`;
|
|
1906
|
+
}
|
|
1907
|
+
__name(getJsonRawFieldAlias, "getJsonRawFieldAlias");
|
|
1908
|
+
function emitJsonNamespaceBlock(typeDefs, typedJsonFields, indent2 = "") {
|
|
1909
|
+
const out = [];
|
|
1910
|
+
for (const [name, typeDef] of sortTypeDefs(typeDefs)) {
|
|
1911
|
+
out.push(`${indent2}export type ${name}JsonShape = {`);
|
|
1912
|
+
for (const field of Object.values(typeDef.fields)) {
|
|
1913
|
+
const optional = field.optional ? "?" : "";
|
|
1914
|
+
out.push(`${indent2} ${field.name}${optional}: ${mapTypeDefFieldToTs(field, typeDefs)};`);
|
|
1915
|
+
}
|
|
1916
|
+
out.push(`${indent2}};`);
|
|
1917
|
+
out.push("");
|
|
1918
|
+
}
|
|
1919
|
+
for (const info of typedJsonFields) {
|
|
1920
|
+
out.push(`${indent2}export type ${getJsonFieldAlias(info)} = ${info.typeDefName}JsonShape;`);
|
|
1921
|
+
out.push("");
|
|
1922
|
+
}
|
|
1923
|
+
if (out.at(-1) === "") {
|
|
1924
|
+
out.pop();
|
|
1925
|
+
}
|
|
1926
|
+
return out;
|
|
1927
|
+
}
|
|
1928
|
+
__name(emitJsonNamespaceBlock, "emitJsonNamespaceBlock");
|
|
1929
|
+
function emitJsonRawNamespaceBlock(typedJsonFields, indent2 = "") {
|
|
1930
|
+
const out = [];
|
|
1931
|
+
for (const info of typedJsonFields.filter((field) => field.sourceTypeName)) {
|
|
1932
|
+
out.push(`${indent2}export type ${getJsonRawFieldAlias(info)} = RawJson.${info.sourceTypeName};`);
|
|
1933
|
+
out.push("");
|
|
1934
|
+
}
|
|
1935
|
+
if (out.at(-1) === "") {
|
|
1936
|
+
out.pop();
|
|
1937
|
+
}
|
|
1938
|
+
return out;
|
|
1939
|
+
}
|
|
1940
|
+
__name(emitJsonRawNamespaceBlock, "emitJsonRawNamespaceBlock");
|
|
1941
|
+
function emitJsonTs(typeDefs, typedJsonFields) {
|
|
1942
|
+
const out = [
|
|
1943
|
+
...emitGeneratedFileBanner(),
|
|
1944
|
+
""
|
|
1945
|
+
];
|
|
1946
|
+
out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields));
|
|
1947
|
+
out.push("");
|
|
1948
|
+
return out.join("\n");
|
|
1949
|
+
}
|
|
1950
|
+
__name(emitJsonTs, "emitJsonTs");
|
|
1951
|
+
function emitJsonRawTs(typedJsonFields) {
|
|
1952
|
+
const out = [
|
|
1953
|
+
...emitGeneratedFileBanner(),
|
|
1954
|
+
"",
|
|
1955
|
+
'import type * as RawJson from "../../supabase/schema/types";',
|
|
1956
|
+
""
|
|
1957
|
+
];
|
|
1958
|
+
out.push(...emitJsonRawNamespaceBlock(typedJsonFields));
|
|
1959
|
+
out.push("");
|
|
1960
|
+
return out.join("\n");
|
|
1961
|
+
}
|
|
1962
|
+
__name(emitJsonRawTs, "emitJsonRawTs");
|
|
1963
|
+
function sortTypeDefs(typeDefs) {
|
|
1964
|
+
return [
|
|
1965
|
+
...typeDefs.entries()
|
|
1966
|
+
].sort(([left], [right]) => left.localeCompare(right));
|
|
1967
|
+
}
|
|
1968
|
+
__name(sortTypeDefs, "sortTypeDefs");
|
|
1969
|
+
function sortTypedJsonFields(typedJsonFields) {
|
|
1970
|
+
return [
|
|
1971
|
+
...typedJsonFields
|
|
1972
|
+
].sort((left, right) => {
|
|
1973
|
+
const leftKey = `${getJsonFieldAlias(left)}:${left.sourceTypeName || ""}`;
|
|
1974
|
+
const rightKey = `${getJsonFieldAlias(right)}:${right.sourceTypeName || ""}`;
|
|
1975
|
+
return leftKey.localeCompare(rightKey);
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
__name(sortTypedJsonFields, "sortTypedJsonFields");
|
|
1979
|
+
|
|
1980
|
+
// src/codegen/emit.ts
|
|
1981
|
+
var DB_ATTR_RE = /@db\.(\w+)(?:\((\d+)\))?/;
|
|
1982
|
+
function buildDerivedEnumName(modelName, fieldName) {
|
|
1983
|
+
return `${toPascalCase(modelName)}${toPascalCase(fieldName)}`;
|
|
1984
|
+
}
|
|
1985
|
+
__name(buildDerivedEnumName, "buildDerivedEnumName");
|
|
1986
|
+
function inferFieldIsNonNull(defaultWhere, fieldName) {
|
|
1987
|
+
if (!defaultWhere) return false;
|
|
1988
|
+
const condition = defaultWhere[fieldName];
|
|
1989
|
+
if (condition === void 0 || condition === null) return false;
|
|
1990
|
+
if (Array.isArray(condition)) return condition.length > 0;
|
|
1991
|
+
if (typeof condition !== "object") return true;
|
|
1992
|
+
if (Object.prototype.hasOwnProperty.call(condition, "not") && Reflect.get(condition, "not") === null) {
|
|
1993
|
+
return true;
|
|
1994
|
+
}
|
|
1995
|
+
if (Object.prototype.hasOwnProperty.call(condition, "in")) {
|
|
1996
|
+
const values = Reflect.get(condition, "in");
|
|
1997
|
+
return Array.isArray(values) && values.length > 0;
|
|
1998
|
+
}
|
|
1999
|
+
return false;
|
|
2000
|
+
}
|
|
2001
|
+
__name(inferFieldIsNonNull, "inferFieldIsNonNull");
|
|
2002
|
+
function applyDerivedFieldOverrides(field, table) {
|
|
2003
|
+
if (!table.derivedFrom) return field;
|
|
2004
|
+
const narrowedValues = table.narrow?.[field.name];
|
|
2005
|
+
return {
|
|
2006
|
+
...field,
|
|
2007
|
+
// Keep base enum type — narrowing is handled at runtime by derived-models plugin
|
|
2008
|
+
optional: narrowedValues && narrowedValues.length > 0 ? false : field.optional && !inferFieldIsNonNull(table.defaultWhere, field.name)
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
__name(applyDerivedFieldOverrides, "applyDerivedFieldOverrides");
|
|
2012
|
+
function collectDerivedEnums(tables, enumMap) {
|
|
2013
|
+
const derivedEnums = /* @__PURE__ */ new Map();
|
|
2014
|
+
const tablesByModel = new Map(tables.map((table) => [
|
|
2015
|
+
table.modelName,
|
|
2016
|
+
table
|
|
2017
|
+
]));
|
|
2018
|
+
for (const table of tables) {
|
|
2019
|
+
if (!table.derivedFrom || !table.narrow) continue;
|
|
2020
|
+
const baseTable = tablesByModel.get(table.derivedFrom);
|
|
2021
|
+
if (!baseTable) continue;
|
|
2022
|
+
const baseFields = /* @__PURE__ */ new Map();
|
|
2023
|
+
for (const jsKey of baseTable.sqlToJsKey.values()) {
|
|
2024
|
+
const column = baseTable.table[jsKey];
|
|
2025
|
+
const field = mapColumn(jsKey, column, enumMap);
|
|
2026
|
+
baseFields.set(field.name === "$hash" ? "hash" : field.name, field);
|
|
2027
|
+
}
|
|
2028
|
+
for (const [fieldName, narrowedValues] of Object.entries(table.narrow)) {
|
|
2029
|
+
if (!narrowedValues.length) continue;
|
|
2030
|
+
const baseField = baseFields.get(fieldName);
|
|
2031
|
+
if (!baseField) {
|
|
2032
|
+
throw new Error(`Unknown narrowed field "${table.modelName}.${fieldName}".`);
|
|
2033
|
+
}
|
|
2034
|
+
const baseEnum = [
|
|
2035
|
+
...enumMap.values()
|
|
2036
|
+
].find((info) => info.zenstackName === baseField.type);
|
|
2037
|
+
if (!baseEnum) {
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
2040
|
+
const values = narrowedValues.map((value) => String(value));
|
|
2041
|
+
for (const value of values) {
|
|
2042
|
+
if (!baseEnum.values.includes(value)) {
|
|
2043
|
+
throw new Error(`Invalid narrowed enum value "${value}" for "${table.modelName}.${fieldName}".`);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
const enumName = buildDerivedEnumName(table.modelName, fieldName);
|
|
2047
|
+
if (derivedEnums.has(enumName)) continue;
|
|
2048
|
+
const mapping = baseEnum.mapping ? Object.fromEntries(Object.entries(baseEnum.mapping).filter(([, value]) => values.includes(value))) : Object.fromEntries(values.map((value) => [
|
|
2049
|
+
toPascalCase(value).toUpperCase(),
|
|
2050
|
+
value
|
|
2051
|
+
]));
|
|
2052
|
+
derivedEnums.set(enumName, {
|
|
2053
|
+
pgName: `$derived:${enumName}`,
|
|
2054
|
+
zenstackName: enumName,
|
|
2055
|
+
values,
|
|
2056
|
+
mapping,
|
|
2057
|
+
mappedName: null
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
return derivedEnums;
|
|
2062
|
+
}
|
|
2063
|
+
__name(collectDerivedEnums, "collectDerivedEnums");
|
|
2064
|
+
function emitEnumBlock(info) {
|
|
2065
|
+
const lines = [];
|
|
2066
|
+
lines.push(` ${info.zenstackName}: {`);
|
|
2067
|
+
lines.push(` name: ${esc(info.zenstackName)},`);
|
|
2068
|
+
const tuples = info.mapping ? (() => {
|
|
2069
|
+
const invertedMap = Object.fromEntries(Object.entries(info.mapping).map(([k, v]) => [
|
|
2070
|
+
v,
|
|
2071
|
+
k
|
|
2072
|
+
]));
|
|
2073
|
+
return info.values.map((v) => {
|
|
2074
|
+
const key = invertedMap[v];
|
|
2075
|
+
if (!key) throw new Error(`Enum "${info.pgName}" value "${v}" not found in mapping.`);
|
|
2076
|
+
return [
|
|
2077
|
+
v,
|
|
2078
|
+
key
|
|
2079
|
+
];
|
|
2080
|
+
});
|
|
2081
|
+
})() : info.values.map((v) => [
|
|
2082
|
+
v,
|
|
2083
|
+
v
|
|
2084
|
+
]);
|
|
2085
|
+
const valuesEntries = tuples.map(([value]) => `${esc(value)}: ${esc(value)}`);
|
|
2086
|
+
lines.push(` values: { ${valuesEntries.join(", ")} },`);
|
|
2087
|
+
lines.push(` fields: {`);
|
|
2088
|
+
for (const [v] of tuples) {
|
|
2089
|
+
lines.push(` ${esc(v)}: { name: ${esc(v)} },`);
|
|
2090
|
+
}
|
|
2091
|
+
lines.push(` },`);
|
|
2092
|
+
const mappedName = info.mappedName === void 0 ? info.pgName : info.mappedName;
|
|
2093
|
+
if (mappedName) {
|
|
2094
|
+
lines.push(` attributes: [{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(mappedName)}) }] }]`);
|
|
2095
|
+
}
|
|
2096
|
+
lines.push(` }`);
|
|
2097
|
+
return lines.join("\n");
|
|
2098
|
+
}
|
|
2099
|
+
__name(emitEnumBlock, "emitEnumBlock");
|
|
2100
|
+
function emitFieldBlock(field) {
|
|
2101
|
+
const parts = [];
|
|
2102
|
+
parts.push(`name: ${esc(field.name)}`);
|
|
2103
|
+
parts.push(`type: ${esc(field.type)}`);
|
|
2104
|
+
if (field.optional) parts.push("optional: true");
|
|
2105
|
+
if (field.array) parts.push("array: true");
|
|
2106
|
+
if (field.id) parts.push("id: true");
|
|
2107
|
+
if (field.unique) parts.push("unique: true");
|
|
2108
|
+
const attrs = [];
|
|
2109
|
+
if (field.id) attrs.push('{ name: "@id" }');
|
|
2110
|
+
if (field.unique) attrs.push('{ name: "@unique" }');
|
|
2111
|
+
if (field.name !== field.sqlName) {
|
|
2112
|
+
attrs.push(`{ name: "@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(field.sqlName)}) }] }`);
|
|
2113
|
+
}
|
|
2114
|
+
for (const da of field.dbAttrs) {
|
|
2115
|
+
const match = da.match(DB_ATTR_RE);
|
|
2116
|
+
if (match) {
|
|
2117
|
+
const [, attrName, arg] = match;
|
|
2118
|
+
if (arg) {
|
|
2119
|
+
attrs.push(`{ name: "@db.${attrName}", args: [{ name: "x", value: ExpressionUtils.literal(${arg}) }] }`);
|
|
2120
|
+
} else {
|
|
2121
|
+
attrs.push(`{ name: "@db.${attrName}" }`);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
if (field.defaultExpr) {
|
|
2126
|
+
const attrValue = field.defaultExpr === "[] as FieldDefault" ? 'ExpressionUtils.literal("[]")' : field.defaultExpr;
|
|
2127
|
+
attrs.push(`{ name: "@default", args: [{ name: "value", value: ${attrValue} }] }`);
|
|
2128
|
+
}
|
|
2129
|
+
if (field.isGenerated) {
|
|
2130
|
+
attrs.push('{ name: "@ignore" }');
|
|
2131
|
+
}
|
|
2132
|
+
if (field.isJsonColumn && field.type !== "Json") {
|
|
2133
|
+
attrs.push('{ name: "@json" }');
|
|
2134
|
+
}
|
|
2135
|
+
if (attrs.length > 0) {
|
|
2136
|
+
parts.push(`attributes: [${attrs.join(", ")}]`);
|
|
2137
|
+
}
|
|
2138
|
+
if (field.defaultExpr) {
|
|
2139
|
+
if (field.defaultExpr.startsWith("ExpressionUtils.literal(")) {
|
|
2140
|
+
const inner = field.defaultExpr.slice("ExpressionUtils.literal(".length, -1);
|
|
2141
|
+
parts.push(`default: ${inner}`);
|
|
2142
|
+
} else {
|
|
2143
|
+
parts.push(`default: ${field.defaultExpr}`);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
return `{ ${parts.join(", ")} }`;
|
|
2147
|
+
}
|
|
2148
|
+
__name(emitFieldBlock, "emitFieldBlock");
|
|
2149
|
+
function emitRelationField(rel, opposite) {
|
|
2150
|
+
const parts = [];
|
|
2151
|
+
parts.push(`name: ${esc(rel.fieldName)}`);
|
|
2152
|
+
parts.push(`type: ${esc(rel.targetModel)}`);
|
|
2153
|
+
if (rel.optional) parts.push("optional: true");
|
|
2154
|
+
if (rel.array) parts.push("array: true");
|
|
2155
|
+
const relParts = [];
|
|
2156
|
+
if (opposite) relParts.push(`opposite: ${esc(opposite)}`);
|
|
2157
|
+
if (rel.relationName) relParts.push(`name: ${esc(rel.relationName)}`);
|
|
2158
|
+
if (rel.fields) relParts.push(`fields: [${rel.fields.map((f) => esc(f)).join(", ")}]`);
|
|
2159
|
+
if (rel.references) relParts.push(`references: [${rel.references.map((r) => esc(r)).join(", ")}]`);
|
|
2160
|
+
if (rel.hasDefault) relParts.push("hasDefault: true");
|
|
2161
|
+
parts.push(`relation: { ${relParts.join(", ")} }`);
|
|
2162
|
+
const attrArgs = [];
|
|
2163
|
+
if (rel.relationName) {
|
|
2164
|
+
attrArgs.push(`{ name: "name", value: ExpressionUtils.literal(${esc(rel.relationName)}) }`);
|
|
2165
|
+
}
|
|
2166
|
+
if (rel.fields) {
|
|
2167
|
+
attrArgs.push(`{ name: "fields", value: ExpressionUtils.array("String", [${rel.fields.map((f) => `ExpressionUtils.field(${esc(f)})`).join(", ")}]) }`);
|
|
2168
|
+
}
|
|
2169
|
+
if (rel.references) {
|
|
2170
|
+
attrArgs.push(`{ name: "references", value: ExpressionUtils.array("String", [${rel.references.map((r) => `ExpressionUtils.field(${esc(r)})`).join(", ")}]) }`);
|
|
2171
|
+
}
|
|
2172
|
+
if (attrArgs.length > 0) {
|
|
2173
|
+
parts.push(`attributes: [{ name: "@relation", args: [${attrArgs.join(", ")}] }]`);
|
|
2174
|
+
}
|
|
2175
|
+
return `{ ${parts.join(", ")} }`;
|
|
2176
|
+
}
|
|
2177
|
+
__name(emitRelationField, "emitRelationField");
|
|
2178
|
+
function emitUnknownLiteral(value) {
|
|
2179
|
+
if (value === null) return "null";
|
|
2180
|
+
if (typeof value === "string") return esc(value);
|
|
2181
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2182
|
+
if (Array.isArray(value)) {
|
|
2183
|
+
return `[${value.map((item) => emitUnknownLiteral(item)).join(", ")}]`;
|
|
2184
|
+
}
|
|
2185
|
+
if (typeof value === "object") {
|
|
2186
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${JSON.stringify(key)}: ${emitUnknownLiteral(item)}`).join(", ")} }`;
|
|
2187
|
+
}
|
|
2188
|
+
throw new Error(`Unsupported config literal: ${String(value)}`);
|
|
2189
|
+
}
|
|
2190
|
+
__name(emitUnknownLiteral, "emitUnknownLiteral");
|
|
2191
|
+
function emitPluginsBlock(modelRelations, searchDefaults, modelScopes) {
|
|
2192
|
+
const lines = [];
|
|
2193
|
+
lines.push(" plugins = {");
|
|
2194
|
+
lines.push(" virtualRelations: {");
|
|
2195
|
+
for (const [model2, relations] of modelRelations) {
|
|
2196
|
+
const virtualRelations = relations.filter((relation) => relation.kind && relation.kind !== "normal");
|
|
2197
|
+
if (virtualRelations.length === 0) continue;
|
|
2198
|
+
lines.push(` ${model2}: {`);
|
|
2199
|
+
for (const relation of virtualRelations) {
|
|
2200
|
+
const parts = [
|
|
2201
|
+
`kind: ${esc(relation.kind)}`,
|
|
2202
|
+
`targetModel: ${esc(relation.targetModel)}`
|
|
2203
|
+
];
|
|
2204
|
+
if (relation.sourceRelation) {
|
|
2205
|
+
parts.push(`relation: ${esc(relation.sourceRelation)}`);
|
|
2206
|
+
}
|
|
2207
|
+
if (relation.throughPath) {
|
|
2208
|
+
parts.push(`path: [${relation.throughPath.map((segment) => esc(segment)).join(", ")}]`);
|
|
2209
|
+
}
|
|
2210
|
+
if (relation.where) {
|
|
2211
|
+
parts.push(`where: ${emitUnknownLiteral(relation.where)}`);
|
|
2212
|
+
}
|
|
2213
|
+
if (relation.single) {
|
|
2214
|
+
parts.push("single: true");
|
|
2215
|
+
}
|
|
2216
|
+
lines.push(` ${relation.fieldName}: { ${parts.join(", ")} },`);
|
|
2217
|
+
}
|
|
2218
|
+
lines.push(" },");
|
|
2219
|
+
}
|
|
2220
|
+
lines.push(" },");
|
|
2221
|
+
lines.push(" searchDefaults: {");
|
|
2222
|
+
for (const [model2, profiles] of Object.entries(searchDefaults)) {
|
|
2223
|
+
if (!profiles) continue;
|
|
2224
|
+
lines.push(` ${model2}: {`);
|
|
2225
|
+
for (const [profile, declaration] of Object.entries(profiles)) {
|
|
2226
|
+
const parts = [
|
|
2227
|
+
`fields: ${emitUnknownLiteral(declaration.fields)}`
|
|
2228
|
+
];
|
|
2229
|
+
if (declaration.mode) {
|
|
2230
|
+
parts.push(`mode: ${esc(declaration.mode)}`);
|
|
2231
|
+
}
|
|
2232
|
+
if (declaration.strategy) {
|
|
2233
|
+
parts.push(`strategy: ${esc(declaration.strategy)}`);
|
|
2234
|
+
}
|
|
2235
|
+
lines.push(` ${profile}: { ${parts.join(", ")} },`);
|
|
2236
|
+
}
|
|
2237
|
+
lines.push(" },");
|
|
2238
|
+
}
|
|
2239
|
+
lines.push(" },");
|
|
2240
|
+
if (Object.keys(modelScopes).length > 0) {
|
|
2241
|
+
lines.push(" modelScopes: {");
|
|
2242
|
+
for (const [scopeModel, where] of Object.entries(modelScopes)) {
|
|
2243
|
+
lines.push(` ${scopeModel}: ${emitUnknownLiteral(where)},`);
|
|
2244
|
+
}
|
|
2245
|
+
lines.push(" },");
|
|
2246
|
+
}
|
|
2247
|
+
lines.push(" } as const;");
|
|
2248
|
+
return lines.join("\n");
|
|
2249
|
+
}
|
|
2250
|
+
__name(emitPluginsBlock, "emitPluginsBlock");
|
|
2251
|
+
function applyTypeDefOverride(field, fieldMapping) {
|
|
2252
|
+
if (!fieldMapping) return field;
|
|
2253
|
+
return {
|
|
2254
|
+
...field,
|
|
2255
|
+
type: fieldMapping.typeDefName,
|
|
2256
|
+
array: fieldMapping.isArray || field.array,
|
|
2257
|
+
dbAttrs: field.dbAttrs.filter((attr) => !attr.startsWith("@db.Json"))
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
__name(applyTypeDefOverride, "applyTypeDefOverride");
|
|
2261
|
+
function emitModelBlock(t, enumMap, modelRelations, inverseRelations, fieldToTypeDef) {
|
|
2262
|
+
const out = [];
|
|
2263
|
+
const { cfg } = t;
|
|
2264
|
+
const fields = [];
|
|
2265
|
+
const fieldByName = /* @__PURE__ */ new Map();
|
|
2266
|
+
for (const jsKey of [
|
|
2267
|
+
...t.sqlToJsKey.values()
|
|
2268
|
+
]) {
|
|
2269
|
+
const col = t.table[jsKey];
|
|
2270
|
+
const field = mapColumn(jsKey, col, enumMap);
|
|
2271
|
+
if (field.sqlName === "$hash") {
|
|
2272
|
+
field.isGenerated = true;
|
|
2273
|
+
field.name = "hash";
|
|
2274
|
+
}
|
|
2275
|
+
const typedField = applyDerivedFieldOverrides(applyTypeDefOverride(field, fieldToTypeDef?.get(`${t.sqlName}.${jsKey}`)), t);
|
|
2276
|
+
fields.push(typedField);
|
|
2277
|
+
fieldByName.set(typedField.name, typedField);
|
|
2278
|
+
}
|
|
2279
|
+
const fkRels = modelRelations.get(t.modelName) || [];
|
|
2280
|
+
const fkFieldMap = /* @__PURE__ */ new Map();
|
|
2281
|
+
for (const rel of fkRels) {
|
|
2282
|
+
if (rel.fields) {
|
|
2283
|
+
for (const f of rel.fields) {
|
|
2284
|
+
if (!fkFieldMap.has(f)) fkFieldMap.set(f, []);
|
|
2285
|
+
fkFieldMap.get(f).push(rel.fieldName);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
out.push(` ${t.modelName}: {`);
|
|
2290
|
+
out.push(` name: ${esc(t.modelName)},`);
|
|
2291
|
+
out.push(` fields: {`);
|
|
2292
|
+
for (const field of fields) {
|
|
2293
|
+
const fkFor = fkFieldMap.get(field.name);
|
|
2294
|
+
let block = emitFieldBlock(field);
|
|
2295
|
+
if (fkFor) {
|
|
2296
|
+
block = block.slice(0, -2) + `, foreignKeyFor: [${fkFor.map((f) => esc(f)).join(", ")}] }`;
|
|
2297
|
+
}
|
|
2298
|
+
out.push(` ${field.name}: ${block},`);
|
|
2299
|
+
}
|
|
2300
|
+
for (const rel of fkRels) {
|
|
2301
|
+
const isVirtualOnly = rel.kind === "through" || rel.kind === "filtered" && !rel.fields;
|
|
2302
|
+
const opposite = isVirtualOnly ? "" : rel._opposite || rel.fieldName;
|
|
2303
|
+
const block = emitRelationField(rel, opposite);
|
|
2304
|
+
out.push(` ${rel.fieldName}: ${block},`);
|
|
2305
|
+
}
|
|
2306
|
+
const invRels = inverseRelations.get(t.modelName) || [];
|
|
2307
|
+
for (const rel of invRels) {
|
|
2308
|
+
const opposite = rel._opposite || rel.fieldName;
|
|
2309
|
+
const block = emitRelationField(rel, opposite);
|
|
2310
|
+
out.push(` ${rel.fieldName}: ${block},`);
|
|
2311
|
+
}
|
|
2312
|
+
for (const computedField of t.computedFields) {
|
|
2313
|
+
out.push(` ${computedField.name}: { name: ${esc(computedField.name)}, type: ${esc(computedField.type)}, computed: true, attributes: [{ name: "@computed" }] },`);
|
|
2314
|
+
}
|
|
2315
|
+
out.push(` },`);
|
|
2316
|
+
if (t.computedFields.length > 0) {
|
|
2317
|
+
out.push(` computedFields: {`);
|
|
2318
|
+
for (const computedField of t.computedFields) {
|
|
2319
|
+
out.push(` ${computedField.name}(_context: { modelAlias: ${esc(t.modelName)} }): ${computedField.tsType} { throw new Error("computed stub"); },`);
|
|
2320
|
+
}
|
|
2321
|
+
out.push(` },`);
|
|
2322
|
+
}
|
|
2323
|
+
const modelAttrs = [];
|
|
2324
|
+
modelAttrs.push(`{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(t.sqlName)}) }] }`);
|
|
2325
|
+
for (const uc of cfg.uniqueConstraints) {
|
|
2326
|
+
const ucCols = uc.columns.map((c) => c.name);
|
|
2327
|
+
if (ucCols.length > 1) {
|
|
2328
|
+
modelAttrs.push(`{ name: "@@unique", args: [{ name: "fields", value: ExpressionUtils.array("String", [${ucCols.map((c) => `ExpressionUtils.field(${esc(t.sqlToJsKey.get(c) || c)})`).join(", ")}]) }] }`);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
if (cfg.primaryKeys.length > 0) {
|
|
2332
|
+
for (const pk of cfg.primaryKeys) {
|
|
2333
|
+
const pkCols = pk.columns.map((c) => c.name);
|
|
2334
|
+
modelAttrs.push(`{ name: "@@id", args: [{ name: "fields", value: ExpressionUtils.array("String", [${pkCols.map((c) => `ExpressionUtils.field(${esc(t.sqlToJsKey.get(c) || c)})`).join(", ")}]) }] }`);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
out.push(` attributes: [${modelAttrs.join(", ")}],`);
|
|
2338
|
+
const idCols = cfg.columns.filter((c) => c.primary).map((c) => t.sqlToJsKey.get(c.name) || c.name);
|
|
2339
|
+
if (idCols.length === 0 && cfg.primaryKeys.length > 0) {
|
|
2340
|
+
const pkCols = cfg.primaryKeys[0].columns.map((c) => t.sqlToJsKey.get(c.name) || c.name);
|
|
2341
|
+
out.push(` idFields: [${pkCols.map((c) => esc(c)).join(", ")}],`);
|
|
2342
|
+
} else {
|
|
2343
|
+
out.push(` idFields: [${idCols.map((c) => esc(c)).join(", ")}],`);
|
|
2344
|
+
}
|
|
2345
|
+
const ufEntries = [];
|
|
2346
|
+
const ufKeys = /* @__PURE__ */ new Set();
|
|
2347
|
+
const addUnique = /* @__PURE__ */ __name((cols) => {
|
|
2348
|
+
const key = cols.join("_");
|
|
2349
|
+
if (ufKeys.has(key)) return;
|
|
2350
|
+
ufKeys.add(key);
|
|
2351
|
+
if (cols.length === 1) {
|
|
2352
|
+
ufEntries.push(`${key}: { type: ${esc(fieldByName.get(key)?.type || "String")} }`);
|
|
2353
|
+
} else {
|
|
2354
|
+
const inner = cols.map((c) => `${c}: { type: ${esc(fieldByName.get(c)?.type || "String")} }`).join(", ");
|
|
2355
|
+
ufEntries.push(`${key}: { ${inner} }`);
|
|
2356
|
+
}
|
|
2357
|
+
}, "addUnique");
|
|
2358
|
+
if (idCols.length > 0) {
|
|
2359
|
+
addUnique(idCols);
|
|
2360
|
+
} else if (cfg.primaryKeys.length > 0) {
|
|
2361
|
+
const pkCols = cfg.primaryKeys[0].columns.map((c) => t.sqlToJsKey.get(c.name) || c.name);
|
|
2362
|
+
addUnique(pkCols);
|
|
2363
|
+
}
|
|
2364
|
+
for (const uc of cfg.uniqueConstraints) {
|
|
2365
|
+
addUnique(uc.columns.map((c) => t.sqlToJsKey.get(c.name) || c.name));
|
|
2366
|
+
}
|
|
2367
|
+
for (const f of fields) {
|
|
2368
|
+
if (f.unique) addUnique([
|
|
2369
|
+
f.name
|
|
2370
|
+
]);
|
|
2371
|
+
}
|
|
2372
|
+
out.push(` uniqueFields: { ${ufEntries.join(", ")} }`);
|
|
2373
|
+
out.push(` },`);
|
|
2374
|
+
return out;
|
|
2375
|
+
}
|
|
2376
|
+
__name(emitModelBlock, "emitModelBlock");
|
|
2377
|
+
function emitViewModelBlock(v, enumMap, fieldToTypeDef) {
|
|
2378
|
+
const out = [];
|
|
2379
|
+
const fields = [];
|
|
2380
|
+
const fieldByName = /* @__PURE__ */ new Map();
|
|
2381
|
+
for (const [jsKey, col] of v.columns) {
|
|
2382
|
+
const field = mapColumn(jsKey, col, enumMap);
|
|
2383
|
+
if (field.sqlName === "$hash") {
|
|
2384
|
+
field.isGenerated = true;
|
|
2385
|
+
field.name = "hash";
|
|
2386
|
+
}
|
|
2387
|
+
const typedField = applyTypeDefOverride(field, fieldToTypeDef?.get(`${v.sqlName}.${jsKey}`));
|
|
2388
|
+
fields.push(typedField);
|
|
2389
|
+
fieldByName.set(typedField.name, typedField);
|
|
2390
|
+
}
|
|
2391
|
+
out.push(` ${v.modelName}: {`);
|
|
2392
|
+
out.push(` name: ${esc(v.modelName)},`);
|
|
2393
|
+
out.push(` isView: true,`);
|
|
2394
|
+
out.push(` fields: {`);
|
|
2395
|
+
for (const field of fields) {
|
|
2396
|
+
const block = emitFieldBlock(field);
|
|
2397
|
+
out.push(` ${field.name}: ${block},`);
|
|
2398
|
+
}
|
|
2399
|
+
out.push(` },`);
|
|
2400
|
+
const modelAttrs = [];
|
|
2401
|
+
modelAttrs.push(`{ name: "@@map", args: [{ name: "name", value: ExpressionUtils.literal(${esc(v.sqlName)}) }] }`);
|
|
2402
|
+
out.push(` attributes: [${modelAttrs.join(", ")}],`);
|
|
2403
|
+
const idCols = [];
|
|
2404
|
+
for (const [jsKey, col] of v.columns) {
|
|
2405
|
+
if (col.primary) {
|
|
2406
|
+
const name = jsKey === "$hash" ? "hash" : jsKey;
|
|
2407
|
+
idCols.push(name);
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
if (idCols.length === 0 && fields.length > 0) {
|
|
2411
|
+
idCols.push(fields[0].name);
|
|
2412
|
+
}
|
|
2413
|
+
out.push(` idFields: [${idCols.map((c) => esc(c)).join(", ")}],`);
|
|
2414
|
+
const ufEntries = [];
|
|
2415
|
+
if (idCols.length > 0) {
|
|
2416
|
+
const key = idCols.join("_");
|
|
2417
|
+
if (idCols.length === 1) {
|
|
2418
|
+
ufEntries.push(`${key}: { type: ${esc(fieldByName.get(key)?.type || "String")} }`);
|
|
2419
|
+
} else {
|
|
2420
|
+
const inner = idCols.map((c) => `${c}: { type: ${esc(fieldByName.get(c)?.type || "String")} }`).join(", ");
|
|
2421
|
+
ufEntries.push(`${key}: { ${inner} }`);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
for (const f of fields) {
|
|
2425
|
+
if (f.unique && !idCols.includes(f.name)) {
|
|
2426
|
+
const key = f.name;
|
|
2427
|
+
ufEntries.push(`${key}: { type: ${esc(f.type)} }`);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
out.push(` uniqueFields: { ${ufEntries.join(", ")} }`);
|
|
2431
|
+
out.push(` },`);
|
|
2432
|
+
return out;
|
|
2433
|
+
}
|
|
2434
|
+
__name(emitViewModelBlock, "emitViewModelBlock");
|
|
2435
|
+
function emitSchemaTs({ tables, enumMap, modelRelations, inverseRelations, searchDefaults, modelScopes, typeDefs, fieldToTypeDef, views }) {
|
|
2436
|
+
const out = [
|
|
2437
|
+
...emitGeneratedFileBanner()
|
|
2438
|
+
];
|
|
2439
|
+
const allEnums = new Map([
|
|
2440
|
+
...enumMap,
|
|
2441
|
+
...collectDerivedEnums(tables, enumMap)
|
|
2442
|
+
]);
|
|
2443
|
+
const hasJsonComputedField = tables.some((table) => table.computedFields.some((field) => field.tsType === "JsonValue"));
|
|
2444
|
+
out.push("");
|
|
2445
|
+
out.push('import { ExpressionUtils, type FieldDefault, type SchemaDef } from "@zenstackhq/schema";');
|
|
2446
|
+
if (hasJsonComputedField) {
|
|
2447
|
+
out.push('import type { JsonValue } from "@zenstackhq/orm";');
|
|
2448
|
+
}
|
|
2449
|
+
out.push("export class SchemaType implements SchemaDef {");
|
|
2450
|
+
out.push(' provider = { type: "postgresql" } as const;');
|
|
2451
|
+
out.push(" models = {");
|
|
2452
|
+
for (const t of tables) {
|
|
2453
|
+
out.push(...emitModelBlock(t, enumMap, modelRelations, inverseRelations, fieldToTypeDef));
|
|
2454
|
+
}
|
|
2455
|
+
if (views) {
|
|
2456
|
+
for (const v of views) {
|
|
2457
|
+
out.push(...emitViewModelBlock(v, enumMap, fieldToTypeDef));
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
out.push(" } as const;");
|
|
2461
|
+
if (typeDefs && typeDefs.size > 0) {
|
|
2462
|
+
out.push(emitTypeDefsBlock(typeDefs));
|
|
2463
|
+
}
|
|
2464
|
+
out.push(" enums = {");
|
|
2465
|
+
for (const [, info] of allEnums) {
|
|
2466
|
+
out.push(emitEnumBlock(info) + ",");
|
|
2467
|
+
}
|
|
2468
|
+
out.push(" } as const;");
|
|
2469
|
+
out.push(emitPluginsBlock(modelRelations, searchDefaults, modelScopes ?? {}));
|
|
2470
|
+
out.push("}");
|
|
2471
|
+
out.push("");
|
|
2472
|
+
out.push("export const schema = new SchemaType();");
|
|
2473
|
+
out.push("");
|
|
2474
|
+
return out.join("\n");
|
|
2475
|
+
}
|
|
2476
|
+
__name(emitSchemaTs, "emitSchemaTs");
|
|
2477
|
+
function emitModelsTs(tables, typedJsonFields = []) {
|
|
2478
|
+
const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
|
|
2479
|
+
const out = [
|
|
2480
|
+
...emitGeneratedFileBanner()
|
|
2481
|
+
];
|
|
2482
|
+
out.push("");
|
|
2483
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2484
|
+
out.push('import type * as Json from "./json";');
|
|
2485
|
+
out.push('import { type SchemaType as Schema } from "./schema";');
|
|
2486
|
+
out.push("");
|
|
2487
|
+
for (const t of tables) {
|
|
2488
|
+
out.push(`export interface ${t.typeName} extends $.ModelResult<Schema, ${esc(t.modelName)}> {}`);
|
|
2489
|
+
out.push(`export namespace ${t.typeName} {`);
|
|
2490
|
+
for (const fieldName of getEntityFieldNames(t)) {
|
|
2491
|
+
const exportName = toPascalCase(fieldName);
|
|
2492
|
+
const jsonAlias = jsonFieldAliases.get(`${t.typeName}.${fieldName}`);
|
|
2493
|
+
if (jsonAlias) {
|
|
2494
|
+
out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
|
|
2495
|
+
} else {
|
|
2496
|
+
out.push(` export type ${exportName} = ${t.typeName}[${esc(fieldName)}];`);
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
out.push("}");
|
|
2500
|
+
out.push("");
|
|
2501
|
+
}
|
|
2502
|
+
return out.join("\n");
|
|
2503
|
+
}
|
|
2504
|
+
__name(emitModelsTs, "emitModelsTs");
|
|
2505
|
+
function emitViewsTs(views, typedJsonFields = []) {
|
|
2506
|
+
const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
|
|
2507
|
+
const out = [
|
|
2508
|
+
...emitGeneratedFileBanner()
|
|
2509
|
+
];
|
|
2510
|
+
out.push("");
|
|
2511
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2512
|
+
out.push('import type * as Json from "./json";');
|
|
2513
|
+
out.push('import { type SchemaType as Schema } from "./schema";');
|
|
2514
|
+
out.push("");
|
|
2515
|
+
for (const v of views) {
|
|
2516
|
+
out.push(`export interface ${v.typeName} extends $.ModelResult<Schema, ${esc(v.modelName)}> {}`);
|
|
2517
|
+
out.push(`export namespace ${v.typeName} {`);
|
|
2518
|
+
for (const fieldName of getEntityFieldNames(v)) {
|
|
2519
|
+
const exportName = toPascalCase(fieldName);
|
|
2520
|
+
const jsonAlias = jsonFieldAliases.get(`${v.typeName}.${fieldName}`);
|
|
2521
|
+
if (jsonAlias) {
|
|
2522
|
+
out.push(` export interface ${exportName} extends Json.${jsonAlias} {}`);
|
|
2523
|
+
} else {
|
|
2524
|
+
out.push(` export type ${exportName} = ${v.typeName}[${esc(fieldName)}];`);
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
out.push("}");
|
|
2528
|
+
out.push("");
|
|
2529
|
+
}
|
|
2530
|
+
return out.join("\n");
|
|
2531
|
+
}
|
|
2532
|
+
__name(emitViewsTs, "emitViewsTs");
|
|
2533
|
+
function emitInputTs(tables) {
|
|
2534
|
+
const out = [
|
|
2535
|
+
...emitGeneratedFileBanner()
|
|
2536
|
+
];
|
|
2537
|
+
out.push("");
|
|
2538
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2539
|
+
out.push('import { type SchemaType as Schema } from "./schema";');
|
|
2540
|
+
out.push("");
|
|
2541
|
+
for (const t of tables) {
|
|
2542
|
+
out.push(`export namespace ${t.typeName} {`);
|
|
2543
|
+
out.push(` export interface FindManyArgs extends $.FindManyArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2544
|
+
out.push(` export interface FindUniqueArgs extends $.FindUniqueArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2545
|
+
out.push(` export interface FindFirstArgs extends $.FindFirstArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2546
|
+
out.push(` export interface ExistsArgs extends $.ExistsArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2547
|
+
out.push(` export interface CreateArgs extends $.CreateArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2548
|
+
out.push(` export interface CreateManyArgs extends $.CreateManyArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2549
|
+
out.push(` export interface CreateManyAndReturnArgs extends $.CreateManyAndReturnArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2550
|
+
out.push(` export interface UpdateArgs extends $.UpdateArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2551
|
+
out.push(` export interface UpdateManyArgs extends $.UpdateManyArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2552
|
+
out.push(` export interface UpdateManyAndReturnArgs extends $.UpdateManyAndReturnArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2553
|
+
out.push(` export interface UpsertArgs extends $.UpsertArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2554
|
+
out.push(` export interface DeleteArgs extends $.DeleteArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2555
|
+
out.push(` export interface DeleteManyArgs extends $.DeleteManyArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2556
|
+
out.push(` export interface CountArgs extends $.CountArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2557
|
+
out.push(` export interface AggregateArgs extends $.AggregateArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2558
|
+
out.push(` export interface GroupByArgs extends $.GroupByArgs<Schema, ${esc(t.modelName)}> {}`);
|
|
2559
|
+
out.push(` export interface WhereInput extends $.WhereInput<Schema, ${esc(t.modelName)}> {}`);
|
|
2560
|
+
out.push(` export interface Select extends $.SelectInput<Schema, ${esc(t.modelName)}> {}`);
|
|
2561
|
+
out.push(` export interface Include extends $.IncludeInput<Schema, ${esc(t.modelName)}> {}`);
|
|
2562
|
+
out.push(` export interface Omit extends $.OmitInput<Schema, ${esc(t.modelName)}> {}`);
|
|
2563
|
+
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>;`);
|
|
2564
|
+
out.push("}");
|
|
2565
|
+
out.push("");
|
|
2566
|
+
}
|
|
2567
|
+
return out.join("\n");
|
|
2568
|
+
}
|
|
2569
|
+
__name(emitInputTs, "emitInputTs");
|
|
2570
|
+
function emitIndexTs({ tables, views, enumMap, typeDefs, typedJsonFields }) {
|
|
2571
|
+
const allEnums = new Map([
|
|
2572
|
+
...enumMap,
|
|
2573
|
+
...collectDerivedEnums(tables, enumMap)
|
|
2574
|
+
]);
|
|
2575
|
+
const jsonFieldAliases = createJsonFieldAliasMap(typedJsonFields);
|
|
2576
|
+
const out = [
|
|
2577
|
+
...emitGeneratedFileBanner()
|
|
2578
|
+
];
|
|
2579
|
+
out.push("");
|
|
2580
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2581
|
+
out.push('import type * as RawJson from "../../supabase/schema/types";');
|
|
2582
|
+
out.push('import { type SchemaType as Schema } from "./schema";');
|
|
2583
|
+
out.push("");
|
|
2584
|
+
out.push("export namespace Json {");
|
|
2585
|
+
out.push(...emitJsonNamespaceBlock(typeDefs, typedJsonFields, " "));
|
|
2586
|
+
out.push("}");
|
|
2587
|
+
out.push("");
|
|
2588
|
+
out.push("export namespace JsonRaw {");
|
|
2589
|
+
const jsonRawLines = emitJsonRawNamespaceBlock(typedJsonFields, " ");
|
|
2590
|
+
if (jsonRawLines.length > 0) {
|
|
2591
|
+
out.push(...jsonRawLines);
|
|
2592
|
+
}
|
|
2593
|
+
out.push("}");
|
|
2594
|
+
out.push("");
|
|
2595
|
+
out.push("export namespace Table {");
|
|
2596
|
+
for (const table of tables) {
|
|
2597
|
+
out.push(...emitEntityNamespaceBlock(table, table.modelName, jsonFieldAliases, " "));
|
|
2598
|
+
out.push("");
|
|
2599
|
+
}
|
|
2600
|
+
out.push("}");
|
|
2601
|
+
out.push("");
|
|
2602
|
+
out.push("export namespace View {");
|
|
2603
|
+
for (const view of views) {
|
|
2604
|
+
out.push(...emitEntityNamespaceBlock(view, view.modelName, jsonFieldAliases, " "));
|
|
2605
|
+
out.push("");
|
|
2606
|
+
}
|
|
2607
|
+
out.push("}");
|
|
2608
|
+
out.push("");
|
|
2609
|
+
out.push("export namespace Input {");
|
|
2610
|
+
for (const table of tables) {
|
|
2611
|
+
out.push(...emitInputNamespaceBlock(table, " "));
|
|
2612
|
+
out.push("");
|
|
2613
|
+
}
|
|
2614
|
+
out.push("}");
|
|
2615
|
+
out.push("");
|
|
2616
|
+
out.push("export namespace ComputedFields {");
|
|
2617
|
+
out.push(" export type All = $.ComputedFieldsOptions<Schema>;");
|
|
2618
|
+
for (const table of tables) {
|
|
2619
|
+
if (table.computedFields.length === 0) continue;
|
|
2620
|
+
out.push(` export type ${table.typeName} = $.ComputedFieldsOptions<Schema>[${esc(table.modelName)}];`);
|
|
2621
|
+
}
|
|
2622
|
+
out.push("}");
|
|
2623
|
+
out.push("");
|
|
2624
|
+
out.push("export namespace Enum {");
|
|
2625
|
+
for (const [, info] of allEnums) {
|
|
2626
|
+
out.push(...emitEnumNamespaceBlock(info, " "));
|
|
2627
|
+
out.push("");
|
|
2628
|
+
}
|
|
2629
|
+
out.push("}");
|
|
2630
|
+
out.push("");
|
|
2631
|
+
return out.join("\n");
|
|
2632
|
+
}
|
|
2633
|
+
__name(emitIndexTs, "emitIndexTs");
|
|
2634
|
+
function emitCompatTs({ tables, views, enumMap, typedJsonFields }) {
|
|
2635
|
+
const out = [
|
|
2636
|
+
...emitGeneratedFileBanner()
|
|
2637
|
+
];
|
|
2638
|
+
const jsonAliases = typedJsonFields.map((field) => `${field.entityTypeName}${toPascalCase(field.fieldName)}Json`);
|
|
2639
|
+
const jsonRawAliases = typedJsonFields.filter((field) => field.sourceTypeName).map((field) => `${field.entityTypeName}${toPascalCase(field.fieldName)}JsonRaw`);
|
|
2640
|
+
out.push("");
|
|
2641
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2642
|
+
out.push('import * as Db from "./index";');
|
|
2643
|
+
out.push('import type { SchemaType as Schema } from "./schema";');
|
|
2644
|
+
out.push("");
|
|
2645
|
+
out.push("export namespace Models {");
|
|
2646
|
+
for (const table of tables) {
|
|
2647
|
+
out.push(...emitCompatEntityAlias(table, "Table", " "));
|
|
2648
|
+
out.push("");
|
|
2649
|
+
}
|
|
2650
|
+
out.push("}");
|
|
2651
|
+
out.push("");
|
|
2652
|
+
out.push("export namespace Views {");
|
|
2653
|
+
for (const view of views) {
|
|
2654
|
+
out.push(...emitCompatEntityAlias(view, "View", " "));
|
|
2655
|
+
out.push("");
|
|
2656
|
+
}
|
|
2657
|
+
out.push("}");
|
|
2658
|
+
out.push("");
|
|
2659
|
+
out.push("export namespace Input {");
|
|
2660
|
+
for (const table of tables) {
|
|
2661
|
+
out.push(...emitCompatInputAliases(table, " "));
|
|
2662
|
+
out.push("");
|
|
2663
|
+
}
|
|
2664
|
+
out.push("}");
|
|
2665
|
+
out.push("");
|
|
2666
|
+
out.push("export namespace Json {");
|
|
2667
|
+
for (const alias of jsonAliases) {
|
|
2668
|
+
out.push(...emitDeprecatedTypeAlias(alias, `Db.Json.${alias}`, " "));
|
|
2669
|
+
}
|
|
2670
|
+
out.push("}");
|
|
2671
|
+
out.push("");
|
|
2672
|
+
out.push("export namespace JsonRaw {");
|
|
2673
|
+
for (const alias of jsonRawAliases) {
|
|
2674
|
+
out.push(...emitDeprecatedTypeAlias(alias, `Db.JsonRaw.${alias}`, " "));
|
|
2675
|
+
}
|
|
2676
|
+
out.push("}");
|
|
2677
|
+
out.push("");
|
|
2678
|
+
out.push("export namespace Enums {");
|
|
2679
|
+
for (const [, info] of enumMap) {
|
|
2680
|
+
if (!info.mapping) continue;
|
|
2681
|
+
out.push(...emitDeprecatedEnumAliases(info.zenstackName, " "));
|
|
2682
|
+
out.push("");
|
|
2683
|
+
}
|
|
2684
|
+
out.push("}");
|
|
2685
|
+
out.push("");
|
|
2686
|
+
for (const table of tables) {
|
|
2687
|
+
out.push(...emitDeprecatedTypeAlias(table.typeName, `Models.${table.typeName}`));
|
|
2688
|
+
}
|
|
2689
|
+
for (const view of views) {
|
|
2690
|
+
out.push(...emitDeprecatedTypeAlias(view.typeName, `Views.${view.typeName}`));
|
|
2691
|
+
}
|
|
2692
|
+
for (const table of tables) {
|
|
2693
|
+
out.push(...emitCompatInputAliases(table));
|
|
2694
|
+
}
|
|
2695
|
+
for (const alias of jsonAliases) {
|
|
2696
|
+
out.push(...emitDeprecatedTypeAlias(alias, `Json.${alias}`));
|
|
2697
|
+
}
|
|
2698
|
+
for (const alias of jsonRawAliases) {
|
|
2699
|
+
out.push(...emitDeprecatedTypeAlias(alias, `JsonRaw.${alias}`));
|
|
2700
|
+
}
|
|
2701
|
+
for (const [, info] of enumMap) {
|
|
2702
|
+
if (!info.mapping) continue;
|
|
2703
|
+
out.push(...emitDeprecatedEnumAliases(info.zenstackName));
|
|
2704
|
+
out.push("");
|
|
2705
|
+
}
|
|
2706
|
+
return out.join("\n");
|
|
2707
|
+
}
|
|
2708
|
+
__name(emitCompatTs, "emitCompatTs");
|
|
2709
|
+
function emitOrmTypesTs(tables) {
|
|
2710
|
+
const out = [
|
|
2711
|
+
...emitGeneratedFileBanner()
|
|
2712
|
+
];
|
|
2713
|
+
out.push("");
|
|
2714
|
+
out.push('import type * as $ from "@zenstackhq/orm";');
|
|
2715
|
+
out.push('import type { SchemaType as Schema } from "./schema";');
|
|
2716
|
+
out.push("");
|
|
2717
|
+
out.push("export type Client = $.ClientContract<Schema>;");
|
|
2718
|
+
out.push("");
|
|
2719
|
+
out.push("export namespace ComputedFields {");
|
|
2720
|
+
out.push(" export type All = $.ComputedFieldsOptions<Schema>;");
|
|
2721
|
+
for (const table of tables) {
|
|
2722
|
+
if (table.computedFields.length === 0) continue;
|
|
2723
|
+
out.push(` export type ${table.typeName} = $.ComputedFieldsOptions<Schema>[${esc(table.modelName)}];`);
|
|
2724
|
+
}
|
|
2725
|
+
out.push("}");
|
|
2726
|
+
out.push("");
|
|
2727
|
+
return out.join("\n");
|
|
2728
|
+
}
|
|
2729
|
+
__name(emitOrmTypesTs, "emitOrmTypesTs");
|
|
2730
|
+
function getEntityFieldNames(entity) {
|
|
2731
|
+
const fieldNames = /* @__PURE__ */ new Set();
|
|
2732
|
+
if ("table" in entity) {
|
|
2733
|
+
for (const jsKey of entity.sqlToJsKey.values()) {
|
|
2734
|
+
fieldNames.add(jsKey === "$hash" ? "hash" : jsKey);
|
|
2735
|
+
}
|
|
2736
|
+
for (const computedField of entity.computedFields) {
|
|
2737
|
+
fieldNames.add(computedField.name);
|
|
2738
|
+
}
|
|
2739
|
+
} else {
|
|
2740
|
+
for (const jsKey of entity.columns.keys()) {
|
|
2741
|
+
fieldNames.add(jsKey === "$hash" ? "hash" : jsKey);
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
return [
|
|
2745
|
+
...fieldNames
|
|
2746
|
+
];
|
|
2747
|
+
}
|
|
2748
|
+
__name(getEntityFieldNames, "getEntityFieldNames");
|
|
2749
|
+
function createJsonFieldAliasMap(typedJsonFields) {
|
|
2750
|
+
return new Map(typedJsonFields.map((field) => [
|
|
2751
|
+
`${field.entityTypeName}.${field.fieldName}`,
|
|
2752
|
+
`${field.entityTypeName}${toPascalCase(field.fieldName)}Json`
|
|
2753
|
+
]));
|
|
2754
|
+
}
|
|
2755
|
+
__name(createJsonFieldAliasMap, "createJsonFieldAliasMap");
|
|
2756
|
+
function emitEntityNamespaceBlock(entity, modelName, jsonFieldAliases, indent2 = "") {
|
|
2757
|
+
const out = [];
|
|
2758
|
+
out.push(`${indent2}export interface ${entity.typeName} extends $.ModelResult<Schema, ${esc(modelName)}> {}`);
|
|
2759
|
+
out.push(`${indent2}export namespace ${entity.typeName} {`);
|
|
2760
|
+
for (const fieldName of getEntityFieldNames(entity)) {
|
|
2761
|
+
const exportName = toPascalCase(fieldName);
|
|
2762
|
+
const jsonAlias = jsonFieldAliases.get(`${entity.typeName}.${fieldName}`);
|
|
2763
|
+
if (jsonAlias) {
|
|
2764
|
+
out.push(`${indent2} export interface ${exportName} extends Json.${jsonAlias} {}`);
|
|
2765
|
+
} else {
|
|
2766
|
+
out.push(`${indent2} export type ${exportName} = ${entity.typeName}[${esc(fieldName)}];`);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
out.push(`${indent2}}`);
|
|
2770
|
+
return out;
|
|
2771
|
+
}
|
|
2772
|
+
__name(emitEntityNamespaceBlock, "emitEntityNamespaceBlock");
|
|
2773
|
+
function emitInputNamespaceBlock(table, indent2 = "") {
|
|
2774
|
+
const out = [];
|
|
2775
|
+
out.push(`${indent2}export namespace ${table.typeName} {`);
|
|
2776
|
+
out.push(`${indent2} export interface FindManyArgs extends $.FindManyArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2777
|
+
out.push(`${indent2} export interface FindUniqueArgs extends $.FindUniqueArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2778
|
+
out.push(`${indent2} export interface FindFirstArgs extends $.FindFirstArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2779
|
+
out.push(`${indent2} export interface ExistsArgs extends $.ExistsArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2780
|
+
out.push(`${indent2} export interface CreateArgs extends $.CreateArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2781
|
+
out.push(`${indent2} export interface CreateManyArgs extends $.CreateManyArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2782
|
+
out.push(`${indent2} export interface CreateManyAndReturnArgs extends $.CreateManyAndReturnArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2783
|
+
out.push(`${indent2} export interface UpdateArgs extends $.UpdateArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2784
|
+
out.push(`${indent2} export interface UpdateManyArgs extends $.UpdateManyArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2785
|
+
out.push(`${indent2} export interface UpdateManyAndReturnArgs extends $.UpdateManyAndReturnArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2786
|
+
out.push(`${indent2} export interface UpsertArgs extends $.UpsertArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2787
|
+
out.push(`${indent2} export interface DeleteArgs extends $.DeleteArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2788
|
+
out.push(`${indent2} export interface DeleteManyArgs extends $.DeleteManyArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2789
|
+
out.push(`${indent2} export interface CountArgs extends $.CountArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2790
|
+
out.push(`${indent2} export interface AggregateArgs extends $.AggregateArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2791
|
+
out.push(`${indent2} export interface GroupByArgs extends $.GroupByArgs<Schema, ${esc(table.modelName)}> {}`);
|
|
2792
|
+
out.push(`${indent2} export interface WhereInput extends $.WhereInput<Schema, ${esc(table.modelName)}> {}`);
|
|
2793
|
+
out.push(`${indent2} export interface Select extends $.SelectInput<Schema, ${esc(table.modelName)}> {}`);
|
|
2794
|
+
out.push(`${indent2} export interface Include extends $.IncludeInput<Schema, ${esc(table.modelName)}> {}`);
|
|
2795
|
+
out.push(`${indent2} export interface Omit extends $.OmitInput<Schema, ${esc(table.modelName)}> {}`);
|
|
2796
|
+
out.push(`${indent2} export type GetPayload<Args extends $.SelectIncludeOmit<Schema, ${esc(table.modelName)}, true>, Options extends $.QueryOptions<Schema> = $.QueryOptions<Schema>> = $.SimplifiedPlainResult<Schema, ${esc(table.modelName)}, Args, Options>;`);
|
|
2797
|
+
out.push(`${indent2}}`);
|
|
2798
|
+
return out;
|
|
2799
|
+
}
|
|
2800
|
+
__name(emitInputNamespaceBlock, "emitInputNamespaceBlock");
|
|
2801
|
+
function emitEnumNamespaceBlock(info, indent2 = "") {
|
|
2802
|
+
if (!info.mapping) return [];
|
|
2803
|
+
const out = [];
|
|
2804
|
+
const entries = Object.entries(info.mapping).map(([key, value]) => `${indent2} ${key}: ${esc(value)}`).join(",\n");
|
|
2805
|
+
out.push(`${indent2}export const ${info.zenstackName} = {`);
|
|
2806
|
+
out.push(entries);
|
|
2807
|
+
out.push(`${indent2}} as const;`);
|
|
2808
|
+
out.push(`${indent2}export type ${info.zenstackName} = (typeof ${info.zenstackName})[keyof typeof ${info.zenstackName}];`);
|
|
2809
|
+
out.push(`${indent2}export type ${info.zenstackName}Key = ${Object.keys(info.mapping).map((key) => esc(key)).join(" | ")};`);
|
|
2810
|
+
out.push(`${indent2}export const ${info.zenstackName}Values = Object.values(${info.zenstackName});`);
|
|
2811
|
+
out.push(`${indent2}export const ${info.zenstackName}Keys = Object.keys(${info.zenstackName}) as ${info.zenstackName}Key[];`);
|
|
2812
|
+
return out;
|
|
2813
|
+
}
|
|
2814
|
+
__name(emitEnumNamespaceBlock, "emitEnumNamespaceBlock");
|
|
2815
|
+
function emitDeprecatedTypeAlias(name, target, indent2 = "") {
|
|
2816
|
+
return [
|
|
2817
|
+
`${indent2}/** @deprecated Use ${target} instead. */`,
|
|
2818
|
+
`${indent2}export type ${name} = ${target};`
|
|
2819
|
+
];
|
|
2820
|
+
}
|
|
2821
|
+
__name(emitDeprecatedTypeAlias, "emitDeprecatedTypeAlias");
|
|
2822
|
+
function emitDeprecatedValueAlias(name, target, indent2 = "") {
|
|
2823
|
+
return [
|
|
2824
|
+
`${indent2}/** @deprecated Use ${target} instead. */`,
|
|
2825
|
+
`${indent2}export const ${name} = ${target};`
|
|
2826
|
+
];
|
|
2827
|
+
}
|
|
2828
|
+
__name(emitDeprecatedValueAlias, "emitDeprecatedValueAlias");
|
|
2829
|
+
function emitDeprecatedEnumAliases(enumName, indent2 = "") {
|
|
2830
|
+
return [
|
|
2831
|
+
...emitDeprecatedValueAlias(enumName, `Db.Enum.${enumName}`, indent2),
|
|
2832
|
+
...emitDeprecatedTypeAlias(enumName, `Db.Enum.${enumName}`, indent2),
|
|
2833
|
+
...emitDeprecatedTypeAlias(`${enumName}Key`, `Db.Enum.${enumName}Key`, indent2),
|
|
2834
|
+
...emitDeprecatedValueAlias(`${enumName}Values`, `Db.Enum.${enumName}Values`, indent2),
|
|
2835
|
+
...emitDeprecatedValueAlias(`${enumName}Keys`, `Db.Enum.${enumName}Keys`, indent2)
|
|
2836
|
+
];
|
|
2837
|
+
}
|
|
2838
|
+
__name(emitDeprecatedEnumAliases, "emitDeprecatedEnumAliases");
|
|
2839
|
+
function emitCompatEntityAlias(entity, namespace, indent2 = "") {
|
|
2840
|
+
const target = `Db.${namespace}.${entity.typeName}`;
|
|
2841
|
+
const out = [
|
|
2842
|
+
`${indent2}/** @deprecated Use ${target} instead. */`
|
|
2843
|
+
];
|
|
2844
|
+
const legacyFields = [
|
|
2845
|
+
...entity.sqlToJsKey.entries()
|
|
2846
|
+
].map(([sqlName, jsName]) => ({
|
|
2847
|
+
sqlName,
|
|
2848
|
+
fieldName: jsName === "$hash" ? "hash" : jsName
|
|
2849
|
+
})).filter(({ sqlName, fieldName }) => sqlName !== "$hash" && sqlName !== fieldName);
|
|
2850
|
+
if (legacyFields.length === 0) {
|
|
2851
|
+
out.push(`${indent2}export type ${entity.typeName} = ${target};`);
|
|
2852
|
+
return out;
|
|
2853
|
+
}
|
|
2854
|
+
out.push(`${indent2}export type ${entity.typeName} = ${target} & {`);
|
|
2855
|
+
for (const { sqlName, fieldName } of legacyFields) {
|
|
2856
|
+
out.push(`${indent2} /** @deprecated Use ${fieldName} instead. */`);
|
|
2857
|
+
out.push(`${indent2} ${esc(sqlName)}: ${target}[${esc(fieldName)}];`);
|
|
2858
|
+
}
|
|
2859
|
+
out.push(`${indent2}};`);
|
|
2860
|
+
return out;
|
|
2861
|
+
}
|
|
2862
|
+
__name(emitCompatEntityAlias, "emitCompatEntityAlias");
|
|
2863
|
+
function emitCompatInputAliases(table, indent2 = "") {
|
|
2864
|
+
const target = `Db.Input.${table.typeName}`;
|
|
2865
|
+
return [
|
|
2866
|
+
...emitDeprecatedTypeAlias(`${table.typeName}FindManyArgs`, `${target}.FindManyArgs`, indent2),
|
|
2867
|
+
...emitDeprecatedTypeAlias(`${table.typeName}FindUniqueArgs`, `${target}.FindUniqueArgs`, indent2),
|
|
2868
|
+
...emitDeprecatedTypeAlias(`${table.typeName}FindFirstArgs`, `${target}.FindFirstArgs`, indent2),
|
|
2869
|
+
...emitDeprecatedTypeAlias(`${table.typeName}ExistsArgs`, `${target}.ExistsArgs`, indent2),
|
|
2870
|
+
...emitDeprecatedTypeAlias(`${table.typeName}CreateArgs`, `${target}.CreateArgs`, indent2),
|
|
2871
|
+
...emitDeprecatedTypeAlias(`${table.typeName}CreateManyArgs`, `${target}.CreateManyArgs`, indent2),
|
|
2872
|
+
...emitDeprecatedTypeAlias(`${table.typeName}CreateManyAndReturnArgs`, `${target}.CreateManyAndReturnArgs`, indent2),
|
|
2873
|
+
...emitDeprecatedTypeAlias(`${table.typeName}UpdateArgs`, `${target}.UpdateArgs`, indent2),
|
|
2874
|
+
...emitDeprecatedTypeAlias(`${table.typeName}UpdateManyArgs`, `${target}.UpdateManyArgs`, indent2),
|
|
2875
|
+
...emitDeprecatedTypeAlias(`${table.typeName}UpdateManyAndReturnArgs`, `${target}.UpdateManyAndReturnArgs`, indent2),
|
|
2876
|
+
...emitDeprecatedTypeAlias(`${table.typeName}UpsertArgs`, `${target}.UpsertArgs`, indent2),
|
|
2877
|
+
...emitDeprecatedTypeAlias(`${table.typeName}DeleteArgs`, `${target}.DeleteArgs`, indent2),
|
|
2878
|
+
...emitDeprecatedTypeAlias(`${table.typeName}DeleteManyArgs`, `${target}.DeleteManyArgs`, indent2),
|
|
2879
|
+
...emitDeprecatedTypeAlias(`${table.typeName}CountArgs`, `${target}.CountArgs`, indent2),
|
|
2880
|
+
...emitDeprecatedTypeAlias(`${table.typeName}AggregateArgs`, `${target}.AggregateArgs`, indent2),
|
|
2881
|
+
...emitDeprecatedTypeAlias(`${table.typeName}GroupByArgs`, `${target}.GroupByArgs`, indent2),
|
|
2882
|
+
...emitDeprecatedTypeAlias(`${table.typeName}WhereInput`, `${target}.WhereInput`, indent2),
|
|
2883
|
+
...emitDeprecatedTypeAlias(`${table.typeName}Select`, `${target}.Select`, indent2),
|
|
2884
|
+
...emitDeprecatedTypeAlias(`${table.typeName}Include`, `${target}.Include`, indent2),
|
|
2885
|
+
...emitDeprecatedTypeAlias(`${table.typeName}Omit`, `${target}.Omit`, indent2),
|
|
2886
|
+
`${indent2}/** @deprecated Use ${target}.GetPayload instead. */`,
|
|
2887
|
+
`${indent2}export type ${table.typeName}GetPayload<Args extends $.SelectIncludeOmit<Schema, ${esc(table.modelName)}, true>, Options extends $.QueryOptions<Schema> = $.QueryOptions<Schema>> = ${target}.GetPayload<Args, Options>;`
|
|
2888
|
+
];
|
|
2889
|
+
}
|
|
2890
|
+
__name(emitCompatInputAliases, "emitCompatInputAliases");
|
|
2891
|
+
function emitEnumsTs(enumMap) {
|
|
2892
|
+
const out = [
|
|
2893
|
+
...emitGeneratedFileBanner()
|
|
2894
|
+
];
|
|
2895
|
+
out.push("");
|
|
2896
|
+
for (const [, info] of enumMap) {
|
|
2897
|
+
if (!info.mapping) continue;
|
|
2898
|
+
const n = info.zenstackName;
|
|
2899
|
+
const entries = Object.entries(info.mapping).map(([k, v]) => ` ${k}: ${esc(v)}`).join(",\n");
|
|
2900
|
+
out.push(`export const ${n} = {
|
|
2901
|
+
${entries},
|
|
2902
|
+
} as const;`);
|
|
2903
|
+
out.push(`export type ${n} = (typeof ${n})[keyof typeof ${n}];`);
|
|
2904
|
+
out.push(`export type ${n}Key = ${Object.keys(info.mapping).map((k) => esc(k)).join(" | ")};`);
|
|
2905
|
+
out.push(`export const ${n}Values = Object.values(${n});`);
|
|
2906
|
+
out.push(`export const ${n}Keys = Object.keys(${n}) as ${n}Key[];`);
|
|
2907
|
+
out.push("");
|
|
2908
|
+
}
|
|
2909
|
+
return out.join("\n");
|
|
2910
|
+
}
|
|
2911
|
+
__name(emitEnumsTs, "emitEnumsTs");
|
|
2912
|
+
|
|
2913
|
+
// src/drizzle/cols.ts
|
|
2914
|
+
var import_drizzle_orm3 = require("drizzle-orm");
|
|
2915
|
+
var import_pg_core6 = require("drizzle-orm/pg-core");
|
|
2916
|
+
|
|
2917
|
+
// src/drizzle/rls.ts
|
|
2918
|
+
var import_drizzle_orm2 = require("drizzle-orm");
|
|
2919
|
+
var import_pg_core5 = require("drizzle-orm/pg-core");
|
|
2920
|
+
var currentAppSlug = import_drizzle_orm2.sql`current_setting('rls.app')`;
|
|
2921
|
+
var hasAppSlug = import_drizzle_orm2.sql`(select ${currentAppSlug} is not null)`;
|
|
2922
|
+
var currentUser = import_drizzle_orm2.sql`current_setting('rls.user')`;
|
|
2923
|
+
var hasUser = import_drizzle_orm2.sql`(select ${currentUser} is not null)`;
|
|
2924
|
+
var hasBypassEnabled = import_drizzle_orm2.sql`(select current_setting('rls.bypass') = 'enabled')`;
|
|
2925
|
+
var TRUE = import_drizzle_orm2.sql`true`;
|
|
2926
|
+
var FALSE = import_drizzle_orm2.sql`false`;
|
|
2927
|
+
var defaultPolicy = /* @__PURE__ */ __name((name, { table, policies }) => {
|
|
2928
|
+
const isSameAppSlug = import_drizzle_orm2.sql`${currentAppSlug} = ${table.appSlug}`;
|
|
2929
|
+
const selectPolicy = (0, import_pg_core5.pgPolicy)(`rls.${name}.select`, {
|
|
2930
|
+
as: "permissive",
|
|
2931
|
+
for: "select",
|
|
2932
|
+
using: import_drizzle_orm2.sql`${isSameAppSlug} or ${hasBypassEnabled}`
|
|
2933
|
+
});
|
|
2934
|
+
const insertPolicy = (0, import_pg_core5.pgPolicy)(`rls.${name}.insert`, {
|
|
2935
|
+
as: "permissive",
|
|
2936
|
+
for: "insert",
|
|
2937
|
+
withCheck: import_drizzle_orm2.sql`${hasAppSlug} or ${hasBypassEnabled}`
|
|
2938
|
+
});
|
|
2939
|
+
const updatePolicy = (0, import_pg_core5.pgPolicy)(`rls.${name}.update`, {
|
|
2940
|
+
as: "permissive",
|
|
2941
|
+
for: "update",
|
|
2942
|
+
using: import_drizzle_orm2.sql`${isSameAppSlug} or ${hasBypassEnabled}`
|
|
2943
|
+
});
|
|
2944
|
+
const deletePolicy = (0, import_pg_core5.pgPolicy)(`rls.${name}.delete`, {
|
|
2945
|
+
as: "permissive",
|
|
2946
|
+
for: "delete",
|
|
2947
|
+
using: import_drizzle_orm2.sql`${hasBypassEnabled} or ${isSameAppSlug}`
|
|
2948
|
+
});
|
|
2949
|
+
const ctx = {
|
|
2950
|
+
currentAppSlug,
|
|
2951
|
+
currentUser,
|
|
2952
|
+
hasAppSlug,
|
|
2953
|
+
hasUser,
|
|
2954
|
+
isSameAppSlug,
|
|
2955
|
+
hasBypass: hasBypassEnabled,
|
|
2956
|
+
TRUE,
|
|
2957
|
+
FALSE
|
|
2958
|
+
};
|
|
2959
|
+
return [
|
|
2960
|
+
typeof policies?.select === "function" ? (0, import_pg_core5.pgPolicy)(`rls.${name}.select`, {
|
|
2961
|
+
as: "permissive",
|
|
2962
|
+
for: "select",
|
|
2963
|
+
using: policies.select(ctx)
|
|
2964
|
+
}) : selectPolicy,
|
|
2965
|
+
typeof policies?.insert === "function" ? (0, import_pg_core5.pgPolicy)(`rls.${name}.insert`, {
|
|
2966
|
+
as: "permissive",
|
|
2967
|
+
for: "insert",
|
|
2968
|
+
withCheck: policies.insert(ctx)
|
|
2969
|
+
}) : insertPolicy,
|
|
2970
|
+
typeof policies?.update === "function" ? (0, import_pg_core5.pgPolicy)(`rls.${name}.update`, {
|
|
2971
|
+
as: "permissive",
|
|
2972
|
+
for: "update",
|
|
2973
|
+
withCheck: policies.update(ctx)
|
|
2974
|
+
}) : updatePolicy,
|
|
2975
|
+
typeof policies?.delete === "function" ? (0, import_pg_core5.pgPolicy)(`rls.${name}.delete`, {
|
|
2976
|
+
as: "permissive",
|
|
2977
|
+
for: "delete",
|
|
2978
|
+
using: policies.delete(ctx)
|
|
2979
|
+
}) : deletePolicy
|
|
2980
|
+
].filter(Boolean);
|
|
2981
|
+
}, "defaultPolicy");
|
|
2982
|
+
|
|
2983
|
+
// src/drizzle/cols.ts
|
|
2984
|
+
var colNumeric = /* @__PURE__ */ __name((name) => {
|
|
2985
|
+
return (0, import_pg_core6.customType)({
|
|
2986
|
+
dataType: /* @__PURE__ */ __name(() => "numeric", "dataType"),
|
|
2987
|
+
fromDriver: Number,
|
|
2988
|
+
toDriver: /* @__PURE__ */ __name((value) => import_drizzle_orm3.sql`${value.toString()}::numeric`, "toDriver")
|
|
2989
|
+
})(name);
|
|
2990
|
+
}, "colNumeric");
|
|
2991
|
+
var colAppSlug = /* @__PURE__ */ __name((name) => (0, import_pg_core6.text)(name).default(currentAppSlug), "colAppSlug");
|
|
2992
|
+
var colTimestamp = /* @__PURE__ */ __name((name) => (0, import_pg_core6.timestamp)(name, {
|
|
2993
|
+
withTimezone: true,
|
|
2994
|
+
mode: "date"
|
|
2995
|
+
}), "colTimestamp");
|
|
2996
|
+
var colCreatedAt = /* @__PURE__ */ __name((name) => colTimestamp(name).defaultNow().notNull(), "colCreatedAt");
|
|
2997
|
+
var colUpdatedAt = /* @__PURE__ */ __name((name) => colTimestamp(name).defaultNow().notNull(), "colUpdatedAt");
|
|
2998
|
+
var colDeletedAt = /* @__PURE__ */ __name((name) => colTimestamp(name), "colDeletedAt");
|
|
2999
|
+
var colId = /* @__PURE__ */ __name((name) => (0, import_pg_core6.uuid)(name).defaultRandom().primaryKey().notNull(), "colId");
|
|
3000
|
+
var auditColumns = /* @__PURE__ */ __name(() => ({
|
|
3001
|
+
createdBy: (0, import_pg_core6.text)("created_by").default(currentUser).notNull(),
|
|
3002
|
+
updatedBy: (0, import_pg_core6.text)("updated_by").default(currentUser).notNull(),
|
|
3003
|
+
createdAt: colCreatedAt("created_at"),
|
|
3004
|
+
updatedAt: colUpdatedAt("updated_at"),
|
|
3005
|
+
deletedAt: colDeletedAt("deleted_at")
|
|
3006
|
+
}), "auditColumns");
|
|
3007
|
+
var appSlugForeignKey = /* @__PURE__ */ __name((table, tableName, appsTable) => (0, import_pg_core6.foreignKey)({
|
|
3008
|
+
columns: [
|
|
3009
|
+
table.appSlug
|
|
3010
|
+
],
|
|
3011
|
+
foreignColumns: [
|
|
3012
|
+
appsTable.slug
|
|
3013
|
+
],
|
|
3014
|
+
name: `${tableName}_app_slug_fkey`
|
|
3015
|
+
}).onUpdate("cascade").onDelete("cascade"), "appSlugForeignKey");
|
|
3016
|
+
|
|
3017
|
+
// src/drizzle/generate.ts
|
|
3018
|
+
var import_node_child_process = require("child_process");
|
|
3019
|
+
var import_node_crypto = require("crypto");
|
|
3020
|
+
var import_node_fs = require("fs");
|
|
3021
|
+
var import_node_path = require("path");
|
|
3022
|
+
var import_node_zlib = require("zlib");
|
|
3023
|
+
var import_pg_core7 = require("drizzle-orm/pg-core");
|
|
3024
|
+
function parseFlags(argv = process.argv, env = process.env) {
|
|
3025
|
+
const dryRun = argv.includes("--dry-run") || env["DRY_RUN"] === "1";
|
|
3026
|
+
const verbose = argv.includes("--verbose") || env["VERBOSE"] === "1" || dryRun;
|
|
3027
|
+
const fix = argv.includes("--fix");
|
|
3028
|
+
return {
|
|
3029
|
+
dryRun,
|
|
3030
|
+
verbose,
|
|
3031
|
+
fix
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
__name(parseFlags, "parseFlags");
|
|
3035
|
+
function computeHash(sql4) {
|
|
3036
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(sql4).digest("hex");
|
|
3037
|
+
return `sha256:${hash}`;
|
|
3038
|
+
}
|
|
3039
|
+
__name(computeHash, "computeHash");
|
|
3040
|
+
function categorizeChanges(prev, curr) {
|
|
3041
|
+
const allKeys = /* @__PURE__ */ new Set([
|
|
3042
|
+
...Object.keys(prev),
|
|
3043
|
+
...Object.keys(curr)
|
|
3044
|
+
]);
|
|
3045
|
+
const changes = [];
|
|
3046
|
+
for (const key of [
|
|
3047
|
+
...allKeys
|
|
3048
|
+
].sort()) {
|
|
3049
|
+
if (!(key in prev)) {
|
|
3050
|
+
changes.push({
|
|
3051
|
+
key,
|
|
3052
|
+
category: "added"
|
|
3053
|
+
});
|
|
3054
|
+
} else if (!(key in curr)) {
|
|
3055
|
+
changes.push({
|
|
3056
|
+
key,
|
|
3057
|
+
category: "removed"
|
|
3058
|
+
});
|
|
3059
|
+
} else if (prev[key] !== curr[key]) {
|
|
3060
|
+
changes.push({
|
|
3061
|
+
key,
|
|
3062
|
+
category: "modified"
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
return changes;
|
|
3067
|
+
}
|
|
3068
|
+
__name(categorizeChanges, "categorizeChanges");
|
|
3069
|
+
function formatChangeSummary(changes) {
|
|
3070
|
+
if (changes.length === 0) return "";
|
|
3071
|
+
const prefixes = {
|
|
3072
|
+
added: "+",
|
|
3073
|
+
modified: "~",
|
|
3074
|
+
removed: "-"
|
|
3075
|
+
};
|
|
3076
|
+
const labels = {
|
|
3077
|
+
added: "new",
|
|
3078
|
+
modified: "modified",
|
|
3079
|
+
removed: "removed"
|
|
3080
|
+
};
|
|
3081
|
+
const lines = changes.map(({ key, category }) => ` ${prefixes[category]} ${key} (${labels[category]})`);
|
|
3082
|
+
return `Custom SQL changes:
|
|
3083
|
+
${lines.join("\n")}`;
|
|
3084
|
+
}
|
|
3085
|
+
__name(formatChangeSummary, "formatChangeSummary");
|
|
3086
|
+
function simpleDiff(prev, curr) {
|
|
3087
|
+
const prevLines = prev.split("\n");
|
|
3088
|
+
const currLines = curr.split("\n");
|
|
3089
|
+
const result = [];
|
|
3090
|
+
let pi = 0;
|
|
3091
|
+
let ci = 0;
|
|
3092
|
+
while (pi < prevLines.length || ci < currLines.length) {
|
|
3093
|
+
if (pi >= prevLines.length) {
|
|
3094
|
+
result.push(`+${currLines[ci]}`);
|
|
3095
|
+
ci++;
|
|
3096
|
+
} else if (ci >= currLines.length) {
|
|
3097
|
+
result.push(`-${prevLines[pi]}`);
|
|
3098
|
+
pi++;
|
|
3099
|
+
} else if (prevLines[pi] === currLines[ci]) {
|
|
3100
|
+
result.push(` ${prevLines[pi]}`);
|
|
3101
|
+
pi++;
|
|
3102
|
+
ci++;
|
|
3103
|
+
} else {
|
|
3104
|
+
result.push(`-${prevLines[pi]}`);
|
|
3105
|
+
result.push(`+${currLines[ci]}`);
|
|
3106
|
+
pi++;
|
|
3107
|
+
ci++;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
return result.join("\n");
|
|
3111
|
+
}
|
|
3112
|
+
__name(simpleDiff, "simpleDiff");
|
|
3113
|
+
function indent(text2) {
|
|
3114
|
+
return text2.split("\n").map((line) => ` ${line}`).join("\n");
|
|
3115
|
+
}
|
|
3116
|
+
__name(indent, "indent");
|
|
3117
|
+
function formatVerboseOutput(changes, currentObjects, prevObjects) {
|
|
3118
|
+
const sections = [];
|
|
3119
|
+
for (const { key, category } of changes) {
|
|
3120
|
+
if (category === "added") {
|
|
3121
|
+
const sql4 = currentObjects[key]?.sql ?? "";
|
|
3122
|
+
sections.push(`+ ${key} (new)
|
|
3123
|
+
${indent(sql4)}`);
|
|
3124
|
+
} else if (category === "modified") {
|
|
3125
|
+
const currSql = currentObjects[key]?.sql ?? "";
|
|
3126
|
+
const prevSql = prevObjects[key]?.sql ?? "";
|
|
3127
|
+
if (prevSql) {
|
|
3128
|
+
const diff = simpleDiff(prevSql, currSql);
|
|
3129
|
+
sections.push(`~ ${key} (modified)
|
|
3130
|
+
--- previous
|
|
3131
|
+
+++ current
|
|
3132
|
+
${indent(diff)}`);
|
|
3133
|
+
} else {
|
|
3134
|
+
sections.push(`~ ${key} (modified \u2014 previous SQL not stored, showing current)
|
|
3135
|
+
${indent(currSql)}`);
|
|
3136
|
+
}
|
|
3137
|
+
} else {
|
|
3138
|
+
sections.push(`- ${key} (removed)`);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
return sections.join("\n");
|
|
3142
|
+
}
|
|
3143
|
+
__name(formatVerboseOutput, "formatVerboseOutput");
|
|
3144
|
+
function readJournal(migrationsDir) {
|
|
3145
|
+
const journalPath = (0, import_node_path.join)(migrationsDir, "meta", "_journal.json");
|
|
3146
|
+
return JSON.parse((0, import_node_fs.readFileSync)(journalPath, "utf-8"));
|
|
3147
|
+
}
|
|
3148
|
+
__name(readJournal, "readJournal");
|
|
3149
|
+
function timestampFromTag(tag) {
|
|
3150
|
+
return tag.match(/^(\d+)/)?.[1] ?? tag;
|
|
3151
|
+
}
|
|
3152
|
+
__name(timestampFromTag, "timestampFromTag");
|
|
3153
|
+
function nowTimestamp() {
|
|
3154
|
+
const d = /* @__PURE__ */ new Date();
|
|
3155
|
+
const p = /* @__PURE__ */ __name((n) => String(n).padStart(2, "0"), "p");
|
|
3156
|
+
return `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
|
|
3157
|
+
}
|
|
3158
|
+
__name(nowTimestamp, "nowTimestamp");
|
|
3159
|
+
function getLatestSnapshotPath(migrationsDir, journal) {
|
|
3160
|
+
if (journal.entries.length === 0) return null;
|
|
3161
|
+
const latest = journal.entries[journal.entries.length - 1];
|
|
3162
|
+
return (0, import_node_path.join)(migrationsDir, "meta", `${timestampFromTag(latest.tag)}_snapshot.json`);
|
|
3163
|
+
}
|
|
3164
|
+
__name(getLatestSnapshotPath, "getLatestSnapshotPath");
|
|
3165
|
+
function readSnapshotCustomObjects(snapshotPath) {
|
|
3166
|
+
const snapshot = JSON.parse((0, import_node_fs.readFileSync)(snapshotPath, "utf-8"));
|
|
3167
|
+
const raw = snapshot.customObjects ?? {};
|
|
3168
|
+
const result = {};
|
|
3169
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
3170
|
+
if (typeof value === "string") {
|
|
3171
|
+
result[key] = {
|
|
3172
|
+
hash: value,
|
|
3173
|
+
sql: ""
|
|
3174
|
+
};
|
|
3175
|
+
} else {
|
|
3176
|
+
result[key] = value;
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
return result;
|
|
3180
|
+
}
|
|
3181
|
+
__name(readSnapshotCustomObjects, "readSnapshotCustomObjects");
|
|
3182
|
+
function writeSnapshotCustomObjects(snapshotPath, objects) {
|
|
3183
|
+
const snapshot = JSON.parse((0, import_node_fs.readFileSync)(snapshotPath, "utf-8"));
|
|
3184
|
+
snapshot.customObjects = objects;
|
|
3185
|
+
(0, import_node_fs.writeFileSync)(snapshotPath, JSON.stringify(snapshot, null, 2) + "\n");
|
|
3186
|
+
}
|
|
3187
|
+
__name(writeSnapshotCustomObjects, "writeSnapshotCustomObjects");
|
|
3188
|
+
function stableStringify(obj) {
|
|
3189
|
+
if (obj === null || typeof obj !== "object") return JSON.stringify(obj);
|
|
3190
|
+
if (Array.isArray(obj)) return `[${obj.map(stableStringify).join(",")}]`;
|
|
3191
|
+
const sorted = Object.keys(obj).sort();
|
|
3192
|
+
const entries = sorted.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
|
|
3193
|
+
return `{${entries.join(",")}}`;
|
|
3194
|
+
}
|
|
3195
|
+
__name(stableStringify, "stableStringify");
|
|
3196
|
+
function packToSgz(migrationsDir) {
|
|
3197
|
+
const metaDir = (0, import_node_path.join)(migrationsDir, "meta");
|
|
3198
|
+
if (!(0, import_node_fs.existsSync)(metaDir)) return;
|
|
3199
|
+
const snapshotFiles = (0, import_node_fs.readdirSync)(metaDir).filter((f) => f.endsWith("_snapshot.json"));
|
|
3200
|
+
const sqlFiles = (0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sql"));
|
|
3201
|
+
for (const file of snapshotFiles) {
|
|
3202
|
+
const timestamp2 = timestampFromTag(file);
|
|
3203
|
+
const sqlFile = sqlFiles.find((f) => f.startsWith(timestamp2));
|
|
3204
|
+
if (!sqlFile) continue;
|
|
3205
|
+
const sqlStem = sqlFile.replace(/\.sql$/, "");
|
|
3206
|
+
const normalized = stableStringify(JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path.join)(metaDir, file), "utf-8")));
|
|
3207
|
+
const compressed = (0, import_node_zlib.gzipSync)(normalized, {
|
|
3208
|
+
level: 9
|
|
3209
|
+
});
|
|
3210
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(migrationsDir, `${sqlStem}.sgz`), compressed);
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
__name(packToSgz, "packToSgz");
|
|
3214
|
+
function unpackFromSgz(migrationsDir) {
|
|
3215
|
+
const metaDir = (0, import_node_path.join)(migrationsDir, "meta");
|
|
3216
|
+
(0, import_node_fs.mkdirSync)(metaDir, {
|
|
3217
|
+
recursive: true
|
|
3218
|
+
});
|
|
3219
|
+
const sgzFiles = (0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sgz")).sort();
|
|
3220
|
+
const sqlFiles = (0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sql"));
|
|
3221
|
+
const entries = [];
|
|
3222
|
+
for (let i = 0; i < sgzFiles.length; i++) {
|
|
3223
|
+
const stem = sgzFiles[i].replace(/\.sgz$/, "");
|
|
3224
|
+
const timestamp2 = timestampFromTag(stem);
|
|
3225
|
+
const decompressed = (0, import_node_zlib.gunzipSync)((0, import_node_fs.readFileSync)((0, import_node_path.join)(migrationsDir, sgzFiles[i])));
|
|
3226
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(metaDir, `${timestamp2}_snapshot.json`), decompressed);
|
|
3227
|
+
const sqlFile = sqlFiles.find((f) => f.startsWith(timestamp2));
|
|
3228
|
+
const tag = sqlFile ? sqlFile.replace(/\.sql$/, "") : stem;
|
|
3229
|
+
entries.push({
|
|
3230
|
+
idx: i,
|
|
3231
|
+
version: "7",
|
|
3232
|
+
when: parseInt(timestamp2, 10),
|
|
3233
|
+
tag,
|
|
3234
|
+
breakpoints: true
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
const journal = {
|
|
3238
|
+
version: "7",
|
|
3239
|
+
dialect: "postgresql",
|
|
3240
|
+
entries
|
|
3241
|
+
};
|
|
3242
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(metaDir, "_journal.json"), JSON.stringify(journal, null, 2) + "\n");
|
|
3243
|
+
}
|
|
3244
|
+
__name(unpackFromSgz, "unpackFromSgz");
|
|
3245
|
+
function cleanMeta(migrationsDir) {
|
|
3246
|
+
const metaDir = (0, import_node_path.join)(migrationsDir, "meta");
|
|
3247
|
+
if ((0, import_node_fs.existsSync)(metaDir)) (0, import_node_fs.rmSync)(metaDir, {
|
|
3248
|
+
recursive: true
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
__name(cleanMeta, "cleanMeta");
|
|
3252
|
+
function listSgzFiles(migrationsDir) {
|
|
3253
|
+
return (0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sgz")).sort();
|
|
3254
|
+
}
|
|
3255
|
+
__name(listSgzFiles, "listSgzFiles");
|
|
3256
|
+
function validateTimestamps(migrationsDir) {
|
|
3257
|
+
const duplicates = [];
|
|
3258
|
+
let prevTimestamp = "";
|
|
3259
|
+
for (const file of listSgzFiles(migrationsDir)) {
|
|
3260
|
+
const ts2 = timestampFromTag(file);
|
|
3261
|
+
if (ts2 === prevTimestamp) duplicates.push(file);
|
|
3262
|
+
prevTimestamp = ts2;
|
|
3263
|
+
}
|
|
3264
|
+
return duplicates;
|
|
3265
|
+
}
|
|
3266
|
+
__name(validateTimestamps, "validateTimestamps");
|
|
3267
|
+
function validateOrder(migrationsDir) {
|
|
3268
|
+
const sgzFiles = listSgzFiles(migrationsDir);
|
|
3269
|
+
const issues = [];
|
|
3270
|
+
let prevContentId = "";
|
|
3271
|
+
for (const file of sgzFiles) {
|
|
3272
|
+
const content = JSON.parse((0, import_node_zlib.gunzipSync)((0, import_node_fs.readFileSync)((0, import_node_path.join)(migrationsDir, file))).toString());
|
|
3273
|
+
if (prevContentId !== "" && content.prevId !== prevContentId) {
|
|
3274
|
+
issues.push({
|
|
3275
|
+
file,
|
|
3276
|
+
expected: prevContentId,
|
|
3277
|
+
actual: content.prevId
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
3280
|
+
prevContentId = content.id;
|
|
3281
|
+
}
|
|
3282
|
+
return issues;
|
|
3283
|
+
}
|
|
3284
|
+
__name(validateOrder, "validateOrder");
|
|
3285
|
+
function fixOrder(migrationsDir, issues) {
|
|
3286
|
+
let lastUsedTs = "";
|
|
3287
|
+
for (const issue of issues) {
|
|
3288
|
+
const sgzPath = (0, import_node_path.join)(migrationsDir, issue.file);
|
|
3289
|
+
const sqlFile = issue.file.replace(/\.sgz$/, ".sql");
|
|
3290
|
+
const sqlPath = (0, import_node_path.join)(migrationsDir, sqlFile);
|
|
3291
|
+
let sqlContent = "";
|
|
3292
|
+
try {
|
|
3293
|
+
sqlContent = (0, import_node_fs.readFileSync)(sqlPath, "utf-8");
|
|
3294
|
+
} catch {
|
|
3295
|
+
}
|
|
3296
|
+
const snapshot = JSON.parse((0, import_node_zlib.gunzipSync)((0, import_node_fs.readFileSync)(sgzPath)).toString());
|
|
3297
|
+
snapshot.prevId = issue.expected;
|
|
3298
|
+
const suffix = sqlFile.replace(/^\d+/, "");
|
|
3299
|
+
try {
|
|
3300
|
+
(0, import_node_fs.unlinkSync)(sqlPath);
|
|
3301
|
+
} catch {
|
|
3302
|
+
}
|
|
3303
|
+
(0, import_node_fs.unlinkSync)(sgzPath);
|
|
3304
|
+
let ts2 = findTimestampAfterDependency(migrationsDir, issue.expected);
|
|
3305
|
+
if (ts2 <= lastUsedTs) ts2 = String(Number(lastUsedTs) + 1);
|
|
3306
|
+
lastUsedTs = ts2;
|
|
3307
|
+
const newStem = `${ts2}${suffix.replace(/\.sql$/, "")}`;
|
|
3308
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(migrationsDir, `${newStem}.sql`), sqlContent);
|
|
3309
|
+
(0, import_node_fs.writeFileSync)((0, import_node_path.join)(migrationsDir, `${newStem}.sgz`), (0, import_node_zlib.gzipSync)(stableStringify(snapshot), {
|
|
3310
|
+
level: 9
|
|
3311
|
+
}));
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
__name(fixOrder, "fixOrder");
|
|
3315
|
+
function findTimestampAfterDependency(migrationsDir, expectedId) {
|
|
3316
|
+
for (const file of listSgzFiles(migrationsDir)) {
|
|
3317
|
+
const content = JSON.parse((0, import_node_zlib.gunzipSync)((0, import_node_fs.readFileSync)((0, import_node_path.join)(migrationsDir, file))).toString());
|
|
3318
|
+
if (content.id === expectedId) {
|
|
3319
|
+
const depTs = timestampFromTag(file);
|
|
3320
|
+
return String(Number(depTs) + 1);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
return nowTimestamp();
|
|
3324
|
+
}
|
|
3325
|
+
__name(findTimestampAfterDependency, "findTimestampAfterDependency");
|
|
3326
|
+
function collectCustomObjects(moduleExports) {
|
|
3327
|
+
return Object.values(moduleExports).filter((v) => v instanceof CustomObject);
|
|
3328
|
+
}
|
|
3329
|
+
__name(collectCustomObjects, "collectCustomObjects");
|
|
3330
|
+
function serializeCustomObject(obj, dialect) {
|
|
3331
|
+
return obj.toSQL(dialect);
|
|
3332
|
+
}
|
|
3333
|
+
__name(serializeCustomObject, "serializeCustomObject");
|
|
3334
|
+
function generateDropSQL(key, createSQL) {
|
|
3335
|
+
const [type] = key.split(":");
|
|
3336
|
+
switch (type) {
|
|
3337
|
+
case "function": {
|
|
3338
|
+
const m = createSQL.match(/CREATE OR REPLACE FUNCTION\s+(\S+)\s*\(/);
|
|
3339
|
+
return m ? `DROP FUNCTION IF EXISTS ${m[1]};` : null;
|
|
3340
|
+
}
|
|
3341
|
+
case "trigger": {
|
|
3342
|
+
const m = createSQL.match(/CREATE OR REPLACE TRIGGER\s+(\S+)[\s\S]*?ON\s+(\S+)/);
|
|
3343
|
+
return m ? `DROP TRIGGER IF EXISTS ${m[1]} ON ${m[2]};` : null;
|
|
3344
|
+
}
|
|
3345
|
+
case "extension": {
|
|
3346
|
+
const m = createSQL.match(/CREATE EXTENSION IF NOT EXISTS\s+"([^"]+)"/);
|
|
3347
|
+
return m ? `DROP EXTENSION IF EXISTS "${m[1]}";` : null;
|
|
3348
|
+
}
|
|
3349
|
+
case "cron": {
|
|
3350
|
+
const m = createSQL.match(/cron\.schedule\('([^']+)'/);
|
|
3351
|
+
return m ? `SELECT cron.unschedule('${m[1]}');` : null;
|
|
3352
|
+
}
|
|
3353
|
+
default:
|
|
3354
|
+
return null;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
__name(generateDropSQL, "generateDropSQL");
|
|
3358
|
+
function findNewMigrationFile(migrationsDir, beforeFiles) {
|
|
3359
|
+
const afterFiles = (0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sql"));
|
|
3360
|
+
const newFile = afterFiles.find((f) => !beforeFiles.has(f));
|
|
3361
|
+
return newFile ? (0, import_node_path.join)(migrationsDir, newFile) : null;
|
|
3362
|
+
}
|
|
3363
|
+
__name(findNewMigrationFile, "findNewMigrationFile");
|
|
3364
|
+
async function generate(migrationsDir, schemaModules, flags = {
|
|
3365
|
+
dryRun: false,
|
|
3366
|
+
verbose: false,
|
|
3367
|
+
fix: false
|
|
3368
|
+
}) {
|
|
3369
|
+
const duplicates = validateTimestamps(migrationsDir);
|
|
3370
|
+
if (duplicates.length > 0) {
|
|
3371
|
+
console.error("Duplicate migration timestamps detected:");
|
|
3372
|
+
for (const file of duplicates) console.error(` ${file}`);
|
|
3373
|
+
console.error("Resolve manually \u2014 each migration must have a unique timestamp.");
|
|
3374
|
+
process.exit(1);
|
|
3375
|
+
}
|
|
3376
|
+
const orderIssues = validateOrder(migrationsDir);
|
|
3377
|
+
if (orderIssues.length > 0) {
|
|
3378
|
+
if (!flags.fix) {
|
|
3379
|
+
console.error("Migration order issues detected:");
|
|
3380
|
+
for (const issue of orderIssues) {
|
|
3381
|
+
console.error(` ${issue.file}: expected prevId="${issue.expected}", actual="${issue.actual}"`);
|
|
3382
|
+
}
|
|
3383
|
+
console.error("Run with --fix to repair.");
|
|
3384
|
+
process.exit(1);
|
|
3385
|
+
}
|
|
3386
|
+
if (flags.dryRun) {
|
|
3387
|
+
console.log("Would fix migration order:");
|
|
3388
|
+
for (const issue of orderIssues) {
|
|
3389
|
+
console.log(` ${issue.file}: re-timestamp, set prevId="${issue.expected}"`);
|
|
3390
|
+
}
|
|
3391
|
+
} else {
|
|
3392
|
+
fixOrder(migrationsDir, orderIssues);
|
|
3393
|
+
console.log(`Fixed ${orderIssues.length} migration order issue(s).`);
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
const dialect = new import_pg_core7.PgDialect();
|
|
3397
|
+
unpackFromSgz(migrationsDir);
|
|
3398
|
+
try {
|
|
3399
|
+
const journal = readJournal(migrationsDir);
|
|
3400
|
+
const snapshotPath = getLatestSnapshotPath(migrationsDir, journal);
|
|
3401
|
+
const prevObjects = snapshotPath ? readSnapshotCustomObjects(snapshotPath) : {};
|
|
3402
|
+
let beforeFiles = /* @__PURE__ */ new Set();
|
|
3403
|
+
if (!flags.dryRun) {
|
|
3404
|
+
beforeFiles = new Set((0, import_node_fs.readdirSync)(migrationsDir).filter((f) => f.endsWith(".sql")));
|
|
3405
|
+
console.log("Running drizzle-kit generate...");
|
|
3406
|
+
try {
|
|
3407
|
+
(0, import_node_child_process.execSync)("pnpm drizzle generate", {
|
|
3408
|
+
stdio: "inherit"
|
|
3409
|
+
});
|
|
3410
|
+
} catch {
|
|
3411
|
+
throw new Error("drizzle-kit generate failed. Aborting.");
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
const allObjects = schemaModules.flatMap(collectCustomObjects);
|
|
3415
|
+
const typeOrder = [
|
|
3416
|
+
"function",
|
|
3417
|
+
"trigger",
|
|
3418
|
+
"extension",
|
|
3419
|
+
"cron"
|
|
3420
|
+
];
|
|
3421
|
+
const ordered = allObjects.filter((o) => typeOrder.includes(o.type)).sort((a, b) => typeOrder.indexOf(a.type) - typeOrder.indexOf(b.type) || a.name.localeCompare(b.name));
|
|
3422
|
+
const currentObjects = {};
|
|
3423
|
+
for (const obj of ordered) {
|
|
3424
|
+
const sqlStr = serializeCustomObject(obj, dialect);
|
|
3425
|
+
const triggerTable = obj instanceof PgTrigger ? `.${obj.tableName}` : "";
|
|
3426
|
+
const key = `${obj.type}:${obj.name}${triggerTable}`;
|
|
3427
|
+
currentObjects[key] = {
|
|
3428
|
+
hash: computeHash(sqlStr),
|
|
3429
|
+
sql: sqlStr
|
|
3430
|
+
};
|
|
3431
|
+
}
|
|
3432
|
+
const prevHashes = Object.fromEntries(Object.entries(prevObjects).map(([key, entry]) => [
|
|
3433
|
+
key,
|
|
3434
|
+
entry.hash
|
|
3435
|
+
]));
|
|
3436
|
+
const currentHashes = Object.fromEntries(Object.entries(currentObjects).map(([key, entry]) => [
|
|
3437
|
+
key,
|
|
3438
|
+
entry.hash
|
|
3439
|
+
]));
|
|
3440
|
+
const changes = categorizeChanges(prevHashes, currentHashes);
|
|
3441
|
+
if (changes.length === 0) {
|
|
3442
|
+
console.log("No custom SQL changes detected.");
|
|
3443
|
+
if (!flags.dryRun) {
|
|
3444
|
+
const latestJournal = readJournal(migrationsDir);
|
|
3445
|
+
const latestSnapshotPath = getLatestSnapshotPath(migrationsDir, latestJournal);
|
|
3446
|
+
if (latestSnapshotPath) writeSnapshotCustomObjects(latestSnapshotPath, currentObjects);
|
|
3447
|
+
packToSgz(migrationsDir);
|
|
3448
|
+
}
|
|
3449
|
+
return;
|
|
3450
|
+
}
|
|
3451
|
+
console.log(formatChangeSummary(changes));
|
|
3452
|
+
if (flags.verbose) {
|
|
3453
|
+
console.log("");
|
|
3454
|
+
console.log(formatVerboseOutput(changes, currentObjects, prevObjects));
|
|
3455
|
+
}
|
|
3456
|
+
if (flags.dryRun) {
|
|
3457
|
+
console.log("\n=== DRY RUN: No files were written ===");
|
|
3458
|
+
return;
|
|
3459
|
+
}
|
|
3460
|
+
let migrationFile = findNewMigrationFile(migrationsDir, beforeFiles);
|
|
3461
|
+
if (!migrationFile) {
|
|
3462
|
+
console.log("No drizzle migration was created. Creating custom migration...");
|
|
3463
|
+
(0, import_node_child_process.execSync)("pnpm drizzle generate --custom", {
|
|
3464
|
+
stdio: "inherit"
|
|
3465
|
+
});
|
|
3466
|
+
migrationFile = findNewMigrationFile(migrationsDir, beforeFiles);
|
|
3467
|
+
if (!migrationFile) throw new Error("Failed to create custom migration file");
|
|
3468
|
+
}
|
|
3469
|
+
const createKeys = changes.filter((c) => c.category !== "removed").map((c) => c.key);
|
|
3470
|
+
const createStatements = createKeys.map((key) => `-- @drizzle-custom ${key}
|
|
3471
|
+
${currentObjects[key].sql}`);
|
|
3472
|
+
const removedKeys = changes.filter((c) => c.category === "removed").map((c) => c.key);
|
|
3473
|
+
const dropStatements = removedKeys.map((key) => {
|
|
3474
|
+
const dropSql = generateDropSQL(key, prevObjects[key]?.sql ?? "");
|
|
3475
|
+
return dropSql ? `-- @drizzle-custom ${key} (removed)
|
|
3476
|
+
${dropSql}` : null;
|
|
3477
|
+
}).filter(Boolean);
|
|
3478
|
+
const allStatements = [
|
|
3479
|
+
...dropStatements,
|
|
3480
|
+
...createStatements
|
|
3481
|
+
].join("\n\n");
|
|
3482
|
+
(0, import_node_fs.appendFileSync)(migrationFile, `
|
|
3483
|
+
-- Custom SQL objects
|
|
3484
|
+
${allStatements}
|
|
3485
|
+
`);
|
|
3486
|
+
if (dropStatements.length > 0) {
|
|
3487
|
+
const dropNames = removedKeys.join(", ");
|
|
3488
|
+
(0, import_node_fs.appendFileSync)(migrationFile, `
|
|
3489
|
+
-- TODO: Review dropped objects (${dropNames})
|
|
3490
|
+
-- If they have dependants (triggers, cron jobs, etc.), add DROP/UPDATE statements below.
|
|
3491
|
+
-- Run 'pnpm dev:init' to verify this migration applies cleanly.
|
|
3492
|
+
|
|
3493
|
+
`);
|
|
3494
|
+
console.log(`\u26A0 ${dropStatements.length} object(s) dropped \u2014 check migration for dependency TODOs`);
|
|
3495
|
+
}
|
|
3496
|
+
const total = createKeys.length + dropStatements.length;
|
|
3497
|
+
console.log(`Appended ${total} custom SQL statement(s) to ${migrationFile}`);
|
|
3498
|
+
const updatedJournal = readJournal(migrationsDir);
|
|
3499
|
+
const updatedSnapshotPath = getLatestSnapshotPath(migrationsDir, updatedJournal);
|
|
3500
|
+
if (updatedSnapshotPath) {
|
|
3501
|
+
writeSnapshotCustomObjects(updatedSnapshotPath, currentObjects);
|
|
3502
|
+
console.log(`Updated custom hashes in ${updatedSnapshotPath}`);
|
|
3503
|
+
}
|
|
3504
|
+
packToSgz(migrationsDir);
|
|
3505
|
+
} finally {
|
|
3506
|
+
cleanMeta(migrationsDir);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
__name(generate, "generate");
|
|
3510
|
+
function drop(migrationsDir) {
|
|
3511
|
+
unpackFromSgz(migrationsDir);
|
|
3512
|
+
try {
|
|
3513
|
+
(0, import_node_child_process.execSync)("pnpm drizzle drop", {
|
|
3514
|
+
stdio: "inherit"
|
|
3515
|
+
});
|
|
3516
|
+
packToSgz(migrationsDir);
|
|
3517
|
+
for (const f of (0, import_node_fs.readdirSync)(migrationsDir)) {
|
|
3518
|
+
if (!f.endsWith(".sgz")) continue;
|
|
3519
|
+
if (!(0, import_node_fs.existsSync)((0, import_node_path.join)(migrationsDir, f.replace(".sgz", ".sql")))) {
|
|
3520
|
+
(0, import_node_fs.unlinkSync)((0, import_node_path.join)(migrationsDir, f));
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
} finally {
|
|
3524
|
+
cleanMeta(migrationsDir);
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
__name(drop, "drop");
|
|
3528
|
+
function custom(migrationsDir) {
|
|
3529
|
+
unpackFromSgz(migrationsDir);
|
|
3530
|
+
try {
|
|
3531
|
+
(0, import_node_child_process.execSync)("pnpm drizzle generate --custom", {
|
|
3532
|
+
stdio: "inherit"
|
|
3533
|
+
});
|
|
3534
|
+
packToSgz(migrationsDir);
|
|
3535
|
+
} finally {
|
|
3536
|
+
cleanMeta(migrationsDir);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
__name(custom, "custom");
|
|
3540
|
+
async function loadSchemaModules(schemaDir) {
|
|
3541
|
+
const sourceNames = [
|
|
3542
|
+
"functions",
|
|
3543
|
+
"triggers",
|
|
3544
|
+
"extensions",
|
|
3545
|
+
"cron"
|
|
3546
|
+
];
|
|
3547
|
+
const importTasks = [];
|
|
3548
|
+
for (const name of sourceNames) {
|
|
3549
|
+
const dirPath = (0, import_node_path.join)(schemaDir, name);
|
|
3550
|
+
const filePath = (0, import_node_path.join)(schemaDir, `${name}.ts`);
|
|
3551
|
+
if ((0, import_node_fs.existsSync)(dirPath) && (0, import_node_fs.statSync)(dirPath).isDirectory()) {
|
|
3552
|
+
const scanDir = /* @__PURE__ */ __name((dir, prefix) => {
|
|
3553
|
+
for (const entry of (0, import_node_fs.readdirSync)(dir)) {
|
|
3554
|
+
const fullPath = (0, import_node_path.join)(dir, entry);
|
|
3555
|
+
if ((0, import_node_fs.statSync)(fullPath).isDirectory()) {
|
|
3556
|
+
scanDir(fullPath, `${prefix}${entry}/`);
|
|
3557
|
+
} else if (entry.endsWith(".ts") && !entry.includes(".test.") && !entry.includes(".spec.")) {
|
|
3558
|
+
importTasks.push(import(fullPath).catch((err) => {
|
|
3559
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3560
|
+
console.error(`Failed to load ${prefix}${entry}: ${msg}`);
|
|
3561
|
+
process.exit(1);
|
|
3562
|
+
}));
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
}, "scanDir");
|
|
3566
|
+
scanDir(dirPath, `${name}/`);
|
|
3567
|
+
} else if ((0, import_node_fs.existsSync)(filePath)) {
|
|
3568
|
+
importTasks.push(import(filePath).catch((err) => {
|
|
3569
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3570
|
+
console.error(`Failed to load ${name}.ts: ${msg}`);
|
|
3571
|
+
process.exit(1);
|
|
3572
|
+
}));
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
return Promise.all(importTasks);
|
|
3576
|
+
}
|
|
3577
|
+
__name(loadSchemaModules, "loadSchemaModules");
|
|
3578
|
+
async function syncMeta(migrationsDir, schemaModules) {
|
|
3579
|
+
const dialect = new import_pg_core7.PgDialect();
|
|
3580
|
+
const allObjects = schemaModules.flatMap(collectCustomObjects);
|
|
3581
|
+
const ordered = allObjects.sort((a, b) => a.type.localeCompare(b.type) || a.name.localeCompare(b.name));
|
|
3582
|
+
const currentObjects = {};
|
|
3583
|
+
for (const obj of ordered) {
|
|
3584
|
+
const sqlStr = serializeCustomObject(obj, dialect);
|
|
3585
|
+
const triggerTable = obj instanceof PgTrigger ? `.${obj.tableName}` : "";
|
|
3586
|
+
currentObjects[`${obj.type}:${obj.name}${triggerTable}`] = {
|
|
3587
|
+
hash: computeHash(sqlStr),
|
|
3588
|
+
sql: sqlStr
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3591
|
+
const sgzFiles = listSgzFiles(migrationsDir);
|
|
3592
|
+
if (sgzFiles.length === 0) {
|
|
3593
|
+
console.error("No .sgz files found. Nothing to sync.");
|
|
3594
|
+
process.exit(1);
|
|
3595
|
+
}
|
|
3596
|
+
const latestSgz = sgzFiles[sgzFiles.length - 1];
|
|
3597
|
+
const sgzPath = (0, import_node_path.join)(migrationsDir, latestSgz);
|
|
3598
|
+
const snap = JSON.parse((0, import_node_zlib.gunzipSync)((0, import_node_fs.readFileSync)(sgzPath)).toString());
|
|
3599
|
+
snap.customObjects = currentObjects;
|
|
3600
|
+
(0, import_node_fs.writeFileSync)(sgzPath, (0, import_node_zlib.gzipSync)(stableStringify(snap), {
|
|
3601
|
+
level: 9
|
|
3602
|
+
}));
|
|
3603
|
+
console.log(`Synced ${Object.keys(currentObjects).length} custom objects into ${latestSgz}`);
|
|
3604
|
+
}
|
|
3605
|
+
__name(syncMeta, "syncMeta");
|
|
3606
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3607
|
+
0 && (module.exports = {
|
|
3608
|
+
APP_SLUG_JS,
|
|
3609
|
+
APP_SLUG_SQL,
|
|
3610
|
+
CustomObject,
|
|
3611
|
+
ENUM_MAP,
|
|
3612
|
+
FALSE,
|
|
3613
|
+
GENERATED_FILE_BANNER,
|
|
3614
|
+
PgCronJob,
|
|
3615
|
+
PgExtension,
|
|
3616
|
+
PgFunction,
|
|
3617
|
+
PgTrigger,
|
|
3618
|
+
TriggerFunction,
|
|
3619
|
+
adaptToLegacyConfig,
|
|
3620
|
+
appSlugForeignKey,
|
|
3621
|
+
assertNoTypedColumnOverrides,
|
|
3622
|
+
auditColumns,
|
|
3623
|
+
buildRelations,
|
|
3624
|
+
buildTypeDefs,
|
|
3625
|
+
capitalize,
|
|
3626
|
+
categorizeChanges,
|
|
3627
|
+
cleanMeta,
|
|
3628
|
+
colAppSlug,
|
|
3629
|
+
colCreatedAt,
|
|
3630
|
+
colDeletedAt,
|
|
3631
|
+
colId,
|
|
3632
|
+
colNumeric,
|
|
3633
|
+
colTimestamp,
|
|
3634
|
+
colUpdatedAt,
|
|
3635
|
+
collectCustomObjects,
|
|
3636
|
+
computeHash,
|
|
3637
|
+
currentAppSlug,
|
|
3638
|
+
currentUser,
|
|
3639
|
+
custom,
|
|
3640
|
+
defaultPolicy,
|
|
3641
|
+
defineConfig,
|
|
3642
|
+
defineModels,
|
|
3643
|
+
derived,
|
|
3644
|
+
discoverEnums,
|
|
3645
|
+
discoverTables,
|
|
3646
|
+
discoverViews,
|
|
3647
|
+
drop,
|
|
3648
|
+
emitCompatTs,
|
|
3649
|
+
emitEnumBlock,
|
|
3650
|
+
emitEnumsTs,
|
|
3651
|
+
emitFieldBlock,
|
|
3652
|
+
emitGeneratedFileBanner,
|
|
3653
|
+
emitIndexTs,
|
|
3654
|
+
emitInputTs,
|
|
3655
|
+
emitJsonNamespaceBlock,
|
|
3656
|
+
emitJsonRawNamespaceBlock,
|
|
3657
|
+
emitJsonRawTs,
|
|
3658
|
+
emitJsonTs,
|
|
3659
|
+
emitModelsTs,
|
|
3660
|
+
emitOrmTypesTs,
|
|
3661
|
+
emitRelationField,
|
|
3662
|
+
emitSchemaTs,
|
|
3663
|
+
emitTypeDefsBlock,
|
|
3664
|
+
emitViewsTs,
|
|
3665
|
+
esc,
|
|
3666
|
+
extend,
|
|
3667
|
+
extractFKs,
|
|
3668
|
+
fixOrder,
|
|
3669
|
+
formatChangeSummary,
|
|
3670
|
+
formatVerboseOutput,
|
|
3671
|
+
generate,
|
|
3672
|
+
generateDropSQL,
|
|
3673
|
+
getDrizzleTableName,
|
|
3674
|
+
getLatestSnapshotPath,
|
|
3675
|
+
hasAppSlug,
|
|
3676
|
+
hasBypassEnabled,
|
|
3677
|
+
loadSchemaModules,
|
|
3678
|
+
many,
|
|
3679
|
+
mapColumn,
|
|
3680
|
+
model,
|
|
3681
|
+
one,
|
|
3682
|
+
packToSgz,
|
|
3683
|
+
parseFlags,
|
|
3684
|
+
pgCron,
|
|
3685
|
+
pgExtension,
|
|
3686
|
+
pgFunction,
|
|
3687
|
+
pgOrmEnum,
|
|
3688
|
+
pgTrigger,
|
|
3689
|
+
pgTypes,
|
|
3690
|
+
readJournal,
|
|
3691
|
+
readSnapshotCustomObjects,
|
|
3692
|
+
serializeCustomObject,
|
|
3693
|
+
simpleDiff,
|
|
3694
|
+
syncMeta,
|
|
3695
|
+
through,
|
|
3696
|
+
toPascalCase,
|
|
3697
|
+
toPgEnum,
|
|
3698
|
+
uncapitalize,
|
|
3699
|
+
unpackFromSgz,
|
|
3700
|
+
validateOrder,
|
|
3701
|
+
validateTimestamps,
|
|
3702
|
+
writeFileIfChanged,
|
|
3703
|
+
writeSnapshotCustomObjects
|
|
3704
|
+
});
|
|
3705
|
+
//# sourceMappingURL=index.cjs.map
|