@postxl/generator 0.6.10 → 0.7.1

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.
@@ -12,6 +12,7 @@ function generateRepository({ model, meta }) {
12
12
  const { idField, fields } = model;
13
13
  const decoder = meta.data.repository.decoderFnName;
14
14
  const uniqueStringFields = fields.filter(fields_1.isUniqueStringField);
15
+ const maxLengthStringFields = fields.filter(fields_1.isMaxLengthStringField);
15
16
  const defaultValueInitFn = `
16
17
  if (item.${(_a = model.defaultField) === null || _a === void 0 ? void 0 : _a.name}) {
17
18
  if (this.defaultValue) {
@@ -36,6 +37,7 @@ function generateRepository({ model, meta }) {
36
37
  return `
37
38
  import { Injectable, Logger } from '@nestjs/common'
38
39
  import { DbService, ${model.sourceName} as DbType } from '@${model.schemaConfig.project}/db'
40
+ import { format, pluralize } from '@pxl/common'
39
41
 
40
42
  import { Repository } from '../repository.type'
41
43
 
@@ -65,15 +67,17 @@ export class ${meta.data.repositoryClassName} implements Repository<
65
67
  ${uniqueStringFields.map((f) => `'${f.name}': new Map<string, ${model.typeName}>()`).join(',\n')}
66
68
  }
67
69
 
68
- constructor(protected db: DbService) {}
70
+ constructor(${model.attributes.inMemoryOnly ? '' : 'protected '}db: DbService) {}
69
71
 
70
72
  public async init() {
71
73
  this.data.clear()
72
74
 
73
75
  ${uniqueStringFields.map((f) => `this.uniqueIds.${f.name}.clear()\n`)}
74
76
 
75
- this.logger.log(\`Loading ${model.typeName} instances into repository...\`)
76
-
77
+ ${model.attributes.inMemoryOnly
78
+ ? 'return Promise.resolve()'
79
+ : `
80
+
77
81
  const data = await this.db.${meta.data.repository.getMethodFnName}.findMany({})
78
82
 
79
83
  for (const rawItem of data) {
@@ -88,17 +92,21 @@ export class ${meta.data.repositoryClassName} implements Repository<
88
92
 
89
93
  ${model.defaultField ? defaultValueInitCheckFn : ''}
90
94
 
91
- this.logger.log(\`Loaded \${this.data.size} instances of ${model.typeName} into repository!\`)
95
+ this.logger.log(\`\${format(this.data.size)} \${pluralize('${model.typeName}', this.data.size)} loaded\`)
96
+ `}
92
97
  }
93
98
 
94
99
  public async reInit(data: ${model.typeName}[]): Promise<void> {
100
+ ${model.attributes.inMemoryOnly
101
+ ? 'return Promise.resolve()'
102
+ : `
95
103
  if (!this.db.useE2ETestDB) {
96
104
  const errorMsg =
97
105
  'ReInit() shall only be called in tests using MockRepositories or in DB configured for E2E tests!'
98
106
  this.logger.error(errorMsg)
99
107
  throw new Error(errorMsg)
100
108
  }
101
- await this.db.runOnlyOnTestDb(() => this.db.${meta.data.repository.getMethodFnName}.createMany({ data: data.map((i) => this.toCreateItem(i)) }))
109
+ await this.db.runOnlyOnTestDb(() => this.db.${meta.data.repository.getMethodFnName}.createMany({ data: data.map((i) => this.toCreateItem(i)) }))`}
102
110
  return this.init()
103
111
  }
104
112
 
@@ -138,6 +146,8 @@ export class ${meta.data.repositoryClassName} implements Repository<
138
146
  }`
139
147
  : ''}
140
148
 
149
+ ${maxLengthStringFields.map((f) => `this.${getEnsureMaxLengthFnName(f)}(item)`).join('\n')}
150
+
141
151
  ${uniqueStringFields.map((f) => `this.${getEnsureUniqueFnName(f)}(item)`).join('\n')}
142
152
 
143
153
  return {
@@ -147,11 +157,17 @@ export class ${meta.data.repositoryClassName} implements Repository<
147
157
  public async createWithId(item: Omit<${model.typeName}, '${idField.name}'> & {
148
158
  id: ${model.brandedIdType}
149
159
  }): Promise<${model.typeName}> {
160
+ ${model.attributes.inMemoryOnly
161
+ ? `
162
+ ${maxLengthStringFields.map((f) => `this.${getEnsureMaxLengthFnName(f)}(item)`).join('\n')}
163
+ ${uniqueStringFields.map((f) => `this.${getEnsureUniqueFnName(f)}(item)`).join('\n')}
164
+ const newItem = await Promise.resolve(item)`
165
+ : `
150
166
  const newItem = this.${decoder}(
151
167
  await this.db.${meta.data.repository.getMethodFnName}.create({
152
168
  data: this.toCreateItem(item as ${model.typeName}),
153
169
  }),
154
- )
170
+ )`}
155
171
 
156
172
  ${uniqueStringFields.map((f) => `this.uniqueIds.${f.name}.set(newItem.${f.name}, newItem)`).join('\n')}
157
173
 
@@ -162,39 +178,54 @@ export class ${meta.data.repositoryClassName} implements Repository<
162
178
  public async create(
163
179
  item: Omit<${model.typeName}, 'id'>
164
180
  ): Promise<${model.typeName}> {
181
+ ${model.attributes.inMemoryOnly && !isGenerated
182
+ ? `throw new Error('Create without Id not possible without autogenerated Id. Please adjust schema if you need this function!')`
183
+ : `
184
+
165
185
  ${isGenerated ? `const id = ++this.currentMaxId\n` : ''}
166
186
 
187
+ ${maxLengthStringFields.map((f) => `this.${getEnsureMaxLengthFnName(f)}(item)`).join('\n')}
188
+
167
189
  ${uniqueStringFields.map((f) => `this.${getEnsureUniqueFnName(f)}(item)`).join('\n')}
168
190
 
191
+ ${model.attributes.inMemoryOnly
192
+ ? `
193
+ const newItem = await Promise.resolve({ item, id })
194
+ `
195
+ : `
169
196
  const newItem = this.${decoder}(
170
197
  await this.db.${meta.data.repository.getMethodFnName}.create({
171
198
  data: {
172
199
  ${isGenerated ? `${idField.sourceName}: id,` : ''}
173
200
  ${[...model.fields.values()]
174
- .filter((f) => f.kind !== 'id')
175
- .map((f) => `${f.sourceName}: item.${f.name}`)
176
- .join(',\n')}
201
+ .filter((f) => f.kind !== 'id')
202
+ .map((f) => `${f.sourceName}: item.${f.name}`)
203
+ .join(',\n')}
177
204
  },
178
205
  }),
179
- )
206
+ )`}
180
207
 
181
208
  ${uniqueStringFields.map((f) => `this.uniqueIds.${f.name}.set(newItem.${f.name}, newItem)`).join('\n')}
182
209
 
183
210
  this.data.set(newItem.id, newItem)
184
- return newItem
211
+ return newItem`}
185
212
  }
186
213
 
187
214
  public async createMany(items: ${model.typeName}[]) {
188
- ${uniqueStringFields.length > 0
215
+ ${uniqueStringFields.length > 0 || maxLengthStringFields.length > 0
189
216
  ? `
190
217
  for (const item of items) {
218
+ ${maxLengthStringFields.map((f) => `this.${getEnsureMaxLengthFnName(f)}(item)`).join('\n')}
191
219
  ${uniqueStringFields.map((f) => `this.${getEnsureUniqueFnName(f)}(item)`).join('\n')}
192
220
  }`
193
221
  : ''}
194
222
 
223
+ ${model.attributes.inMemoryOnly
224
+ ? 'await Promise.resolve()'
225
+ : `
195
226
  await this.db.${meta.data.repository.getMethodFnName}.createMany({ data: items.map(item => ({
196
227
  ${[...model.fields.values()].map((f) => `${f.sourceName}: item.${f.name}`).join(',\n')}}))
197
- })
228
+ })`}
198
229
 
199
230
  for (const item of items) {
200
231
  this.data.set(item.id, item)
@@ -214,6 +245,16 @@ export class ${meta.data.repositoryClassName} implements Repository<
214
245
  throw new Error(\`Could not update ${meta.userFriendlyName} with id \${item.id}. Not found!\`)
215
246
  }
216
247
 
248
+
249
+ ${maxLengthStringFields
250
+ .map((f) => {
251
+ return `
252
+ if (item.${f.name} !== undefined && existingItem.${f.name} !== item.${f.name}) {
253
+ this.${getEnsureMaxLengthFnName(f)}(item)
254
+ }
255
+ `;
256
+ })
257
+ .join('\n')}
217
258
  ${uniqueStringFields
218
259
  .map((f) => {
219
260
  return `
@@ -223,7 +264,12 @@ export class ${meta.data.repositoryClassName} implements Repository<
223
264
  `;
224
265
  })
225
266
  .join('\n')}
226
-
267
+
268
+ ${model.attributes.inMemoryOnly
269
+ ? `
270
+ const newItem = await Promise.resolve({ ...existingItem, ...item })
271
+ `
272
+ : `
227
273
  const newItem = this.${decoder}(
228
274
  await this.db.${meta.data.repository.getMethodFnName}.update({
229
275
  where: {
@@ -231,16 +277,14 @@ export class ${meta.data.repositoryClassName} implements Repository<
231
277
  },
232
278
  data: {
233
279
  ${[...model.fields.values()]
234
- .filter((f) => f.kind !== 'id')
235
- .map((f) => f.isRequired
236
- ? `${f.sourceName}: item.${f.name} ?? existingItem.${f.name}`
237
- : `${f.sourceName}: item.${f.name}`)
238
- .join(',\n')}
239
-
240
-
280
+ .filter((f) => f.kind !== 'id')
281
+ .map((f) => f.isRequired
282
+ ? `${f.sourceName}: item.${f.name} ?? existingItem.${f.name}`
283
+ : `${f.sourceName}: item.${f.name}`)
284
+ .join(',\n')}
241
285
  },
242
286
  }),
243
- )
287
+ )`}
244
288
 
245
289
  ${uniqueStringFields
246
290
  .map((f) => {
@@ -265,13 +309,31 @@ export class ${meta.data.repositoryClassName} implements Repository<
265
309
  throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
266
310
  }
267
311
 
312
+ ${model.attributes.inMemoryOnly
313
+ ? `
314
+ await Promise.resolve()
315
+ `
316
+ : `
268
317
  await this.db.${meta.data.repository.getMethodFnName}.delete({ where: { ${idField.sourceName}:id } })
269
-
318
+ `}
319
+
270
320
  ${uniqueStringFields.map((f) => `this.uniqueIds.${f.name}.delete(existingItem.${f.name})`).join('\n')}
271
321
 
272
322
  this.data.delete(${meta.types.toBrandedIdTypeFnName}(id))
273
323
  }
274
324
 
325
+ ${maxLengthStringFields.map((f) => {
326
+ return `
327
+ /**
328
+ * Utility function that ensures that the ${f.name} field has a max length of ${f.attributes.maxLength}
329
+ */
330
+ private ${getEnsureMaxLengthFnName(f)}(item: { ${f.name}?: string }) {
331
+ if (!item.${f.name}) return
332
+ if (item.${f.name}.length <= ${f.attributes.maxLength}) return
333
+ item.${f.name} = item.${f.name}.substring(0, ${f.attributes.maxLength - 4}) + \`...\`
334
+ }`;
335
+ })}
336
+
275
337
  ${uniqueStringFields
276
338
  .map((f) => {
277
339
  return `
@@ -314,3 +376,6 @@ exports.generateRepository = generateRepository;
314
376
  function getEnsureUniqueFnName(field) {
315
377
  return `ensureUnique${(0, string_1.toPascalCase)(field.name)}`;
316
378
  }
379
+ function getEnsureMaxLengthFnName(field) {
380
+ return `ensureMaxLength${(0, string_1.toPascalCase)(field.name)}`;
381
+ }
@@ -28,6 +28,11 @@ export type ModelAttributes = {
28
28
  * Note: Prisma has it's own schema attribute - but does not expose it in the DMMF.
29
29
  */
30
30
  databaseSchema?: string;
31
+ /**
32
+ * Schema tag: ´@@InMemoryOnly()`
33
+ * Whether the model should be stored in the database or only in memory.
34
+ */
35
+ inMemoryOnly: boolean;
31
36
  };
32
37
  export type FieldAttributes = {
33
38
  /**
@@ -33,3 +33,7 @@ export declare const getDefaultValueForType: (type: string) => string;
33
33
  * Returns true if the given field is unique and a string field.
34
34
  */
35
35
  export declare const isUniqueStringField: (f: Field) => boolean;
36
+ /**
37
+ * Returns true if the given field has a maxLength attribute.
38
+ */
39
+ export declare const isMaxLengthStringField: (f: Field) => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUniqueStringField = exports.getDefaultValueForType = exports.getEnumFields = exports.getRelationFields = exports.getScalarFields = exports.getDefaultField = void 0;
3
+ exports.isMaxLengthStringField = exports.isUniqueStringField = exports.getDefaultValueForType = exports.getEnumFields = exports.getRelationFields = exports.getScalarFields = exports.getDefaultField = void 0;
4
4
  /**
5
5
  * The default field of the model.
6
6
  * Note: A model can only have one or no default field!
@@ -47,3 +47,9 @@ exports.getDefaultValueForType = getDefaultValueForType;
47
47
  const isUniqueStringField = (f) => (f.kind === 'id' && f.isUnique && f.unbrandedTypeName === 'string') ||
48
48
  (f.kind === 'scalar' && f.isUnique && f.typeName === 'string');
49
49
  exports.isUniqueStringField = isUniqueStringField;
50
+ /**
51
+ * Returns true if the given field has a maxLength attribute.
52
+ */
53
+ const isMaxLengthStringField = (f) => (f.kind === 'id' && !!f.attributes.maxLength && f.unbrandedTypeName === 'string') ||
54
+ (f.kind === 'scalar' && !!f.attributes.maxLength && f.typeName === 'string');
55
+ exports.isMaxLengthStringField = isMaxLengthStringField;
@@ -53,6 +53,7 @@ function getModelAttributes(model) {
53
53
  skipUpdate: Object.hasOwn(attributes, 'skipUpdate') || Object.hasOwn(attributes, 'customUpdate'),
54
54
  skipCreate: Object.hasOwn(attributes, 'skipCreate') || Object.hasOwn(attributes, 'customCreate'),
55
55
  skipDelete: Object.hasOwn(attributes, 'skipDelete') || Object.hasOwn(attributes, 'customDelete'),
56
+ inMemoryOnly: Object.hasOwn(attributes, 'inMemoryOnly'),
56
57
  description: attributes.description && (0, remeda_1.isString)(attributes.description) ? attributes.description : undefined,
57
58
  databaseSchema: attributes.schema && (0, remeda_1.isString)(attributes.schema) ? attributes.schema : undefined,
58
59
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.6.10",
3
+ "version": "0.7.1",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {