@vibeorm/generator 1.3.1 → 2.0.0-alpha.10

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.
@@ -1,252 +0,0 @@
1
- import type { Model, Schema } from "@vibeorm/parser";
2
- import { fileHeader, toCamelCase } from "../utils.ts";
3
-
4
- /**
5
- * Generates the main index.ts file that:
6
- * - Re-exports all types
7
- * - Creates the VibeClient class that wires delegates to the runtime
8
- */
9
- export function generateClient(params: { schema: Schema }): string {
10
- const { schema } = params;
11
- const parts: string[] = [fileHeader()];
12
-
13
- // Re-exports
14
- parts.push(`export * from "./enums.ts";`);
15
- parts.push(`export * from "./models.ts";`);
16
- parts.push(`export * from "./inputs.ts";`);
17
- parts.push(`export * from "./args.ts";`);
18
- parts.push(`export * from "./result.ts";`);
19
- parts.push(`export * from "./delegates.ts";`);
20
- parts.push(`export * from "./schemas.ts";`);
21
- parts.push(`export * from "./view-types.ts";`);
22
- parts.push(``);
23
-
24
- // Import delegate types
25
- const delegateImports = schema.models
26
- .map((m) => `${m.name}Delegate`)
27
- .join(", ");
28
- parts.push(`import type { ${delegateImports} } from "./delegates.ts";`);
29
-
30
- // Import view types
31
- parts.push(`import type { ViewDefinitionInput, ViewClient } from "./view-types.ts";`);
32
-
33
- // Import runtime
34
- parts.push(`import { createClient } from "@vibeorm/runtime";`);
35
- parts.push(`import type { VibeClientOptions, TransactionOptions } from "@vibeorm/runtime";`);
36
- parts.push(``);
37
-
38
- // Import schemas for validation wiring
39
- const schemaImports = schema.models.flatMap((m) => [
40
- `${m.name}Schema`,
41
- `${m.name}CreateInputSchema`,
42
- `${m.name}UpdateInputSchema`,
43
- `${m.name}WhereInputSchema`,
44
- ]);
45
- parts.push(`import { ${schemaImports.join(", ")} } from "./schemas.ts";`);
46
- parts.push(``);
47
-
48
- // Generate the model metadata object that the runtime needs
49
- parts.push(generateModelMeta({ schema }));
50
-
51
- // Generate the schemas map for validation wiring
52
- parts.push(generateSchemasMap({ schema }));
53
-
54
- // Generate the VibeClient type (intersection of all delegates)
55
- const clientProperties = schema.models
56
- .map((m) => generateClientProperty({ model: m }))
57
- .join("\n");
58
-
59
- parts.push(`export type VibeClientInstance = {
60
- ${clientProperties}
61
- $transaction<T>(fn: (tx: VibeClientInstance) => Promise<T>, options?: TransactionOptions): Promise<T>;
62
- $transaction(promises: Promise<unknown>[], options?: TransactionOptions): Promise<unknown[]>;
63
- $queryRaw<T = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Promise<T[]>;
64
- $executeRaw(strings: TemplateStringsArray, ...values: unknown[]): Promise<number>;
65
- $queryRawUnsafe<T = unknown>(query: string, ...values: unknown[]): Promise<T[]>;
66
- $executeRawUnsafe(query: string, ...values: unknown[]): Promise<number>;
67
- $connect(): Promise<void>;
68
- $disconnect(): Promise<void>;
69
-
70
- /**
71
- * Create a read-only view that restricts which fields are returned per model.
72
- *
73
- * @example
74
- * const publicApi = db.defineView({
75
- * name: "public-api",
76
- * definition: {
77
- * user: { id: true, name: true, createdAt: true },
78
- * post: { id: true, title: true },
79
- * },
80
- * });
81
- *
82
- * // Only returns { id, name, createdAt }
83
- * const users = await publicApi.user.findMany();
84
- *
85
- * // Reveal extra fields (accessible but excluded from JSON.stringify)
86
- * const user = await publicApi.user.findUniqueOrThrow({
87
- * where: { id: 1 },
88
- * reveal: { email: true },
89
- * });
90
- * user.email; // accessible
91
- * JSON.stringify(user); // { id, name, createdAt } — email excluded
92
- * user.$unsafe(); // { id, name, createdAt, email } — escape hatch
93
- */
94
- defineView<D extends ViewDefinitionInput>(params: {
95
- name: string;
96
- definition: D;
97
- }): ViewClient<D>;
98
- };
99
- `);
100
-
101
- // Generate the VibeClient constructor function
102
- parts.push(`export function VibeClient(options: VibeClientOptions): VibeClientInstance {
103
- return createClient({
104
- options,
105
- modelMeta: MODEL_META,
106
- schemas: options.validate ? SCHEMAS : undefined,
107
- }) as unknown as VibeClientInstance;
108
- }
109
- `);
110
-
111
- return parts.join("\n");
112
- }
113
-
114
- function generateClientProperty(params: { model: Model }): string {
115
- const { model } = params;
116
- const modelVar = toCamelCase({ str: model.name });
117
-
118
- return ` /**
119
- * Operations for the ${model.name} model.
120
- *
121
- * @example
122
- * const rows = await db.${modelVar}.findMany();
123
- *
124
- * @example
125
- * const filteredRows = await db.${modelVar}.findMany({
126
- * where: {
127
- * // Add ${model.name}-specific filters here
128
- * },
129
- * });
130
- *
131
- * @example
132
- * const page = await db.${modelVar}.findMany({
133
- * where: {
134
- * // Add ${model.name}-specific filters here
135
- * },
136
- * orderBy: {
137
- * // e.g. createdAt: "desc"
138
- * },
139
- * take: 20,
140
- * skip: 0,
141
- * });
142
- */
143
- ${modelVar}: ${model.name}Delegate;`;
144
- }
145
-
146
- function generateModelMeta(params: { schema: Schema }): string {
147
- const { schema } = params;
148
-
149
- const modelEntries = schema.models.map((model) => {
150
- const scalarFields = model.fields
151
- .filter((f) => f.kind === "scalar" || f.kind === "enum")
152
- .map((f) => {
153
- const dbName = f.kind === "scalar" ? f.dbName : f.dbName;
154
- const isUpdatedAt = f.kind === "scalar" && f.isUpdatedAt;
155
- const extras: string[] = [];
156
- if (isUpdatedAt) extras.push(`isUpdatedAt: true`);
157
- if (f.kind === "scalar") extras.push(`type: "${f.prismaType}"`);
158
- if (f.isList) extras.push(`isList: true`);
159
-
160
- // Emit default kind for application-level generation (uuid, cuid, nanoid, ulid)
161
- if (f.default) {
162
- const appLevelDefaults = new Set(["uuid", "cuid", "nanoid", "ulid"]);
163
- if (appLevelDefaults.has(f.default.kind)) {
164
- extras.push(`hasDefault: "${f.default.kind}"`);
165
- } else if (f.default.kind !== "dbgenerated") {
166
- // autoincrement, now, literal — DB handles these, but runtime should know
167
- extras.push(`hasDefault: true`);
168
- }
169
- }
170
-
171
- // Extract @vibeorm.idPrefix from documentation comment
172
- const doc = (f.kind === "scalar" || f.kind === "enum") ? f.documentation : undefined;
173
- if (doc) {
174
- const prefixMatch = doc.match(/@vibeorm\.idPrefix\(["']([^"']+)["']\)/);
175
- if (prefixMatch) {
176
- extras.push(`idPrefix: "${prefixMatch[1]}"`);
177
- }
178
- }
179
-
180
- const extraStr = extras.length > 0 ? `, ${extras.join(", ")}` : "";
181
- return ` { name: "${f.name}", dbName: "${dbName}", kind: "${f.kind}" as const${extraStr} }`;
182
- });
183
-
184
- const relationFields = model.fields
185
- .filter((f) => f.kind === "relation")
186
- .map((f) => {
187
- if (f.kind !== "relation") return "";
188
- const isM2M = f.relation.type === "manyToMany";
189
- let joinTableLine = "";
190
- if (isM2M) {
191
- const sorted = [model.name, f.relatedModel].sort();
192
- const jtName = `_${sorted[0]}To${sorted[1]}`;
193
- joinTableLine = `\n joinTable: "${jtName}",`;
194
- }
195
- const relationNameLine = f.relation.name
196
- ? `\n relationName: "${f.relation.name}",`
197
- : "";
198
- return ` {
199
- name: "${f.name}",
200
- kind: "relation" as const,
201
- relatedModel: "${f.relatedModel}",
202
- type: "${f.relation.type}" as const,
203
- isList: ${f.isList},
204
- isForeignKey: ${f.relation.isForeignKey},
205
- fields: ${JSON.stringify(f.relation.fields)},
206
- references: ${JSON.stringify(f.relation.references)},${relationNameLine}${joinTableLine}
207
- }`;
208
- });
209
-
210
- const pkFields = JSON.stringify(model.primaryKey.fields);
211
- const uniqueFields = model.fields
212
- .filter((f) => (f.kind === "scalar" || f.kind === "enum") && f.isUnique)
213
- .map((f) => `"${f.name}"`);
214
-
215
- return ` ${toCamelCase({ str: model.name })}: {
216
- name: "${model.name}",
217
- dbName: "${model.dbName}",
218
- primaryKey: ${pkFields},
219
- uniqueFields: [${uniqueFields.join(", ")}],
220
- scalarFields: [
221
- ${scalarFields.join(",\n")}
222
- ],
223
- relationFields: [
224
- ${relationFields.join(",\n")}
225
- ],
226
- }`;
227
- });
228
-
229
- return `const MODEL_META = {
230
- ${modelEntries.join(",\n")}
231
- } as const;
232
- `;
233
- }
234
-
235
- function generateSchemasMap(params: { schema: Schema }): string {
236
- const { schema } = params;
237
-
238
- const entries = schema.models.map((model) => {
239
- const key = toCamelCase({ str: model.name });
240
- return ` ${key}: {
241
- model: ${model.name}Schema,
242
- createInput: ${model.name}CreateInputSchema,
243
- updateInput: ${model.name}UpdateInputSchema,
244
- whereInput: ${model.name}WhereInputSchema,
245
- }`;
246
- });
247
-
248
- return `const SCHEMAS = {
249
- ${entries.join(",\n")}
250
- };
251
- `;
252
- }