prisma-generator-express 1.11.4 → 1.13.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.
Files changed (67) hide show
  1. package/README.md +51 -3
  2. package/dist/generator.js +2 -12
  3. package/dist/generator.js.map +1 -1
  4. package/dist/helpers/generateAggregate.js +13 -13
  5. package/dist/helpers/generateAggregate.js.map +1 -1
  6. package/dist/helpers/generateCount.js +12 -13
  7. package/dist/helpers/generateCount.js.map +1 -1
  8. package/dist/helpers/generateCreate.js +13 -15
  9. package/dist/helpers/generateCreate.js.map +1 -1
  10. package/dist/helpers/generateCreateMany.js +13 -15
  11. package/dist/helpers/generateCreateMany.js.map +1 -1
  12. package/dist/helpers/generateDelete.js +12 -15
  13. package/dist/helpers/generateDelete.js.map +1 -1
  14. package/dist/helpers/generateDeleteMany.js +13 -14
  15. package/dist/helpers/generateDeleteMany.js.map +1 -1
  16. package/dist/helpers/generateFindFirst.js +10 -15
  17. package/dist/helpers/generateFindFirst.js.map +1 -1
  18. package/dist/helpers/generateFindMany.js +10 -15
  19. package/dist/helpers/generateFindMany.js.map +1 -1
  20. package/dist/helpers/generateFindUnique.js +10 -15
  21. package/dist/helpers/generateFindUnique.js.map +1 -1
  22. package/dist/helpers/generateGroupBy.js +12 -13
  23. package/dist/helpers/generateGroupBy.js.map +1 -1
  24. package/dist/helpers/generateRouteFile.js +68 -35
  25. package/dist/helpers/generateRouteFile.js.map +1 -1
  26. package/dist/helpers/generateUpdate.js +12 -15
  27. package/dist/helpers/generateUpdate.js.map +1 -1
  28. package/dist/helpers/generateUpdateMany.js +12 -15
  29. package/dist/helpers/generateUpdateMany.js.map +1 -1
  30. package/dist/helpers/generateUpsert.js +12 -15
  31. package/dist/helpers/generateUpsert.js.map +1 -1
  32. package/dist/utils/copyFiles.js +26 -0
  33. package/dist/utils/copyFiles.js.map +1 -0
  34. package/package.json +4 -1
  35. package/src/copy/createOutputValidatorMiddleware.ts +44 -0
  36. package/src/copy/createValidatorMiddleware.ts +55 -0
  37. package/src/copy/encodeQueryParams.spec.ts +303 -0
  38. package/src/copy/encodeQueryParams.ts +44 -0
  39. package/src/copy/misc.spec.ts +62 -0
  40. package/src/copy/misc.ts +25 -0
  41. package/src/copy/parseQueryParams.spec.ts +187 -0
  42. package/src/copy/parseQueryParams.ts +42 -0
  43. package/src/copy/routeConfig.ts +34 -0
  44. package/src/copy/transformZod.spec.ts +556 -0
  45. package/src/copy/transformZod.ts +119 -0
  46. package/src/generator.ts +3 -13
  47. package/src/helpers/generateAggregate.ts +13 -13
  48. package/src/helpers/generateCount.ts +12 -13
  49. package/src/helpers/generateCreate.ts +14 -15
  50. package/src/helpers/generateCreateMany.ts +13 -15
  51. package/src/helpers/generateDelete.ts +13 -15
  52. package/src/helpers/generateDeleteMany.ts +14 -14
  53. package/src/helpers/generateFindFirst.ts +10 -15
  54. package/src/helpers/generateFindMany.ts +10 -15
  55. package/src/helpers/generateFindUnique.ts +10 -15
  56. package/src/helpers/generateGroupBy.ts +12 -13
  57. package/src/helpers/generateRouteFile.ts +68 -35
  58. package/src/helpers/generateUpdate.ts +13 -15
  59. package/src/helpers/generateUpdateMany.ts +13 -15
  60. package/src/helpers/generateUpsert.ts +13 -15
  61. package/src/utils/copyFiles.ts +27 -0
  62. package/dist/helpers/generateQsParser.js +0 -56
  63. package/dist/helpers/generateQsParser.js.map +0 -1
  64. package/dist/helpers/generateRouteConfigType.js +0 -34
  65. package/dist/helpers/generateRouteConfigType.js.map +0 -1
  66. package/src/helpers/generateQsParser.ts +0 -51
  67. package/src/helpers/generateRouteConfigType.ts +0 -29
@@ -1 +1 @@
1
- {"version":3,"file":"generateFindUnique.js","sourceRoot":"","sources":["../../src/helpers/generateFindUnique.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAOhD,MAAM,0BAA0B,GAAG,CAAC,OAG1C,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,YAAY,CAAA;IAC7C,MAAM,aAAa,GAAG,UAAU,SAAS,gBAAgB,CAAA;IAEzD,OAAO;EACP,qBAAqB,CAAC,OAAO,CAAC,YAAY,EAAE,aAAa,SAAS,IAAI,CAAC;;;;;;;;;;;WAW9D,aAAa;;;;;aAKX,SAAS;;;gFAG0D,aAAa;;wBAErE,YAAY;;;;;;oCAMA,IAAA,8BAAoB,EAAC,SAAS,CAAC,4BAA4B,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1G,CAAA;AACF,CAAC,CAAA;AA/DY,QAAA,0BAA0B,8BA+DtC"}
1
+ {"version":3,"file":"generateFindUnique.js","sourceRoot":"","sources":["../../src/helpers/generateFindUnique.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAOhD,MAAM,0BAA0B,GAAG,CAAC,OAG1C,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,YAAY,CAAA;IAC7C,MAAM,aAAa,GAAG,UAAU,SAAS,gBAAgB,CAAA;IAEzD,OAAO;EACP,qBAAqB,CAAC,OAAO,CAAC,YAAY,EAAE,aAAa,SAAS,IAAI,CAAC;;;;;;;;;;;WAW9D,aAAa;;;;;aAKX,SAAS;;;;gFAI0D,aAAa;;wBAErE,YAAY;;;;;;;;oCAQA,IAAA,8BAAoB,EAAC,SAAS,CAAC,4BAA4B,aAAa;;;;;;;;;;;;;;;;;EAiB1G,CAAA;AACF,CAAC,CAAA;AA1DY,QAAA,0BAA0B,8BA0DtC"}
@@ -19,37 +19,36 @@ interface GroupByRequest extends Request {
19
19
  query: Partial<${argsTypeName}> & ParsedQs;
20
20
  outputValidation?: ZodTypeAny;
21
21
  omitOutputValidation?: boolean;
22
+ locals?: {
23
+ outputValidator?: ZodTypeAny;
24
+ };
22
25
  }
23
26
 
24
27
  export type GroupByMiddleware = RequestHandler<ParamsDictionary, any, {}, ParsedQs>;
25
28
 
26
29
  export async function ${functionName}(req: GroupByRequest, res: Response, next: NextFunction) {
27
30
  try {
28
- if (!req.outputValidation && !req.omitOutputValidation) {
31
+ const outputValidator = req.locals?.outputValidator || req.outputValidation;
32
+
33
+ if (!outputValidator && !req.omitOutputValidation) {
29
34
  throw new Error('Output validation schema or omission flag must be provided.');
30
35
  }
31
36
 
32
37
  // @ts-ignore
33
38
  const result = await req.prisma.${(0, strings_1.lowercaseFirstLetter)(modelName)}.groupBy(req.query);
34
39
 
35
- if (!req.omitOutputValidation && req.outputValidation) {
36
- const validationResult = req.outputValidation.safeParse(result);
40
+ if (!req.omitOutputValidation && outputValidator) {
41
+ const validationResult = outputValidator.safeParse(result);
37
42
  if (validationResult.success) {
38
- res.status(200).json(validationResult.data);
43
+ return res.status(200).json(validationResult.data);
39
44
  } else {
40
- res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
45
+ return res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
41
46
  }
42
47
  } else {
43
- res.status(200).json(result);
48
+ return res.status(200).json(result);
44
49
  }
45
50
  } catch (error: unknown) {
46
- console.error('Error in handling groupBy request:', error);
47
- if (error instanceof Error) {
48
- res.status(500).json({ error: error.message });
49
- } else {
50
- res.status(500).json({ error: "Unknown error occurred" });
51
- }
52
- next(error);
51
+ return next(error);
53
52
  }
54
53
  }`;
55
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"generateGroupBy.js","sourceRoot":"","sources":["../../src/helpers/generateGroupBy.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAUhD,MAAM,uBAAuB,GAAG,CAAC,OAGvC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,SAAS,CAAA;IAC1C,MAAM,YAAY,GAAG,UAAU,SAAS,aAAa,CAAA;IAErD,OAAO;EACP,qBAAqB;;;;;;;;mBAQJ,YAAY;;;;;;;wBAOP,YAAY;;;;;;;sCAOE,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;EAqBnE,CAAA;AACF,CAAC,CAAA;AAtDY,QAAA,uBAAuB,2BAsDnC"}
1
+ {"version":3,"file":"generateGroupBy.js","sourceRoot":"","sources":["../../src/helpers/generateGroupBy.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAUhD,MAAM,uBAAuB,GAAG,CAAC,OAGvC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,SAAS,CAAA;IAC1C,MAAM,YAAY,GAAG,UAAU,SAAS,aAAa,CAAA;IAErD,OAAO;EACP,qBAAqB;;;;;;;;mBAQJ,YAAY;;;;;;;;;;wBAUP,YAAY;;;;;;;;;sCASE,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;EAenE,CAAA;AACF,CAAC,CAAA;AArDY,QAAA,uBAAuB,2BAqDnC"}
@@ -4,8 +4,12 @@ exports.generateRouterFunction = void 0;
4
4
  function generateRouterFunction({ model, }) {
5
5
  const modelName = model.name;
6
6
  const routerFunctionName = `${modelName}Router`;
7
- return `
8
- import express, { RequestHandler } from 'express';
7
+ return `import express, {
8
+ NextFunction,
9
+ RequestHandler,
10
+ Request,
11
+ Response,
12
+ } from 'express'
9
13
  import { ParsedQs } from 'qs'
10
14
  import { ${modelName}FindFirst } from './${modelName}FindFirst';
11
15
  import { ${modelName}FindMany } from './${modelName}FindMany';
@@ -20,13 +24,16 @@ import { ${modelName}DeleteMany } from './${modelName}DeleteMany';
20
24
  import { ${modelName}Aggregate } from './${modelName}Aggregate';
21
25
  import { ${modelName}Count } from './${modelName}Count';
22
26
  import { ${modelName}GroupBy } from './${modelName}GroupBy';
23
- import { RouteConfig } from "../RouteConfig";
24
- import qs from "qs";
27
+ import { createValidatorMiddleware, ValidatorOptions } from '../createValidatorMiddleware'
28
+ import { createOutputValidatorMiddleware } from '../createOutputValidatorMiddleware'
29
+ import { RouteConfig, ValidatorConfig } from '../routeConfig'
25
30
  import { parseQueryParams } from "../ParseQueryParams";
26
31
 
27
32
  const defaultBeforeAfter = {
28
33
  before: [] as RequestHandler[],
29
34
  after: [] as RequestHandler[],
35
+ input: undefined,
36
+ output: undefined,
30
37
  };
31
38
 
32
39
  /**
@@ -43,113 +50,139 @@ export function ${routerFunctionName}(config: RouteConfig<RequestHandler>) {
43
50
  path: string,
44
51
  method: "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head",
45
52
  middlewares: RequestHandler[],
46
- handler: RequestHandler
53
+ handler: RequestHandler,
54
+ inputValidator?: ValidatorConfig,
55
+ outputValidator?: ValidatorConfig
47
56
  ) => {
48
- router[method](basePath + path, (req, res, next) => {
49
- if (req.query)
50
- req.query = parseQueryParams(qs.parse(req.query as Record<string, string>)) as ParsedQs; next();
51
- }, ...middlewares, handler);
57
+ const middlewaresWithValidators: RequestHandler[] = [
58
+ (req, res, next) => {
59
+ if (req.query) {
60
+ req.query = parseQueryParams(req.query as Record<string, string>) as ParsedQs;
61
+ }
62
+ next();
63
+ },
64
+ ...middlewares
65
+ ];
66
+
67
+ if (inputValidator) {
68
+ middlewaresWithValidators.push(createValidatorMiddleware({
69
+ schema: inputValidator.schema,
70
+ allowedPaths: inputValidator.allow,
71
+ forbiddenPaths: inputValidator.forbid,
72
+ target: method === 'get' ? 'query' : 'body',
73
+ }));
74
+ }
75
+
76
+ middlewaresWithValidators.push((req, res, next) => {
77
+ res.locals.outputValidator = outputValidator;
78
+ next();
79
+ });
80
+
81
+ middlewaresWithValidators.push(handler);
82
+
83
+ router[method](basePath + path, ...middlewaresWithValidators);
52
84
  };
53
85
 
86
+
54
87
  if (config.enableAll || config?.findFirst) {
55
- const { before = [], after = [] } = config.findFirst || defaultBeforeAfter;
56
- setupRoute('/first', 'get', before, ${modelName}FindFirst as RequestHandler);
88
+ const { before = [], after = [], input, output } = config.findFirst || defaultBeforeAfter;
89
+ setupRoute('/first', 'get', before, ${modelName}FindFirst as RequestHandler, input, output);
57
90
  if (after.length) {
58
91
  router.use(basePath + '/first', ...after);
59
92
  }
60
93
  }
61
94
 
62
95
  if (config.enableAll || config?.findMany) {
63
- const { before = [], after = [] } = config.findMany || defaultBeforeAfter;
64
- setupRoute('/', 'get', before, ${modelName}FindMany as RequestHandler);
96
+ const { before = [], after = [], input, output } = config.findMany || defaultBeforeAfter;
97
+ setupRoute('/', 'get', before, ${modelName}FindMany as RequestHandler, input, output);
65
98
  if (after.length) {
66
99
  router.use(basePath + '/', ...after);
67
100
  }
68
101
  }
69
102
 
70
103
  if (config.enableAll || config?.findUnique) {
71
- const { before = [], after = [] } = config.findUnique || defaultBeforeAfter;
72
- setupRoute('/:id', 'get', before, ${modelName}FindUnique as any);
104
+ const { before = [], after = [], input, output } = config.findUnique || defaultBeforeAfter;
105
+ setupRoute('/:id', 'get', before, ${modelName}FindUnique as any, input, output);
73
106
  if (after.length) {
74
107
  router.use(basePath + '/:id', ...after);
75
108
  }
76
109
  }
77
110
 
78
111
  if (config.enableAll || config?.create) {
79
- const { before = [], after = [] } = config.create || defaultBeforeAfter;
80
- setupRoute('/', 'post', before, ${modelName}Create as RequestHandler);
112
+ const { before = [], after = [], input, output } = config.create || defaultBeforeAfter;
113
+ setupRoute('/', 'post', before, ${modelName}Create as RequestHandler, input, output);
81
114
  if (after.length) {
82
115
  router.use(basePath + '/', ...after);
83
116
  }
84
117
  }
85
118
 
86
119
  if (config.enableAll || config?.createMany) {
87
- const { before = [], after = [] } = config.createMany || defaultBeforeAfter;
88
- setupRoute('/many', 'post', before, ${modelName}CreateMany as RequestHandler);
120
+ const { before = [], after = [], input, output } = config.createMany || defaultBeforeAfter;
121
+ setupRoute('/many', 'post', before, ${modelName}CreateMany as RequestHandler, input, output);
89
122
  if (after.length) {
90
123
  router.use(basePath + '/many', ...after);
91
124
  }
92
125
  }
93
126
 
94
127
  if (config.enableAll || config?.update) {
95
- const { before = [], after = [] } = config.update || defaultBeforeAfter;
96
- setupRoute('/', 'put', before, ${modelName}Update as RequestHandler);
128
+ const { before = [], after = [], input, output } = config.update || defaultBeforeAfter;
129
+ setupRoute('/', 'put', before, ${modelName}Update as RequestHandler, input, output);
97
130
  if (after.length) {
98
131
  router.use(basePath + '/', ...after);
99
132
  }
100
133
  }
101
134
 
102
135
  if (config.enableAll || config?.updateMany) {
103
- const { before = [], after = [] } = config.updateMany || defaultBeforeAfter;
104
- setupRoute('/many', 'put', before, ${modelName}UpdateMany as RequestHandler);
136
+ const { before = [], after = [], input, output } = config.updateMany || defaultBeforeAfter;
137
+ setupRoute('/many', 'put', before, ${modelName}UpdateMany as RequestHandler, input, output);
105
138
  if (after.length) {
106
139
  router.use(basePath + '/many', ...after);
107
140
  }
108
141
  }
109
142
 
110
143
  if (config.enableAll || config?.upsert) {
111
- const { before = [], after = [] } = config.upsert || defaultBeforeAfter;
112
- setupRoute('/', 'patch', before, ${modelName}Upsert as RequestHandler);
144
+ const { before = [], after = [], input, output } = config.upsert || defaultBeforeAfter;
145
+ setupRoute('/', 'patch', before, ${modelName}Upsert as RequestHandler, input, output);
113
146
  if (after.length) {
114
147
  router.use(basePath + '/', ...after);
115
148
  }
116
149
  }
117
150
 
118
151
  if (config.enableAll || config?.delete) {
119
- const { before = [], after = [] } = config.delete || defaultBeforeAfter;
120
- setupRoute('/', 'delete', before, ${modelName}Delete as RequestHandler);
152
+ const { before = [], after = [], input, output } = config.delete || defaultBeforeAfter;
153
+ setupRoute('/', 'delete', before, ${modelName}Delete as RequestHandler, input, output);
121
154
  if (after.length) {
122
155
  router.use(basePath + '/', ...after);
123
156
  }
124
157
  }
125
158
 
126
159
  if (config.enableAll || config?.deleteMany) {
127
- const { before = [], after = [] } = config.deleteMany || defaultBeforeAfter;
128
- setupRoute('/many', 'delete', before, ${modelName}DeleteMany as RequestHandler);
160
+ const { before = [], after = [], input, output } = config.deleteMany || defaultBeforeAfter;
161
+ setupRoute('/many', 'delete', before, ${modelName}DeleteMany as RequestHandler, input, output);
129
162
  if (after.length) {
130
163
  router.use(basePath + '/many', ...after);
131
164
  }
132
165
  }
133
166
 
134
167
  if (config.enableAll || config?.aggregate) {
135
- const { before = [], after = [] } = config.aggregate || defaultBeforeAfter;
136
- setupRoute('/aggregate', 'get', before, ${modelName}Aggregate as RequestHandler);
168
+ const { before = [], after = [], input, output } = config.aggregate || defaultBeforeAfter;
169
+ setupRoute('/aggregate', 'get', before, ${modelName}Aggregate as RequestHandler, input, output);
137
170
  if (after.length) {
138
171
  router.use(basePath + '/aggregate', ...after);
139
172
  }
140
173
  }
141
174
 
142
175
  if (config.enableAll || config?.count) {
143
- const { before = [], after = [] } = config.count || defaultBeforeAfter;
144
- setupRoute('/count', 'get', before, ${modelName}Count as RequestHandler);
176
+ const { before = [], after = [], input, output } = config.count || defaultBeforeAfter;
177
+ setupRoute('/count', 'get', before, ${modelName}Count as RequestHandler, input, output);
145
178
  if (after.length) {
146
179
  router.use(basePath + '/count', ...after);
147
180
  }
148
181
  }
149
182
 
150
183
  if (config.enableAll || config?.groupBy) {
151
- const { before = [], after = [] } = config.groupBy || defaultBeforeAfter;
152
- setupRoute('/groupby', 'get', before, ${modelName}GroupBy as RequestHandler);
184
+ const { before = [], after = [], input, output } = config.groupBy || defaultBeforeAfter;
185
+ setupRoute('/groupby', 'get', before, ${modelName}GroupBy as RequestHandler, input, output);
153
186
  if (after.length) {
154
187
  router.use(basePath + '/groupby', ...after);
155
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generateRouteFile.js","sourceRoot":"","sources":["../../src/helpers/generateRouteFile.ts"],"names":[],"mappings":";;;AAEA,SAAgB,sBAAsB,CAAC,EACrC,KAAK,GAGN;IACC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,kBAAkB,GAAG,GAAG,SAAS,QAAQ,CAAA;IAE/C,OAAO;;;WAGE,SAAS,uBAAuB,SAAS;WACzC,SAAS,sBAAsB,SAAS;WACxC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,uBAAuB,SAAS;WACzC,SAAS,mBAAmB,SAAS;WACrC,SAAS,qBAAqB,SAAS;;;;;;;;;;;qCAWb,SAAS;;;;;kBAK5B,kBAAkB;;iFAE6C,SAAS,CAAC,WAAW,EAAE;;;;;;;;;;;;;;;;0CAgB9D,SAAS;;;;;;;;qCAQd,SAAS;;;;;;;;wCAQN,SAAS;;;;;;;;sCAQX,SAAS;;;;;;;;0CAQL,SAAS;;;;;;;;qCAQd,SAAS;;;;;;;;yCAQL,SAAS;;;;;;;;uCAQX,SAAS;;;;;;;;wCAQR,SAAS;;;;;;;;4CAQL,SAAS;;;;;;;;8CAQP,SAAS;;;;;;;;0CAQb,SAAS;;;;;;;;4CAQP,SAAS;;;;;;;;CAQpD,CAAA;AACD,CAAC;AAlKD,wDAkKC"}
1
+ {"version":3,"file":"generateRouteFile.js","sourceRoot":"","sources":["../../src/helpers/generateRouteFile.ts"],"names":[],"mappings":";;;AAEA,SAAgB,sBAAsB,CAAC,EACrC,KAAK,GAGN;IACC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,kBAAkB,GAAG,GAAG,SAAS,QAAQ,CAAA;IAE/C,OAAO;;;;;;;WAOE,SAAS,uBAAuB,SAAS;WACzC,SAAS,sBAAsB,SAAS;WACxC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,oBAAoB,SAAS;WACtC,SAAS,oBAAoB,SAAS;WACtC,SAAS,wBAAwB,SAAS;WAC1C,SAAS,uBAAuB,SAAS;WACzC,SAAS,mBAAmB,SAAS;WACrC,SAAS,qBAAqB,SAAS;;;;;;;;;;;;;;qCAcb,SAAS;;;;;kBAK5B,kBAAkB;;iFAE6C,SAAS,CAAC,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0CA0C9D,SAAS;;;;;;;;qCAQd,SAAS;;;;;;;;wCAQN,SAAS;;;;;;;;sCAQX,SAAS;;;;;;;;0CAQL,SAAS;;;;;;;;qCAQd,SAAS;;;;;;;;yCAQL,SAAS;;;;;;;;uCAQX,SAAS;;;;;;;;wCAQR,SAAS;;;;;;;;4CAQL,SAAS;;;;;;;;8CAQP,SAAS;;;;;;;;0CAQb,SAAS;;;;;;;;4CAQP,SAAS;;;;;;;;CAQpD,CAAA;AACD,CAAC;AAnMD,wDAmMC"}
@@ -18,38 +18,35 @@ interface UpdateRequest extends Request {
18
18
  body: ${argsTypeName};
19
19
  outputValidation?: ZodTypeAny;
20
20
  omitOutputValidation?: boolean;
21
+ locals?: {
22
+ outputValidator?: ZodTypeAny;
23
+ };
21
24
  }
22
25
 
23
26
  export type UpdateMiddleware = RequestHandler<ParamsDictionary, any, ${argsTypeName}, Record<string, any>>
24
27
 
25
28
  export async function ${functionName}(req: UpdateRequest, res: Response, next: NextFunction) {
26
29
  try {
27
- if (!req.outputValidation && !req.omitOutputValidation) {
30
+ const outputValidator = req.locals?.outputValidator || req.outputValidation;
31
+
32
+ if (!outputValidator && !req.omitOutputValidation) {
28
33
  throw new Error('Output validation schema or omission flag must be provided.');
29
34
  }
30
35
 
31
36
  const data = await req.prisma.${(0, strings_1.lowercaseFirstLetter)(modelName)}.update(req.body);
32
37
 
33
- if (!req.omitOutputValidation && req.outputValidation) {
34
- const validationResult = req.outputValidation.safeParse(data);
38
+ if (!req.omitOutputValidation && outputValidator) {
39
+ const validationResult = outputValidator.safeParse(data);
35
40
  if (validationResult.success) {
36
- res.status(200).json(validationResult.data);
41
+ return res.status(200).json(validationResult.data);
37
42
  } else {
38
- res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
43
+ return res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
39
44
  }
40
- } else if (!req.omitOutputValidation) {
41
- throw new Error('Output validation schema must be provided unless explicitly omitted.');
42
45
  } else {
43
- res.status(200).json(data);
46
+ return res.status(200).json(data);
44
47
  }
45
48
  } catch (error: unknown) {
46
- console.error('Error in handling update request:', error);
47
- if (error instanceof Error) {
48
- res.status(500).json({ error: error.message });
49
- } else {
50
- res.status(500).json({ error: "Unknown error occurred" });
51
- }
52
- next(error);
49
+ return next(error);
53
50
  }
54
51
  }`;
55
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"generateUpdate.js","sourceRoot":"","sources":["../../src/helpers/generateUpdate.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAOhD,MAAM,sBAAsB,GAAG,CAAC,OAGtC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,QAAQ,CAAA;IACzC,MAAM,YAAY,GAAG,UAAU,SAAS,YAAY,CAAA;IAEpD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;uEAKiD,YAAY;;wBAE3D,YAAY;;;;;;oCAMA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;EAuBjE,CAAA;AACF,CAAC,CAAA;AAtDY,QAAA,sBAAsB,0BAsDlC"}
1
+ {"version":3,"file":"generateUpdate.js","sourceRoot":"","sources":["../../src/helpers/generateUpdate.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAQhD,MAAM,sBAAsB,GAAG,CAAC,OAGtC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,QAAQ,CAAA;IACzC,MAAM,YAAY,GAAG,UAAU,SAAS,YAAY,CAAA;IAEpD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;;;;uEAQiD,YAAY;;wBAE3D,YAAY;;;;;;;;oCAQA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;EAejE,CAAA;AACF,CAAC,CAAA;AAnDY,QAAA,sBAAsB,0BAmDlC"}
@@ -18,38 +18,35 @@ interface UpdateManyRequest extends Request {
18
18
  body: ${argsTypeName};
19
19
  outputValidation?: ZodTypeAny;
20
20
  omitOutputValidation?: boolean;
21
+ locals?: {
22
+ outputValidator?: ZodTypeAny;
23
+ };
21
24
  }
22
25
 
23
26
  export type UpdateManyMiddleware = RequestHandler<ParamsDictionary, any, ${argsTypeName}, Record<string, any>>
24
27
 
25
28
  export async function ${functionName}(req: UpdateManyRequest, res: Response, next: NextFunction) {
26
29
  try {
27
- if (!req.outputValidation && !req.omitOutputValidation) {
30
+ const outputValidator = req.locals?.outputValidator || req.outputValidation;
31
+
32
+ if (!outputValidator && !req.omitOutputValidation) {
28
33
  throw new Error('Output validation schema or omission flag must be provided.');
29
34
  }
30
35
 
31
36
  const data = await req.prisma.${(0, strings_1.lowercaseFirstLetter)(modelName)}.updateMany(req.body);
32
37
 
33
- if (!req.omitOutputValidation && req.outputValidation) {
34
- const validationResult = req.outputValidation.safeParse(data);
38
+ if (!req.omitOutputValidation && outputValidator) {
39
+ const validationResult = outputValidator.safeParse(data);
35
40
  if (validationResult.success) {
36
- res.status(200).json({ count: validationResult.data.count });
41
+ return res.status(200).json({ count: validationResult.data.count });
37
42
  } else {
38
- res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
43
+ return res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
39
44
  }
40
- } else if (!req.omitOutputValidation) {
41
- throw new Error('Output validation schema must be provided unless explicitly omitted.');
42
45
  } else {
43
- res.status(200).json({ count: data.count });
46
+ return res.status(200).json({ count: data.count });
44
47
  }
45
48
  } catch (error: unknown) {
46
- console.error('Error in handling updateMany request:', error);
47
- if (error instanceof Error) {
48
- res.status(500).json({ error: error.message });
49
- } else {
50
- res.status(500).json({ error: "Unknown error occurred" });
51
- }
52
- next(error);
49
+ return next(error);
53
50
  }
54
51
  }`;
55
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"generateUpdateMany.js","sourceRoot":"","sources":["../../src/helpers/generateUpdateMany.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAOhD,MAAM,0BAA0B,GAAG,CAAC,OAG1C,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,YAAY,CAAA;IAC7C,MAAM,YAAY,GAAG,UAAU,SAAS,gBAAgB,CAAA;IAExD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;2EAKqD,YAAY;;wBAE/D,YAAY;;;;;;oCAMA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;EAuBjE,CAAA;AACF,CAAC,CAAA;AAtDY,QAAA,0BAA0B,8BAsDtC"}
1
+ {"version":3,"file":"generateUpdateMany.js","sourceRoot":"","sources":["../../src/helpers/generateUpdateMany.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAQhD,MAAM,0BAA0B,GAAG,CAAC,OAG1C,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,YAAY,CAAA;IAC7C,MAAM,YAAY,GAAG,UAAU,SAAS,gBAAgB,CAAA;IAExD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;;;;2EAQqD,YAAY;;wBAE/D,YAAY;;;;;;;;oCAQA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;EAejE,CAAA;AACF,CAAC,CAAA;AAnDY,QAAA,0BAA0B,8BAmDtC"}
@@ -18,38 +18,35 @@ interface UpsertRequest extends Request {
18
18
  body: ${argsTypeName};
19
19
  outputValidation?: ZodTypeAny;
20
20
  omitOutputValidation?: boolean;
21
+ locals?: {
22
+ outputValidator?: ZodTypeAny;
23
+ };
21
24
  }
22
25
 
23
26
  export type UpsertMiddleware = RequestHandler<ParamsDictionary, any, ${argsTypeName}, Record<string, any>>
24
27
 
25
28
  export async function ${functionName}(req: UpsertRequest, res: Response, next: NextFunction) {
26
29
  try {
27
- if (!req.outputValidation && !req.omitOutputValidation) {
30
+ const outputValidator = req.locals?.outputValidator || req.outputValidation;
31
+
32
+ if (!outputValidator && !req.omitOutputValidation) {
28
33
  throw new Error('Output validation schema or omission flag must be provided.');
29
34
  }
30
35
 
31
36
  const data = await req.prisma.${(0, strings_1.lowercaseFirstLetter)(modelName)}.upsert(req.body);
32
37
 
33
- if (!req.omitOutputValidation && req.outputValidation) {
34
- const validationResult = req.outputValidation.safeParse(data);
38
+ if (!req.omitOutputValidation && outputValidator) {
39
+ const validationResult = outputValidator.safeParse(data);
35
40
  if (validationResult.success) {
36
- res.status(200).json(validationResult.data);
41
+ return res.status(200).json(validationResult.data);
37
42
  } else {
38
- res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
43
+ return res.status(400).json({ error: 'Invalid data format', details: validationResult.error });
39
44
  }
40
- } else if (!req.omitOutputValidation) {
41
- throw new Error('Output validation schema must be provided unless explicitly omitted.');
42
45
  } else {
43
- res.status(200).json(data);
46
+ return res.status(200).json(data);
44
47
  }
45
48
  } catch (error: unknown) {
46
- console.error('Error in handling upsert request:', error);
47
- if (error instanceof Error) {
48
- res.status(500).json({ error: error.message });
49
- } else {
50
- res.status(500).json({ error: "Unknown error occurred" });
51
- }
52
- next(error);
49
+ return next(error);
53
50
  }
54
51
  }`;
55
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"generateUpsert.js","sourceRoot":"","sources":["../../src/helpers/generateUpsert.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAQhD,MAAM,sBAAsB,GAAG,CAAC,OAGtC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,QAAQ,CAAA;IACzC,MAAM,YAAY,GAAG,UAAU,SAAS,YAAY,CAAA;IAEpD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;uEAKiD,YAAY;;wBAE3D,YAAY;;;;;;oCAMA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;EAuBjE,CAAA;AACF,CAAC,CAAA;AAtDY,QAAA,sBAAsB,0BAsDlC"}
1
+ {"version":3,"file":"generateUpsert.js","sourceRoot":"","sources":["../../src/helpers/generateUpsert.ts"],"names":[],"mappings":";;;AACA,8CAAuD;AAShD,MAAM,sBAAsB,GAAG,CAAC,OAGtC,EAAU,EAAE;IACX,MAAM,EAAE,KAAK,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAA;IAChD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAA;IAC5B,MAAM,YAAY,GAAG,GAAG,SAAS,QAAQ,CAAA;IACzC,MAAM,YAAY,GAAG,UAAU,SAAS,YAAY,CAAA;IAEpD,OAAO;EACP,qBAAqB;;;;;;;UAOb,YAAY;;;;;;;;uEAQiD,YAAY;;wBAE3D,YAAY;;;;;;;;oCAQA,IAAA,8BAAoB,EAAC,SAAS,CAAC;;;;;;;;;;;;;;;EAejE,CAAA;AACF,CAAC,CAAA;AAnDY,QAAA,sBAAsB,0BAmDlC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.copyFiles = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const copyFiles = async (options, destPath) => {
10
+ var _a;
11
+ const sourceDir = path_1.default.join(__dirname.replace('dist', 'src'), '..', 'copy');
12
+ const destinationDir = destPath || ((_a = options.generator.output) === null || _a === void 0 ? void 0 : _a.value);
13
+ const files = await promises_1.default.readdir(sourceDir);
14
+ for (const file of files) {
15
+ if (file.endsWith('.spec.ts')) {
16
+ continue;
17
+ }
18
+ const sourceFile = path_1.default.join(sourceDir, file);
19
+ const destinationFile = path_1.default.join(destinationDir, file);
20
+ await promises_1.default.mkdir(path_1.default.dirname(destinationFile), { recursive: true });
21
+ await promises_1.default.copyFile(sourceFile, destinationFile);
22
+ }
23
+ console.log(`Files copied from ${sourceDir} to ${destinationDir}`);
24
+ };
25
+ exports.copyFiles = copyFiles;
26
+ //# sourceMappingURL=copyFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyFiles.js","sourceRoot":"","sources":["../../src/utils/copyFiles.ts"],"names":[],"mappings":";;;;;;AACA,2DAA4B;AAC5B,gDAAuB;AAEhB,MAAM,SAAS,GAAG,KAAK,EAC5B,OAAyB,EACzB,QAAiB,EACjB,EAAE;;IACF,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3E,MAAM,cAAc,GAAG,QAAQ,KAAI,MAAA,OAAO,CAAC,SAAS,CAAC,MAAM,0CAAE,KAAM,CAAA,CAAA;IAEnE,MAAM,KAAK,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,SAAQ;QACV,CAAC;QAED,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAC7C,MAAM,eAAe,GAAG,cAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;QAEvD,MAAM,kBAAE,CAAC,KAAK,CAAC,cAAI,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClE,MAAM,kBAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,CAAA;IAChD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,qBAAqB,SAAS,OAAO,cAAc,EAAE,CAAC,CAAA;AACpE,CAAC,CAAA;AAtBY,QAAA,SAAS,aAsBrB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "prisma-generator-express",
3
3
  "description": "Prisma generator of Express CRUD API",
4
- "version": "1.11.4",
4
+ "version": "1.13.0",
5
5
  "main": "dist/generator.js",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -16,6 +16,7 @@
16
16
  "build": "npx tsc",
17
17
  "prepack": "yarn build",
18
18
  "test": "jest",
19
+ "coverage": "jest --coverage",
19
20
  "prepublishOnly": "node copy.js "
20
21
  },
21
22
  "dependencies": {
@@ -23,6 +24,7 @@
23
24
  "@prisma/generator-helper": "5.14.0",
24
25
  "@prisma/sdk": "4.0.0",
25
26
  "express": "^4.19.2",
27
+ "lodash": "^4.17.21",
26
28
  "prettier": "3.2.5",
27
29
  "zod": "^3.23.8"
28
30
  },
@@ -32,6 +34,7 @@
32
34
  "@semantic-release/git": "^10.0.1",
33
35
  "@types/express": "^4.17.21",
34
36
  "@types/jest": "29.5.12",
37
+ "@types/lodash": "^4.17.4",
35
38
  "@types/node": "20.12.12",
36
39
  "@types/prettier": "3.0.0",
37
40
  "jest": "29.7.0",
@@ -0,0 +1,44 @@
1
+ import { NextFunction } from 'express'
2
+ import { allow, forbid } from './transformZod'
3
+ import { ValidatorOptions } from './createValidatorMiddleware'
4
+
5
+ /**
6
+ * Creates a middleware for validating response data using a Zod schema.
7
+ * @param {ValidatorOptions} options - The validation options.
8
+ * @param {ZodSchema<any>} options.schema - The Zod schema to validate the response data.
9
+ * @param {string[]} [options.allowedPaths] - Paths that are allowed in the response data.
10
+ * @param {string[]} [options.forbiddenPaths] - Paths that are forbidden in the response data.
11
+ * @returns {function} Express middleware function.
12
+ */
13
+ export function createOutputValidatorMiddleware({
14
+ schema,
15
+ allowedPaths,
16
+ forbiddenPaths,
17
+ }: ValidatorOptions) {
18
+ if (allowedPaths) {
19
+ schema = allow(schema, allowedPaths)
20
+ }
21
+
22
+ if (forbiddenPaths) {
23
+ schema = forbid(schema, forbiddenPaths)
24
+ }
25
+
26
+ return (req: Request, res: Response, next: NextFunction) => {
27
+ const originalSend = res.send
28
+
29
+ res.send = function (data) {
30
+ const validationResult = schema.safeParse(data)
31
+ if (!validationResult.success) {
32
+ const errors = validationResult.error.errors
33
+ return next({
34
+ status: 400,
35
+ message: 'Output validation failed',
36
+ errors,
37
+ })
38
+ }
39
+ return originalSend.call(this, data)
40
+ }
41
+
42
+ next()
43
+ }
44
+ }
@@ -0,0 +1,55 @@
1
+ import { Request, Response, NextFunction } from 'express'
2
+ import { ZodSchema } from 'zod'
3
+ import { allow, forbid } from './transformZod'
4
+
5
+ export interface ValidatorOptions {
6
+ schema: ZodSchema<any>
7
+ allowedPaths?: string[]
8
+ forbiddenPaths?: string[]
9
+ target?: 'body' | 'query'
10
+ }
11
+
12
+ /**
13
+ * Creates a middleware for validating request data using a Zod schema.
14
+ * @param {ValidatorOptions} options - The validation options.
15
+ * @param {ZodSchema<any>} options.schema - The Zod schema to validate the request data.
16
+ * @param {string[]} [options.allowedPaths] - Paths that are allowed in the request data. For example [`where.user.id`, `select.id`]
17
+ * @param {string[]} [options.forbiddenPaths] - Paths that are forbidden in the request data.
18
+ * @param {'body' | 'query'} [options.target='body'] - The part of the request to validate ('body' or 'query').
19
+ * @returns {function} Express middleware function.
20
+ */
21
+ export function createValidatorMiddleware({
22
+ schema,
23
+ allowedPaths,
24
+ forbiddenPaths,
25
+ target = 'body',
26
+ }: ValidatorOptions) {
27
+ if (allowedPaths) {
28
+ schema = allow(schema, allowedPaths)
29
+ }
30
+
31
+ if (forbiddenPaths) {
32
+ schema = forbid(schema, forbiddenPaths)
33
+ }
34
+
35
+ return (req: Request, res: Response, next: NextFunction) => {
36
+ let validationResult
37
+
38
+ if (target === 'query') {
39
+ validationResult = schema.safeParse(req.query)
40
+ } else {
41
+ validationResult = schema.safeParse(req.body)
42
+ }
43
+
44
+ if (!validationResult.success) {
45
+ const errors = validationResult.error.errors
46
+ return next({
47
+ status: 400,
48
+ message: 'Validation failed',
49
+ errors,
50
+ })
51
+ }
52
+
53
+ next()
54
+ }
55
+ }