@postxl/generator 0.67.0 → 0.69.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 (28) hide show
  1. package/dist/generator.js +0 -10
  2. package/dist/generators/indices/dataservice.generator.js +1 -1
  3. package/dist/generators/indices/dispatcher-service.generator.js +1 -1
  4. package/dist/generators/indices/importexport-convert-import-functions.generator.js +1 -23
  5. package/dist/generators/indices/importexport-exporter-class.generator.js +1 -1
  6. package/dist/generators/indices/importexport-import-service.generator.js +1 -1
  7. package/dist/generators/models/businesslogic-update.generator.js +12 -25
  8. package/dist/generators/models/businesslogic-view.generator.js +30 -2
  9. package/dist/generators/models/importexport-decoder.generator.js +10 -15
  10. package/dist/generators/models/react.generator/context.generator.js +1 -1
  11. package/dist/generators/models/repository.generator.d.ts +0 -7
  12. package/dist/generators/models/repository.generator.js +274 -656
  13. package/dist/generators/models/route.generator.js +11 -8
  14. package/dist/lib/attributes.d.ts +0 -5
  15. package/dist/lib/meta.d.ts +21 -69
  16. package/dist/lib/meta.js +6 -27
  17. package/dist/lib/schema/types.d.ts +8 -1
  18. package/dist/lib/schema/types.js +3 -1
  19. package/dist/prisma/attributes.js +0 -2
  20. package/package.json +1 -1
  21. package/dist/generators/indices/datamock-module.generator.d.ts +0 -9
  22. package/dist/generators/indices/datamock-module.generator.js +0 -64
  23. package/dist/generators/indices/datamocker.generator.d.ts +0 -9
  24. package/dist/generators/indices/datamocker.generator.js +0 -88
  25. package/dist/generators/indices/emptydatabasemigration.generator.d.ts +0 -11
  26. package/dist/generators/indices/emptydatabasemigration.generator.js +0 -34
  27. package/dist/generators/indices/testdata-service.generator.d.ts +0 -9
  28. package/dist/generators/indices/testdata-service.generator.js +0 -84
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRepositoryMethodsTypeSignatures = exports.generateMockRepository = exports.generateRepository = void 0;
3
+ exports.getRepositoryMethodsTypeSignatures = exports.generateRepository = void 0;
4
4
  const imports_1 = require("../../lib/imports");
5
5
  const meta_1 = require("../../lib/meta");
6
6
  const fields_1 = require("../../lib/schema/fields");
@@ -51,41 +51,14 @@ function generateRepository({ model, meta }) {
51
51
  const validationBlocks = generateValidationBlocks({ model, meta });
52
52
  const indexBlocks = generateIndexBlocks({ model, schemaMeta, meta, imports });
53
53
  const relationsBlocks = generateRelationsBlocks({ model, meta, imports });
54
- let mainBlocks;
55
- if (model.attributes.inMemoryOnly) {
56
- mainBlocks = _generateMainBuildingBlocks_InMemoryOnly({
57
- model,
58
- meta,
59
- schemaMeta,
60
- imports,
61
- blocks: {
62
- uniqueStringFieldsBlocks,
63
- relationsBlocks,
64
- defaultValueBlocks,
65
- idBlocks,
66
- indexBlocks,
67
- maxLengthBlocks,
68
- validationBlocks,
69
- },
70
- });
71
- }
72
- else {
73
- mainBlocks = generateMainBuildingBlocks_InDatabase({
74
- model,
75
- meta,
76
- schemaMeta,
77
- imports,
78
- blocks: {
79
- uniqueStringFieldsBlocks,
80
- relationsBlocks,
81
- defaultValueBlocks,
82
- idBlocks,
83
- indexBlocks,
84
- maxLengthBlocks,
85
- validationBlocks,
86
- },
87
- });
88
- }
54
+ imports.addImports({
55
+ [meta.types.importPath]: [meta.types.zodDecoderFnNames.fromDatabase],
56
+ [schemaMeta.backendModules.db.databaseService.location.import]: [schemaMeta.backendModules.db.databaseService.name],
57
+ [schemaMeta.backendModules.db.typesImportPath]: [(0, types_1.toAnnotatedTypeName)((0, types_1.toTypeName)(`${model.sourceName} as DbType`))],
58
+ [(0, types_1.toPackageName)('@postxl/runtime')]: [(0, types_1.toFunctionName)('format'), (0, types_1.toFunctionName)('pluralize')],
59
+ });
60
+ const userRepositorySpecificBlocks = generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports });
61
+ const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
89
62
  return `
90
63
  import { Injectable, Logger } from '@nestjs/common'
91
64
  ${idBlocks.libraryImports}
@@ -108,19 +81,43 @@ export class ${meta.data.repository.className} implements Repository<${model.typ
108
81
 
109
82
  ${indexBlocks.nestedMapDeclarations.join('\n')}
110
83
 
111
- ${mainBlocks.userRepositorySpecificBlocks.rootUserNameConst}
84
+ ${userRepositorySpecificBlocks.rootUserNameConst}
112
85
 
113
- ${mainBlocks.userRepositorySpecificBlocks.getterBlock}
86
+ ${userRepositorySpecificBlocks.getterBlock}
114
87
 
115
- ${mainBlocks.constructorCode}
88
+ constructor(protected db: ${schemaMeta.backendModules.db.databaseService.name}) {}
116
89
 
117
- ${mainBlocks.initCode}
90
+ public async init() {
91
+ this.data.clear()
118
92
 
119
- ${mainBlocks.reInitCode}
93
+ ${relationsBlocks.clearCode.join('\n')}
120
94
 
121
- ${mainBlocks.deleteAllCode}
95
+ ${uniqueStringFieldsBlocks.clearCode.join('\n')}
96
+
97
+ ${defaultValueBlocks.init.resetCode}
98
+
99
+ ${indexBlocks.initCode.join('\n')}
122
100
 
123
- ${mainBlocks.userRepositorySpecificBlocks.rootUserInitializeBlock}
101
+ const data = await this.db.${meta.data.repository.getMethodFnName}.findMany({})
102
+
103
+ for (const rawItem of data) {
104
+ const item = this.${meta.data.repository.decoderFnName}(rawItem)
105
+ this.set(item)
106
+
107
+ ${defaultValueBlocks.init.setCode}
108
+ }
109
+
110
+ ${idBlocks.initCode}
111
+
112
+ ${defaultValueBlocks.init.checkCode}
113
+
114
+ ${userRepositorySpecificBlocks.initCall}
115
+
116
+ this.logger.log(\`\${format(this.data.size)} \${pluralize('${model.typeName}', this.data.size)} loaded\`)
117
+ ${indexBlocks.initLogCode.join('\n')}
118
+ }
119
+
120
+ ${userRepositorySpecificBlocks.rootUserInitializeBlock}
124
121
 
125
122
  // NOTE: The current implementation is synchronous, but it needs to be async to conform to the interface.
126
123
  // eslint-disable-next-line @typescript-eslint/require-await
@@ -161,21 +158,237 @@ export class ${meta.data.repository.className} implements Repository<${model.typ
161
158
  return this.data.size
162
159
  }
163
160
 
164
- ${mainBlocks.createCode}
161
+ ${(0, jsdoc_1.toJsDocComment)([
162
+ `Checks that item has the ${idField.name} field.`,
163
+ `In case none exists, ${idBlocks.verifyFunctionComment}`,
164
+ uniqueStringFieldsBlocks.verifyFunctionComment,
165
+ maxLengthBlocks.verifyFunctionComment,
166
+ ])}
167
+ private verifyItem(
168
+ item: ${idBlocks.verifyFunctionParameterType}
169
+ ): ${idBlocks.createFunctionParameterType} {
170
+ ${idBlocks.verifyCode}
171
+
172
+ ${maxLengthBlocks.verifyCode.join('\n')}
165
173
 
166
- ${mainBlocks.createManyCode}
174
+ ${uniqueStringFieldsBlocks.verifyCode.join('\n')}
175
+
176
+ ${validationBlocks.verifyCode.join('\n')}
177
+
178
+ return {
179
+ ${idField.name},
180
+ ${model.fields
181
+ .filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
182
+ .map((f) => `${f.name}: item.${f.name}`)
183
+ .join(',\n')}
184
+ }
185
+ }
186
+
187
+ private toCreateItem(item: ${idBlocks.createFunctionParameterType}) {
188
+ return {
189
+ ${model.fields
190
+ .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
191
+ .map((f) => `${f.sourceName}: item.${f.name}`)
192
+ .join(',\n')},
193
+ }
194
+ }
195
+
196
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.create.jsDoc)}
197
+ public async create(
198
+ { item, execution }: ${methodTypeSignatures.create.parameters[0]}
199
+ ): ${methodTypeSignatures.create.returnType} {
200
+ const mutationId = await execution.startCreateMutation({
201
+ model: '${meta.actions.actionScopeConstType}',
202
+ createObject: item
203
+ })
204
+
205
+ try {
206
+ const newItem = this.${meta.data.repository.decoderFnName}(
207
+ await this.db.${meta.data.repository.getMethodFnName}.create({
208
+ data: this.toCreateItem(this.verifyItem(item)),
209
+ }),
210
+ )
211
+
212
+ this.set(newItem)
213
+ await execution.finishCreateMutation({ mutationId, createdObject: newItem, entityId: newItem.id })
214
+ return newItem
215
+ } catch (error) {
216
+ await execution.errorMutation({ mutationId, error })
217
+ throw error
218
+ }
219
+ }
220
+
221
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.createMany.jsDoc)}
222
+ public async createMany(
223
+ {items, execution}: ${methodTypeSignatures.createMany.parameters[0]}
224
+ ): ${methodTypeSignatures.createMany.returnType} {
225
+ const mutationId = await execution.startCreateManyMutation({
226
+ model: '${meta.actions.actionScopeConstType}',
227
+ createObjects: items
228
+ })
229
+
230
+ try {
231
+ const newItems = items.map((item) => this.verifyItem(item))
232
+
233
+ await this.db.${meta.data.repository.getMethodFnName}.createMany({ data: newItems.map(i => this.toCreateItem(i)) })
234
+
235
+ const dbItems = await this.db.${meta.data.repository.getMethodFnName}.findMany({
236
+ where: {
237
+ ${model.idField.sourceName}: { in: newItems.map(i => i.${model.idField.name}) }
238
+ }
239
+ })
240
+
241
+ const result = dbItems.map((item) => this.${meta.data.repository.decoderFnName}(item))
242
+
243
+ for (const item of result) {
244
+ this.set(item)
245
+ }
246
+
247
+ await execution.finishCreateManyMutation({
248
+ mutationId,
249
+ createdObjects: result,
250
+ entityIds: newItems.map((i) => i.id),
251
+ })
252
+ return result
253
+ } catch (error) {
254
+ await execution.errorMutation({ mutationId, error })
255
+ throw error
256
+ }
257
+ }
258
+
259
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.update.jsDoc)}
260
+ public async update(
261
+ { item, execution }: ${methodTypeSignatures.update.parameters[0]}
262
+ ): ${methodTypeSignatures.update.returnType} {
263
+ const existingItem = await this.get(item.${idField.name})
264
+ if (!existingItem) {
265
+ throw new Error(\`Could not update ${meta.userFriendlyName} with id \${item.id}. Not found!\`)
266
+ }
267
+
268
+ const mutationId = await execution.startUpdateMutation({
269
+ model: '${meta.actions.actionScopeConstType}',
270
+ entityId: item.id,
271
+ sourceObject: existingItem,
272
+ updateObject: item,
273
+ })
274
+ try {
275
+ ${maxLengthBlocks.updateCode.join('\n')}
167
276
 
168
- ${mainBlocks.updateCode}
277
+ ${uniqueStringFieldsBlocks.updateCode.join('\n')}
278
+
279
+ const newItem = this.${meta.data.repository.decoderFnName}(
280
+ await this.db.${meta.data.repository.getMethodFnName}.update({
281
+ where: {
282
+ ${idField.sourceName}: item.${idField.name},
283
+ },
284
+ data: {
285
+ ${[...model.fields.values()]
286
+ .filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
287
+ .map((f) => f.isRequired
288
+ ? `${f.sourceName}: item.${f.name} ?? existingItem.${f.name}`
289
+ : `${f.sourceName}: item.${f.name}`)
290
+ .join(',\n')}
291
+ },
292
+ }),
293
+ )
294
+
295
+ this.remove(existingItem)
296
+ this.set(newItem)
297
+
298
+ await execution.finishUpdateMutation({ mutationId, updatedObject: newItem })
299
+ return newItem
300
+ } catch (error) {
301
+ await execution.errorMutation({ mutationId, error })
302
+ throw error
303
+ }
304
+ }
169
305
 
170
- ${mainBlocks.updateManyCode}
306
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.updateMany.jsDoc)}
307
+ public async updateMany(
308
+ { items, execution }: ${methodTypeSignatures.updateMany.parameters[0]}
309
+ ): ${methodTypeSignatures.updateMany.returnType} {
310
+ const result: ${model.typeName}[] = []
311
+ for (const item of items) {
312
+ try {
313
+ const updated = await this.update({ item, execution })
314
+ result.push(updated)
315
+ } catch {
316
+ /* empty */
317
+ }
318
+ }
319
+ return result
320
+ }
321
+
322
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsert.jsDoc)}
323
+ public async upsert(
324
+ { item, execution }: ${methodTypeSignatures.upsert.parameters[0]}
325
+ ): ${methodTypeSignatures.upsert.returnType} {
326
+ const existingItem = item.${model.idField.name} ? (await this.get(item.${model.idField.name})) : null
327
+ if (existingItem) {
328
+ return this.update({ item: item as ${meta.types.dto.update}, execution })
329
+ } else {
330
+ return this.create({ item: item as ${meta.types.dto.create}, execution })
331
+ }
332
+ }
333
+
334
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsertMany.jsDoc)}
335
+ public async upsertMany(
336
+ { items, execution }: ${methodTypeSignatures.upsertMany.parameters[0]}
337
+ ): ${methodTypeSignatures.upsertMany.returnType} {
338
+ const result: ${model.typeName}[] = []
339
+ for (const item of items) {
340
+ try {
341
+ const updated = await this.upsert({ item, execution })
342
+ result.push(updated)
343
+ } catch {
344
+ /* empty */
345
+ }
346
+ }
347
+ return result
348
+ }
171
349
 
172
- ${mainBlocks.upsertCode}
350
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.delete.jsDoc)}
351
+ public async delete(
352
+ { id, execution }: ${methodTypeSignatures.delete.parameters[0]}
353
+ ): ${methodTypeSignatures.delete.returnType} {
354
+ const existingItem = await this.get(id)
355
+ if (!existingItem) {
356
+ throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
357
+ }
173
358
 
174
- ${mainBlocks.upsertManyCode}
359
+ const mutationId = await execution.startDeleteMutation({
360
+ model: '${meta.actions.actionScopeConstType}',
361
+ entityId: id,
362
+ sourceObject: existingItem,
363
+ })
364
+ try {
175
365
 
176
- ${mainBlocks.deleteCode}
366
+ await this.db.${meta.data.repository.getMethodFnName}.delete({ where: { ${idField.sourceName}:id } })
367
+
368
+ this.remove(existingItem)
369
+ await execution.finishDeleteMutation({ mutationId })
370
+ return id
371
+ } catch (error) {
372
+ await execution.errorMutation({ mutationId, error })
373
+ throw error
374
+ }
375
+ }
177
376
 
178
- ${mainBlocks.deleteManyCode}
377
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.deleteMany.jsDoc)}
378
+ public async deleteMany(
379
+ { ids, execution }: ${methodTypeSignatures.deleteMany.parameters[0]}
380
+ ): ${methodTypeSignatures.deleteMany.returnType} {
381
+ const deletedIds: ${model.brandedIdType}[] = []
382
+ for (const id of ids) {
383
+ try {
384
+ await this.delete({ id, execution })
385
+ deletedIds.push(id)
386
+ } catch {
387
+ /* empty */
388
+ }
389
+ }
390
+ return deletedIds
391
+ }
179
392
 
180
393
  ${relationsBlocks.getterFunctions.join('\n')}
181
394
 
@@ -210,581 +423,20 @@ export class ${meta.data.repository.className} implements Repository<${model.typ
210
423
  ${indexBlocks.removeCode.join('\n')}
211
424
  }
212
425
 
213
- ${mainBlocks.databaseDecoderCode}
426
+ /**
427
+ * Utility function that converts a given Database object to a TypeScript model instance
428
+ */
429
+ private ${meta.data.repository.decoderFnName}(
430
+ item: Pick<DbType, ${model.fields.map((f) => `'${f.sourceName}'`).join(' | ')}>
431
+ ): ${model.typeName} {
432
+ return ${meta.types.zodDecoderFnNames.fromDatabase}.parse({
433
+ ${model.fields.map((f) => `${f.name}: item.${f.sourceName}`).join(',\n')}
434
+ })
435
+ }
214
436
  }
215
437
  `;
216
438
  }
217
439
  exports.generateRepository = generateRepository;
218
- /**
219
- * Generates a mock repository data structure for a given model: same a repository, but in memory only.
220
- */
221
- function generateMockRepository({ model: modelSource, meta: metaSource, }) {
222
- // We re-use the repository block, but we change the meta data to use the mock repository name and the model to be in memory only
223
- const meta = Object.assign(Object.assign({}, metaSource), { data: Object.assign(Object.assign({}, metaSource.data), { repository: Object.assign(Object.assign({}, metaSource.data.repository), { className: metaSource.data.mockRepository.className, location: metaSource.data.mockRepository.location }) }) });
224
- const model = Object.assign(Object.assign({}, modelSource), { attributes: Object.assign(Object.assign({}, modelSource.attributes), { inMemoryOnly: true }) });
225
- return generateRepository({ model, meta });
226
- }
227
- exports.generateMockRepository = generateMockRepository;
228
- /**
229
- * Generates the main building blocks of the repository for in-memory model.
230
- */
231
- function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, schemaMeta, imports, blocks, }) {
232
- const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
233
- const userRepositorySpecificBlocks = generateUserRepositorySpecificBlocks_InMemoryOnly({ model, meta, imports });
234
- imports.addImport({
235
- from: schemaMeta.backendModules.common.importPath,
236
- items: ['removeUndefinedProperties'].map(types_1.toFunctionName),
237
- });
238
- return {
239
- constructorCode: '',
240
- userRepositorySpecificBlocks,
241
- initCode: `
242
- // NOTE: The current implementation is synchronous, but it needs to be async to conform to the interface.
243
- // eslint-disable-next-line @typescript-eslint/require-await
244
- public async init() {
245
- this.data.clear()
246
-
247
- ${blocks.relationsBlocks.clearCode.join('\n')}
248
-
249
- ${blocks.uniqueStringFieldsBlocks.clearCode.join('\n')}
250
-
251
- ${blocks.defaultValueBlocks.init.resetCode}
252
-
253
- ${blocks.indexBlocks.initCode.join('\n')}
254
-
255
- ${userRepositorySpecificBlocks.initCall}
256
- }`,
257
- reInitCode: `
258
- public async reInit({items, execution}: ${methodTypeSignatures.createMany.parameters[0]}): Promise<void> {
259
- await this.init()
260
- await this.createMany({items, execution})
261
- }`,
262
- deleteAllCode: `
263
- public async deleteAll(): Promise<void> {
264
- return this.init()
265
- }`,
266
- createCode: `
267
- ${(0, jsdoc_1.toJsDocComment)([
268
- `Checks that item has the ${model.idField.name} field.`,
269
- `In case none exists, ${blocks.idBlocks.verifyFunctionComment}`,
270
- blocks.uniqueStringFieldsBlocks.verifyFunctionComment,
271
- blocks.maxLengthBlocks.verifyFunctionComment,
272
- ])}
273
- private verifyItem(
274
- item: ${blocks.idBlocks.verifyFunctionParameterType}
275
- ): ${model.name} {
276
- ${blocks.idBlocks.verifyCode}
277
-
278
- ${blocks.maxLengthBlocks.verifyCode.join('\n')}
279
-
280
- ${blocks.uniqueStringFieldsBlocks.verifyCode.join('\n')}
281
-
282
- ${blocks.validationBlocks.verifyCode.join('\n')}
283
-
284
- return {
285
- ${model.idField.name},
286
- ${model.fields
287
- .filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
288
- .map((f) => `${f.name}: item.${f.name}`)
289
- .join(',\n')},
290
- ${model.createdAtField ? `${model.createdAtField.sourceName}: new Date(),` : ''}
291
- ${model.updatedAtField ? `${model.updatedAtField.sourceName}: new Date(),` : ''}
292
- }
293
- }
294
-
295
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.create.jsDoc)}
296
- // Non-mocked version is async - so we keep type-compatible signatures for create() and createWithId()
297
- // eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars
298
- public async create(
299
- { item, execution }: ${methodTypeSignatures.create.parameters[0]}
300
- ): ${methodTypeSignatures.create.returnType} {
301
- const mutationId = await execution.startCreateMutation({
302
- model: '${meta.actions.actionScopeConstType}',
303
- createObject: item
304
- })
305
-
306
- try {
307
- const newItem = this.verifyItem(item)
308
-
309
- this.set(newItem)
310
- await execution.finishCreateMutation({ mutationId, createdObject: newItem, entityId: newItem.id })
311
- return newItem
312
- } catch (error) {
313
- await execution.errorMutation({ mutationId, error })
314
- throw error
315
- }
316
- }`,
317
- createManyCode: `
318
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.createMany.jsDoc)}
319
- public async createMany(
320
- { items, execution }: ${methodTypeSignatures.createMany.parameters[0]}
321
- ): ${methodTypeSignatures.createMany.returnType} {
322
- const mutationId = await execution.startCreateManyMutation({
323
- model: '${meta.actions.actionScopeConstType}',
324
- createObjects: items
325
- })
326
-
327
- try {
328
- const newItems = items.map((item) => this.verifyItem(item))
329
-
330
- for (const item of newItems) {
331
- this.set(item)
332
- }
333
-
334
- await execution.finishCreateManyMutation({
335
- mutationId,
336
- createdObjects: newItems,
337
- entityIds: newItems.map((i) => i.id),
338
- })
339
- return newItems
340
- } catch (error) {
341
- await execution.errorMutation({ mutationId, error })
342
- throw error
343
- }
344
- }`,
345
- updateCode: `
346
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.update.jsDoc)}
347
- public async update(
348
- { item, execution }: ${methodTypeSignatures.update.parameters[0]}
349
- ): ${methodTypeSignatures.update.returnType} {
350
- const existingItem = await this.get(item.id)
351
-
352
- if (!existingItem) {
353
- throw new Error(\`Could not update ${meta.userFriendlyName} with id \${item.id}. Not found!\`)
354
- }
355
- const mutationId = await execution.startUpdateMutation({
356
- model: '${meta.actions.actionScopeConstType}',
357
- entityId: item.id,
358
- sourceObject: existingItem,
359
- updateObject: item,
360
- })
361
- try {
362
- ${blocks.maxLengthBlocks.updateCode.join('\n')}
363
-
364
- ${blocks.uniqueStringFieldsBlocks.updateCode.join('\n')}
365
-
366
- const newItem = { ...existingItem, ...removeUndefinedProperties(item) }
367
- ${model.updatedAtField ? `newItem.${model.updatedAtField.name} = new Date()` : ''}
368
-
369
- this.remove(existingItem)
370
- this.set(newItem)
371
-
372
- await execution.finishUpdateMutation({ mutationId, updatedObject: newItem })
373
- return newItem
374
- } catch (error) {
375
- await execution.errorMutation({ mutationId, error })
376
- throw error
377
- }
378
- }`,
379
- updateManyCode: `
380
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.updateMany.jsDoc)}
381
- public async updateMany(
382
- { items, execution }: ${methodTypeSignatures.updateMany.parameters[0]}
383
- ): ${methodTypeSignatures.updateMany.returnType} {
384
- const result: ${model.typeName}[] = []
385
- for (const item of items) {
386
- try {
387
- const updated = await this.update({ item, execution })
388
- result.push(updated)
389
- } catch {
390
- /* empty */
391
- }
392
- }
393
- return result
394
- }`,
395
- upsertCode: `
396
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsert.jsDoc)}
397
- public async upsert(
398
- { item, execution }: ${methodTypeSignatures.upsert.parameters[0]}
399
- ): ${methodTypeSignatures.upsert.returnType} {
400
- const existingItem = item.${model.idField.name} ? (await this.get(item.${model.idField.name})) : null
401
- if (existingItem) {
402
- return this.update({ item: item as ${meta.types.dto.update}, execution })
403
- } else {
404
- return this.create({ item: item as ${meta.types.dto.create}, execution })
405
- }
406
- }`,
407
- upsertManyCode: `
408
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsertMany.jsDoc)}
409
- public async upsertMany(
410
- { items, execution }: ${methodTypeSignatures.upsertMany.parameters[0]}
411
- ): ${methodTypeSignatures.upsertMany.returnType} {
412
- const result: ${model.typeName}[] = []
413
- for (const item of items) {
414
- try {
415
- const updated = await this.upsert({ item, execution })
416
- result.push(updated)
417
- } catch {
418
- /* empty */
419
- }
420
- }
421
- return result
422
- }`,
423
- deleteCode: `
424
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.delete.jsDoc)}
425
- public async delete(
426
- { id, execution }: ${methodTypeSignatures.delete.parameters[0]}
427
- ): ${methodTypeSignatures.delete.returnType} {
428
- const existingItem = await this.get(id)
429
- if (!existingItem) {
430
- throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
431
- }
432
- const mutationId = await execution.startDeleteMutation({
433
- model: '${meta.actions.actionScopeConstType}',
434
- entityId: id,
435
- sourceObject: existingItem,
436
- })
437
- try {
438
- this.remove(existingItem)
439
- await execution.finishDeleteMutation({ mutationId })
440
- return id
441
- } catch (error) {
442
- await execution.errorMutation({ mutationId, error })
443
- throw error
444
- }
445
- }`,
446
- deleteManyCode: `
447
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.deleteMany.jsDoc)}
448
- public async deleteMany(
449
- { ids, execution }: ${methodTypeSignatures.deleteMany.parameters[0]}
450
- ): ${methodTypeSignatures.deleteMany.returnType} {
451
- const deletedIds: ${model.brandedIdType}[] = []
452
- for (const id of ids) {
453
- try {
454
- await this.delete({ id, execution })
455
- deletedIds.push(id)
456
- } catch {
457
- /* empty */
458
- }
459
- }
460
- return deletedIds
461
- }`,
462
- databaseDecoderCode: ``,
463
- };
464
- }
465
- /**
466
- * Generates the methods of the repository for a model that is stored in the database.
467
- */
468
- function generateMainBuildingBlocks_InDatabase({ model, meta, schemaMeta, imports, blocks, }) {
469
- const decoderFunctionName = meta.data.repository.decoderFnName;
470
- const { idField } = model;
471
- imports.addImports({
472
- [meta.types.importPath]: [meta.types.zodDecoderFnNames.fromDatabase],
473
- [schemaMeta.backendModules.db.databaseService.location.import]: [schemaMeta.backendModules.db.databaseService.name],
474
- [schemaMeta.backendModules.db.typesImportPath]: [(0, types_1.toAnnotatedTypeName)((0, types_1.toTypeName)(`${model.sourceName} as DbType`))],
475
- [schemaMeta.backendModules.common.importPath]: [
476
- schemaMeta.backendModules.common.functions.format,
477
- schemaMeta.backendModules.common.functions.pluralize,
478
- ],
479
- });
480
- const dbTableName = [model.sourceSchemaName, model.sourceName]
481
- .filter((s) => s != null)
482
- .map((part) => `"${part}"`)
483
- .join('.');
484
- const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
485
- const userRepositorySpecificBlocks = generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports });
486
- return {
487
- constructorCode: `constructor(protected db: ${schemaMeta.backendModules.db.databaseService.name}) {}`,
488
- userRepositorySpecificBlocks,
489
- initCode: `
490
- public async init() {
491
- this.data.clear()
492
-
493
- ${blocks.relationsBlocks.clearCode.join('\n')}
494
-
495
- ${blocks.uniqueStringFieldsBlocks.clearCode.join('\n')}
496
-
497
- ${blocks.defaultValueBlocks.init.resetCode}
498
-
499
- ${blocks.indexBlocks.initCode.join('\n')}
500
-
501
- const data = await this.db.${meta.data.repository.getMethodFnName}.findMany({})
502
-
503
- for (const rawItem of data) {
504
- const item = this.${decoderFunctionName}(rawItem)
505
- this.set(item)
506
-
507
- ${blocks.defaultValueBlocks.init.setCode}
508
- }
509
-
510
- ${blocks.idBlocks.initCode}
511
-
512
- ${blocks.defaultValueBlocks.init.checkCode}
513
-
514
- ${userRepositorySpecificBlocks.initCall}
515
-
516
- this.logger.log(\`\${format(this.data.size)} \${pluralize('${model.typeName}', this.data.size)} loaded\`)
517
- ${blocks.indexBlocks.initLogCode.join('\n')}
518
- }`,
519
- reInitCode: `
520
- public async reInit(
521
- { items, execution }: ${methodTypeSignatures.createMany.parameters[0]}
522
- ): Promise<void> {
523
- if (!this.db.isTestDB) {
524
- const errorMsg =
525
- 'ReInit() shall only be called in tests using MockRepositories or in DB configured for E2E tests!'
526
- this.logger.error(errorMsg)
527
- throw new Error(errorMsg)
528
- }
529
-
530
- await this.db.runOnlyOnTestDb(() => this.createMany({ items, execution }))
531
-
532
- return this.init()
533
- }`,
534
- deleteAllCode: `
535
- public async deleteAll(): Promise<void> {
536
- await this.db.runOnlyOnTestDb(() => this.db.$executeRaw\`DELETE FROM ${dbTableName}\`)
537
-
538
- return this.init()
539
- }
540
- `,
541
- // prettier-ignore
542
- createCode: `
543
- ${(0, jsdoc_1.toJsDocComment)([
544
- `Checks that item has the ${idField.name} field.`,
545
- `In case none exists, ${blocks.idBlocks.verifyFunctionComment}`,
546
- blocks.uniqueStringFieldsBlocks.verifyFunctionComment,
547
- blocks.maxLengthBlocks.verifyFunctionComment,
548
- ])}
549
- private verifyItem(
550
- item: ${blocks.idBlocks.verifyFunctionParameterType}
551
- ): ${blocks.idBlocks.createFunctionParameterType} {
552
- ${blocks.idBlocks.verifyCode}
553
-
554
- ${blocks.maxLengthBlocks.verifyCode.join('\n')}
555
-
556
- ${blocks.uniqueStringFieldsBlocks.verifyCode.join('\n')}
557
-
558
- ${blocks.validationBlocks.verifyCode.join('\n')}
559
-
560
- return {
561
- ${idField.name},
562
- ${model.fields
563
- .filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
564
- .map((f) => `${f.name}: item.${f.name}`)
565
- .join(',\n')}
566
- }
567
- }
568
-
569
- private toCreateItem(item: ${blocks.idBlocks.createFunctionParameterType}) {
570
- return {
571
- ${model.fields
572
- .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
573
- .map((f) => `${f.sourceName}: item.${f.name}`)
574
- .join(',\n')},
575
- }
576
- }
577
-
578
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.create.jsDoc)}
579
- public async create(
580
- { item, execution }: ${methodTypeSignatures.create.parameters[0]}
581
- ): ${methodTypeSignatures.create.returnType} {
582
- const mutationId = await execution.startCreateMutation({
583
- model: '${meta.actions.actionScopeConstType}',
584
- createObject: item
585
- })
586
-
587
- try {
588
- const newItem = this.${decoderFunctionName}(
589
- await this.db.${meta.data.repository.getMethodFnName}.create({
590
- data: this.toCreateItem(this.verifyItem(item)),
591
- }),
592
- )
593
-
594
- this.set(newItem)
595
- await execution.finishCreateMutation({ mutationId, createdObject: newItem, entityId: newItem.id })
596
- return newItem
597
- } catch (error) {
598
- await execution.errorMutation({ mutationId, error })
599
- throw error
600
- }
601
- }`,
602
- // prettier-ignore
603
- createManyCode: `
604
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.createMany.jsDoc)}
605
- public async createMany(
606
- {items, execution}: ${methodTypeSignatures.createMany.parameters[0]}
607
- ): ${methodTypeSignatures.createMany.returnType} {
608
- const mutationId = await execution.startCreateManyMutation({
609
- model: '${meta.actions.actionScopeConstType}',
610
- createObjects: items
611
- })
612
-
613
- try {
614
- const newItems = items.map((item) => this.verifyItem(item))
615
-
616
- await this.db.${meta.data.repository.getMethodFnName}.createMany({ data: newItems.map(i => this.toCreateItem(i)) })
617
-
618
- const dbItems = await this.db.${meta.data.repository.getMethodFnName}.findMany({
619
- where: {
620
- ${model.idField.sourceName}: { in: newItems.map(i => i.${model.idField.name}) }
621
- }
622
- })
623
-
624
- const result = dbItems.map((item) => this.${decoderFunctionName}(item))
625
-
626
- for (const item of result) {
627
- this.set(item)
628
- }
629
-
630
- await execution.finishCreateManyMutation({
631
- mutationId,
632
- createdObjects: result,
633
- entityIds: newItems.map((i) => i.id),
634
- })
635
- return result
636
- } catch (error) {
637
- await execution.errorMutation({ mutationId, error })
638
- throw error
639
- }
640
- }`,
641
- updateCode: `
642
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.update.jsDoc)}
643
- public async update(
644
- { item, execution }: ${methodTypeSignatures.update.parameters[0]}
645
- ): ${methodTypeSignatures.update.returnType} {
646
- const existingItem = await this.get(item.${idField.name})
647
- if (!existingItem) {
648
- throw new Error(\`Could not update ${meta.userFriendlyName} with id \${item.id}. Not found!\`)
649
- }
650
-
651
- const mutationId = await execution.startUpdateMutation({
652
- model: '${meta.actions.actionScopeConstType}',
653
- entityId: item.id,
654
- sourceObject: existingItem,
655
- updateObject: item,
656
- })
657
- try {
658
- ${blocks.maxLengthBlocks.updateCode.join('\n')}
659
-
660
- ${blocks.uniqueStringFieldsBlocks.updateCode.join('\n')}
661
-
662
- const newItem = this.${decoderFunctionName}(
663
- await this.db.${meta.data.repository.getMethodFnName}.update({
664
- where: {
665
- ${idField.sourceName}: item.${idField.name},
666
- },
667
- data: {
668
- ${[...model.fields.values()]
669
- .filter((f) => f.kind !== 'id' && !f.attributes.isReadonly)
670
- .map((f) => f.isRequired
671
- ? `${f.sourceName}: item.${f.name} ?? existingItem.${f.name}`
672
- : `${f.sourceName}: item.${f.name}`)
673
- .join(',\n')}
674
- },
675
- }),
676
- )
677
-
678
- this.remove(existingItem)
679
- this.set(newItem)
680
-
681
- await execution.finishUpdateMutation({ mutationId, updatedObject: newItem })
682
- return newItem
683
- } catch (error) {
684
- await execution.errorMutation({ mutationId, error })
685
- throw error
686
- }
687
- }`,
688
- updateManyCode: `
689
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.updateMany.jsDoc)}
690
- public async updateMany(
691
- { items, execution }: ${methodTypeSignatures.updateMany.parameters[0]}
692
- ): ${methodTypeSignatures.updateMany.returnType} {
693
- const result: ${model.typeName}[] = []
694
- for (const item of items) {
695
- try {
696
- const updated = await this.update({ item, execution })
697
- result.push(updated)
698
- } catch {
699
- /* empty */
700
- }
701
- }
702
- return result
703
- }`,
704
- upsertCode: `
705
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsert.jsDoc)}
706
- public async upsert(
707
- { item, execution }: ${methodTypeSignatures.upsert.parameters[0]}
708
- ): ${methodTypeSignatures.upsert.returnType} {
709
- const existingItem = item.${model.idField.name} ? (await this.get(item.${model.idField.name})) : null
710
- if (existingItem) {
711
- return this.update({ item: item as ${meta.types.dto.update}, execution })
712
- } else {
713
- return this.create({ item: item as ${meta.types.dto.create}, execution })
714
- }
715
- }`,
716
- upsertManyCode: `
717
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsertMany.jsDoc)}
718
- public async upsertMany(
719
- { items, execution }: ${methodTypeSignatures.upsertMany.parameters[0]}
720
- ): ${methodTypeSignatures.upsertMany.returnType} {
721
- const result: ${model.typeName}[] = []
722
- for (const item of items) {
723
- try {
724
- const updated = await this.upsert({ item, execution })
725
- result.push(updated)
726
- } catch {
727
- /* empty */
728
- }
729
- }
730
- return result
731
- }`,
732
- deleteCode: `
733
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.delete.jsDoc)}
734
- public async delete(
735
- { id, execution }: ${methodTypeSignatures.delete.parameters[0]}
736
- ): ${methodTypeSignatures.delete.returnType} {
737
- const existingItem = await this.get(id)
738
- if (!existingItem) {
739
- throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
740
- }
741
-
742
- const mutationId = await execution.startDeleteMutation({
743
- model: '${meta.actions.actionScopeConstType}',
744
- entityId: id,
745
- sourceObject: existingItem,
746
- })
747
- try {
748
-
749
- await this.db.${meta.data.repository.getMethodFnName}.delete({ where: { ${idField.sourceName}:id } })
750
-
751
- this.remove(existingItem)
752
- await execution.finishDeleteMutation({ mutationId })
753
- return id
754
- } catch (error) {
755
- await execution.errorMutation({ mutationId, error })
756
- throw error
757
- }
758
- }`,
759
- deleteManyCode: `
760
- ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.deleteMany.jsDoc)}
761
- public async deleteMany(
762
- { ids, execution }: ${methodTypeSignatures.deleteMany.parameters[0]}
763
- ): ${methodTypeSignatures.deleteMany.returnType} {
764
- const deletedIds: ${model.brandedIdType}[] = []
765
- for (const id of ids) {
766
- try {
767
- await this.delete({ id, execution })
768
- deletedIds.push(id)
769
- } catch {
770
- /* empty */
771
- }
772
- }
773
- return deletedIds
774
- }`,
775
- databaseDecoderCode: `
776
- /**
777
- * Utility function that converts a given Database object to a TypeScript model instance
778
- */
779
- private ${decoderFunctionName}(
780
- item: Pick<DbType, ${model.fields.map((f) => `'${f.sourceName}'`).join(' | ')}>
781
- ): ${model.typeName} {
782
- return ${meta.types.zodDecoderFnNames.fromDatabase}.parse({
783
- ${model.fields.map((f) => `${f.name}: item.${f.sourceName}`).join(',\n')}
784
- })
785
- }`,
786
- };
787
- }
788
440
  function generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports, }) {
789
441
  if (model.name !== 'User') {
790
442
  return {
@@ -821,40 +473,6 @@ function generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports,
821
473
  }`,
822
474
  };
823
475
  }
824
- function generateUserRepositorySpecificBlocks_InMemoryOnly({ model, meta, imports, }) {
825
- if (model.name !== 'User') {
826
- return {
827
- rootUserNameConst: '',
828
- getterBlock: '',
829
- initCall: '',
830
- rootUserInitializeBlock: '',
831
- };
832
- }
833
- const { rootUserId, rootUserValue } = generateSharedRootUserBlocks({ model, meta, imports });
834
- return {
835
- rootUserNameConst: `public static ROOT_USER_ID = ${meta.types.toBrandedIdTypeFnName}(${rootUserId})`,
836
- getterBlock: `
837
- // We initialize the root user in the init() function
838
- private _rootUser!: ${meta.types.typeName}
839
- public get rootUser(): ${meta.types.typeName} {
840
- return this._rootUser
841
- }`,
842
- initCall: `await this.initializeRootUser()`,
843
- rootUserInitializeBlock: `
844
- private async initializeRootUser(): Promise<void> {
845
- const existingRootUser = await this.get(${meta.data.repository.className}.ROOT_USER_ID)
846
- if (existingRootUser) {
847
- this._rootUser = existingRootUser
848
- return
849
- }
850
-
851
- const rawUser = { ${rootUserValue} }
852
- const newRootUser = this.verifyItem (rawUser)
853
- this.set(newRootUser)
854
- this._rootUser = newRootUser
855
- }`,
856
- };
857
- }
858
476
  function generateSharedRootUserBlocks({ model, meta, imports, }) {
859
477
  var _a;
860
478
  const providedDefault = model.attributes.systemUser;