@postxl/generator 0.74.2 → 1.0.3

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 (189) hide show
  1. package/LICENSE +50 -0
  2. package/README.md +79 -1
  3. package/dist/generator-manager.class.d.ts +59 -0
  4. package/dist/generator-manager.class.js +221 -0
  5. package/dist/generator.class.d.ts +90 -0
  6. package/dist/generator.class.js +32 -0
  7. package/dist/generator.context.d.ts +174 -0
  8. package/dist/generator.context.js +125 -0
  9. package/dist/helpers/branded.types.d.ts +149 -0
  10. package/dist/helpers/branded.types.js +111 -0
  11. package/dist/helpers/config-builder.class.d.ts +27 -0
  12. package/dist/helpers/config-builder.class.js +54 -0
  13. package/dist/helpers/import-generator.class.d.ts +70 -0
  14. package/dist/helpers/import-generator.class.js +166 -0
  15. package/dist/helpers/importable.types.d.ts +52 -0
  16. package/dist/helpers/importable.types.js +15 -0
  17. package/dist/helpers/index-generator.class.d.ts +10 -0
  18. package/dist/helpers/index-generator.class.js +46 -0
  19. package/dist/helpers/index.d.ts +8 -0
  20. package/dist/helpers/index.js +24 -0
  21. package/dist/helpers/package-json.generator.d.ts +56 -0
  22. package/dist/helpers/package-json.generator.js +36 -0
  23. package/dist/helpers/tsconfig.generator.d.ts +1 -0
  24. package/dist/helpers/tsconfig.generator.js +14 -0
  25. package/dist/helpers/verify-context.d.ts +4 -0
  26. package/dist/helpers/verify-context.js +23 -0
  27. package/dist/index.d.ts +5 -0
  28. package/dist/index.js +21 -0
  29. package/dist/utils/checksum.d.ts +10 -0
  30. package/dist/utils/checksum.js +132 -0
  31. package/dist/utils/fs-utils.d.ts +34 -0
  32. package/dist/utils/fs-utils.js +126 -0
  33. package/dist/utils/index.d.ts +10 -0
  34. package/dist/utils/index.js +26 -0
  35. package/dist/utils/jsdoc.d.ts +12 -0
  36. package/dist/utils/jsdoc.js +37 -0
  37. package/dist/utils/lint.d.ts +46 -0
  38. package/dist/utils/lint.js +154 -0
  39. package/dist/utils/lockfile.d.ts +7 -0
  40. package/dist/utils/lockfile.js +80 -0
  41. package/dist/utils/logger.class.d.ts +25 -0
  42. package/dist/utils/logger.class.js +55 -0
  43. package/dist/utils/merge-conflict.d.ts +55 -0
  44. package/dist/utils/merge-conflict.js +264 -0
  45. package/dist/utils/path.d.ts +52 -0
  46. package/dist/utils/path.js +183 -0
  47. package/dist/utils/prettier-config.d.ts +2 -0
  48. package/dist/utils/prettier-config.js +13 -0
  49. package/dist/utils/prettier.d.ts +5 -0
  50. package/dist/utils/prettier.js +67 -0
  51. package/dist/utils/prettier.skiptest.d.ts +1 -0
  52. package/dist/utils/prettier.skiptest.js +22 -0
  53. package/dist/utils/promise.d.ts +2 -0
  54. package/dist/utils/promise.js +10 -0
  55. package/dist/utils/string-functions.d.ts +9 -0
  56. package/dist/utils/string-functions.js +23 -0
  57. package/dist/utils/sync-log-result.d.ts +9 -0
  58. package/dist/utils/sync-log-result.js +90 -0
  59. package/dist/utils/sync.d.ts +143 -0
  60. package/dist/utils/sync.js +325 -0
  61. package/dist/utils/template.d.ts +66 -0
  62. package/dist/utils/template.js +159 -0
  63. package/dist/utils/vfs.class.d.ts +115 -0
  64. package/dist/utils/vfs.class.js +239 -0
  65. package/dist/utils/zip.d.ts +13 -0
  66. package/dist/utils/zip.js +40 -0
  67. package/package.json +53 -31
  68. package/dist/generator.d.ts +0 -13
  69. package/dist/generator.js +0 -455
  70. package/dist/generators/enums/react.generator.d.ts +0 -10
  71. package/dist/generators/enums/react.generator.js +0 -110
  72. package/dist/generators/enums/types.generator.d.ts +0 -10
  73. package/dist/generators/enums/types.generator.js +0 -39
  74. package/dist/generators/indices/data/module.generator.d.ts +0 -9
  75. package/dist/generators/indices/data/module.generator.js +0 -60
  76. package/dist/generators/indices/data/service.generator.d.ts +0 -9
  77. package/dist/generators/indices/data/service.generator.js +0 -249
  78. package/dist/generators/indices/data/types.generator.d.ts +0 -9
  79. package/dist/generators/indices/data/types.generator.js +0 -49
  80. package/dist/generators/indices/dispatcher-service.generator.d.ts +0 -9
  81. package/dist/generators/indices/dispatcher-service.generator.js +0 -107
  82. package/dist/generators/indices/export/class.generator.d.ts +0 -9
  83. package/dist/generators/indices/export/class.generator.js +0 -140
  84. package/dist/generators/indices/export/encoder.generator.d.ts +0 -9
  85. package/dist/generators/indices/export/encoder.generator.js +0 -50
  86. package/dist/generators/indices/import/convert-functions.generator.d.ts +0 -9
  87. package/dist/generators/indices/import/convert-functions.generator.js +0 -509
  88. package/dist/generators/indices/import/decoder.generator.d.ts +0 -9
  89. package/dist/generators/indices/import/decoder.generator.js +0 -40
  90. package/dist/generators/indices/import/service.generator.d.ts +0 -9
  91. package/dist/generators/indices/import/service.generator.js +0 -573
  92. package/dist/generators/indices/import/types.generator.d.ts +0 -9
  93. package/dist/generators/indices/import/types.generator.js +0 -242
  94. package/dist/generators/indices/repositories.generator.d.ts +0 -9
  95. package/dist/generators/indices/repositories.generator.js +0 -25
  96. package/dist/generators/indices/routes.generator.d.ts +0 -9
  97. package/dist/generators/indices/routes.generator.js +0 -29
  98. package/dist/generators/indices/seed-migration.generator.d.ts +0 -9
  99. package/dist/generators/indices/seed-migration.generator.js +0 -36
  100. package/dist/generators/indices/seed-template.generator.d.ts +0 -9
  101. package/dist/generators/indices/seed-template.generator.js +0 -80
  102. package/dist/generators/indices/testids.generator.d.ts +0 -7
  103. package/dist/generators/indices/testids.generator.js +0 -71
  104. package/dist/generators/indices/types.generator.d.ts +0 -10
  105. package/dist/generators/indices/types.generator.js +0 -35
  106. package/dist/generators/indices/update/actiontypes.generator.d.ts +0 -9
  107. package/dist/generators/indices/update/actiontypes.generator.js +0 -49
  108. package/dist/generators/indices/update/module.generator.d.ts +0 -9
  109. package/dist/generators/indices/update/module.generator.js +0 -41
  110. package/dist/generators/indices/update/service.generator.d.ts +0 -9
  111. package/dist/generators/indices/update/service.generator.js +0 -34
  112. package/dist/generators/indices/view/module.generator.d.ts +0 -9
  113. package/dist/generators/indices/view/module.generator.js +0 -39
  114. package/dist/generators/indices/view/service.generator.d.ts +0 -9
  115. package/dist/generators/indices/view/service.generator.js +0 -34
  116. package/dist/generators/models/admin.page.generator.d.ts +0 -7
  117. package/dist/generators/models/admin.page.generator.js +0 -74
  118. package/dist/generators/models/export/encoder.generator.d.ts +0 -9
  119. package/dist/generators/models/export/encoder.generator.js +0 -51
  120. package/dist/generators/models/import/decoder.generator.d.ts +0 -9
  121. package/dist/generators/models/import/decoder.generator.js +0 -148
  122. package/dist/generators/models/react/context.generator.d.ts +0 -9
  123. package/dist/generators/models/react/context.generator.js +0 -71
  124. package/dist/generators/models/react/index.d.ts +0 -10
  125. package/dist/generators/models/react/index.js +0 -31
  126. package/dist/generators/models/react/library.generator.d.ts +0 -10
  127. package/dist/generators/models/react/library.generator.js +0 -94
  128. package/dist/generators/models/react/lookup.generator.d.ts +0 -9
  129. package/dist/generators/models/react/lookup.generator.js +0 -175
  130. package/dist/generators/models/react/modals.generator.d.ts +0 -23
  131. package/dist/generators/models/react/modals.generator.js +0 -710
  132. package/dist/generators/models/repository.generator.d.ts +0 -9
  133. package/dist/generators/models/repository.generator.js +0 -955
  134. package/dist/generators/models/route.generator.d.ts +0 -9
  135. package/dist/generators/models/route.generator.js +0 -92
  136. package/dist/generators/models/seed.generator.d.ts +0 -21
  137. package/dist/generators/models/seed.generator.js +0 -285
  138. package/dist/generators/models/stub.generator.d.ts +0 -9
  139. package/dist/generators/models/stub.generator.js +0 -92
  140. package/dist/generators/models/types.generator.d.ts +0 -9
  141. package/dist/generators/models/types.generator.js +0 -125
  142. package/dist/generators/models/update/service.generator.d.ts +0 -10
  143. package/dist/generators/models/update/service.generator.js +0 -302
  144. package/dist/generators/models/view/service.generator.d.ts +0 -10
  145. package/dist/generators/models/view/service.generator.js +0 -239
  146. package/dist/lib/attributes.d.ts +0 -114
  147. package/dist/lib/attributes.js +0 -2
  148. package/dist/lib/exports.d.ts +0 -45
  149. package/dist/lib/exports.js +0 -90
  150. package/dist/lib/imports.d.ts +0 -65
  151. package/dist/lib/imports.js +0 -114
  152. package/dist/lib/meta.d.ts +0 -1191
  153. package/dist/lib/meta.js +0 -434
  154. package/dist/lib/schema/fields.d.ts +0 -46
  155. package/dist/lib/schema/fields.js +0 -62
  156. package/dist/lib/schema/schema.d.ts +0 -466
  157. package/dist/lib/schema/schema.js +0 -18
  158. package/dist/lib/schema/types.d.ts +0 -201
  159. package/dist/lib/schema/types.js +0 -112
  160. package/dist/lib/serializer.d.ts +0 -15
  161. package/dist/lib/serializer.js +0 -24
  162. package/dist/lib/test-id-collector.d.ts +0 -42
  163. package/dist/lib/test-id-collector.js +0 -53
  164. package/dist/lib/types.d.ts +0 -7
  165. package/dist/lib/types.js +0 -13
  166. package/dist/lib/typescript.d.ts +0 -5
  167. package/dist/lib/typescript.js +0 -22
  168. package/dist/lib/utils/ast.d.ts +0 -29
  169. package/dist/lib/utils/ast.js +0 -23
  170. package/dist/lib/utils/error.d.ts +0 -17
  171. package/dist/lib/utils/error.js +0 -52
  172. package/dist/lib/utils/file.d.ts +0 -10
  173. package/dist/lib/utils/file.js +0 -56
  174. package/dist/lib/utils/jsdoc.d.ts +0 -9
  175. package/dist/lib/utils/jsdoc.js +0 -37
  176. package/dist/lib/utils/logger.d.ts +0 -17
  177. package/dist/lib/utils/logger.js +0 -12
  178. package/dist/lib/utils/string.d.ts +0 -40
  179. package/dist/lib/utils/string.js +0 -187
  180. package/dist/lib/utils/types.d.ts +0 -12
  181. package/dist/lib/utils/types.js +0 -2
  182. package/dist/lib/zod.d.ts +0 -8
  183. package/dist/lib/zod.js +0 -60
  184. package/dist/prisma/attributes.d.ts +0 -21
  185. package/dist/prisma/attributes.js +0 -175
  186. package/dist/prisma/client-path.d.ts +0 -7
  187. package/dist/prisma/client-path.js +0 -29
  188. package/dist/prisma/parse.d.ts +0 -12
  189. package/dist/prisma/parse.js +0 -452
@@ -1,302 +0,0 @@
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.generateModelBusinessLogicUpdate = void 0;
7
- const assert_1 = __importDefault(require("assert"));
8
- const imports_1 = require("../../../lib/imports");
9
- const meta_1 = require("../../../lib/meta");
10
- const fields_1 = require("../../../lib/schema/fields");
11
- const types_1 = require("../../../lib/schema/types");
12
- const types_2 = require("../../../lib/types");
13
- const typescript_1 = require("../../../lib/typescript");
14
- const jsdoc_1 = require("../../../lib/utils/jsdoc");
15
- const zod_1 = require("../../../lib/zod");
16
- /**
17
- * Generates update business logic for a given model.
18
- * The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
19
- */
20
- function generateModelBusinessLogicUpdate({ model, meta }) {
21
- const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
22
- const { view, update, types, data } = meta;
23
- const imports = imports_1.ImportsGenerator.from(meta.update.serviceClassLocation.path).addImports({
24
- [data.repository.location.import]: data.repository.className,
25
- [types.importPath]: [model.brandedIdType, types.typeName, types.toBrandedIdTypeFnName, (0, types_1.toTypeName)('User')],
26
- [view.serviceLocation.import]: [view.serviceClassName],
27
- [schemaMeta.actions.execution.interfaceLocation.import]: [schemaMeta.actions.execution.interface],
28
- [schemaMeta.actions.dispatcher.definitionLocation.import]: [schemaMeta.actions.dispatcher.definition],
29
- [schemaMeta.update.serviceLocation.path]: schemaMeta.update.serviceClassName,
30
- [schemaMeta.view.serviceLocation.import]: schemaMeta.view.serviceClassName,
31
- });
32
- for (const field of (0, fields_1.getRelationFields)(model)) {
33
- // NOTE: We add `toBrandedType` functions for foreign models for decoders.
34
- if (field.relationToModel.typeName === model.typeName) {
35
- continue;
36
- }
37
- const refModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
38
- imports.addImport({
39
- from: refModelMeta.types.importPath,
40
- items: [refModelMeta.types.toBrandedIdTypeFnName],
41
- });
42
- }
43
- const cloneFn = generateCloneFn({ model, meta, imports });
44
- return /* ts */ `
45
- import { Inject, Injectable, forwardRef } from '@nestjs/common'
46
- import { z } from 'zod'
47
-
48
- ${imports.generate()}
49
-
50
- import { TRPCError } from '@trpc/server'
51
-
52
- export type Scope = "${meta.actions.actionScopeConstType}"
53
-
54
- export type Actions = {
55
- ${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
56
- create: {
57
- payload: CreatePayload
58
- result: ${types.typeName}
59
- }
60
-
61
- ${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
62
- update: {
63
- payload: UpdatePayload
64
- result: ${types.typeName}
65
- }
66
-
67
- ${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
68
- upsert: {
69
- payload: UpsertPayload
70
- result: ${types.typeName}
71
- }
72
-
73
- ${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} and returns its id.`])}
74
- delete: {
75
- payload: ${model.brandedIdType}
76
- result: ${model.brandedIdType}
77
- }
78
- }
79
-
80
- /**
81
- * Zod decoder for validating the create input of a ${meta.userFriendlyName}.
82
- */
83
- export const ${meta.update.createInputDecoder} = z.object({
84
- ${model.fields
85
- .filter((f) => !f.attributes.isReadonly)
86
- .map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f })}`)
87
- .join(',')}
88
- })
89
-
90
- type CreatePayload = z.infer<typeof ${meta.update.createInputDecoder}>
91
-
92
- /**
93
- * Zod decoder for validating the update input of a ${meta.userFriendlyName} .
94
- */
95
- export const ${meta.update.updateInputDecoder} = z.object({
96
- ${model.fields
97
- .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
98
- .map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
99
- .join(',')}
100
- })
101
-
102
- type UpdatePayload = z.infer<typeof ${meta.update.updateInputDecoder}>
103
-
104
- /**
105
- * Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
106
- */
107
- export const ${meta.update.upsertInputDecoder} = z.union([
108
- ${meta.update.updateInputDecoder},
109
- ${meta.update.createInputDecoder}
110
- ])
111
-
112
- type UpsertPayload = z.infer<typeof ${meta.update.upsertInputDecoder}>
113
-
114
- export type ${update.serviceInterfaceName} = ${schemaMeta.actions.dispatcher.definition}<Actions>
115
-
116
- @Injectable()
117
- export class ${update.serviceClassName} implements ${update.serviceInterfaceName} {
118
-
119
- /**
120
- * Instance of the ${meta.userFriendlyName} view service for convenience.
121
- */
122
- private view: ${view.serviceClassName}
123
-
124
- constructor(
125
- private readonly data: ${data.repository.className},
126
-
127
- @Inject(forwardRef(() => ${schemaMeta.update.serviceClassName}))
128
- private readonly updateService: ${schemaMeta.update.serviceClassName},
129
-
130
- @Inject(forwardRef(() => ${schemaMeta.view.serviceClassName}))
131
- private readonly viewService: ${schemaMeta.view.serviceClassName}
132
- ) {
133
- this.view = this.viewService.${view.serviceVariableName}
134
- }
135
-
136
- ${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
137
- public async create({ data, execution }: {
138
- data: CreatePayload;
139
- execution: ${schemaMeta.actions.execution.interface}
140
- }): Promise<${types.typeName}> {
141
- // NOTE: User from execution.user should be authorized to create this item.
142
- // eslint-disable-next-line no-constant-condition
143
- if (false) {
144
- throw new TRPCError({
145
- code: 'UNAUTHORIZED',
146
- message: \`You are not authorized to create a ${meta.userFriendlyName}\`,
147
- })
148
- }
149
-
150
- return this.data.create({ item: data, execution })
151
- }
152
-
153
- ${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
154
- public async update({ data, execution }: {
155
- data: UpdatePayload;
156
- execution: ${schemaMeta.actions.execution.interface}
157
- }): Promise<${types.typeName}> {
158
- // NOTE: We need to make sure that the user is authorized to access the item
159
- await this.authorize(data.id, execution.user)
160
-
161
- return this.data.update({ item: data, execution })
162
- }
163
-
164
- ${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
165
- public async upsert({ data, execution }: {
166
- data: UpsertPayload;
167
- execution: ${schemaMeta.actions.execution.interface}
168
- }): Promise<${types.typeName}> {
169
- if ('id' in data) {
170
- await this.authorize(data.id, execution.user)
171
- } else {
172
- // eslint-disable-next-line no-constant-condition
173
- if (false) {
174
- throw new TRPCError({
175
- code: 'UNAUTHORIZED',
176
- message: \`You are not authorized to create a ${meta.userFriendlyName}\`,
177
- })
178
- }
179
- }
180
-
181
- return this.data.upsert({ item: data, execution })
182
- }
183
-
184
- ${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} instance and returns its id.`])}
185
- public async delete({ data, execution }: {
186
- data: ${model.brandedIdType};
187
- execution: ${schemaMeta.actions.execution.interface}
188
- }): Promise<${model.brandedIdType}> {
189
- // NOTE: We need to make sure that the user is authorized to access the item
190
- await this.authorize(data, execution.user)
191
-
192
- return this.data.delete({ id: data, execution })
193
- }
194
-
195
- ${cloneFn}
196
-
197
- /**
198
- * Authorizes access to ${meta.userFriendlyName}.
199
- */
200
- public async authorize(id: ${model.brandedIdType}, user: User): Promise<void> {
201
- // NOTE: Root user is always authorized.
202
- if (this.viewService.users.data.rootUser.id === user.id) {
203
- return
204
- }
205
- const item = await this.data.get(id)
206
- if (!item) {
207
- throw new Error(\`${meta.userFriendlyName} with id \${id} not found\`)
208
- }
209
- // eslint-disable-next-line no-constant-condition
210
- if (false) {
211
- throw new TRPCError({
212
- code: 'UNAUTHORIZED',
213
- message: \`You are not authorized to access ${meta.userFriendlyName} with id \${id}\`,
214
- })
215
- }
216
- }
217
- }
218
- `;
219
- }
220
- exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
221
- function generateCloneFn({ model, meta, imports }) {
222
- const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
223
- for (const enumField of (0, fields_1.getEnumFields)(model)) {
224
- const enumMeta = (0, meta_1.getEnumMetadata)(enumField);
225
- imports.addTypeImport({
226
- from: enumMeta.types.importPath,
227
- items: [enumField.typeName],
228
- });
229
- }
230
- const fnInputFields = model.fields
231
- .filter((f) => {
232
- switch (f.kind) {
233
- case 'id':
234
- case 'scalar':
235
- case 'enum':
236
- return true;
237
- case 'relation':
238
- return false;
239
- default:
240
- throw new types_2.ExhaustiveSwitchCheck(f);
241
- }
242
- })
243
- .map((f) => {
244
- const type = (0, typescript_1.getFieldType)(f);
245
- switch (f.kind) {
246
- case 'id':
247
- return `${f.name}: ${type}`;
248
- case 'scalar':
249
- case 'enum':
250
- if (f.isUnique) {
251
- // NOTE: `unique` fields require a new value.
252
- if (f.isRequired) {
253
- return `${f.name}: ${type}`;
254
- }
255
- return `${f.name}: ${type} | null`;
256
- }
257
- // NOTE: Non-unique fields can be copied from the source.
258
- if (f.isRequired) {
259
- return `${f.name}?: ${type}`;
260
- }
261
- return `${f.name}?: ${type} | null`;
262
- case 'relation':
263
- (0, assert_1.default)(false);
264
- break;
265
- default:
266
- throw new types_2.ExhaustiveSwitchCheck(f);
267
- }
268
- });
269
- const foreignKeyMappings = (0, fields_1.getRelationFields)(model).map((f) => {
270
- if (f.isRequired) {
271
- return `${f.name}: mappings.get({ model: '${f.relationToModel.typeName}', id: item.${f.name} })`;
272
- }
273
- return `${f.name}: item.${f.name} ? mappings.get({ model: '${f.relationToModel.typeName}', id: item.${f.name} }) : null`;
274
- });
275
- if (foreignKeyMappings.length > 0) {
276
- imports.addImports({
277
- [schemaMeta.types.importPath]: [schemaMeta.types.idTypesIndex],
278
- [(0, types_1.toPackageName)('@postxl/runtime')]: [(0, types_1.toClassName)('TypedMapping')],
279
- });
280
- }
281
- return `
282
- ${(0, jsdoc_1.toJsDocComment)([`Clones a ${meta.userFriendlyName} with mapped foreign ids.`])}
283
- public async clone(
284
- { data, execution }: {
285
- data: { ${fnInputFields.join('; ')} },
286
- execution: ${schemaMeta.actions.execution.interface}
287
- },
288
- ${foreignKeyMappings.length > 0 ? `mappings = new TypedMapping<${schemaMeta.types.idTypesIndex}>()` : ''}
289
- ): Promise<${meta.types.typeName}> {
290
- const clone = await this.data.clone({
291
- id: data.id,
292
- item: (${foreignKeyMappings.length > 0 ? 'item' : ''}) => ({
293
- ...data,
294
- ${foreignKeyMappings.join(',\n')}
295
- }),
296
- execution
297
- })
298
-
299
- return clone
300
- }
301
- `;
302
- }
@@ -1,10 +0,0 @@
1
- import { ModelMetaData } from '../../../lib/meta';
2
- import { Model } from '../../../lib/schema/schema';
3
- /**
4
- * Generates view business logic for a given model.
5
- * The view logic exposes all information and links of a model. See template's readme for more info.
6
- */
7
- export declare function generateModelBusinessLogicView({ model, meta }: {
8
- model: Model;
9
- meta: ModelMetaData;
10
- }): string;
@@ -1,239 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateModelBusinessLogicView = void 0;
4
- const imports_1 = require("../../../lib/imports");
5
- const meta_1 = require("../../../lib/meta");
6
- const fields_1 = require("../../../lib/schema/fields");
7
- const types_1 = require("../../../lib/schema/types");
8
- const ast_1 = require("../../../lib/utils/ast");
9
- /**
10
- * Generates view business logic for a given model.
11
- * The view logic exposes all information and links of a model. See template's readme for more info.
12
- */
13
- function generateModelBusinessLogicView({ model, meta }) {
14
- const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
15
- const imports = imports_1.ImportsGenerator.from(meta.view.serviceLocation.path);
16
- imports.addImports({
17
- [meta.data.repository.location.import]: meta.data.repository.className,
18
- [meta.types.importPath]: [
19
- (0, types_1.toAnnotatedTypeName)(model.brandedIdType),
20
- (0, types_1.toAnnotatedTypeName)(meta.types.typeName),
21
- (0, types_1.toAnnotatedTypeName)((0, types_1.toTypeName)('User')),
22
- ],
23
- [schemaMeta.view.serviceLocation.path]: schemaMeta.view.serviceClassName,
24
- });
25
- const compareFnBlock = (0, ast_1.createSwitchStatement)({
26
- field: 'field',
27
- cases: (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'string' }).map((f) => ({
28
- match: `"${f.name}"`,
29
- block: `return (a[field] || '').localeCompare(b[field] || '')`,
30
- })),
31
- defaultBlock: 'return 0',
32
- });
33
- const stringFieldFilters = (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'string' }).map((f) => {
34
- return {
35
- match: `"${f.name}"`,
36
- block: `
37
- if (typeof value !== 'string') {
38
- return false
39
- }
40
-
41
- switch (operator) {
42
- case 'contains': {
43
- return (item[field] || '').toLowerCase().includes(value.toLowerCase())
44
- }
45
- default: {
46
- return false
47
- }
48
- }
49
- `,
50
- };
51
- });
52
- const numberFieldsFilters = (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'number' }).map((f) => {
53
- return {
54
- match: `"${f.name}"`,
55
- block: `
56
- const toCompare = item[field]
57
- if (typeof value !== 'number' || toCompare === null) {
58
- return false
59
- }
60
-
61
- switch (operator) {
62
- case 'eq': {
63
- return item[field] === value
64
- }
65
- case 'gt': {
66
- return toCompare > value
67
- }
68
- case 'lt': {
69
- return toCompare < value
70
- }
71
- default: {
72
- return false
73
- }
74
- }
75
- `,
76
- };
77
- });
78
- const filterFnBlock = (0, ast_1.createSwitchStatement)({
79
- field: 'field',
80
- cases: [...stringFieldFilters, ...numberFieldsFilters],
81
- defaultBlock: 'return false',
82
- });
83
- return /* ts */ `
84
- /* eslint-disable @typescript-eslint/no-unused-vars */
85
- import z from 'zod'
86
-
87
- import { Inject, Injectable, forwardRef } from '@nestjs/common'
88
-
89
- ${imports.generate()}
90
-
91
- import { TRPCError } from '@trpc/server'
92
-
93
-
94
- /**
95
- * Cursor decoder.
96
- */
97
- export const ${meta.view.cursorDecoder} = z.object({ startRow: z.number(), endRow: z.number() })
98
-
99
- type Cursor = z.infer<typeof ${meta.view.cursorDecoder}>
100
-
101
- /**
102
- * Filter operator decoder.
103
- */
104
- export const ${meta.view.filterOperatorDecoder} = z.enum([
105
- 'eq',
106
- 'neq',
107
- 'gt',
108
- 'gte',
109
- 'lt',
110
- 'lte',
111
- 'in',
112
- 'nin',
113
- 'contains',
114
- 'ncontains',
115
- 'starts',
116
- 'ends',
117
- ])
118
-
119
- type FilterOperator = z.infer<typeof ${meta.view.filterOperatorDecoder}>
120
-
121
- @Injectable()
122
- export class ${meta.view.serviceClassName} {
123
- constructor(
124
- public readonly data: ${meta.data.repository.className},
125
- @Inject(forwardRef(() => ${schemaMeta.view.serviceClassName}))
126
- private readonly viewService: ${schemaMeta.view.serviceClassName}
127
- ) {}
128
-
129
- /**
130
- * Returns the raw ${meta.userFriendlyName} with the given id or null if it does not exist.
131
- * Raw: The ${meta.userFriendlyName} only contains linked Ids, not the linked items themselves.
132
- */
133
- public async get({ id, user }: { id: ${model.brandedIdType}, user: User }): Promise<${meta.types.typeName} | null> {
134
- const item = await this.data.get(id)
135
- if (!item) {
136
- return null
137
- }
138
-
139
- // NOTE: Authorizing user to access the item.
140
- await this.authorize({ item, user })
141
-
142
- return item
143
- }
144
-
145
- /**
146
- * Returns a map of all ${meta.userFriendlyNamePlural}.
147
- */
148
- public async getAll(user: User): Promise<Map<${meta.types.brandedIdType}, ${model.typeName}>> {
149
- const result = await this.data.getAll()
150
-
151
- // NOTE: Removing non-authorized items from the result.
152
- for (const [key, value] of result.entries()) {
153
- try {
154
- await this.authorize({ item: value, user })
155
- } catch (e) {
156
- result.delete(key)
157
- }
158
- }
159
-
160
- return result
161
- }
162
-
163
- /**
164
- * Returns a list of filtered, sorted and paginated ${meta.userFriendlyNamePlural}.
165
- */
166
- public async getList({
167
- filter,
168
- sort,
169
- cursor,
170
- user,
171
- }: {
172
- filter?: { field: keyof ${model.typeName}; operator: FilterOperator; value: string | number }
173
- sort?: { field: keyof ${model.typeName}; ascending: boolean }
174
- cursor?: Cursor
175
- user: User,
176
- },
177
- ) {
178
- const items = await this.data.getAll()
179
-
180
- // NOTE: Removing non-authorized items from the result.
181
- for (const [key, value] of items.entries()) {
182
- try {
183
- await this.authorize({ item: value, user })
184
- } catch (e) {
185
- items.delete(key)
186
- }
187
- }
188
- const authorized = [...items.values()]
189
-
190
- const filtered = !filter
191
- ? authorized
192
- : authorized.filter((item) => filterFn(item, filter.field, filter.operator, filter.value))
193
-
194
- const filteredAndSorted = !sort
195
- ? filtered
196
- : filtered.sort((a, b) => (sort.ascending ? compare(a, b, sort.field) : -compare(a, b, sort.field)))
197
-
198
- const paginated = !cursor ? filteredAndSorted : filteredAndSorted.slice(cursor.startRow, cursor.endRow)
199
- return { rows: paginated, count: authorized.length }
200
- }
201
-
202
- /**
203
- * Authorizes access to ${meta.userFriendlyName}.
204
- */
205
- // eslint-disable-next-line @typescript-eslint/require-await
206
- public async authorize({ item, user}: { item: ${model.typeName}, user: User }): Promise<void> {
207
- // eslint-disable-next-line no-constant-condition
208
- if (false) {
209
- throw new TRPCError({
210
- code: 'UNAUTHORIZED',
211
- message: \`You are not authorized to access ${meta.userFriendlyName} with id \${item.id}\`,
212
- })
213
- }
214
- }
215
- }
216
-
217
- // Utility Functions
218
-
219
- /**
220
- * Compares two ${model.typeName} instances by the given field.
221
- */
222
- function compare(a: ${model.typeName}, b: ${model.typeName}, field: keyof ${model.typeName}) {
223
- ${compareFnBlock}
224
- }
225
-
226
- /**
227
- * Filters the given ${model.typeName} by the given field, using provided operator and value.
228
- */
229
- function filterFn(
230
- item: ${model.typeName},
231
- field: keyof ${model.typeName},
232
- operator: FilterOperator,
233
- value: string | number
234
- ): boolean {
235
- ${filterFnBlock}
236
- }
237
- `;
238
- }
239
- exports.generateModelBusinessLogicView = generateModelBusinessLogicView;
@@ -1,114 +0,0 @@
1
- export type AttributeValue = unknown;
2
- export type Attributes = Record<string, AttributeValue>;
3
- export type ModelAttributes = {
4
- /**
5
- * Schema tag: ´@@Ignore()`
6
- */
7
- ignore: boolean;
8
- /**
9
- * Schema tag: ´@@Description("Description of the model")`
10
- */
11
- description?: string;
12
- /**
13
- * Schema tag: ´@@Schema("Configuration")`
14
- * The database schema that the model belongs to.
15
- * @internal
16
- * Note: Prisma has it's own schema attribute - but does not expose it in the DMMF.
17
- */
18
- databaseSchema: string;
19
- /**
20
- * Schema tag: ´@@Index()`
21
- * Creates an index on the given fields.
22
- */
23
- index?: string[];
24
- /**
25
- * Schema tag: ´@@Seed()`
26
- * Seed to use for random generation.
27
- */
28
- randomSeed?: number;
29
- /**
30
- * Schema tag: ´@@SystemUser()`
31
- * The user that is used for system actions.
32
- */
33
- systemUser?: object;
34
- };
35
- export type FieldAttributes = {
36
- /**
37
- * Schema tag: ´@@Ignore()`
38
- *
39
- * Field will be ignored by the generator and not be exposed from the database.
40
- */
41
- ignore: boolean;
42
- /**
43
- * Schema tag: ´@@Readonly()`
44
- *
45
- * Field is generated by the database and shall not be edited by the user. It is readable though.
46
- */
47
- isReadonly: boolean;
48
- /**
49
- * Derived from Prisma's @updatedAt attribute.
50
- *
51
- * Field represents the last time the record was updated.
52
- */
53
- isUpdatedAt: boolean;
54
- /**
55
- * Automatically set is field name is "createdAt".
56
- * Field represents the time the record was created.
57
- */
58
- isCreatedAt: boolean;
59
- /**
60
- * Schema tag: ´@@Description("Description of the field")`
61
- *
62
- * The description that is generated as a JSDoc comment in the code.
63
- */
64
- description?: string;
65
- /**
66
- * Schema tag: ´@@Examples("Example1", "Example2")` or `@@Example("Example1")`
67
- *
68
- * Examples that are generated as a JSDoc comment in the code and used as seed/test data.
69
- */
70
- examples?: (string | number | boolean | null)[];
71
- /**
72
- * Schema tag: ´@@DefaultField()`
73
- * The property of the model that identifies the default row.
74
- *
75
- * If this is set, the repository will verify that exactly one record has this field set to true - and use it as the default record.
76
- */
77
- isDefaultField?: boolean;
78
- /**
79
- * Schema tag: `@@MaxLength(int)`
80
- * The maximum length of a string.
81
- */
82
- maxLength?: number;
83
- /**
84
- * Schema tag: `@@IsNameField()`
85
- * The field that should be used as the default label for the model.
86
- *
87
- * If this is set, the repository will verify that exactly one record has this field set to true - and use it as the default label.
88
- *
89
- * If this attribute is set, this field will be used in the code/UI as the field that specifies the model's name. If not provided, we check for the existence of the`name` field. If that is not found, we use the `id` field as the name field.
90
- */
91
- isNameField?: boolean;
92
- /**
93
- * Schema tag: `@@Label("Label")`
94
- * The human readable label/name of the field.
95
- *
96
- * If not provided, we use the field name.
97
- */
98
- label: string;
99
- };
100
- export type EnumAttributes = {
101
- /**
102
- * The description of the enum.
103
- * Schema tag: ´@@Description("Description of the model")`
104
- */
105
- description?: string;
106
- /**
107
- * A dictionary of value descriptions.
108
- *
109
- * Note: Unfortunately, the DMMF does not support attributes for Enum values. So we use an attribute on the enum itself to define the descriptions.
110
- *
111
- * Schema tag: ´@@Schema("ValueDescription")`
112
- */
113
- valueDescription?: Record<string, string>;
114
- };
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });