pecunia-cli 0.2.8 → 0.3.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/api.mjs +1 -1
- package/dist/generators-DyDUFaYK.mjs +710 -0
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/generators-BXA4y5O8.mjs +0 -1542
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
import fs, { existsSync } from "node:fs";
|
|
2
|
+
import fs$1 from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { getMigrations } from "pecunia-root";
|
|
5
|
+
import { capitalizeFirstLetter, getPaymentTables, initGetFieldName, initGetModelName } from "pecunia-core";
|
|
6
|
+
import prettier from "prettier";
|
|
7
|
+
import { produceSchema } from "@mrleebo/prisma-ast";
|
|
8
|
+
|
|
9
|
+
//#region src/generators/drizzle.ts
|
|
10
|
+
function convertToSnakeCase(str, camelCase) {
|
|
11
|
+
if (camelCase) return str;
|
|
12
|
+
return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
const generateDrizzleSchema = async ({ options, file, adapter }) => {
|
|
15
|
+
const tables = getPaymentTables(options);
|
|
16
|
+
const filePath = file || "./src/db/schema.ts";
|
|
17
|
+
const databaseType = adapter.options?.provider;
|
|
18
|
+
const projectRoot = process.cwd();
|
|
19
|
+
if (!databaseType) throw new Error("Database provider type is undefined during Drizzle schema generation. Please define a `provider` in the Drizzle adapter config.");
|
|
20
|
+
const resolvedSchemaPath = path.isAbsolute(filePath) ? filePath : path.resolve(projectRoot, filePath);
|
|
21
|
+
const schemaDir = path.dirname(resolvedSchemaPath);
|
|
22
|
+
if (!existsSync(schemaDir)) await fs$1.mkdir(schemaDir, { recursive: true });
|
|
23
|
+
const fileExist = existsSync(resolvedSchemaPath);
|
|
24
|
+
let code = generateImport({
|
|
25
|
+
databaseType,
|
|
26
|
+
tables,
|
|
27
|
+
options
|
|
28
|
+
});
|
|
29
|
+
const getModelName = initGetModelName({
|
|
30
|
+
schema: tables,
|
|
31
|
+
usePlural: adapter.options?.adapterConfig?.usePlural
|
|
32
|
+
});
|
|
33
|
+
const getFieldName = initGetFieldName({
|
|
34
|
+
schema: tables,
|
|
35
|
+
usePlural: adapter.options?.adapterConfig?.usePlural
|
|
36
|
+
});
|
|
37
|
+
const tableNameMap = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const tableKey in tables) tableNameMap.set(tableKey, getModelName(tableKey));
|
|
39
|
+
function getType(name, field, databaseType$1) {
|
|
40
|
+
name = convertToSnakeCase(name, adapter.options?.camelCase);
|
|
41
|
+
if (field.references?.field === "id") {
|
|
42
|
+
if (databaseType$1 === "mysql") return `varchar('${name}', { length: 36 })`;
|
|
43
|
+
return `text('${name}')`;
|
|
44
|
+
}
|
|
45
|
+
const type = field.type;
|
|
46
|
+
if (typeof type !== "string") {
|
|
47
|
+
if (Array.isArray(type) && type.every((x) => typeof x === "string")) return {
|
|
48
|
+
sqlite: `text({ enum: [${type.map((x) => `'${x}'`).join(", ")}] })`,
|
|
49
|
+
pg: `text('${name}', { enum: [${type.map((x) => `'${x}'`).join(", ")}] })`,
|
|
50
|
+
mysql: `mysqlEnum([${type.map((x) => `'${x}'`).join(", ")}])`
|
|
51
|
+
}[databaseType$1];
|
|
52
|
+
throw new TypeError(`Invalid field type for field ${name}`);
|
|
53
|
+
}
|
|
54
|
+
const dbTypeMap = {
|
|
55
|
+
string: {
|
|
56
|
+
sqlite: `text('${name}')`,
|
|
57
|
+
pg: `text('${name}')`,
|
|
58
|
+
mysql: field.unique ? `varchar('${name}', { length: 255 })` : field.references ? `varchar('${name}', { length: 36 })` : field.sortable ? `varchar('${name}', { length: 255 })` : field.index ? `varchar('${name}', { length: 255 })` : `text('${name}')`
|
|
59
|
+
},
|
|
60
|
+
boolean: {
|
|
61
|
+
sqlite: `integer('${name}', { mode: 'boolean' })`,
|
|
62
|
+
pg: `boolean('${name}')`,
|
|
63
|
+
mysql: `boolean('${name}')`
|
|
64
|
+
},
|
|
65
|
+
number: {
|
|
66
|
+
sqlite: `integer('${name}')`,
|
|
67
|
+
pg: field.bigint ? `bigint('${name}', { mode: 'number' })` : `integer('${name}')`,
|
|
68
|
+
mysql: field.bigint ? `bigint('${name}', { mode: 'number' })` : `int('${name}')`
|
|
69
|
+
},
|
|
70
|
+
date: {
|
|
71
|
+
sqlite: `integer('${name}', { mode: 'timestamp_ms' })`,
|
|
72
|
+
pg: `timestamp('${name}')`,
|
|
73
|
+
mysql: `timestamp('${name}', { fsp: 3 })`
|
|
74
|
+
},
|
|
75
|
+
"number[]": {
|
|
76
|
+
sqlite: `text('${name}', { mode: "json" })`,
|
|
77
|
+
pg: field.bigint ? `bigint('${name}', { mode: 'number' }).array()` : `integer('${name}').array()`,
|
|
78
|
+
mysql: `text('${name}', { mode: 'json' })`
|
|
79
|
+
},
|
|
80
|
+
"string[]": {
|
|
81
|
+
sqlite: `text('${name}', { mode: "json" })`,
|
|
82
|
+
pg: `text('${name}').array()`,
|
|
83
|
+
mysql: `text('${name}', { mode: "json" })`
|
|
84
|
+
},
|
|
85
|
+
json: {
|
|
86
|
+
sqlite: `text('${name}', { mode: "json" })`,
|
|
87
|
+
pg: `jsonb('${name}')`,
|
|
88
|
+
mysql: `json('${name}', { mode: "json" })`
|
|
89
|
+
},
|
|
90
|
+
uuid: {
|
|
91
|
+
sqlite: `text('${name}')`,
|
|
92
|
+
pg: `uuid('${name}')`,
|
|
93
|
+
mysql: `varchar('${name}', { length: 36 })`
|
|
94
|
+
}
|
|
95
|
+
}[type];
|
|
96
|
+
if (!dbTypeMap) throw new Error(`Unsupported field type '${field.type}' for field '${name}'.`);
|
|
97
|
+
return dbTypeMap[databaseType$1];
|
|
98
|
+
}
|
|
99
|
+
const tableDefinitions = [];
|
|
100
|
+
for (const tableKey in tables) {
|
|
101
|
+
const table = tables[tableKey];
|
|
102
|
+
const modelName = getModelName(tableKey);
|
|
103
|
+
const fields = table.fields;
|
|
104
|
+
const idFieldType = table.fields.id?.type;
|
|
105
|
+
let id;
|
|
106
|
+
if (databaseType === "pg" && idFieldType === "uuid") id = `uuid('id').primaryKey()`;
|
|
107
|
+
else if (databaseType === "mysql") id = `varchar('id', { length: 36 }).primaryKey()`;
|
|
108
|
+
else id = `text('id').primaryKey()`;
|
|
109
|
+
const indexes = [];
|
|
110
|
+
const references = [];
|
|
111
|
+
for (const field of Object.keys(fields)) {
|
|
112
|
+
if (field === "id") continue;
|
|
113
|
+
const attr = fields[field];
|
|
114
|
+
const fieldName = attr.fieldName || field;
|
|
115
|
+
if (attr.index && !attr.unique) indexes.push({
|
|
116
|
+
type: "index",
|
|
117
|
+
name: `${modelName}_${fieldName}_idx`,
|
|
118
|
+
on: fieldName
|
|
119
|
+
});
|
|
120
|
+
else if (attr.index && attr.unique) indexes.push({
|
|
121
|
+
type: "uniqueIndex",
|
|
122
|
+
name: `${modelName}_${fieldName}_uidx`,
|
|
123
|
+
on: fieldName
|
|
124
|
+
});
|
|
125
|
+
if (attr.references) {
|
|
126
|
+
const referencedModelName = tableNameMap.get(attr.references.model) || getModelName(attr.references.model);
|
|
127
|
+
const onDelete = attr.references.onDelete || "no action";
|
|
128
|
+
references.push({
|
|
129
|
+
fieldName,
|
|
130
|
+
referencedTable: referencedModelName,
|
|
131
|
+
referencedField: getFieldName({
|
|
132
|
+
model: attr.references.model,
|
|
133
|
+
field: attr.references.field
|
|
134
|
+
}),
|
|
135
|
+
onDelete,
|
|
136
|
+
required: attr.required ?? false,
|
|
137
|
+
originalModel: attr.references.model
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
tableDefinitions.push({
|
|
142
|
+
modelName,
|
|
143
|
+
tableKey,
|
|
144
|
+
fields,
|
|
145
|
+
id,
|
|
146
|
+
indexes,
|
|
147
|
+
references
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const modelKeyToTableKey = /* @__PURE__ */ new Map();
|
|
151
|
+
for (const tableKey in tables) {
|
|
152
|
+
const table = tables[tableKey];
|
|
153
|
+
const modelName = getModelName(tableKey);
|
|
154
|
+
modelKeyToTableKey.set(tableKey, tableKey);
|
|
155
|
+
modelKeyToTableKey.set(modelName, tableKey);
|
|
156
|
+
modelKeyToTableKey.set(table.modelName, tableKey);
|
|
157
|
+
}
|
|
158
|
+
const referenceGraph = /* @__PURE__ */ new Map();
|
|
159
|
+
for (const tableDef of tableDefinitions) for (const ref of tableDef.references) {
|
|
160
|
+
const referencedTableKey = modelKeyToTableKey.get(ref.originalModel);
|
|
161
|
+
if (!referencedTableKey) continue;
|
|
162
|
+
const key = `${tableDef.tableKey}->${referencedTableKey}`;
|
|
163
|
+
referenceGraph.set(key, {
|
|
164
|
+
...ref,
|
|
165
|
+
sourceTable: tableDef.tableKey,
|
|
166
|
+
sourceModelName: tableDef.modelName
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const skipReferences = /* @__PURE__ */ new Set();
|
|
170
|
+
for (const tableDef of tableDefinitions) for (const ref of tableDef.references) {
|
|
171
|
+
const referencedTableKey = modelKeyToTableKey.get(ref.originalModel);
|
|
172
|
+
if (!referencedTableKey) continue;
|
|
173
|
+
const reverseKey = `${referencedTableKey}->${tableDef.tableKey}`;
|
|
174
|
+
const reverseRef = referenceGraph.get(reverseKey);
|
|
175
|
+
if (reverseRef) {
|
|
176
|
+
const thisIsNullableWithSetNull = !ref.required && ref.onDelete === "set null";
|
|
177
|
+
const reverseIsNullableWithSetNull = !reverseRef.required && reverseRef.onDelete === "set null";
|
|
178
|
+
if (thisIsNullableWithSetNull) continue;
|
|
179
|
+
if (reverseIsNullableWithSetNull) continue;
|
|
180
|
+
if (!ref.required && (reverseRef.required || ref.onDelete !== "cascade" && reverseRef.onDelete === "cascade")) skipReferences.add(`${tableDef.tableKey}.${ref.fieldName}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for (const tableDef of tableDefinitions) {
|
|
184
|
+
const { modelName, fields, id, indexes, references } = tableDef;
|
|
185
|
+
const assignIndexes = (indexesToAssign) => {
|
|
186
|
+
if (!indexesToAssign.length) return "";
|
|
187
|
+
const parts = [`, (table) => [`];
|
|
188
|
+
for (const index of indexesToAssign) parts.push(` ${index.type}("${index.name}").on(table.${index.on}),`);
|
|
189
|
+
parts.push(`]`);
|
|
190
|
+
return parts.join("\n");
|
|
191
|
+
};
|
|
192
|
+
const referenceMap = /* @__PURE__ */ new Map();
|
|
193
|
+
for (const ref of references) referenceMap.set(ref.fieldName, ref);
|
|
194
|
+
const fieldDefinitions = Object.keys(fields).filter((field) => field !== "id").map((field) => {
|
|
195
|
+
const attr = fields[field];
|
|
196
|
+
const fieldName = attr.fieldName || field;
|
|
197
|
+
let type = getType(fieldName, attr, databaseType);
|
|
198
|
+
let comment = "";
|
|
199
|
+
if (attr.defaultValue !== null && typeof attr.defaultValue !== "undefined") if (typeof attr.defaultValue === "function") {
|
|
200
|
+
if (attr.type === "date" && attr.defaultValue.toString().includes("new Date()")) if (databaseType === "sqlite") type += `.default(sql\`(cast(unixepoch('subsecond') * 1000 as integer))\`)`;
|
|
201
|
+
else type += `.defaultNow()`;
|
|
202
|
+
} else if (typeof attr.defaultValue === "string") type += `.default("${attr.defaultValue}")`;
|
|
203
|
+
else type += `.default(${attr.defaultValue})`;
|
|
204
|
+
if (attr.onUpdate && attr.type === "date") {
|
|
205
|
+
if (typeof attr.onUpdate === "function") type += `.$onUpdate(${attr.onUpdate})`;
|
|
206
|
+
}
|
|
207
|
+
const ref = referenceMap.get(fieldName);
|
|
208
|
+
const shouldSkipReference = skipReferences.has(`${tableDef.tableKey}.${fieldName}`);
|
|
209
|
+
let referenceChain = "";
|
|
210
|
+
if (ref && !shouldSkipReference) referenceChain = `.references(() => ${ref.referencedTable}.${ref.referencedField}, { onDelete: '${ref.onDelete}' })`;
|
|
211
|
+
else if (ref && shouldSkipReference) {
|
|
212
|
+
const reverseKey = `${ref.originalModel}->${tableDef.tableKey}`;
|
|
213
|
+
const reverseRef = referenceGraph.get(reverseKey);
|
|
214
|
+
if (reverseRef) comment = `\n // FK constraint removed to break circular dependency with ${ref.referencedTable}\n // Primary FK: ${reverseRef.sourceModelName}.${reverseRef.fieldName} -> ${modelName}.${fieldName}\n // This field still maintains referential integrity via application logic and Drizzle relations`;
|
|
215
|
+
else comment = `\n // FK constraint removed to break circular dependency with ${ref.referencedTable}\n // This field still maintains referential integrity via application logic and Drizzle relations`;
|
|
216
|
+
}
|
|
217
|
+
const isRequired = attr.required === true;
|
|
218
|
+
const fieldDef = `${fieldName}: ${type}${isRequired ? ".notNull()" : ""}${attr.unique ? ".unique()" : ""}${referenceChain}`;
|
|
219
|
+
return comment ? `${comment}\n ${fieldDef}` : fieldDef;
|
|
220
|
+
});
|
|
221
|
+
const schema = `export const ${modelName} = ${databaseType}Table("${convertToSnakeCase(modelName, adapter.options?.camelCase)}", {
|
|
222
|
+
id: ${id},
|
|
223
|
+
${fieldDefinitions.join(",\n ")}
|
|
224
|
+
}${assignIndexes(indexes)});`;
|
|
225
|
+
code += `\n${schema}\n`;
|
|
226
|
+
}
|
|
227
|
+
let relationsString = "";
|
|
228
|
+
for (const tableKey in tables) {
|
|
229
|
+
const table = tables[tableKey];
|
|
230
|
+
const modelName = getModelName(tableKey);
|
|
231
|
+
const oneRelations = [];
|
|
232
|
+
const manyRelations = [];
|
|
233
|
+
if (table.relations) {
|
|
234
|
+
for (const [relationName, relationDef] of Object.entries(table.relations)) {
|
|
235
|
+
const referencedModelName = getModelName(relationDef.model);
|
|
236
|
+
const foreignKeyField = table.fields[relationDef.foreignKey];
|
|
237
|
+
const isSelfReferential = relationDef.model === tableKey || referencedModelName === modelName;
|
|
238
|
+
const generateRelationName = (fkName) => {
|
|
239
|
+
let cleaned = convertToSnakeCase(fkName, adapter.options?.camelCase).replace(/_by_id$/, "").replace(/_id$/, "");
|
|
240
|
+
const participleToNoun = {
|
|
241
|
+
"reversed": "reversal",
|
|
242
|
+
"created": "creation",
|
|
243
|
+
"updated": "update"
|
|
244
|
+
};
|
|
245
|
+
if (participleToNoun[cleaned]) cleaned = participleToNoun[cleaned];
|
|
246
|
+
return `${convertToSnakeCase(modelName, adapter.options?.camelCase)}_${cleaned}`;
|
|
247
|
+
};
|
|
248
|
+
if (relationDef.kind === "one") {
|
|
249
|
+
if (foreignKeyField?.references) {
|
|
250
|
+
const fieldRef = `${modelName}.${getFieldName({
|
|
251
|
+
model: tableKey,
|
|
252
|
+
field: relationDef.foreignKey
|
|
253
|
+
})}`;
|
|
254
|
+
const referenceRef = `${referencedModelName}.${getFieldName({
|
|
255
|
+
model: relationDef.model,
|
|
256
|
+
field: foreignKeyField.references.field || "id"
|
|
257
|
+
})}`;
|
|
258
|
+
oneRelations.push({
|
|
259
|
+
key: relationName,
|
|
260
|
+
model: referencedModelName,
|
|
261
|
+
type: "one",
|
|
262
|
+
reference: {
|
|
263
|
+
field: fieldRef,
|
|
264
|
+
references: referenceRef,
|
|
265
|
+
fieldName: relationDef.foreignKey
|
|
266
|
+
},
|
|
267
|
+
relationName: isSelfReferential ? generateRelationName(relationDef.foreignKey) : void 0
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
} else if (relationDef.kind === "many") {
|
|
271
|
+
const referencedTable = tables[relationDef.model];
|
|
272
|
+
if (referencedTable) {
|
|
273
|
+
const fkField = Object.entries(referencedTable.fields).find(([_, field]) => field.references && (field.references.model === tableKey || field.references.model === getModelName(tableKey)));
|
|
274
|
+
if (fkField) {
|
|
275
|
+
const [fkFieldName] = fkField;
|
|
276
|
+
const fieldRef = `${referencedModelName}.${getFieldName({
|
|
277
|
+
model: relationDef.model,
|
|
278
|
+
field: fkFieldName
|
|
279
|
+
})}`;
|
|
280
|
+
const referenceRef = `${modelName}.${getFieldName({
|
|
281
|
+
model: tableKey,
|
|
282
|
+
field: "id"
|
|
283
|
+
})}`;
|
|
284
|
+
let relationNameForMany;
|
|
285
|
+
if (isSelfReferential) {
|
|
286
|
+
const matchingOne = oneRelations.find((rel) => rel.reference?.fieldName === fkFieldName && rel.model === referencedModelName);
|
|
287
|
+
if (matchingOne?.relationName) relationNameForMany = matchingOne.relationName;
|
|
288
|
+
else {
|
|
289
|
+
let cleaned = convertToSnakeCase(fkFieldName, adapter.options?.camelCase).replace(/_by_id$/, "").replace(/_id$/, "");
|
|
290
|
+
const participleToNoun = {
|
|
291
|
+
"reversed": "reversal",
|
|
292
|
+
"created": "creation",
|
|
293
|
+
"updated": "update"
|
|
294
|
+
};
|
|
295
|
+
if (participleToNoun[cleaned]) cleaned = participleToNoun[cleaned];
|
|
296
|
+
relationNameForMany = `${convertToSnakeCase(modelName, adapter.options?.camelCase)}_${cleaned}`;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
manyRelations.push({
|
|
300
|
+
key: relationName,
|
|
301
|
+
model: referencedModelName,
|
|
302
|
+
type: "many",
|
|
303
|
+
reference: {
|
|
304
|
+
field: fieldRef,
|
|
305
|
+
references: referenceRef,
|
|
306
|
+
fieldName: fkFieldName
|
|
307
|
+
},
|
|
308
|
+
relationName: relationNameForMany
|
|
309
|
+
});
|
|
310
|
+
} else manyRelations.push({
|
|
311
|
+
key: relationName,
|
|
312
|
+
model: referencedModelName,
|
|
313
|
+
type: "many"
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const oneRel of oneRelations) {
|
|
319
|
+
if (!oneRel.relationName || !oneRel.reference) continue;
|
|
320
|
+
const oneRelFieldName = oneRel.reference.fieldName;
|
|
321
|
+
const matchingMany = manyRelations.find((manyRel) => manyRel.model === oneRel.model && manyRel.reference?.fieldName === oneRelFieldName);
|
|
322
|
+
if (matchingMany) matchingMany.relationName = oneRel.relationName;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const relationsByModel = /* @__PURE__ */ new Map();
|
|
326
|
+
for (const relation of oneRelations) {
|
|
327
|
+
if (!relation.reference) continue;
|
|
328
|
+
const modelKey = relation.key;
|
|
329
|
+
if (!relationsByModel.has(modelKey)) relationsByModel.set(modelKey, []);
|
|
330
|
+
relationsByModel.get(modelKey).push(relation);
|
|
331
|
+
}
|
|
332
|
+
const duplicateRelations = [];
|
|
333
|
+
const singleRelations = [];
|
|
334
|
+
for (const [_modelKey, rels] of relationsByModel.entries()) if (rels.length > 1) duplicateRelations.push(...rels);
|
|
335
|
+
else singleRelations.push(rels[0]);
|
|
336
|
+
for (const relation of duplicateRelations) {
|
|
337
|
+
if (!relation.reference) continue;
|
|
338
|
+
const fieldName = relation.reference.fieldName;
|
|
339
|
+
const relationExportName = `${modelName}${fieldName.charAt(0).toUpperCase() + fieldName.slice(1)}Relations`;
|
|
340
|
+
const relationNameParam = relation.relationName ? `,\n relationName: "${relation.relationName}"` : "";
|
|
341
|
+
const tableRelation = `export const ${relationExportName} = relations(${modelName}, ({ one }) => ({
|
|
342
|
+
${relation.key}: one(${relation.model}, {
|
|
343
|
+
fields: [${relation.reference.field}],
|
|
344
|
+
references: [${relation.reference.references}]${relationNameParam}
|
|
345
|
+
})
|
|
346
|
+
}))`;
|
|
347
|
+
relationsString += `\n${tableRelation}\n`;
|
|
348
|
+
}
|
|
349
|
+
const hasOne = singleRelations.length > 0;
|
|
350
|
+
const hasMany = manyRelations.length > 0;
|
|
351
|
+
if (hasOne && hasMany) {
|
|
352
|
+
const tableRelation = `export const ${modelName}Relations = relations(${modelName}, ({ one, many }) => ({
|
|
353
|
+
${singleRelations.map((relation) => {
|
|
354
|
+
if (!relation.reference) return "";
|
|
355
|
+
const relationNameParam = relation.relationName ? `,\n relationName: "${relation.relationName}"` : "";
|
|
356
|
+
return ` ${relation.key}: one(${relation.model}, {
|
|
357
|
+
fields: [${relation.reference.field}],
|
|
358
|
+
references: [${relation.reference.references}]${relationNameParam}
|
|
359
|
+
})`;
|
|
360
|
+
}).filter((x) => x !== "").join(",\n ")}${singleRelations.length > 0 && manyRelations.length > 0 ? "," : ""}
|
|
361
|
+
${manyRelations.map(({ key, model, relationName }) => {
|
|
362
|
+
return ` ${key}: many(${model}${relationName ? `, { relationName: "${relationName}" }` : ""})`;
|
|
363
|
+
}).join(",\n ")}
|
|
364
|
+
}))`;
|
|
365
|
+
relationsString += `\n${tableRelation}\n`;
|
|
366
|
+
} else if (hasOne) {
|
|
367
|
+
const tableRelation = `export const ${modelName}Relations = relations(${modelName}, ({ one }) => ({
|
|
368
|
+
${singleRelations.map((relation) => {
|
|
369
|
+
if (!relation.reference) return "";
|
|
370
|
+
const relationNameParam = relation.relationName ? `,\n relationName: "${relation.relationName}"` : "";
|
|
371
|
+
return ` ${relation.key}: one(${relation.model}, {
|
|
372
|
+
fields: [${relation.reference.field}],
|
|
373
|
+
references: [${relation.reference.references}]${relationNameParam}
|
|
374
|
+
})`;
|
|
375
|
+
}).filter((x) => x !== "").join(",\n ")}
|
|
376
|
+
}))`;
|
|
377
|
+
relationsString += `\n${tableRelation}\n`;
|
|
378
|
+
} else if (hasMany) {
|
|
379
|
+
const tableRelation = `export const ${modelName}Relations = relations(${modelName}, ({ many }) => ({
|
|
380
|
+
${manyRelations.map(({ key, model, relationName }) => {
|
|
381
|
+
return ` ${key}: many(${model}${relationName ? `, { relationName: "${relationName}" }` : ""})`;
|
|
382
|
+
}).join(",\n ")}
|
|
383
|
+
}))`;
|
|
384
|
+
relationsString += `\n${tableRelation}\n`;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
code += `\n${relationsString}`;
|
|
388
|
+
return {
|
|
389
|
+
code: await prettier.format(code, { parser: "typescript" }),
|
|
390
|
+
fileName: path.relative(projectRoot, resolvedSchemaPath),
|
|
391
|
+
overwrite: fileExist
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
function generateImport({ databaseType, tables }) {
|
|
395
|
+
const rootImports = ["relations"];
|
|
396
|
+
const coreImports = [];
|
|
397
|
+
let hasBigint = false;
|
|
398
|
+
let hasJson = false;
|
|
399
|
+
let hasUuid = false;
|
|
400
|
+
for (const table of Object.values(tables)) {
|
|
401
|
+
for (const field of Object.values(table.fields)) {
|
|
402
|
+
if (field.bigint) hasBigint = true;
|
|
403
|
+
if (field.type === "json") hasJson = true;
|
|
404
|
+
if (field.type === "uuid") hasUuid = true;
|
|
405
|
+
}
|
|
406
|
+
if (hasJson && hasBigint && hasUuid) break;
|
|
407
|
+
}
|
|
408
|
+
coreImports.push(`${databaseType}Table`);
|
|
409
|
+
coreImports.push(databaseType === "mysql" ? "varchar, text" : databaseType === "pg" ? "text" : "text");
|
|
410
|
+
coreImports.push(hasBigint ? databaseType !== "sqlite" ? "bigint" : "" : "");
|
|
411
|
+
coreImports.push(databaseType !== "sqlite" ? "timestamp, boolean" : "");
|
|
412
|
+
if (databaseType === "mysql") {
|
|
413
|
+
if (Object.values(tables).some((table) => Object.values(table.fields).some((field) => (field.type === "number" || field.type === "number[]") && !field.bigint))) coreImports.push("int");
|
|
414
|
+
if (Object.values(tables).some((table) => Object.values(table.fields).some((field) => typeof field.type !== "string" && Array.isArray(field.type) && field.type.every((x) => typeof x === "string")))) coreImports.push("mysqlEnum");
|
|
415
|
+
} else if (databaseType === "pg") {
|
|
416
|
+
if (Object.values(tables).some((table) => Object.values(table.fields).some((field) => (field.type === "number" || field.type === "number[]") && !field.bigint))) coreImports.push("integer");
|
|
417
|
+
if (hasUuid) coreImports.push("uuid");
|
|
418
|
+
} else coreImports.push("integer");
|
|
419
|
+
if (hasJson) {
|
|
420
|
+
if (databaseType === "pg") coreImports.push("jsonb");
|
|
421
|
+
if (databaseType === "mysql") coreImports.push("json");
|
|
422
|
+
}
|
|
423
|
+
if (databaseType === "sqlite" && Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.type === "date" && field.defaultValue && typeof field.defaultValue === "function" && field.defaultValue.toString().includes("new Date()")))) rootImports.push("sql");
|
|
424
|
+
const hasIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.index && !field.unique));
|
|
425
|
+
const hasUniqueIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.unique && field.index));
|
|
426
|
+
if (hasIndexes) coreImports.push("index");
|
|
427
|
+
if (hasUniqueIndexes) coreImports.push("uniqueIndex");
|
|
428
|
+
return `${rootImports.length > 0 ? `import { ${rootImports.join(", ")} } from "drizzle-orm";\n` : ""}import { ${coreImports.map((x) => x.trim()).filter((x) => x !== "").join(", ")} } from "drizzle-orm/${databaseType}-core";\n`;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/generators/kysely.ts
|
|
433
|
+
const generateKyselySchema = async ({ options, file, adapter }) => {
|
|
434
|
+
const { compileMigrations } = await getMigrations(options);
|
|
435
|
+
const migrations = await compileMigrations();
|
|
436
|
+
const migrationFile = file || `./better-auth_migrations/${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}.sql`;
|
|
437
|
+
return {
|
|
438
|
+
code: migrations.trim() === ";" ? "" : migrations,
|
|
439
|
+
fileName: migrationFile
|
|
440
|
+
};
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
//#endregion
|
|
444
|
+
//#region src/utils/get-package-info.ts
|
|
445
|
+
function getPackageInfo(cwd) {
|
|
446
|
+
const packageJsonPath = cwd ? path.join(cwd, "package.json") : path.join("package.json");
|
|
447
|
+
return JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
448
|
+
}
|
|
449
|
+
function getPrismaVersion(cwd) {
|
|
450
|
+
try {
|
|
451
|
+
const packageInfo = getPackageInfo(cwd);
|
|
452
|
+
const prismaVersion = packageInfo.dependencies?.prisma || packageInfo.devDependencies?.prisma || packageInfo.dependencies?.["@prisma/client"] || packageInfo.devDependencies?.["@prisma/client"];
|
|
453
|
+
if (!prismaVersion) return null;
|
|
454
|
+
const match = prismaVersion.match(/(\d+)/);
|
|
455
|
+
return match ? parseInt(match[1], 10) : null;
|
|
456
|
+
} catch {
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/generators/prisma.ts
|
|
463
|
+
const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
464
|
+
const provider = adapter.options?.provider || "postgresql";
|
|
465
|
+
const tables = getPaymentTables(options);
|
|
466
|
+
const filePath = file || "./prisma/schema.prisma";
|
|
467
|
+
const schemaPrismaExist = existsSync(path.join(process.cwd(), filePath));
|
|
468
|
+
const getModelName = initGetModelName({
|
|
469
|
+
schema: getPaymentTables(options),
|
|
470
|
+
usePlural: adapter.options?.adapterConfig?.usePlural
|
|
471
|
+
});
|
|
472
|
+
const getFieldName = initGetFieldName({
|
|
473
|
+
schema: getPaymentTables(options),
|
|
474
|
+
usePlural: false
|
|
475
|
+
});
|
|
476
|
+
let schemaPrisma = "";
|
|
477
|
+
if (schemaPrismaExist) schemaPrisma = await fs$1.readFile(path.join(process.cwd(), filePath), "utf-8");
|
|
478
|
+
else schemaPrisma = getNewPrisma(provider, process.cwd());
|
|
479
|
+
const prismaVersion = getPrismaVersion(process.cwd());
|
|
480
|
+
if (prismaVersion && prismaVersion >= 7 && schemaPrismaExist) schemaPrisma = produceSchema(schemaPrisma, (builder) => {
|
|
481
|
+
const generator = builder.findByType("generator", { name: "client" });
|
|
482
|
+
if (generator && generator.properties) {
|
|
483
|
+
const providerProp = generator.properties.find((prop) => prop.type === "assignment" && prop.key === "provider");
|
|
484
|
+
if (providerProp && providerProp.value === "\"prisma-client-js\"") providerProp.value = "\"prisma-client\"";
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
const manyToManyRelations = /* @__PURE__ */ new Map();
|
|
488
|
+
for (const table in tables) {
|
|
489
|
+
const fields = tables[table]?.fields;
|
|
490
|
+
for (const field in fields) {
|
|
491
|
+
const attr = fields[field];
|
|
492
|
+
if (attr.references) {
|
|
493
|
+
const referencedOriginalModel = attr.references.model;
|
|
494
|
+
const referencedModelNameCap = capitalizeFirstLetter(getModelName(tables[referencedOriginalModel]?.modelName || referencedOriginalModel));
|
|
495
|
+
if (!manyToManyRelations.has(referencedModelNameCap)) manyToManyRelations.set(referencedModelNameCap, /* @__PURE__ */ new Set());
|
|
496
|
+
const currentModelNameCap = capitalizeFirstLetter(getModelName(tables[table]?.modelName || table));
|
|
497
|
+
manyToManyRelations.get(referencedModelNameCap).add(currentModelNameCap);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
const indexedFields = /* @__PURE__ */ new Map();
|
|
502
|
+
for (const table in tables) {
|
|
503
|
+
const fields = tables[table]?.fields;
|
|
504
|
+
const modelName = capitalizeFirstLetter(getModelName(tables[table]?.modelName || table));
|
|
505
|
+
indexedFields.set(modelName, []);
|
|
506
|
+
for (const field in fields) {
|
|
507
|
+
const attr = fields[field];
|
|
508
|
+
if (attr.index && !attr.unique) {
|
|
509
|
+
const fieldName = attr.fieldName || field;
|
|
510
|
+
indexedFields.get(modelName).push(fieldName);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const schema = produceSchema(schemaPrisma, (builder) => {
|
|
515
|
+
for (const table in tables) {
|
|
516
|
+
const originalTableName = table;
|
|
517
|
+
const customModelName = tables[table]?.modelName || table;
|
|
518
|
+
const modelName = capitalizeFirstLetter(getModelName(customModelName));
|
|
519
|
+
const fields = tables[table]?.fields;
|
|
520
|
+
function getType({ isBigint, isOptional, type }) {
|
|
521
|
+
if (type === "string") return isOptional ? "String?" : "String";
|
|
522
|
+
if (type === "number" && isBigint) return isOptional ? "BigInt?" : "BigInt";
|
|
523
|
+
if (type === "number") return isOptional ? "Int?" : "Int";
|
|
524
|
+
if (type === "boolean") return isOptional ? "Boolean?" : "Boolean";
|
|
525
|
+
if (type === "date") return isOptional ? "DateTime?" : "DateTime";
|
|
526
|
+
if (type === "json") {
|
|
527
|
+
if (provider === "sqlite" || provider === "mysql") return isOptional ? "String?" : "String";
|
|
528
|
+
return isOptional ? "Json?" : "Json";
|
|
529
|
+
}
|
|
530
|
+
if (type === "string[]") {
|
|
531
|
+
if (provider === "sqlite" || provider === "mysql") return isOptional ? "String?" : "String";
|
|
532
|
+
return "String[]";
|
|
533
|
+
}
|
|
534
|
+
if (type === "number[]") {
|
|
535
|
+
if (provider === "sqlite" || provider === "mysql") return "String";
|
|
536
|
+
return "Int[]";
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const prismaModel = builder.findByType("model", { name: modelName });
|
|
540
|
+
if (!prismaModel) builder.model(modelName).field("id", "String").attribute("id");
|
|
541
|
+
for (const field in fields) {
|
|
542
|
+
const attr = fields[field];
|
|
543
|
+
const fieldName = attr.fieldName || field;
|
|
544
|
+
if (prismaModel) {
|
|
545
|
+
if (builder.findByType("field", {
|
|
546
|
+
name: fieldName,
|
|
547
|
+
within: prismaModel.properties
|
|
548
|
+
})) continue;
|
|
549
|
+
}
|
|
550
|
+
const fieldBuilder = builder.model(modelName).field(fieldName, getType({
|
|
551
|
+
isBigint: attr?.bigint || false,
|
|
552
|
+
isOptional: !attr?.required,
|
|
553
|
+
type: "string"
|
|
554
|
+
}));
|
|
555
|
+
if (field === "id") fieldBuilder.attribute("id");
|
|
556
|
+
if (attr.unique) builder.model(modelName).blockAttribute(`unique([${fieldName}])`);
|
|
557
|
+
if (attr.defaultValue !== void 0) {
|
|
558
|
+
if (Array.isArray(attr.defaultValue)) {
|
|
559
|
+
if (attr.type === "json") {
|
|
560
|
+
if (Object.prototype.toString.call(attr.defaultValue[0]) === "[object Object]") {
|
|
561
|
+
fieldBuilder.attribute(`default("${JSON.stringify(attr.defaultValue).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
let jsonArray = [];
|
|
565
|
+
for (const value of attr.defaultValue) jsonArray.push(value);
|
|
566
|
+
fieldBuilder.attribute(`default("${JSON.stringify(jsonArray).replace(/"/g, "\\\"")}")`);
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
if (attr.defaultValue.length === 0) {
|
|
570
|
+
fieldBuilder.attribute(`default([])`);
|
|
571
|
+
continue;
|
|
572
|
+
} else if (typeof attr.defaultValue[0] === "string" && attr.type === "string[]") {
|
|
573
|
+
let valueArray = [];
|
|
574
|
+
for (const value of attr.defaultValue) valueArray.push(JSON.stringify(value));
|
|
575
|
+
fieldBuilder.attribute(`default([${valueArray}])`);
|
|
576
|
+
} else if (typeof attr.defaultValue[0] === "number") {
|
|
577
|
+
let valueArray = [];
|
|
578
|
+
for (const value of attr.defaultValue) valueArray.push(`${value}`);
|
|
579
|
+
fieldBuilder.attribute(`default([${valueArray}])`);
|
|
580
|
+
}
|
|
581
|
+
} else if (typeof attr.defaultValue === "object" && !Array.isArray(attr.defaultValue) && attr.defaultValue !== null) {
|
|
582
|
+
if (Object.entries(attr.defaultValue).length === 0) {
|
|
583
|
+
fieldBuilder.attribute(`default("{}")`);
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
fieldBuilder.attribute(`default("${JSON.stringify(attr.defaultValue).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`);
|
|
587
|
+
}
|
|
588
|
+
if (field === "createdAt") fieldBuilder.attribute("default(now())");
|
|
589
|
+
else if (typeof attr.defaultValue === "string" && provider !== "mysql") fieldBuilder.attribute(`default("${attr.defaultValue}")`);
|
|
590
|
+
else if (typeof attr.defaultValue === "boolean" || typeof attr.defaultValue === "number") fieldBuilder.attribute(`default(${attr.defaultValue})`);
|
|
591
|
+
else if (typeof attr.defaultValue === "function") {}
|
|
592
|
+
}
|
|
593
|
+
if (field === "updatedAt" && attr.onUpdate) fieldBuilder.attribute("updatedAt");
|
|
594
|
+
else if (attr.onUpdate) {}
|
|
595
|
+
if (attr.references) {
|
|
596
|
+
const referencedOriginalModelName = getModelName(attr.references.model);
|
|
597
|
+
const referencedCustomModelName = tables[referencedOriginalModelName]?.modelName || referencedOriginalModelName;
|
|
598
|
+
let action = "NoAction";
|
|
599
|
+
if (attr.references.onDelete === "cascade") action = "Cascade";
|
|
600
|
+
else if (attr.references.onDelete === "no action") action = "NoAction";
|
|
601
|
+
else if (attr.references.onDelete === "set null") action = "SetNull";
|
|
602
|
+
else if (attr.references.onDelete === "set default") action = "SetDefault";
|
|
603
|
+
else if (attr.references.onDelete === "restrict") action = "Restrict";
|
|
604
|
+
const relationField = `relation(fields: [${getFieldName({
|
|
605
|
+
model: originalTableName,
|
|
606
|
+
field: fieldName
|
|
607
|
+
})}], references: [${getFieldName({
|
|
608
|
+
model: attr.references.model,
|
|
609
|
+
field: attr.references.field
|
|
610
|
+
})}], onDelete: ${action})`;
|
|
611
|
+
builder.model(modelName).field(referencedCustomModelName.toLowerCase(), `${capitalizeFirstLetter(referencedCustomModelName)}${!attr.required ? "?" : ""}`).attribute(relationField);
|
|
612
|
+
}
|
|
613
|
+
if (!attr.unique && !attr.references && provider === "mysql" && attr.type === "string") builder.model(modelName).field(fieldName).attribute("db.Text");
|
|
614
|
+
}
|
|
615
|
+
if (manyToManyRelations.has(modelName)) for (const relatedModel of manyToManyRelations.get(modelName)) {
|
|
616
|
+
const relatedTableName = Object.keys(tables).find((key) => capitalizeFirstLetter(tables[key]?.modelName || key) === relatedModel);
|
|
617
|
+
const relatedFields = relatedTableName ? tables[relatedTableName]?.fields : {};
|
|
618
|
+
const [_fieldKey, fkFieldAttr] = Object.entries(relatedFields || {}).find(([_fieldName, fieldAttr]) => fieldAttr.references && getModelName(fieldAttr.references.model) === getModelName(originalTableName)) || [];
|
|
619
|
+
const isUnique = fkFieldAttr?.unique === true;
|
|
620
|
+
const fieldName = isUnique || adapter.options?.usePlural === true ? `${relatedModel.toLowerCase()}` : `${relatedModel.toLowerCase()}s`;
|
|
621
|
+
if (!builder.findByType("field", {
|
|
622
|
+
name: fieldName,
|
|
623
|
+
within: prismaModel?.properties
|
|
624
|
+
})) builder.model(modelName).field(fieldName, `${relatedModel}${isUnique ? "?" : "[]"}`);
|
|
625
|
+
}
|
|
626
|
+
const indexedFieldsForModel = indexedFields.get(modelName);
|
|
627
|
+
if (indexedFieldsForModel && indexedFieldsForModel.length > 0) for (const fieldName of indexedFieldsForModel) {
|
|
628
|
+
if (prismaModel) {
|
|
629
|
+
if (prismaModel.properties.some((v) => v.type === "attribute" && v.name === "index" && JSON.stringify(v.args[0]?.value).includes(fieldName))) continue;
|
|
630
|
+
}
|
|
631
|
+
const field = Object.entries(fields).find(([key, attr]) => (attr.fieldName || key) === fieldName)?.[1];
|
|
632
|
+
let indexField = fieldName;
|
|
633
|
+
if (provider === "mysql" && field && field.type === "string") indexField = `${fieldName}(length: 191)`;
|
|
634
|
+
builder.model(modelName).blockAttribute(`index([${indexField}])`);
|
|
635
|
+
}
|
|
636
|
+
const hasAttribute = builder.findByType("attribute", {
|
|
637
|
+
name: "map",
|
|
638
|
+
within: prismaModel?.properties
|
|
639
|
+
});
|
|
640
|
+
const hasChanged = customModelName !== originalTableName;
|
|
641
|
+
if (!hasAttribute) builder.model(modelName).blockAttribute("map", `${getModelName(hasChanged ? customModelName : originalTableName)}`);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
const schemaChanged = schema.trim() !== schemaPrisma.trim();
|
|
645
|
+
return {
|
|
646
|
+
code: schemaChanged ? schema : "",
|
|
647
|
+
fileName: filePath,
|
|
648
|
+
overwrite: schemaPrismaExist && schemaChanged
|
|
649
|
+
};
|
|
650
|
+
};
|
|
651
|
+
const getNewPrisma = (provider, cwd) => {
|
|
652
|
+
const prismaVersion = getPrismaVersion(cwd);
|
|
653
|
+
return `generator client {
|
|
654
|
+
provider = "${prismaVersion && prismaVersion >= 7 ? "prisma-client" : "prisma-client-js"}"
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
datasource db {
|
|
658
|
+
provider = "${provider}"
|
|
659
|
+
url = ${provider === "sqlite" ? `"file:./dev.db"` : `env("DATABASE_URL")`}
|
|
660
|
+
}`;
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
//#endregion
|
|
664
|
+
//#region src/generators/mongodb.ts
|
|
665
|
+
const generateMongoDBSchema = async ({ options, file, adapter }) => {
|
|
666
|
+
const tables = getPaymentTables(options);
|
|
667
|
+
const filePath = file || "./mongodb-schema.ts";
|
|
668
|
+
initGetModelName({
|
|
669
|
+
schema: tables,
|
|
670
|
+
usePlural: adapter?.options?.adapterConfig?.usePlural
|
|
671
|
+
});
|
|
672
|
+
initGetFieldName({
|
|
673
|
+
schema: tables,
|
|
674
|
+
usePlural: false
|
|
675
|
+
});
|
|
676
|
+
return {
|
|
677
|
+
code: await prettier.format(`// MongoDB schema setup
|
|
678
|
+
// Generated from schema definitions
|
|
679
|
+
// DO NOT EDIT MANUALLY - This file is auto-generated
|
|
680
|
+
|
|
681
|
+
// Schema definitions for MongoDB collections
|
|
682
|
+
// Use this file to set up your MongoDB collections and indexes
|
|
683
|
+
`, { parser: "typescript" }),
|
|
684
|
+
fileName: filePath,
|
|
685
|
+
overwrite: true
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
//#endregion
|
|
690
|
+
//#region src/generators/index.ts
|
|
691
|
+
const adapters = {
|
|
692
|
+
prisma: generatePrismaSchema,
|
|
693
|
+
drizzle: generateDrizzleSchema,
|
|
694
|
+
kysely: generateKyselySchema,
|
|
695
|
+
mongodb: generateMongoDBSchema
|
|
696
|
+
};
|
|
697
|
+
const generateSchema = async (opts) => {
|
|
698
|
+
const adapter = opts.adapter;
|
|
699
|
+
const generator = adapter.id in adapters ? adapters[adapter.id] : null;
|
|
700
|
+
if (generator) return generator(opts);
|
|
701
|
+
if (adapter.createSchema) return adapter.createSchema(opts.options, opts.file).then(({ code, path: fileName, overwrite }) => ({
|
|
702
|
+
code,
|
|
703
|
+
fileName,
|
|
704
|
+
overwrite
|
|
705
|
+
}));
|
|
706
|
+
throw new Error(`${adapter.id} is not supported. If it is a custom adapter, please request the maintainer to implement createSchema`);
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
//#endregion
|
|
710
|
+
export { generateKyselySchema as a, getPackageInfo as i, generateSchema as n, generateDrizzleSchema as o, generatePrismaSchema as r, adapters as t };
|