@vibeorm/generator 1.0.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.
@@ -0,0 +1,213 @@
1
+ import type { Model, Schema, ScalarField, EnumField } from "@vibeorm/parser";
2
+ import { fileHeader, toCamelCase } from "../utils.ts";
3
+
4
+ const NUMERIC_PRISMA_TYPES = new Set(["Int", "Float", "Decimal", "BigInt"]);
5
+
6
+ /**
7
+ * Generates delegate interfaces for each model.
8
+ * These are the user-facing APIs: db.user.findMany(), db.post.create(), etc.
9
+ *
10
+ * Each method uses a generic parameter to capture the exact literal type
11
+ * of the args object, enabling TypeScript to narrow the return type
12
+ * through the GetFindResult conditional type.
13
+ */
14
+ export function generateDelegates(params: { schema: Schema }): string {
15
+ const { schema } = params;
16
+ const parts: string[] = [fileHeader()];
17
+
18
+ // Imports
19
+ const argsImports = schema.models
20
+ .flatMap((m) => [
21
+ `${m.name}FindManyArgs`,
22
+ `${m.name}FindFirstArgs`,
23
+ `${m.name}FindUniqueArgs`,
24
+ `${m.name}CreateArgs`,
25
+ `${m.name}CreateManyArgs`,
26
+ `${m.name}CreateManyAndReturnArgs`,
27
+ `${m.name}UpdateArgs`,
28
+ `${m.name}UpsertArgs`,
29
+ `${m.name}DeleteArgs`,
30
+ `${m.name}DeleteManyArgs`,
31
+ `${m.name}UpdateManyArgs`,
32
+ `${m.name}CountArgs`,
33
+ `${m.name}AggregateArgs`,
34
+ `${m.name}GroupByArgs`,
35
+ ])
36
+ .join(", ");
37
+ parts.push(`import type { ${argsImports} } from "./args.ts";`);
38
+
39
+ const payloadImports = schema.models
40
+ .map((m) => `$${m.name}Payload`)
41
+ .join(", ");
42
+ parts.push(`import type { ${payloadImports} } from "./models.ts";`);
43
+
44
+ parts.push(`import type { GetResult } from "./result.ts";`);
45
+
46
+ // Import enums if any models have enum fields
47
+ if (schema.enums.length > 0) {
48
+ const enumImports = schema.enums.map((e) => e.name).join(", ");
49
+ parts.push(`import type { ${enumImports} } from "./enums.ts";`);
50
+ }
51
+ parts.push("");
52
+
53
+ // Generate delegate for each model
54
+ for (const model of schema.models) {
55
+ parts.push(generateModelDelegate({ model }));
56
+ parts.push(generateAggregateResultType({ model }));
57
+ parts.push(generateGroupByResultType({ model }));
58
+ }
59
+
60
+ return parts.join("\n");
61
+ }
62
+
63
+ function generateModelDelegate(params: { model: Model }): string {
64
+ const { model } = params;
65
+ const p = `$${model.name}Payload`;
66
+
67
+ return `export type ${model.name}Delegate = {
68
+ findMany<T extends ${model.name}FindManyArgs>(
69
+ args?: T,
70
+ ): Promise<GetResult<${p}, T, "findMany">>;
71
+
72
+ findFirst<T extends ${model.name}FindFirstArgs>(
73
+ args?: T,
74
+ ): Promise<GetResult<${p}, T, "findFirst">>;
75
+
76
+ findUnique<T extends ${model.name}FindUniqueArgs>(
77
+ args: T,
78
+ ): Promise<GetResult<${p}, T, "findUnique">>;
79
+
80
+ findUniqueOrThrow<T extends ${model.name}FindUniqueArgs>(
81
+ args: T,
82
+ ): Promise<GetResult<${p}, T, "findUniqueOrThrow">>;
83
+
84
+ findFirstOrThrow<T extends ${model.name}FindFirstArgs>(
85
+ args?: T,
86
+ ): Promise<GetResult<${p}, T, "findFirstOrThrow">>;
87
+
88
+ create<T extends ${model.name}CreateArgs>(
89
+ args: T,
90
+ ): Promise<GetResult<${p}, T, "create">>;
91
+
92
+ createMany(
93
+ args: ${model.name}CreateManyArgs,
94
+ ): Promise<{ count: number }>;
95
+
96
+ createManyAndReturn<T extends ${model.name}CreateManyAndReturnArgs>(
97
+ args: T,
98
+ ): Promise<GetResult<${p}, T, "createManyAndReturn">>;
99
+
100
+ update<T extends ${model.name}UpdateArgs>(
101
+ args: T,
102
+ ): Promise<GetResult<${p}, T, "update">>;
103
+
104
+ upsert<T extends ${model.name}UpsertArgs>(
105
+ args: T,
106
+ ): Promise<GetResult<${p}, T, "upsert">>;
107
+
108
+ delete<T extends ${model.name}DeleteArgs>(
109
+ args: T,
110
+ ): Promise<GetResult<${p}, T, "delete">>;
111
+
112
+ deleteMany(
113
+ args?: ${model.name}DeleteManyArgs,
114
+ ): Promise<{ count: number }>;
115
+
116
+ updateMany(
117
+ args: ${model.name}UpdateManyArgs,
118
+ ): Promise<{ count: number }>;
119
+
120
+ count(
121
+ args?: ${model.name}CountArgs,
122
+ ): Promise<number>;
123
+
124
+ aggregate(
125
+ args: ${model.name}AggregateArgs,
126
+ ): Promise<Aggregate${model.name}Result>;
127
+
128
+ groupBy(
129
+ args: ${model.name}GroupByArgs,
130
+ ): Promise<${model.name}GroupByResult[]>;
131
+ };
132
+ `;
133
+ }
134
+
135
+ function generateAggregateResultType(params: { model: Model }): string {
136
+ const { model } = params;
137
+
138
+ const scalarFields = model.fields.filter(
139
+ (f): f is ScalarField => f.kind === "scalar"
140
+ );
141
+ const numericFields = scalarFields.filter(
142
+ (f) => NUMERIC_PRISMA_TYPES.has(f.prismaType)
143
+ );
144
+
145
+ const countFields = [
146
+ ` _all: number;`,
147
+ ...scalarFields.map((f) => ` ${f.name}: number;`),
148
+ ];
149
+
150
+ const avgFields = numericFields.map((f) => ` ${f.name}: number | null;`);
151
+ const sumFields = numericFields.map((f) => ` ${f.name}: number | null;`);
152
+ const minFields = scalarFields.map((f) => {
153
+ const tsType = f.tsType;
154
+ return ` ${f.name}: ${tsType} | null;`;
155
+ });
156
+ const maxFields = scalarFields.map((f) => {
157
+ const tsType = f.tsType;
158
+ return ` ${f.name}: ${tsType} | null;`;
159
+ });
160
+
161
+ return `export type Aggregate${model.name}Result = {
162
+ _count: number | {
163
+ ${countFields.join("\n")}
164
+ };
165
+ _avg: {
166
+ ${avgFields.length > 0 ? avgFields.join("\n") : " [key: string]: never;"}
167
+ } | null;
168
+ _sum: {
169
+ ${sumFields.length > 0 ? sumFields.join("\n") : " [key: string]: never;"}
170
+ } | null;
171
+ _min: {
172
+ ${minFields.join("\n")}
173
+ } | null;
174
+ _max: {
175
+ ${maxFields.join("\n")}
176
+ } | null;
177
+ };
178
+ `;
179
+ }
180
+
181
+ function generateGroupByResultType(params: { model: Model }): string {
182
+ const { model } = params;
183
+
184
+ const scalarFields = model.fields.filter(
185
+ (f): f is ScalarField => f.kind === "scalar"
186
+ );
187
+
188
+ // GroupBy result is a partial of scalars + aggregate fields
189
+ const scalarEntries = scalarFields.map((f) => {
190
+ const tsType = f.tsType;
191
+ const nullable = f.isRequired ? "" : " | null";
192
+ return ` ${f.name}?: ${tsType}${nullable};`;
193
+ });
194
+
195
+ // Also include enum fields
196
+ const enumEntries = model.fields
197
+ .filter((f) => f.kind === "enum")
198
+ .map((f) => {
199
+ if (f.kind !== "enum") return "";
200
+ const nullable = f.isRequired ? "" : " | null";
201
+ return ` ${f.name}?: ${f.enumName}${nullable};`;
202
+ });
203
+
204
+ return `export type ${model.name}GroupByResult = {
205
+ ${[...scalarEntries, ...enumEntries].join("\n")}
206
+ _count?: number | Record<string, number>;
207
+ _avg?: Record<string, number | null>;
208
+ _sum?: Record<string, number | null>;
209
+ _min?: Record<string, unknown>;
210
+ _max?: Record<string, unknown>;
211
+ };
212
+ `;
213
+ }
@@ -0,0 +1,28 @@
1
+ import type { Enum } from "@vibeorm/parser";
2
+ import { fileHeader } from "../utils.ts";
3
+
4
+ export function generateEnums(params: { enums: Enum[] }): string {
5
+ const { enums } = params;
6
+
7
+ if (enums.length === 0) {
8
+ return fileHeader() + "\nexport {};\n";
9
+ }
10
+
11
+ const parts: string[] = [fileHeader()];
12
+
13
+ for (const enumDef of enums) {
14
+ // Generate a const object (not a TS enum — objects are more flexible)
15
+ const values = enumDef.values
16
+ .map((v) => ` ${v.name}: "${v.name}" as const`)
17
+ .join(",\n");
18
+
19
+ parts.push(`export const ${enumDef.name} = {
20
+ ${values},
21
+ } as const;
22
+
23
+ export type ${enumDef.name} = (typeof ${enumDef.name})[keyof typeof ${enumDef.name}];
24
+ `);
25
+ }
26
+
27
+ return parts.join("\n");
28
+ }