@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.
- package/README.md +58 -0
- package/package.json +42 -0
- package/src/generate.ts +65 -0
- package/src/generators/generate-args.ts +322 -0
- package/src/generators/generate-client.ts +186 -0
- package/src/generators/generate-delegates.ts +213 -0
- package/src/generators/generate-enums.ts +28 -0
- package/src/generators/generate-inputs.ts +626 -0
- package/src/generators/generate-models.ts +103 -0
- package/src/generators/generate-result.ts +163 -0
- package/src/generators/generate-schemas.ts +474 -0
- package/src/index.ts +2 -0
- package/src/utils.ts +51 -0
|
@@ -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
|
+
}
|