prisma-guard 1.23.0 → 1.25.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 +126 -39
- package/dist/generator/index.js +312 -257
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +766 -403
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +65 -25
- package/dist/runtime/index.d.ts +65 -25
- package/dist/runtime/index.js +766 -403
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/generator/index.js
CHANGED
|
@@ -2,8 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
// src/generator/index.ts
|
|
4
4
|
import pkg from "@prisma/generator-helper";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { relative } from "path";
|
|
7
|
+
|
|
8
|
+
// src/generator/emit-client.ts
|
|
9
|
+
function emitClient(_dmmf, prismaClientImport) {
|
|
10
|
+
return `import type { PrismaClient } from '${prismaClientImport}'
|
|
11
|
+
import type { GuardInput, GuardedModel } from 'prisma-guard'
|
|
12
|
+
import { createGuard } from 'prisma-guard'
|
|
13
|
+
import { SCOPE_MAP, TYPE_MAP, ENUM_MAP, ZOD_CHAINS, GUARD_CONFIG, UNIQUE_MAP, ZOD_DEFAULTS } from './index'
|
|
14
|
+
import type { ScopeRoot } from './index'
|
|
15
|
+
|
|
16
|
+
interface GuardModelExtension {
|
|
17
|
+
$allModels: {
|
|
18
|
+
guard<TDelegate>(this: TDelegate, input: GuardInput, caller?: string): GuardedModel<TDelegate>
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const guard = createGuard<typeof TYPE_MAP, ScopeRoot, GuardModelExtension>({
|
|
23
|
+
scopeMap: SCOPE_MAP,
|
|
24
|
+
typeMap: TYPE_MAP,
|
|
25
|
+
enumMap: ENUM_MAP,
|
|
26
|
+
zodChains: ZOD_CHAINS,
|
|
27
|
+
guardConfig: GUARD_CONFIG,
|
|
28
|
+
uniqueMap: UNIQUE_MAP,
|
|
29
|
+
zodDefaults: ZOD_DEFAULTS,
|
|
30
|
+
})
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
7
33
|
|
|
8
34
|
// src/generator/emit-scope-map.ts
|
|
9
35
|
function isScopeRoot(documentation) {
|
|
@@ -94,6 +120,212 @@ export type ScopeRoot = ${scopeRootType}
|
|
|
94
120
|
return { source };
|
|
95
121
|
}
|
|
96
122
|
|
|
123
|
+
// src/generator/emit-type-map.ts
|
|
124
|
+
function uniqueSelector(fields, name) {
|
|
125
|
+
if (typeof name === "string" && name.trim().length > 0)
|
|
126
|
+
return name;
|
|
127
|
+
return fields.join("_");
|
|
128
|
+
}
|
|
129
|
+
function collectUniqueConstraints(model) {
|
|
130
|
+
const fieldSetSeen = /* @__PURE__ */ new Set();
|
|
131
|
+
const selectorToFields = /* @__PURE__ */ new Map();
|
|
132
|
+
const constraints = [];
|
|
133
|
+
function fieldsKey(fields) {
|
|
134
|
+
return fields.join("\0");
|
|
135
|
+
}
|
|
136
|
+
function add(fields, selector) {
|
|
137
|
+
if (fields.length === 0)
|
|
138
|
+
return;
|
|
139
|
+
const normalizedSelector = fields.length === 1 ? fields[0] : uniqueSelector(fields, selector);
|
|
140
|
+
const key = fieldsKey(fields);
|
|
141
|
+
const existingFieldsForSelector = selectorToFields.get(normalizedSelector);
|
|
142
|
+
if (existingFieldsForSelector && existingFieldsForSelector !== key) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`prisma-guard: Unique selector "${normalizedSelector}" on model "${model.name}" maps to multiple field sets.`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (fieldSetSeen.has(key))
|
|
148
|
+
return;
|
|
149
|
+
fieldSetSeen.add(key);
|
|
150
|
+
selectorToFields.set(normalizedSelector, key);
|
|
151
|
+
constraints.push({
|
|
152
|
+
selector: normalizedSelector,
|
|
153
|
+
fields: [...fields]
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
for (const field of model.fields) {
|
|
157
|
+
if (field.isId)
|
|
158
|
+
add([field.name], field.name);
|
|
159
|
+
}
|
|
160
|
+
if (model.primaryKey) {
|
|
161
|
+
add([...model.primaryKey.fields], model.primaryKey.name);
|
|
162
|
+
}
|
|
163
|
+
for (const field of model.fields) {
|
|
164
|
+
if (field.isUnique)
|
|
165
|
+
add([field.name], field.name);
|
|
166
|
+
}
|
|
167
|
+
const uniqueIndexes = model.uniqueIndexes ?? [];
|
|
168
|
+
for (const index of uniqueIndexes) {
|
|
169
|
+
add([...index.fields], index.name);
|
|
170
|
+
}
|
|
171
|
+
for (const fields of model.uniqueFields) {
|
|
172
|
+
add([...fields], fields.length === 1 ? fields[0] : fields.join("_"));
|
|
173
|
+
}
|
|
174
|
+
return constraints;
|
|
175
|
+
}
|
|
176
|
+
function emitTypeMap(dmmf) {
|
|
177
|
+
const enumNames = new Set(dmmf.datamodel.enums.map((e) => e.name));
|
|
178
|
+
for (const e of dmmf.datamodel.enums) {
|
|
179
|
+
if (e.values.length === 0) {
|
|
180
|
+
throw new Error(`prisma-guard: Enum "${e.name}" has zero values.`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const modelEntries = dmmf.datamodel.models.map((model) => {
|
|
184
|
+
const fieldEntries = model.fields.map((field) => {
|
|
185
|
+
const isRelation = field.kind === "object" || field.relationName != null;
|
|
186
|
+
const isEnum = enumNames.has(field.type);
|
|
187
|
+
const isUnsupported = field.kind === "unsupported";
|
|
188
|
+
const meta = [
|
|
189
|
+
`type: ${JSON.stringify(field.type)}`,
|
|
190
|
+
`isList: ${field.isList}`,
|
|
191
|
+
`isRequired: ${field.isRequired}`,
|
|
192
|
+
`isId: ${field.isId}`,
|
|
193
|
+
`isRelation: ${isRelation}`,
|
|
194
|
+
`hasDefault: ${field.hasDefaultValue}`,
|
|
195
|
+
`isUpdatedAt: ${field.isUpdatedAt}`
|
|
196
|
+
];
|
|
197
|
+
if (isEnum)
|
|
198
|
+
meta.push(`isEnum: true`);
|
|
199
|
+
if (isUnsupported)
|
|
200
|
+
meta.push(`isUnsupported: true`);
|
|
201
|
+
if (field.isUnique)
|
|
202
|
+
meta.push(`isUnique: true`);
|
|
203
|
+
return ` ${JSON.stringify(field.name)}: { ${meta.join(", ")} },`;
|
|
204
|
+
}).join("\n");
|
|
205
|
+
return ` ${JSON.stringify(model.name)}: {
|
|
206
|
+
${fieldEntries}
|
|
207
|
+
},`;
|
|
208
|
+
}).join("\n");
|
|
209
|
+
const enumEntries = dmmf.datamodel.enums.map((e) => {
|
|
210
|
+
const values = e.values.map((v) => JSON.stringify(v.name)).join(", ");
|
|
211
|
+
return ` ${JSON.stringify(e.name)}: [${values}],`;
|
|
212
|
+
}).join("\n");
|
|
213
|
+
const uniqueMapEntries = dmmf.datamodel.models.map((model) => {
|
|
214
|
+
const constraints = collectUniqueConstraints(model);
|
|
215
|
+
if (constraints.length === 0)
|
|
216
|
+
return null;
|
|
217
|
+
const constraintsStr = constraints.map((c) => {
|
|
218
|
+
const fields = c.fields.map((f) => JSON.stringify(f)).join(", ");
|
|
219
|
+
return `{ selector: ${JSON.stringify(c.selector)}, fields: [${fields}] }`;
|
|
220
|
+
}).join(", ");
|
|
221
|
+
return ` ${JSON.stringify(model.name)}: [${constraintsStr}],`;
|
|
222
|
+
}).filter(Boolean).join("\n");
|
|
223
|
+
const typeMapSource = `export const TYPE_MAP = {
|
|
224
|
+
${modelEntries}
|
|
225
|
+
} as const
|
|
226
|
+
`;
|
|
227
|
+
const enumMapSource = `export const ENUM_MAP = {
|
|
228
|
+
${enumEntries}
|
|
229
|
+
} as const
|
|
230
|
+
`;
|
|
231
|
+
const uniqueMapSource = `export const UNIQUE_MAP = {
|
|
232
|
+
${uniqueMapEntries}
|
|
233
|
+
} as const
|
|
234
|
+
`;
|
|
235
|
+
const typesSource = [
|
|
236
|
+
`export type ModelName = keyof typeof TYPE_MAP`,
|
|
237
|
+
`export type FieldName<M extends ModelName> = keyof (typeof TYPE_MAP)[M]`
|
|
238
|
+
].join("\n");
|
|
239
|
+
return `${typeMapSource}
|
|
240
|
+
${enumMapSource}
|
|
241
|
+
${uniqueMapSource}
|
|
242
|
+
${typesSource}
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/shared/operation-shape-keys.ts
|
|
247
|
+
var OPERATION_SHAPE_KEYS = {
|
|
248
|
+
findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
249
|
+
findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
250
|
+
findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
251
|
+
findUnique: ["where", "include", "select"],
|
|
252
|
+
findUniqueOrThrow: ["where", "include", "select"],
|
|
253
|
+
findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
254
|
+
count: ["where", "select", "cursor", "orderBy", "skip", "take"],
|
|
255
|
+
aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
256
|
+
groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
|
|
257
|
+
create: ["data", "select", "include"],
|
|
258
|
+
createMany: ["data"],
|
|
259
|
+
createManyAndReturn: ["data", "select", "include"],
|
|
260
|
+
update: ["data", "where", "select", "include"],
|
|
261
|
+
updateMany: ["data", "where"],
|
|
262
|
+
updateManyAndReturn: ["data", "where", "select", "include"],
|
|
263
|
+
upsert: ["where", "create", "update", "select", "include"],
|
|
264
|
+
delete: ["where", "select", "include"],
|
|
265
|
+
deleteMany: ["where"]
|
|
266
|
+
};
|
|
267
|
+
var READ_METHOD_ALLOWED_ARGS = {
|
|
268
|
+
findMany: new Set(OPERATION_SHAPE_KEYS.findMany),
|
|
269
|
+
findFirst: new Set(OPERATION_SHAPE_KEYS.findFirst),
|
|
270
|
+
findFirstOrThrow: new Set(OPERATION_SHAPE_KEYS.findFirstOrThrow),
|
|
271
|
+
findUnique: new Set(OPERATION_SHAPE_KEYS.findUnique),
|
|
272
|
+
findUniqueOrThrow: new Set(OPERATION_SHAPE_KEYS.findUniqueOrThrow),
|
|
273
|
+
count: new Set(OPERATION_SHAPE_KEYS.count),
|
|
274
|
+
aggregate: new Set(OPERATION_SHAPE_KEYS.aggregate),
|
|
275
|
+
groupBy: new Set(OPERATION_SHAPE_KEYS.groupBy)
|
|
276
|
+
};
|
|
277
|
+
var MUTATION_SHAPE_KEYS = {
|
|
278
|
+
create: new Set(OPERATION_SHAPE_KEYS.create),
|
|
279
|
+
createMany: new Set(OPERATION_SHAPE_KEYS.createMany),
|
|
280
|
+
createManyAndReturn: new Set(OPERATION_SHAPE_KEYS.createManyAndReturn),
|
|
281
|
+
update: new Set(OPERATION_SHAPE_KEYS.update),
|
|
282
|
+
updateMany: new Set(OPERATION_SHAPE_KEYS.updateMany),
|
|
283
|
+
updateManyAndReturn: new Set(OPERATION_SHAPE_KEYS.updateManyAndReturn),
|
|
284
|
+
upsert: new Set(OPERATION_SHAPE_KEYS.upsert),
|
|
285
|
+
delete: new Set(OPERATION_SHAPE_KEYS.delete),
|
|
286
|
+
deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/generator/emit-typed-shapes.ts
|
|
290
|
+
var OPERATIONS = Object.keys(OPERATION_SHAPE_KEYS);
|
|
291
|
+
function cap(s) {
|
|
292
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
293
|
+
}
|
|
294
|
+
function emitTypedShapes(dmmf, depth) {
|
|
295
|
+
const header = `import type { TYPE_MAP, UNIQUE_MAP } from './index'
|
|
296
|
+
import type {
|
|
297
|
+
TypedGuardShape,
|
|
298
|
+
OperationShape,
|
|
299
|
+
ShapeInput,
|
|
300
|
+
TypedProjection,
|
|
301
|
+
TypedInclude,
|
|
302
|
+
TypedCountSelect,
|
|
303
|
+
} from 'prisma-guard'
|
|
304
|
+
|
|
305
|
+
type TM = typeof TYPE_MAP
|
|
306
|
+
type UM = typeof UNIQUE_MAP
|
|
307
|
+
|
|
308
|
+
`;
|
|
309
|
+
const blocks = dmmf.datamodel.models.map((model) => {
|
|
310
|
+
const m = model.name;
|
|
311
|
+
const projAlias = `export type ${m}Select = TypedProjection<TM, '${m}', ${depth}, UM>
|
|
312
|
+
export type ${m}Projection = ${m}Select
|
|
313
|
+
export type ${m}Include = TypedInclude<TM, '${m}', ${depth}, UM>
|
|
314
|
+
export type ${m}CountSelect = TypedCountSelect<TM, '${m}'>
|
|
315
|
+
`;
|
|
316
|
+
const guardAlias = `export type ${m}GuardShape = TypedGuardShape<TM, '${m}', ${depth}, UM>
|
|
317
|
+
`;
|
|
318
|
+
const opAliases = OPERATIONS.map((op) => {
|
|
319
|
+
const c = cap(op);
|
|
320
|
+
return `export type ${m}${c}Shape = OperationShape<TM, '${m}', '${op}', ${depth}, UM>
|
|
321
|
+
export type ${m}${c}ShapeInput<TCtx = unknown> = ShapeInput<${m}${c}Shape, TCtx>
|
|
322
|
+
`;
|
|
323
|
+
}).join("");
|
|
324
|
+
return projAlias + guardAlias + opAliases;
|
|
325
|
+
}).join("\n");
|
|
326
|
+
return header + blocks;
|
|
327
|
+
}
|
|
328
|
+
|
|
97
329
|
// src/generator/emit-zod-chains.ts
|
|
98
330
|
import { z as z2 } from "zod";
|
|
99
331
|
|
|
@@ -790,247 +1022,6 @@ ${entries}
|
|
|
790
1022
|
};
|
|
791
1023
|
}
|
|
792
1024
|
|
|
793
|
-
// src/generator/emit-type-map.ts
|
|
794
|
-
function collectUniqueConstraints(model) {
|
|
795
|
-
const seen = /* @__PURE__ */ new Set();
|
|
796
|
-
const constraints = [];
|
|
797
|
-
function add(fields) {
|
|
798
|
-
const key = fields.join("\0");
|
|
799
|
-
if (seen.has(key))
|
|
800
|
-
return;
|
|
801
|
-
seen.add(key);
|
|
802
|
-
constraints.push(fields);
|
|
803
|
-
}
|
|
804
|
-
for (const field of model.fields) {
|
|
805
|
-
if (field.isId)
|
|
806
|
-
add([field.name]);
|
|
807
|
-
}
|
|
808
|
-
if (model.primaryKey) {
|
|
809
|
-
add([...model.primaryKey.fields]);
|
|
810
|
-
}
|
|
811
|
-
for (const field of model.fields) {
|
|
812
|
-
if (field.isUnique)
|
|
813
|
-
add([field.name]);
|
|
814
|
-
}
|
|
815
|
-
for (const fields of model.uniqueFields) {
|
|
816
|
-
add([...fields]);
|
|
817
|
-
}
|
|
818
|
-
return constraints;
|
|
819
|
-
}
|
|
820
|
-
function emitTypeMap(dmmf) {
|
|
821
|
-
const enumNames = new Set(dmmf.datamodel.enums.map((e) => e.name));
|
|
822
|
-
for (const e of dmmf.datamodel.enums) {
|
|
823
|
-
if (e.values.length === 0) {
|
|
824
|
-
throw new Error(`prisma-guard: Enum "${e.name}" has zero values.`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
const modelEntries = dmmf.datamodel.models.map((model) => {
|
|
828
|
-
const fieldEntries = model.fields.map((field) => {
|
|
829
|
-
const isRelation = field.kind === "object" || field.relationName != null;
|
|
830
|
-
const isEnum = enumNames.has(field.type);
|
|
831
|
-
const isUnsupported = field.kind === "unsupported";
|
|
832
|
-
const meta = [
|
|
833
|
-
`type: ${JSON.stringify(field.type)}`,
|
|
834
|
-
`isList: ${field.isList}`,
|
|
835
|
-
`isRequired: ${field.isRequired}`,
|
|
836
|
-
`isId: ${field.isId}`,
|
|
837
|
-
`isRelation: ${isRelation}`,
|
|
838
|
-
`hasDefault: ${field.hasDefaultValue}`,
|
|
839
|
-
`isUpdatedAt: ${field.isUpdatedAt}`
|
|
840
|
-
];
|
|
841
|
-
if (isEnum)
|
|
842
|
-
meta.push(`isEnum: true`);
|
|
843
|
-
if (isUnsupported)
|
|
844
|
-
meta.push(`isUnsupported: true`);
|
|
845
|
-
if (field.isUnique)
|
|
846
|
-
meta.push(`isUnique: true`);
|
|
847
|
-
return ` ${JSON.stringify(field.name)}: { ${meta.join(", ")} },`;
|
|
848
|
-
}).join("\n");
|
|
849
|
-
return ` ${JSON.stringify(model.name)}: {
|
|
850
|
-
${fieldEntries}
|
|
851
|
-
},`;
|
|
852
|
-
}).join("\n");
|
|
853
|
-
const enumEntries = dmmf.datamodel.enums.map((e) => {
|
|
854
|
-
const values = e.values.map((v) => JSON.stringify(v.name)).join(", ");
|
|
855
|
-
return ` ${JSON.stringify(e.name)}: [${values}],`;
|
|
856
|
-
}).join("\n");
|
|
857
|
-
const uniqueMapEntries = dmmf.datamodel.models.map((model) => {
|
|
858
|
-
const constraints = collectUniqueConstraints(model);
|
|
859
|
-
if (constraints.length === 0)
|
|
860
|
-
return null;
|
|
861
|
-
const constraintsStr = constraints.map((c) => `[${c.map((f) => JSON.stringify(f)).join(", ")}]`).join(", ");
|
|
862
|
-
return ` ${JSON.stringify(model.name)}: [${constraintsStr}],`;
|
|
863
|
-
}).filter(Boolean).join("\n");
|
|
864
|
-
const typeMapSource = `export const TYPE_MAP = {
|
|
865
|
-
${modelEntries}
|
|
866
|
-
} as const
|
|
867
|
-
`;
|
|
868
|
-
const enumMapSource = `export const ENUM_MAP = {
|
|
869
|
-
${enumEntries}
|
|
870
|
-
} as const
|
|
871
|
-
`;
|
|
872
|
-
const uniqueMapSource = `export const UNIQUE_MAP = {
|
|
873
|
-
${uniqueMapEntries}
|
|
874
|
-
} as const
|
|
875
|
-
`;
|
|
876
|
-
const typesSource = [
|
|
877
|
-
`export type ModelName = keyof typeof TYPE_MAP`,
|
|
878
|
-
`export type FieldName<M extends ModelName> = keyof (typeof TYPE_MAP)[M]`
|
|
879
|
-
].join("\n");
|
|
880
|
-
return `${typeMapSource}
|
|
881
|
-
${enumMapSource}
|
|
882
|
-
${uniqueMapSource}
|
|
883
|
-
${typesSource}
|
|
884
|
-
`;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
// src/shared/constants.ts
|
|
888
|
-
var SHAPE_CONFIG_KEY_LIST = [
|
|
889
|
-
"where",
|
|
890
|
-
"include",
|
|
891
|
-
"select",
|
|
892
|
-
"orderBy",
|
|
893
|
-
"cursor",
|
|
894
|
-
"take",
|
|
895
|
-
"skip",
|
|
896
|
-
"distinct",
|
|
897
|
-
"having",
|
|
898
|
-
"_count",
|
|
899
|
-
"_avg",
|
|
900
|
-
"_sum",
|
|
901
|
-
"_min",
|
|
902
|
-
"_max",
|
|
903
|
-
"by"
|
|
904
|
-
];
|
|
905
|
-
var SHAPE_CONFIG_KEYS = new Set(SHAPE_CONFIG_KEY_LIST);
|
|
906
|
-
var GUARD_SHAPE_KEY_LIST = [
|
|
907
|
-
"data",
|
|
908
|
-
"create",
|
|
909
|
-
"update",
|
|
910
|
-
...SHAPE_CONFIG_KEY_LIST
|
|
911
|
-
];
|
|
912
|
-
var GUARD_SHAPE_KEYS = new Set(GUARD_SHAPE_KEY_LIST);
|
|
913
|
-
var TO_MANY_RELATION_OPS = /* @__PURE__ */ new Set(["some", "every", "none"]);
|
|
914
|
-
var TO_ONE_RELATION_OPS = /* @__PURE__ */ new Set(["is", "isNot"]);
|
|
915
|
-
var ALL_RELATION_OPS = /* @__PURE__ */ new Set([...TO_MANY_RELATION_OPS, ...TO_ONE_RELATION_OPS]);
|
|
916
|
-
function toDelegateKey(modelName) {
|
|
917
|
-
return modelName[0].toLowerCase() + modelName.slice(1);
|
|
918
|
-
}
|
|
919
|
-
var FORCED_MARKER = Symbol.for("prisma-guard.forced");
|
|
920
|
-
var UNSUPPORTED_MARKER = Symbol.for("prisma-guard.unsupported");
|
|
921
|
-
|
|
922
|
-
// src/generator/emit-client.ts
|
|
923
|
-
function emitClient(dmmf) {
|
|
924
|
-
const modelEntries = dmmf.datamodel.models.map((model) => {
|
|
925
|
-
const key = toDelegateKey(model.name);
|
|
926
|
-
return ` ${key}: {
|
|
927
|
-
guard(input: GuardInput, caller?: string): GuardedModel<PrismaClient['${key}']>
|
|
928
|
-
}`;
|
|
929
|
-
}).join("\n");
|
|
930
|
-
return `import type { PrismaClient } from '@prisma/client'
|
|
931
|
-
import type { GuardInput, GuardedModel } from 'prisma-guard'
|
|
932
|
-
import { createGuard } from 'prisma-guard'
|
|
933
|
-
import { SCOPE_MAP, TYPE_MAP, ENUM_MAP, ZOD_CHAINS, GUARD_CONFIG, UNIQUE_MAP, ZOD_DEFAULTS } from './index'
|
|
934
|
-
import type { ScopeRoot } from './index'
|
|
935
|
-
|
|
936
|
-
interface GuardModelExtension {
|
|
937
|
-
${modelEntries}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
export const guard = createGuard<typeof TYPE_MAP, ScopeRoot, GuardModelExtension>({
|
|
941
|
-
scopeMap: SCOPE_MAP,
|
|
942
|
-
typeMap: TYPE_MAP,
|
|
943
|
-
enumMap: ENUM_MAP,
|
|
944
|
-
zodChains: ZOD_CHAINS,
|
|
945
|
-
guardConfig: GUARD_CONFIG,
|
|
946
|
-
uniqueMap: UNIQUE_MAP,
|
|
947
|
-
zodDefaults: ZOD_DEFAULTS,
|
|
948
|
-
})
|
|
949
|
-
`;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// src/shared/operation-shape-keys.ts
|
|
953
|
-
var OPERATION_SHAPE_KEYS = {
|
|
954
|
-
findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
955
|
-
findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
956
|
-
findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
957
|
-
findUnique: ["where", "include", "select"],
|
|
958
|
-
findUniqueOrThrow: ["where", "include", "select"],
|
|
959
|
-
findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
960
|
-
count: ["where", "select", "cursor", "orderBy", "skip", "take"],
|
|
961
|
-
aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
962
|
-
groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
|
|
963
|
-
create: ["data", "select", "include"],
|
|
964
|
-
createMany: ["data"],
|
|
965
|
-
createManyAndReturn: ["data", "select", "include"],
|
|
966
|
-
update: ["data", "where", "select", "include"],
|
|
967
|
-
updateMany: ["data", "where"],
|
|
968
|
-
updateManyAndReturn: ["data", "where", "select", "include"],
|
|
969
|
-
upsert: ["where", "create", "update", "select", "include"],
|
|
970
|
-
delete: ["where", "select", "include"],
|
|
971
|
-
deleteMany: ["where"]
|
|
972
|
-
};
|
|
973
|
-
var READ_METHOD_ALLOWED_ARGS = {
|
|
974
|
-
findMany: new Set(OPERATION_SHAPE_KEYS.findMany),
|
|
975
|
-
findFirst: new Set(OPERATION_SHAPE_KEYS.findFirst),
|
|
976
|
-
findFirstOrThrow: new Set(OPERATION_SHAPE_KEYS.findFirstOrThrow),
|
|
977
|
-
findUnique: new Set(OPERATION_SHAPE_KEYS.findUnique),
|
|
978
|
-
findUniqueOrThrow: new Set(OPERATION_SHAPE_KEYS.findUniqueOrThrow),
|
|
979
|
-
count: new Set(OPERATION_SHAPE_KEYS.count),
|
|
980
|
-
aggregate: new Set(OPERATION_SHAPE_KEYS.aggregate),
|
|
981
|
-
groupBy: new Set(OPERATION_SHAPE_KEYS.groupBy)
|
|
982
|
-
};
|
|
983
|
-
var MUTATION_SHAPE_KEYS = {
|
|
984
|
-
create: new Set(OPERATION_SHAPE_KEYS.create),
|
|
985
|
-
createMany: new Set(OPERATION_SHAPE_KEYS.createMany),
|
|
986
|
-
createManyAndReturn: new Set(OPERATION_SHAPE_KEYS.createManyAndReturn),
|
|
987
|
-
update: new Set(OPERATION_SHAPE_KEYS.update),
|
|
988
|
-
updateMany: new Set(OPERATION_SHAPE_KEYS.updateMany),
|
|
989
|
-
updateManyAndReturn: new Set(OPERATION_SHAPE_KEYS.updateManyAndReturn),
|
|
990
|
-
upsert: new Set(OPERATION_SHAPE_KEYS.upsert),
|
|
991
|
-
delete: new Set(OPERATION_SHAPE_KEYS.delete),
|
|
992
|
-
deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
|
|
993
|
-
};
|
|
994
|
-
|
|
995
|
-
// src/generator/emit-typed-shapes.ts
|
|
996
|
-
var OPERATIONS = Object.keys(OPERATION_SHAPE_KEYS);
|
|
997
|
-
function cap(s) {
|
|
998
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
999
|
-
}
|
|
1000
|
-
function emitTypedShapes(dmmf, depth) {
|
|
1001
|
-
const header = `import type { TYPE_MAP } from './index'
|
|
1002
|
-
import type {
|
|
1003
|
-
TypedGuardShape,
|
|
1004
|
-
OperationShape,
|
|
1005
|
-
ShapeInput,
|
|
1006
|
-
TypedProjection,
|
|
1007
|
-
TypedInclude,
|
|
1008
|
-
TypedCountSelect,
|
|
1009
|
-
} from 'prisma-guard'
|
|
1010
|
-
|
|
1011
|
-
type TM = typeof TYPE_MAP
|
|
1012
|
-
|
|
1013
|
-
`;
|
|
1014
|
-
const blocks = dmmf.datamodel.models.map((model) => {
|
|
1015
|
-
const m = model.name;
|
|
1016
|
-
const projAlias = `export type ${m}Select = TypedProjection<TM, '${m}', ${depth}>
|
|
1017
|
-
export type ${m}Projection = ${m}Select
|
|
1018
|
-
export type ${m}Include = TypedInclude<TM, '${m}', ${depth}>
|
|
1019
|
-
export type ${m}CountSelect = TypedCountSelect<TM, '${m}'>
|
|
1020
|
-
`;
|
|
1021
|
-
const guardAlias = `export type ${m}GuardShape = TypedGuardShape<TM, '${m}', ${depth}>
|
|
1022
|
-
`;
|
|
1023
|
-
const opAliases = OPERATIONS.map((op) => {
|
|
1024
|
-
const c = cap(op);
|
|
1025
|
-
return `export type ${m}${c}Shape = OperationShape<TM, '${m}', '${op}', ${depth}>
|
|
1026
|
-
export type ${m}${c}ShapeInput<TCtx = unknown> = ShapeInput<${m}${c}Shape, TCtx>
|
|
1027
|
-
`;
|
|
1028
|
-
}).join("");
|
|
1029
|
-
return projAlias + guardAlias + opAliases;
|
|
1030
|
-
}).join("\n");
|
|
1031
|
-
return header + blocks;
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
1025
|
// src/generator/index.ts
|
|
1035
1026
|
var { generatorHandler } = pkg;
|
|
1036
1027
|
var VALID_ON_INVALID_ZOD = /* @__PURE__ */ new Set(["error", "warn"]);
|
|
@@ -1073,7 +1064,7 @@ function emitZodDefaults(defaults) {
|
|
|
1073
1064
|
`;
|
|
1074
1065
|
}
|
|
1075
1066
|
const mapEntries = entries.map(([model, fields]) => {
|
|
1076
|
-
const fieldsStr = fields.map((
|
|
1067
|
+
const fieldsStr = fields.map((field) => JSON.stringify(field)).join(", ");
|
|
1077
1068
|
return ` ${JSON.stringify(model)}: [${fieldsStr}],`;
|
|
1078
1069
|
}).join("\n");
|
|
1079
1070
|
return `export const ZOD_DEFAULTS: Record<string, readonly string[]> = {
|
|
@@ -1081,6 +1072,35 @@ ${mapEntries}
|
|
|
1081
1072
|
}
|
|
1082
1073
|
`;
|
|
1083
1074
|
}
|
|
1075
|
+
function getProviderValue(provider) {
|
|
1076
|
+
if (typeof provider === "string")
|
|
1077
|
+
return provider;
|
|
1078
|
+
if (provider && typeof provider === "object" && "value" in provider) {
|
|
1079
|
+
const value = provider.value;
|
|
1080
|
+
if (typeof value === "string")
|
|
1081
|
+
return value;
|
|
1082
|
+
}
|
|
1083
|
+
return "";
|
|
1084
|
+
}
|
|
1085
|
+
function isPrismaClientProvider(provider) {
|
|
1086
|
+
const value = getProviderValue(provider);
|
|
1087
|
+
return value === "prisma-client-js" || value.endsWith("/prisma-client-js");
|
|
1088
|
+
}
|
|
1089
|
+
function normalizeImportPath(path) {
|
|
1090
|
+
const normalized = path.replace(/\\/g, "/");
|
|
1091
|
+
if (normalized.startsWith("."))
|
|
1092
|
+
return normalized;
|
|
1093
|
+
return `./${normalized}`;
|
|
1094
|
+
}
|
|
1095
|
+
function resolvePrismaClientImport(options, guardOutput) {
|
|
1096
|
+
const prismaClientGenerator = options.otherGenerators.find(
|
|
1097
|
+
(generator) => isPrismaClientProvider(generator.provider)
|
|
1098
|
+
);
|
|
1099
|
+
const clientOutput = prismaClientGenerator?.output?.value;
|
|
1100
|
+
if (!clientOutput)
|
|
1101
|
+
return "@prisma/client";
|
|
1102
|
+
return normalizeImportPath(relative(guardOutput, clientOutput));
|
|
1103
|
+
}
|
|
1084
1104
|
generatorHandler({
|
|
1085
1105
|
onManifest() {
|
|
1086
1106
|
return {
|
|
@@ -1093,15 +1113,49 @@ generatorHandler({
|
|
|
1093
1113
|
if (!output)
|
|
1094
1114
|
throw new Error("prisma-guard: No output directory specified");
|
|
1095
1115
|
const config = options.generator.config ?? {};
|
|
1096
|
-
const onInvalidZod = validateConfigEnum(
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1116
|
+
const onInvalidZod = validateConfigEnum(
|
|
1117
|
+
"onInvalidZod",
|
|
1118
|
+
config.onInvalidZod ?? "error",
|
|
1119
|
+
VALID_ON_INVALID_ZOD
|
|
1120
|
+
);
|
|
1121
|
+
const onAmbiguousScope = validateConfigEnum(
|
|
1122
|
+
"onAmbiguousScope",
|
|
1123
|
+
config.onAmbiguousScope ?? "error",
|
|
1124
|
+
VALID_ON_AMBIGUOUS_SCOPE
|
|
1125
|
+
);
|
|
1126
|
+
const onMissingScopeContext = validateConfigEnum(
|
|
1127
|
+
"onMissingScopeContext",
|
|
1128
|
+
config.onMissingScopeContext ?? "error",
|
|
1129
|
+
VALID_ON_MISSING_SCOPE_CONTEXT
|
|
1130
|
+
);
|
|
1131
|
+
const findUniqueMode = validateConfigEnum(
|
|
1132
|
+
"findUniqueMode",
|
|
1133
|
+
config.findUniqueMode ?? "reject",
|
|
1134
|
+
VALID_FIND_UNIQUE_MODE
|
|
1135
|
+
);
|
|
1136
|
+
const onScopeRelationWrite = validateConfigEnum(
|
|
1137
|
+
"onScopeRelationWrite",
|
|
1138
|
+
config.onScopeRelationWrite ?? "error",
|
|
1139
|
+
VALID_ON_SCOPE_RELATION_WRITE
|
|
1140
|
+
);
|
|
1141
|
+
const strictDecimal = validateBooleanConfig(
|
|
1142
|
+
"strictDecimal",
|
|
1143
|
+
config.strictDecimal,
|
|
1144
|
+
false
|
|
1145
|
+
);
|
|
1146
|
+
const enforceProjection = validateBooleanConfig(
|
|
1147
|
+
"enforceProjection",
|
|
1148
|
+
config.enforceProjection,
|
|
1149
|
+
false
|
|
1150
|
+
);
|
|
1151
|
+
const typedGuardShapes = validateBooleanConfig(
|
|
1152
|
+
"typedGuardShapes",
|
|
1153
|
+
config.typedGuardShapes,
|
|
1154
|
+
true
|
|
1155
|
+
);
|
|
1156
|
+
const typedGuardRelationDepth = validateDepthConfig(
|
|
1157
|
+
config.typedGuardRelationDepth
|
|
1158
|
+
);
|
|
1105
1159
|
const dmmf = options.dmmf;
|
|
1106
1160
|
const parts = [];
|
|
1107
1161
|
parts.push(
|
|
@@ -1122,12 +1176,13 @@ generatorHandler({
|
|
|
1122
1176
|
parts.push(zodChainsSource);
|
|
1123
1177
|
parts.push(emitZodDefaults(defaults));
|
|
1124
1178
|
mkdirSync(output, { recursive: true });
|
|
1125
|
-
writeFileSync(
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1179
|
+
writeFileSync(`${output}/index.ts`, parts.join("\n"), "utf-8");
|
|
1180
|
+
const prismaClientImport = resolvePrismaClientImport(options, output);
|
|
1181
|
+
const clientSource = emitClient(dmmf, prismaClientImport);
|
|
1182
|
+
writeFileSync(`${output}/client.ts`, clientSource, "utf-8");
|
|
1128
1183
|
if (typedGuardShapes) {
|
|
1129
1184
|
writeFileSync(
|
|
1130
|
-
|
|
1185
|
+
`${output}/shapes.ts`,
|
|
1131
1186
|
emitTypedShapes(dmmf, typedGuardRelationDepth),
|
|
1132
1187
|
"utf-8"
|
|
1133
1188
|
);
|