@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
|
-
|
|
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(
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
+
}
|
package/dist/lib/attributes.d.ts
CHANGED
|
@@ -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
|
};
|