@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,573 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateImportService = void 0;
4
- const imports_1 = require("../../../lib/imports");
5
- const meta_1 = require("../../../lib/meta");
6
- const types_1 = require("../../../lib/schema/types");
7
- const string_1 = require("../../../lib/utils/string");
8
- /**
9
- * Generates the Import Service class for the Import module
10
- */
11
- function generateImportService({ models, meta }) {
12
- const imports = imports_1.ImportsGenerator.from(meta.import.importService.location.path);
13
- const { types, decoder, converterFunctions } = meta.import;
14
- const { delta_Fields, delta, delta_Model } = types;
15
- const { create, errors, unchanged, update } = delta_Model;
16
- const { nonUnique, invalidReference, invalidType, isRequiredDependency, missingField } = errors;
17
- const { dto } = meta.types;
18
- imports.addImports({
19
- [meta.data.dataService.location.import]: [meta.data.dataService.class],
20
- [meta.data.types.location.import]: [(0, types_1.toAnnotatedTypeName)(meta.data.types.bulkMutation)],
21
- [meta.types.importPath]: [
22
- (0, types_1.toAnnotatedTypeName)(dto.genericModel),
23
- (0, types_1.toAnnotatedTypeName)(dto.idType),
24
- (0, types_1.toAnnotatedTypeName)(dto.update),
25
- ],
26
- [meta.actions.execution.interfaceLocation.import]: [meta.actions.execution.interface],
27
- [meta.actions.dispatcher.classLocation.import]: [meta.actions.dispatcher.class],
28
- [types.location.path]: [
29
- (0, types_1.toAnnotatedTypeName)(delta),
30
- (0, types_1.toAnnotatedTypeName)(delta_Fields),
31
- (0, types_1.toAnnotatedTypeName)(delta_Model.type),
32
- (0, types_1.toAnnotatedTypeName)(delta_Model.errors.invalidReference.type),
33
- (0, types_1.toAnnotatedTypeName)(delta_Model.errors.isRequiredDependency.type),
34
- ],
35
- [decoder.location.path]: [(0, types_1.toAnnotatedTypeName)(decoder.decodedPXLModelDataTypeName)],
36
- [converterFunctions.location.path]: [converterFunctions.deltaToBulkMutations],
37
- });
38
- const resultAssignments = [];
39
- const detectDeltaFunctions = [];
40
- for (const model of models) {
41
- const modelMeta = (0, meta_1.getModelMetadata)({ model });
42
- imports.addTypeImport({
43
- from: modelMeta.types.importPath,
44
- items: [modelMeta.types.typeName, modelMeta.types.brandedIdType],
45
- });
46
- resultAssignments.push(`${modelMeta.seed.constantName}: await this.detect${modelMeta.internalSingularNameCapitalized}Delta(data.${modelMeta.seed.constantName}),`);
47
- detectDeltaFunctions.push(generateDetectDeltaFunction({ model, modelMeta, models, schemaMeta: meta, imports }));
48
- }
49
- return /* ts */ `
50
- import { Injectable } from '@nestjs/common'
51
- import { ExhaustiveSwitchCheck } from '@postxl/runtime'
52
-
53
- ${imports.generate()}
54
-
55
- import { Action_Import } from './actions'
56
-
57
-
58
- type Delta_Result<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> =
59
- | { type: '${create.discriminant}' }
60
- | { type: '${update.discriminant}'; delta: ${delta_Fields}<Model, ID>; existingItem: Model }
61
- | { type: '${delta_Model.delete.discriminant}'; existingItem: Model }
62
- | { type: '${unchanged.discriminant}' }
63
-
64
- @Injectable()
65
- export class ${meta.import.importService.name} {
66
- constructor(
67
- private readonly data: ${meta.data.dataService.class},
68
- private readonly dispatcher: ${meta.actions.dispatcher.class},
69
- ) {
70
- // We have a circular dependency between DispatcherService and ${meta.import.importService.name}.
71
- // In order to avoid trouble, instead of using Nest's forwardRef(), we inject the dispatcher service here
72
- // and set the dispatcher's ${meta.import.importService.sharedName} to this instance.
73
- this.dispatcher.${meta.import.importService.sharedName} =this
74
- }
75
-
76
-
77
- /**
78
- * Will be called by the dispatcher service to dispatch the given action.
79
- */
80
- public async dispatch({
81
- action,
82
- execution
83
- }: {
84
- action: Action_Import;
85
- execution: ${meta.actions.execution.interface}
86
- }) {
87
- switch (action.type) {
88
- case 'detect-delta':
89
- return this.detectDelta(action.payload.data)
90
- case 'execute-upsert':
91
- return this.executeUpsert({ delta: action.payload, execution })
92
- case 'execute-direct-upsert':
93
- return this.executeDirectUpsert({ data: action.payload.data, execution })
94
-
95
- default:
96
- throw new ExhaustiveSwitchCheck(action)
97
- }
98
- }
99
-
100
- public async detectDelta(data: ${decoder.decodedPXLModelDataTypeName}): Promise<{
101
- bulkMutations: ${meta.data.types.bulkMutation}[]
102
- upsertResult: ${delta}
103
- }> {
104
- const upsertResult: ${delta} = {
105
- ${resultAssignments.join('\n')}
106
- }
107
-
108
- const bulkMutations: ${meta.data.types.bulkMutation}[] = ${converterFunctions.deltaToBulkMutations}(upsertResult)
109
- return { bulkMutations, upsertResult }
110
- }
111
-
112
- public async executeUpsert({
113
- delta,
114
- execution
115
- }: {
116
- delta: Delta;
117
- execution: ${meta.actions.execution.interface}
118
- }) {
119
- const bulkMutations = ${converterFunctions.deltaToBulkMutations}(delta)
120
- return this.data.${meta.data.dataService.executeBulkMutations}({ steps: bulkMutations, execution })
121
- }
122
-
123
- public async executeDirectUpsert({
124
- data,
125
- execution
126
- }: {
127
- data: ${meta.import.decoder.decodedPXLModelDataTypeName};
128
- execution: ${meta.actions.execution.interface}
129
- }) {
130
- const { bulkMutations } = await this.detectDelta(data)
131
- return this.data.${meta.data.dataService.executeBulkMutations}({ steps: bulkMutations, execution })
132
- }
133
-
134
- /**
135
- * Generic function to determine what action (create/update/delete/unchanged) to take with an item
136
- * In case the type is update it also includes the delta for a given item. In case of delete, it also includes
137
- * the existing item.
138
- *
139
- * NOTE: The function does not implement any logic to automatically determine if an item should be deleted.
140
- * Implement this logic based on the business requirements!
141
- */
142
- private async determineDeltaResult<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
143
- item,
144
- getId,
145
- getDelta,
146
- }: {
147
- item: Model
148
- getId: (id: ID) => Promise<Model | null>
149
- getDelta: ({ item, existingItem }: { item: Model; existingItem: Model }) => ${delta_Fields}<Model, ID>
150
- }): Promise<Delta_Result<Model, ID>> {
151
- if (item.id === undefined || item.id === '') {
152
- return { type: '${create.discriminant}' }
153
- }
154
- const existingItem = await getId(item.id)
155
-
156
- if (!existingItem) {
157
- return { type: '${create.discriminant}' }
158
- }
159
-
160
- const delta = getDelta({ item, existingItem })
161
-
162
- if (Object.keys(delta).length > 0) {
163
- return { type: '${update.discriminant}', delta, existingItem }
164
- }
165
-
166
- // We do not have a default logic to identify deletions. Implement it here, e.g. using a
167
- // custom "Action" field in the Excel table. If it is set to "Delete", we can handle the delete here.
168
- // return {type: '${delta_Model.delete.discriminant}', existingItem}
169
-
170
- // If we reach this point, we assume the item has not changed
171
- return { type: '${unchanged.discriminant}' }
172
- }
173
-
174
- private getDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
175
- item,
176
- existingItem,
177
- properties,
178
- }: {
179
- item: Model
180
- existingItem: Model
181
- properties: (keyof Omit<Model, 'id'>)[]
182
- }): ${delta_Fields}<Model, ID> {
183
- const delta: ${delta_Fields}<Model, ID> = {}
184
-
185
- for (const property of properties) {
186
- addDelta({ delta, existingItem, item, property })
187
- }
188
-
189
- return delta
190
- }
191
-
192
- /**
193
- * Detects changes for a model and returns the result as a Delta_Model object.
194
- */
195
- private async detectModelDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}, ModelErrors>({
196
- items,
197
- getId,
198
- getDelta,
199
- validateCreate,
200
- validateUpdate,
201
- validateDelete,
202
- }: {
203
- items?: Model[]
204
- getId: (id: ID) => Promise<Model | null>
205
- getDelta: (args: { item: Model; existingItem: Model }) => ${delta_Fields}<Model, ID>
206
- validateCreate: (args: { item: Model }) => Promise<ModelErrors[]>
207
- validateUpdate: (args: { item: Model; existingItem: Model }) => Promise<ModelErrors[]>
208
- validateDelete: (args: { existingItem: Model }) => Promise<ModelErrors[]>
209
- }): Promise<Delta_Model<Model, ID, ModelErrors>[]> {
210
- const upsertResult: Delta_Model<Model, ID, ModelErrors>[] = []
211
-
212
- if (items === undefined || items.length === 0) {
213
- return upsertResult
214
- }
215
-
216
- for (const item of items) {
217
- const deltaResult = await this.determineDeltaResult({ item, getId, getDelta })
218
-
219
- switch (deltaResult.type) {
220
- case 'create': {
221
- const errors = await validateCreate({ item })
222
- if (errors.length === 0) {
223
- upsertResult.push({ type: '${create.discriminant}', input: item, createDTO: item })
224
- } else {
225
- upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
226
- }
227
- break
228
- }
229
-
230
- case 'update': {
231
- const errors = await validateUpdate({ item, existingItem: deltaResult.existingItem })
232
- if (errors.length === 0) {
233
- upsertResult.push({
234
- type: '${update.discriminant}',
235
- input: item,
236
- delta: deltaResult.delta,
237
- updateDTO: deltaToUpdateDtoFunction({ id: item.id, delta: deltaResult.delta }),
238
- })
239
- } else {
240
- upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
241
- }
242
- break
243
- }
244
-
245
- case 'delete': {
246
- const errors = await validateDelete({ existingItem: deltaResult.existingItem })
247
- if (errors.length === 0) {
248
- upsertResult.push({ type: '${delta_Model.delete.discriminant}', input: item })
249
- } else {
250
- upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
251
- }
252
- break
253
- }
254
-
255
- case 'unchanged': {
256
- upsertResult.push({ type: '${unchanged.discriminant}', input: item })
257
- break
258
- }
259
-
260
- default:
261
- throw new ExhaustiveSwitchCheck(deltaResult)
262
- }
263
- }
264
-
265
- return upsertResult
266
- }
267
-
268
- /**
269
- * Internal helper function that removes undefined values from an array.
270
- */
271
- private keepErrors<O, I extends O | undefined>(errors: I[]): O[] {
272
- return errors.filter((error) => error !== undefined) as O[]
273
- }
274
-
275
- private validateRequiredFields<
276
- Model extends ${dto.genericModel}<ID>,
277
- ID extends ${dto.idType},
278
- FieldName extends Extract<keyof Omit<Model, 'id'>, string>
279
- >({
280
- item,
281
- fieldNames,
282
- }: {
283
- item: Model
284
- fieldNames: FieldName[]
285
- }): ${missingField.type}<FieldName>[] {
286
- const errors: ${missingField.type}<FieldName>[] = []
287
- for (const fieldName of fieldNames) {
288
- if (item[fieldName] === undefined) {
289
- errors.push({ error: '${missingField.discriminant}', fieldName })
290
- }
291
- }
292
- if (errors.length > 0) {
293
- return errors
294
- } else {
295
- return []
296
- }
297
- }
298
-
299
- private async validateReferenceField<
300
- Model extends ${dto.genericModel}<ID>,
301
- ID extends ${dto.idType},
302
- RelatedModel extends ${dto.genericModel}<RelatedID>,
303
- RelatedID extends ${dto.idType},
304
- FieldName extends keyof Omit<Model, 'id'> & string,
305
- Value extends RelatedID,
306
- RelatedModelName extends string,
307
- >({
308
- item,
309
- fieldName,
310
- relatedModel,
311
- getExistingItem,
312
- }: {
313
- item: Partial<Model>
314
- fieldName: FieldName
315
- relatedModel: RelatedModelName
316
- getExistingItem: (id: RelatedID) => Promise<RelatedModel | null>
317
- }): Promise<${invalidReference.type}<RelatedModelName, FieldName, Value> | undefined> {
318
- const value: Value | undefined = item[fieldName] as Value | undefined
319
- if (value === undefined) {
320
- return undefined
321
- }
322
- const existingItem = await getExistingItem(value)
323
- if (!existingItem) {
324
- return { error: '${invalidReference.discriminant}', relatedModel, fieldName, value }
325
- }
326
- return undefined
327
- }
328
-
329
- private async validateUniqueField<
330
- Model extends ${dto.genericModel}<ID>,
331
- ID extends ${dto.idType},
332
- FieldName extends keyof Omit<Model, 'id'> & string,
333
- Value extends Model[FieldName],
334
- >({
335
- item,
336
- fieldName,
337
- getExistingItem,
338
- }: {
339
- item: Partial<Model>
340
- fieldName: FieldName
341
- getExistingItem: (fieldValue: Value) => Promise<Model | undefined>
342
- }): Promise<${nonUnique.type}<FieldName, Value> | undefined> {
343
- const value: Value | undefined = item[fieldName] as Value | undefined
344
- if (value === undefined) {
345
- return undefined
346
- }
347
- const existingItem = await getExistingItem(value)
348
- if (existingItem) {
349
- return { error: '${nonUnique.discriminant}', fieldName, value }
350
- }
351
- return undefined
352
- }
353
-
354
- private validateInt<
355
- Model extends ${dto.genericModel}<ID>,
356
- ID extends ${dto.idType},
357
- FieldName extends keyof Omit<Model, 'id'> & string,
358
- >({
359
- item,
360
- fieldName,
361
- }: {
362
- item: Model
363
- fieldName: FieldName
364
- }): ${invalidType.type}<FieldName, 'Int', number> | undefined {
365
- const value: number | undefined | null = item[fieldName] as number | undefined | null
366
- //we handle undefined and null in other value checks so we can ignore them here
367
- if (value === undefined || value === null) {
368
- return undefined
369
- }
370
-
371
- if (value !== Math.floor(value)) {
372
- return { error: '${invalidType.discriminant}', fieldName, typeExpected: 'Int', value }
373
- }
374
- return undefined
375
- }
376
-
377
- private async validateRequiredDependency<
378
- Model extends ${dto.genericModel}<ID>,
379
- ID extends ${dto.idType},
380
- RelatedModelName extends string,
381
- RelatedField extends string,
382
- RelatedModel extends ${dto.genericModel}<RelatedID>,
383
- RelatedID extends ${dto.idType},
384
- >({
385
- item,
386
- relatedModel,
387
- relatedField,
388
- getReferencedItems,
389
- }: {
390
- item: Model
391
- relatedModel: RelatedModelName
392
- relatedField: RelatedField
393
- getReferencedItems: (id: ID) => Promise<RelatedModel[]>
394
- }): Promise<
395
- ${isRequiredDependency.type}<RelatedModelName, RelatedField, RelatedModel, RelatedID> | undefined
396
- > {
397
- const relatedItems = await getReferencedItems(item.id)
398
- if (relatedItems.length > 0) {
399
- return undefined
400
- }
401
- return { error: '${isRequiredDependency.discriminant}', relatedModel, relatedField, relatedItems }
402
- }
403
-
404
- ${detectDeltaFunctions.join('\n')}
405
- }
406
-
407
- /**
408
- * Adds a delta entry for a property to the given delta object if the property
409
- * of the item is different from the existing item
410
- */
411
- function addDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
412
- delta,
413
- existingItem,
414
- item,
415
- property,
416
- }: {
417
- delta: ${delta_Fields}<Model, ID>
418
- existingItem: Model
419
- item: Model
420
- property: keyof Omit<Model, 'id'>
421
- }): void {
422
- if (existingItem[property] === item[property]) {
423
- return
424
- }
425
- delta[property] = { old: existingItem[property], new: item[property] }
426
- }
427
-
428
- /**
429
- * Converts a Delta to an UpdateDTO.
430
- */
431
- function deltaToUpdateDtoFunction<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
432
- id,
433
- delta,
434
- }: {
435
- id: ID
436
- delta: ${delta_Fields}<Model, ID>
437
- }): ${dto.update}<Model, ID> {
438
- const updateDTO = {
439
- id: id,
440
- } as UpdateDTO<Model, ID>
441
-
442
- for (const [key, value] of Object.entries(delta)) {
443
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
444
- const updatedValue = value.new as Model[keyof Omit<Model, 'id'>]
445
- updateDTO[key as keyof Omit<Model, 'id'>] = updatedValue
446
- }
447
- return updateDTO
448
- }`;
449
- }
450
- exports.generateImportService = generateImportService;
451
- function generateDetectDeltaFunction({ model, modelMeta, models, schemaMeta, imports, }) {
452
- const { types } = schemaMeta.import;
453
- const { delta_Model } = types;
454
- imports.addTypeImport({
455
- from: types.location.path,
456
- items: [modelMeta.import.delta_Model_Errors],
457
- });
458
- const returnType = `${delta_Model.type}<${model.typeName}, ${modelMeta.types.brandedIdType}, ${modelMeta.import.delta_Model_Errors}>[]`;
459
- const sharedValidations = [];
460
- const requiredFields = [];
461
- const fieldNames = [];
462
- for (const field of model.fields) {
463
- if (field.name === 'id' ||
464
- field.attributes.isReadonly ||
465
- field.attributes.isCreatedAt ||
466
- field.attributes.isUpdatedAt) {
467
- continue;
468
- }
469
- const fieldName = field.name;
470
- fieldNames.push(`'${fieldName}'`);
471
- if (field.isRequired) {
472
- requiredFields.push(`'${fieldName}'`);
473
- }
474
- if (field.kind === 'scalar') {
475
- if (field.isUnique) {
476
- imports.addTypeImport({
477
- from: schemaMeta.import.types.location.path,
478
- items: [delta_Model.errors.nonUnique.type],
479
- });
480
- const getByName = `getBy${(0, string_1.toPascalCase)(fieldName)}`;
481
- sharedValidations.push(`this.validateUniqueField({
482
- item,
483
- fieldName: '${fieldName}',
484
- getExistingItem: (value) => this.data.${modelMeta.data.dataServiceName}.${getByName}(value)
485
- })`);
486
- }
487
- if (field.validation && field.validation.type === 'int') {
488
- imports.addTypeImport({
489
- from: schemaMeta.import.types.location.path,
490
- items: [delta_Model.errors.invalidType.type],
491
- });
492
- sharedValidations.push(`this.validateInt({item, fieldName: '${fieldName}'})`);
493
- }
494
- }
495
- else if (field.kind === 'relation') {
496
- const relatedModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
497
- sharedValidations.push(`this.validateReferenceField({
498
- item,
499
- fieldName: '${fieldName}',
500
- relatedModel: '${field.relationToModel.name}',
501
- getExistingItem: (id: ${field.relationToModel.brandedIdType}) => this.data.${relatedModelMeta.data.dataServiceName}.get(id)
502
- })`);
503
- }
504
- }
505
- const deleteValidations = [];
506
- for (const relatedModel of models) {
507
- if (relatedModel.name === model.name) {
508
- continue;
509
- }
510
- for (const relatedField of relatedModel.fields) {
511
- if (relatedField.kind !== 'relation' ||
512
- relatedField.relationToModel.name !== model.name ||
513
- !relatedField.isRequired) {
514
- continue;
515
- }
516
- const relatedModelMeta = (0, meta_1.getModelMetadata)({ model: relatedModel });
517
- const relatedFieldName = (0, string_1.toPascalCase)(relatedField.name);
518
- deleteValidations.push(`
519
- await this.validateRequiredDependency({
520
- item: existingItem,
521
- relatedModel: '${relatedModel.name}',
522
- relatedField: '${relatedField.name}',
523
- getReferencedItems: async (id: ${modelMeta.types.brandedIdType}) => [
524
- ...(await this.data.${relatedModelMeta.data.dataServiceName}.getItemsFor${relatedFieldName}(id)).values()
525
- ]
526
- })`);
527
- }
528
- }
529
- if (requiredFields.length > 0) {
530
- imports.addTypeImport({
531
- from: schemaMeta.import.types.location.path,
532
- items: [delta_Model.errors.missingField.type],
533
- });
534
- }
535
- const requiredFieldsValidation = requiredFields.length > 0
536
- ? `...this.validateRequiredFields({item, fieldNames: [${requiredFields.join(',')}]}),`
537
- : '';
538
- const sharedValidationsFunction = sharedValidations.length > 0
539
- ? `(item: ${model.name}) => Promise.all([${sharedValidations.join(',\n')}])`
540
- : 'async () => Promise.resolve([])';
541
- const validateDelete = deleteValidations.length > 0
542
- ? `async ({ existingItem }) => this.keepErrors([${deleteValidations.join(',\n')}])`
543
- : 'async () => Promise.resolve([])';
544
- return /* ts */ `
545
- /**
546
- * Detects changes for ${modelMeta.userFriendlyName} and returns the result as a ${delta_Model.type} object.
547
- */
548
- private async detect${modelMeta.internalSingularNameCapitalized}Delta(
549
- items?: ${model.typeName}[]
550
- ): Promise<${returnType}> {
551
- const sharedValidations: (item: ${model.name}) => Promise<(${modelMeta.import.delta_Model_Errors} | undefined)[]> =
552
- ${sharedValidationsFunction}
553
-
554
- return this.detectModelDelta({
555
- items,
556
- getId: (id: ${model.brandedIdType}) => this.data.${modelMeta.data.dataServiceName}.get(id),
557
- getDelta: ({ item, existingItem }: { item: ${model.name}; existingItem: ${model.name} }) =>
558
- this.getDelta({
559
- item,
560
- existingItem,
561
- properties: [${fieldNames.join(',')}],
562
- }),
563
- validateCreate: async ({ item }): Promise<${modelMeta.import.delta_Model_Errors}[]> =>
564
- this.keepErrors([
565
- ${requiredFieldsValidation}
566
- ...(await sharedValidations(item)),
567
- ]),
568
- validateUpdate: async ({ item }): Promise<${modelMeta.import.delta_Model_Errors}[]> =>
569
- this.keepErrors(await sharedValidations(item)),
570
- validateDelete: ${validateDelete},
571
- })
572
- }`;
573
- }
@@ -1,9 +0,0 @@
1
- import { SchemaMetaData } from '../../../lib/meta';
2
- import { Model } from '../../../lib/schema/schema';
3
- /**
4
- * Generates types for import module.
5
- */
6
- export declare function generateImportTypes({ models, meta }: {
7
- models: Model[];
8
- meta: SchemaMetaData;
9
- }): string;