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