@postxl/generator 0.38.2 → 0.40.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.
- package/dist/generator.js +43 -21
- package/dist/generators/enums/types.generator.js +1 -1
- package/dist/generators/indices/businesslogic-actiontypes.generator.js +1 -1
- package/dist/generators/indices/businesslogic-update-module.generator.js +2 -2
- package/dist/generators/indices/businesslogic-update-service.generator.js +1 -1
- package/dist/generators/indices/businesslogic-view-module.generator.js +2 -2
- package/dist/generators/indices/businesslogic-view-service.generator.js +1 -1
- package/dist/generators/indices/{seed-service.generator.d.ts → data-types.generator.d.ts} +2 -2
- package/dist/generators/indices/data-types.generator.js +48 -0
- package/dist/generators/indices/datamock-module.generator.js +11 -11
- package/dist/generators/indices/datamocker.generator.js +1 -1
- package/dist/generators/indices/datamodule.generator.js +34 -52
- package/dist/generators/indices/dataservice.generator.js +202 -9
- package/dist/generators/indices/dispatcher-service.generator.js +20 -10
- package/dist/generators/indices/emptydatabasemigration.generator.d.ts +2 -0
- package/dist/generators/indices/emptydatabasemigration.generator.js +14 -7
- package/dist/generators/indices/importexport-convert-import-functions.generator.d.ts +9 -0
- package/dist/generators/indices/importexport-convert-import-functions.generator.js +528 -0
- package/dist/generators/indices/importexport-exporter-class.generator.d.ts +9 -0
- package/dist/generators/indices/importexport-exporter-class.generator.js +116 -0
- package/dist/generators/indices/importexport-import-service.generator.d.ts +9 -0
- package/dist/generators/indices/importexport-import-service.generator.js +563 -0
- package/dist/generators/indices/{seeddata-type.generator.d.ts → importexport-types.generator.d.ts} +2 -2
- package/dist/generators/indices/importexport-types.generator.js +234 -0
- package/dist/generators/indices/repositories.generator.js +8 -8
- package/dist/generators/indices/seed-migration.generator.js +1 -1
- package/dist/generators/indices/seed-template.generator.js +1 -1
- package/dist/generators/indices/selectors.generator.d.ts +7 -0
- package/dist/generators/indices/selectors.generator.js +82 -0
- package/dist/generators/indices/{seed-template-decoder.generator.d.ts → testdata-service.generator.d.ts} +2 -2
- package/dist/generators/indices/testdata-service.generator.js +71 -0
- package/dist/generators/models/businesslogic-update.generator.js +6 -6
- package/dist/generators/models/businesslogic-view.generator.js +4 -4
- package/dist/generators/models/importexport-decoder.generator.d.ts +23 -0
- package/dist/generators/models/importexport-decoder.generator.js +234 -0
- package/dist/generators/models/react.generator/library.generator.js +4 -0
- package/dist/generators/models/react.generator/modals.generator.js +35 -8
- package/dist/generators/models/repository.generator.js +156 -18
- package/dist/generators/models/route.generator.js +2 -2
- package/dist/generators/models/stub.generator.js +1 -1
- package/dist/generators/models/types.generator.js +1 -1
- package/dist/lib/id-collector.d.ts +43 -0
- package/dist/lib/id-collector.js +53 -0
- package/dist/lib/imports.d.ts +1 -1
- package/dist/lib/meta.d.ts +480 -122
- package/dist/lib/meta.js +187 -74
- package/dist/lib/schema/schema.d.ts +58 -43
- package/dist/lib/schema/types.d.ts +63 -12
- package/dist/lib/schema/types.js +27 -7
- package/dist/lib/utils/string.d.ts +1 -0
- package/dist/lib/utils/string.js +1 -0
- package/dist/prisma/parse.js +4 -4
- package/package.json +2 -2
- package/dist/generators/indices/seed-service.generator.js +0 -356
- package/dist/generators/indices/seed-template-decoder.generator.js +0 -151
- package/dist/generators/indices/seeddata-type.generator.js +0 -42
|
@@ -14,8 +14,8 @@ const string_1 = require("../../lib/utils/string");
|
|
|
14
14
|
function generateRepository({ model, meta }) {
|
|
15
15
|
const { idField } = model;
|
|
16
16
|
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
17
|
-
const imports = imports_1.ImportsGenerator.from(meta.data.
|
|
18
|
-
[schemaMeta.data.
|
|
17
|
+
const imports = imports_1.ImportsGenerator.from(meta.data.repository.filePath).addImports({
|
|
18
|
+
[schemaMeta.data.repository.typeFilePath]: schemaMeta.data.repository.typeName,
|
|
19
19
|
[meta.types.importPath]: [
|
|
20
20
|
model.typeName,
|
|
21
21
|
model.brandedIdType,
|
|
@@ -24,7 +24,7 @@ function generateRepository({ model, meta }) {
|
|
|
24
24
|
meta.types.dto.update,
|
|
25
25
|
meta.types.dto.upsert,
|
|
26
26
|
],
|
|
27
|
-
[schemaMeta.actions.importPath]: [schemaMeta.actions.
|
|
27
|
+
[schemaMeta.actions.importPath]: [schemaMeta.actions.actionExecution.interface],
|
|
28
28
|
});
|
|
29
29
|
// NOTE: We first generate different parts of the code responsible for a particular task
|
|
30
30
|
// and then we combine them into the final code block.
|
|
@@ -37,7 +37,7 @@ function generateRepository({ model, meta }) {
|
|
|
37
37
|
// and allow being called with an id,
|
|
38
38
|
// 3.) unique string fields are ensured to be unique,
|
|
39
39
|
// 4.) max length string fields are ensured to not exceed their max length,
|
|
40
|
-
// 5.) index for fields marked with index attribute,
|
|
40
|
+
// 5.) index for fields marked with index or unique attribute,
|
|
41
41
|
// 6.) relations are indexed by the foreign key.
|
|
42
42
|
//
|
|
43
43
|
// The repository is generated differently based on whether the model is stored in the database or in memory.
|
|
@@ -47,6 +47,7 @@ function generateRepository({ model, meta }) {
|
|
|
47
47
|
const defaultValueBlocks = generateDefaultBlocks({ model, meta });
|
|
48
48
|
const uniqueStringFieldsBlocks = generateUniqueFieldsBlocks({ model, meta });
|
|
49
49
|
const maxLengthBlocks = generateMaxLengthBlocks({ model, meta });
|
|
50
|
+
const validationBlocks = generateValidationBlocks({ model, meta });
|
|
50
51
|
const indexBlocks = generateIndexBlocks({ model, meta, imports });
|
|
51
52
|
const relationsBlocks = generateRelationsBlocks({ model, meta, imports });
|
|
52
53
|
let mainBlocks;
|
|
@@ -55,12 +56,14 @@ function generateRepository({ model, meta }) {
|
|
|
55
56
|
model,
|
|
56
57
|
meta,
|
|
57
58
|
schemaMeta,
|
|
59
|
+
imports,
|
|
58
60
|
blocks: {
|
|
59
61
|
uniqueStringFieldsBlocks,
|
|
60
62
|
defaultValueBlocks,
|
|
61
63
|
idBlocks,
|
|
62
64
|
indexBlocks,
|
|
63
65
|
maxLengthBlocks,
|
|
66
|
+
validationBlocks,
|
|
64
67
|
},
|
|
65
68
|
});
|
|
66
69
|
}
|
|
@@ -76,6 +79,7 @@ function generateRepository({ model, meta }) {
|
|
|
76
79
|
idBlocks,
|
|
77
80
|
indexBlocks,
|
|
78
81
|
maxLengthBlocks,
|
|
82
|
+
validationBlocks,
|
|
79
83
|
},
|
|
80
84
|
});
|
|
81
85
|
}
|
|
@@ -85,9 +89,9 @@ ${idBlocks.libraryImports}
|
|
|
85
89
|
${imports.generate()}
|
|
86
90
|
|
|
87
91
|
@Injectable()
|
|
88
|
-
export class ${meta.data.
|
|
92
|
+
export class ${meta.data.repository.className} implements Repository<${model.typeName}, ${idField.unbrandedTypeName}> {
|
|
89
93
|
protected data: Map<${model.brandedIdType}, ${model.typeName}> = new Map()
|
|
90
|
-
protected logger = new Logger(${meta.data.
|
|
94
|
+
protected logger = new Logger(${meta.data.repository.className}.name)
|
|
91
95
|
|
|
92
96
|
${relationsBlocks.mapDeclarations.join('\n')}
|
|
93
97
|
|
|
@@ -96,11 +100,15 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
96
100
|
${idBlocks.generateNextIdFunctionName}
|
|
97
101
|
|
|
98
102
|
protected uniqueIds = {
|
|
99
|
-
${uniqueStringFieldsBlocks.mapDeclarations.join(',\n')}
|
|
103
|
+
${uniqueStringFieldsBlocks.mapDeclarations.join(',\n')}
|
|
100
104
|
}
|
|
101
|
-
|
|
105
|
+
|
|
102
106
|
${indexBlocks.nestedMapDeclarations.join('\n')}
|
|
103
107
|
|
|
108
|
+
${mainBlocks.userRepositorySpecificBlocks.rootUserNameConst}
|
|
109
|
+
|
|
110
|
+
${mainBlocks.userRepositorySpecificBlocks.getterBlock}
|
|
111
|
+
|
|
104
112
|
${mainBlocks.constructorCode}
|
|
105
113
|
|
|
106
114
|
${mainBlocks.initCode}
|
|
@@ -109,6 +117,8 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
109
117
|
|
|
110
118
|
${mainBlocks.deleteAllCode}
|
|
111
119
|
|
|
120
|
+
${mainBlocks.userRepositorySpecificBlocks.rootUserInitializeBlock}
|
|
121
|
+
|
|
112
122
|
public async get(id: ${model.brandedIdType} | null): Promise<${model.typeName} | null> {
|
|
113
123
|
if (id === null) {
|
|
114
124
|
return Promise.resolve(null)
|
|
@@ -126,6 +136,8 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
126
136
|
|
|
127
137
|
${indexBlocks.getterFunctions.join('\n')}
|
|
128
138
|
|
|
139
|
+
${uniqueStringFieldsBlocks.getByFunctions.join('\n')}
|
|
140
|
+
|
|
129
141
|
public async filter(predicate: (item: ${model.typeName}) => boolean): Promise<${model.typeName}[]> {
|
|
130
142
|
return (await this.getAllAsArray()).filter(predicate)
|
|
131
143
|
}
|
|
@@ -197,7 +209,7 @@ exports.generateRepository = generateRepository;
|
|
|
197
209
|
*/
|
|
198
210
|
function generateMockRepository({ model: modelSource, meta: metaSource, }) {
|
|
199
211
|
// 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
|
|
200
|
-
const meta = Object.assign(Object.assign({}, metaSource), { data: Object.assign(Object.assign({}, metaSource.data), {
|
|
212
|
+
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, filePath: metaSource.data.mockRepository.filePath }) }) });
|
|
201
213
|
const model = Object.assign(Object.assign({}, modelSource), { attributes: Object.assign(Object.assign({}, modelSource.attributes), { inMemoryOnly: true }) });
|
|
202
214
|
return generateRepository({ model, meta });
|
|
203
215
|
}
|
|
@@ -205,10 +217,12 @@ exports.generateMockRepository = generateMockRepository;
|
|
|
205
217
|
/**
|
|
206
218
|
* Generates the main building blocks of the repository for in-memory model.
|
|
207
219
|
*/
|
|
208
|
-
function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
220
|
+
function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, imports, blocks, }) {
|
|
209
221
|
const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
|
|
222
|
+
const userRepositorySpecificBlocks = generateUserRepositorySpecificBlocks_InMemoryOnly({ model, meta, imports });
|
|
210
223
|
return {
|
|
211
224
|
constructorCode: '',
|
|
225
|
+
userRepositorySpecificBlocks,
|
|
212
226
|
initCode: `
|
|
213
227
|
public async init() {
|
|
214
228
|
this.data.clear()
|
|
@@ -218,6 +232,8 @@ function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
218
232
|
|
|
219
233
|
${blocks.indexBlocks.initCode.join('\n')}
|
|
220
234
|
|
|
235
|
+
${userRepositorySpecificBlocks.initCall}
|
|
236
|
+
|
|
221
237
|
return Promise.resolve()
|
|
222
238
|
}`,
|
|
223
239
|
reInitCode: `
|
|
@@ -245,6 +261,8 @@ function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
245
261
|
|
|
246
262
|
${blocks.uniqueStringFieldsBlocks.verifyCode.join('\n')}
|
|
247
263
|
|
|
264
|
+
${blocks.validationBlocks.verifyCode.join('\n')}
|
|
265
|
+
|
|
248
266
|
return {
|
|
249
267
|
${model.idField.name},
|
|
250
268
|
${model.fields
|
|
@@ -446,8 +464,10 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
446
464
|
.map((part) => `"${part}"`)
|
|
447
465
|
.join('.');
|
|
448
466
|
const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
|
|
467
|
+
const userRepositorySpecificBlocks = generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports });
|
|
449
468
|
return {
|
|
450
469
|
constructorCode: `constructor(protected db: DbService) {}`,
|
|
470
|
+
userRepositorySpecificBlocks,
|
|
451
471
|
initCode: `
|
|
452
472
|
public async init() {
|
|
453
473
|
this.data.clear()
|
|
@@ -471,6 +491,8 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
471
491
|
|
|
472
492
|
${blocks.defaultValueBlocks.init.checkCode}
|
|
473
493
|
|
|
494
|
+
${userRepositorySpecificBlocks.initCall}
|
|
495
|
+
|
|
474
496
|
this.logger.log(\`\${format(this.data.size)} \${pluralize('${model.typeName}', this.data.size)} loaded\`)
|
|
475
497
|
${blocks.indexBlocks.initLogCode.join('\n')}
|
|
476
498
|
}`,
|
|
@@ -512,6 +534,8 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
512
534
|
${blocks.maxLengthBlocks.verifyCode.join('\n')}
|
|
513
535
|
|
|
514
536
|
${blocks.uniqueStringFieldsBlocks.verifyCode.join('\n')}
|
|
537
|
+
|
|
538
|
+
${blocks.validationBlocks.verifyCode.join('\n')}
|
|
515
539
|
|
|
516
540
|
return {
|
|
517
541
|
${idField.name},
|
|
@@ -741,6 +765,100 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
741
765
|
}`,
|
|
742
766
|
};
|
|
743
767
|
}
|
|
768
|
+
function generateUserRepositorySpecificBlocks_InDatabase({ model, meta, imports, }) {
|
|
769
|
+
if (model.name !== 'User') {
|
|
770
|
+
return {
|
|
771
|
+
rootUserNameConst: '',
|
|
772
|
+
getterBlock: '',
|
|
773
|
+
initCall: '',
|
|
774
|
+
rootUserInitializeBlock: '',
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
imports.addImport({
|
|
778
|
+
from: meta.types.importPath,
|
|
779
|
+
items: [(0, types_1.toTypeName)('UserRole')],
|
|
780
|
+
});
|
|
781
|
+
return {
|
|
782
|
+
rootUserNameConst: `public static ROOT_USER_ID = ${meta.types.toBrandedIdTypeFnName}('root')`,
|
|
783
|
+
getterBlock: `
|
|
784
|
+
// We initialize the root user in the init() function
|
|
785
|
+
private _rootUser!: ${meta.types.typeName}
|
|
786
|
+
public get rootUser(): ${meta.types.typeName} {
|
|
787
|
+
return this._rootUser
|
|
788
|
+
}`,
|
|
789
|
+
initCall: `await this.initializeRootUser()`,
|
|
790
|
+
rootUserInitializeBlock: `
|
|
791
|
+
private async initializeRootUser(): Promise<void> {
|
|
792
|
+
const existingRootUser = await this.get(${meta.data.repository.className}.ROOT_USER_ID)
|
|
793
|
+
if (existingRootUser) {
|
|
794
|
+
this._rootUser = existingRootUser
|
|
795
|
+
return
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const rawUser = await this.db.user.create({
|
|
799
|
+
data: {
|
|
800
|
+
id: ${meta.data.repository.className}.ROOT_USER_ID,
|
|
801
|
+
name: 'System',
|
|
802
|
+
email: 'system@postxl.com',
|
|
803
|
+
role: UserRole.Admin,
|
|
804
|
+
login: 'not-set',
|
|
805
|
+
familyName: 'System user',
|
|
806
|
+
age: 0,
|
|
807
|
+
countryId: null,
|
|
808
|
+
},
|
|
809
|
+
})
|
|
810
|
+
const newRootUser = this.toUser(rawUser)
|
|
811
|
+
this.set(newRootUser)
|
|
812
|
+
this._rootUser = newRootUser
|
|
813
|
+
}`,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
function generateUserRepositorySpecificBlocks_InMemoryOnly({ model, meta, imports, }) {
|
|
817
|
+
if (model.name !== 'User') {
|
|
818
|
+
return {
|
|
819
|
+
rootUserNameConst: '',
|
|
820
|
+
getterBlock: '',
|
|
821
|
+
initCall: '',
|
|
822
|
+
rootUserInitializeBlock: '',
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
imports.addImport({
|
|
826
|
+
from: meta.types.importPath,
|
|
827
|
+
items: [(0, types_1.toTypeName)('UserRole')],
|
|
828
|
+
});
|
|
829
|
+
return {
|
|
830
|
+
rootUserNameConst: `public static ROOT_USER_ID = ${meta.types.toBrandedIdTypeFnName}('root')`,
|
|
831
|
+
getterBlock: `
|
|
832
|
+
// We initialize the root user in the init() function
|
|
833
|
+
private _rootUser!: ${meta.types.typeName}
|
|
834
|
+
public get rootUser(): ${meta.types.typeName} {
|
|
835
|
+
return this._rootUser
|
|
836
|
+
}`,
|
|
837
|
+
initCall: `await this.initializeRootUser()`,
|
|
838
|
+
rootUserInitializeBlock: `
|
|
839
|
+
private async initializeRootUser(): Promise<void> {
|
|
840
|
+
const existingRootUser = await this.get(${meta.data.repository.className}.ROOT_USER_ID)
|
|
841
|
+
if (existingRootUser) {
|
|
842
|
+
this._rootUser = existingRootUser
|
|
843
|
+
return
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const rawUser = {
|
|
847
|
+
id: ${meta.data.repository.className}.ROOT_USER_ID,
|
|
848
|
+
name: 'System',
|
|
849
|
+
email: 'system@postxl.com',
|
|
850
|
+
role: UserRole.Admin,
|
|
851
|
+
login: 'not-set',
|
|
852
|
+
familyName: 'System user',
|
|
853
|
+
age: 0,
|
|
854
|
+
countryId: null,
|
|
855
|
+
}
|
|
856
|
+
const newRootUser = this.verifyItem (rawUser)
|
|
857
|
+
this.set(newRootUser)
|
|
858
|
+
this._rootUser = newRootUser
|
|
859
|
+
}`,
|
|
860
|
+
};
|
|
861
|
+
}
|
|
744
862
|
/**
|
|
745
863
|
* Generates code chunks responsible for verifying the ID validity of a model instance and generating the id
|
|
746
864
|
* value of a model with auto-generated id.
|
|
@@ -768,42 +886,42 @@ function getRepositoryMethodsTypeSignatures({ model, meta }) {
|
|
|
768
886
|
return {
|
|
769
887
|
create: {
|
|
770
888
|
jsDoc: [`Creates a new ${meta.userFriendlyName} and returns it.`],
|
|
771
|
-
parameters: [`{item: ${meta.types.dto.create}, execution: ${schemaMeta.actions.
|
|
889
|
+
parameters: [`{item: ${meta.types.dto.create}, execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
772
890
|
returnType: `Promise<${model.typeName}>`,
|
|
773
891
|
},
|
|
774
892
|
createMany: {
|
|
775
893
|
jsDoc: [`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`],
|
|
776
|
-
parameters: [`{items: ${meta.types.dto.create}[], execution: ${schemaMeta.actions.
|
|
894
|
+
parameters: [`{items: ${meta.types.dto.create}[], execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
777
895
|
returnType: `Promise<${model.typeName}[]>`,
|
|
778
896
|
},
|
|
779
897
|
update: {
|
|
780
898
|
jsDoc: [`Updates a ${meta.userFriendlyName} and returns it.`],
|
|
781
|
-
parameters: [`{item: ${meta.types.dto.update}, execution: ${schemaMeta.actions.
|
|
899
|
+
parameters: [`{item: ${meta.types.dto.update}, execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
782
900
|
returnType: `Promise<${model.typeName}>`,
|
|
783
901
|
},
|
|
784
902
|
updateMany: {
|
|
785
903
|
jsDoc: [`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`],
|
|
786
|
-
parameters: [`{items: ${meta.types.dto.update}[], execution: ${schemaMeta.actions.
|
|
904
|
+
parameters: [`{items: ${meta.types.dto.update}[], execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
787
905
|
returnType: `Promise<${model.typeName}[]>`,
|
|
788
906
|
},
|
|
789
907
|
upsert: {
|
|
790
908
|
jsDoc: [`Creates or updates a ${meta.userFriendlyName} and returns it.`],
|
|
791
|
-
parameters: [`{item: ${meta.types.dto.upsert}, execution: ${schemaMeta.actions.
|
|
909
|
+
parameters: [`{item: ${meta.types.dto.upsert}, execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
792
910
|
returnType: `Promise<${model.typeName}>`,
|
|
793
911
|
},
|
|
794
912
|
upsertMany: {
|
|
795
913
|
jsDoc: [`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`],
|
|
796
|
-
parameters: [`{items: ${meta.types.dto.upsert}[], execution: ${schemaMeta.actions.
|
|
914
|
+
parameters: [`{items: ${meta.types.dto.upsert}[], execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
797
915
|
returnType: `Promise<${model.typeName}[]>`,
|
|
798
916
|
},
|
|
799
917
|
delete: {
|
|
800
918
|
jsDoc: [`Deletes a ${meta.userFriendlyName} and returns its id.`],
|
|
801
|
-
parameters: [`{id: ${model.brandedIdType}, execution: ${schemaMeta.actions.
|
|
919
|
+
parameters: [`{id: ${model.brandedIdType}, execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
802
920
|
returnType: `Promise<${model.brandedIdType}>`,
|
|
803
921
|
},
|
|
804
922
|
deleteMany: {
|
|
805
923
|
jsDoc: [`Deletes multiple ${meta.userFriendlyNamePlural} and returns their ids.`],
|
|
806
|
-
parameters: [`{ids: ${model.brandedIdType}[], execution: ${schemaMeta.actions.
|
|
924
|
+
parameters: [`{ids: ${model.brandedIdType}[], execution: ${schemaMeta.actions.actionExecution.interface}}`],
|
|
807
925
|
returnType: `Promise<${model.brandedIdType}[]>`,
|
|
808
926
|
},
|
|
809
927
|
};
|
|
@@ -929,6 +1047,7 @@ function generateUniqueFieldsBlocks({ model }) {
|
|
|
929
1047
|
const fields = model.fields.filter(fields_1.isUniqueStringField);
|
|
930
1048
|
const result = {
|
|
931
1049
|
mapDeclarations: [],
|
|
1050
|
+
getByFunctions: [],
|
|
932
1051
|
clearCode: [],
|
|
933
1052
|
verifyFunctionComment: '',
|
|
934
1053
|
verifyCode: [],
|
|
@@ -939,6 +1058,10 @@ function generateUniqueFieldsBlocks({ model }) {
|
|
|
939
1058
|
};
|
|
940
1059
|
for (const f of fields) {
|
|
941
1060
|
result.mapDeclarations.push(`'${f.name}': new Map<string, ${model.typeName}>()`);
|
|
1061
|
+
result.getByFunctions.push(`
|
|
1062
|
+
public async getBy${(0, string_1.toPascalCase)(f.name)}(${f.name}: string): Promise<${model.typeName} | undefined> {
|
|
1063
|
+
return Promise.resolve(this.uniqueIds.${f.name}.get(${(0, string_1.toCamelCase)(f.name)}))
|
|
1064
|
+
}`);
|
|
942
1065
|
result.clearCode.push(`this.uniqueIds.${f.name}.clear()`);
|
|
943
1066
|
result.verifyCode.push(`this.${getEnsureUniqueFnName(f)}(item)`);
|
|
944
1067
|
result.updateCode.push(`
|
|
@@ -1025,6 +1148,21 @@ function generateMaxLengthBlocks({ model }) {
|
|
|
1025
1148
|
function getEnsureMaxLengthFnName(field) {
|
|
1026
1149
|
return `ensureMaxLength${(0, string_1.toPascalCase)(field.name)}`;
|
|
1027
1150
|
}
|
|
1151
|
+
function generateValidationBlocks({ model }) {
|
|
1152
|
+
const fields = model.fields.filter((f) => f.kind === 'scalar' && f.validation && f.validation.type === 'int');
|
|
1153
|
+
const result = {
|
|
1154
|
+
verifyCode: [],
|
|
1155
|
+
};
|
|
1156
|
+
for (const f of fields) {
|
|
1157
|
+
const itemExists = f.isRequired ? '' : `item.${f.name} !== null && `;
|
|
1158
|
+
result.verifyCode.push(`
|
|
1159
|
+
// ensure that ${f.name} is an integer
|
|
1160
|
+
if (${itemExists}item.${f.name} !== Math.floor(item.${f.name})) {
|
|
1161
|
+
throw new Error(\`Invalid value for field ${f.name}: \${item.${f.name}}. Value must be an integer.\`)
|
|
1162
|
+
}`);
|
|
1163
|
+
}
|
|
1164
|
+
return result;
|
|
1165
|
+
}
|
|
1028
1166
|
function generateIndexBlocks({ model, imports, }) {
|
|
1029
1167
|
const indexes = model.attributes.index ? [getIndexDefinition({ fieldNames: model.attributes.index, model })] : [];
|
|
1030
1168
|
if (indexes.length > 0) {
|
|
@@ -31,7 +31,7 @@ function generateRoute({ model, meta }) {
|
|
|
31
31
|
meta.businessLogic.update.createActionFunctionNameDeleteMany,
|
|
32
32
|
],
|
|
33
33
|
});
|
|
34
|
-
return `
|
|
34
|
+
return /* ts */ `
|
|
35
35
|
import { z } from 'zod'
|
|
36
36
|
import { procedure, router } from '../trpc'
|
|
37
37
|
|
|
@@ -107,7 +107,7 @@ function generateRoutesIndex({ models, meta }) {
|
|
|
107
107
|
for (const { meta } of mm) {
|
|
108
108
|
imports.addImport({ items: [meta.trpc.routerName], from: meta.trpc.routerFilePath });
|
|
109
109
|
}
|
|
110
|
-
return `
|
|
110
|
+
return /* ts */ `
|
|
111
111
|
${imports.generate()}
|
|
112
112
|
|
|
113
113
|
/**
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type ElementId = string & {
|
|
2
|
+
__brand: 'ElementId';
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* The SelectorCollector is used to generate and track HTML element IDs.
|
|
6
|
+
* The idea is that it is instantiated once and then used to generate IDs throughout the generators.
|
|
7
|
+
* After the files are generated, all generated IDs can be serialized to a file.
|
|
8
|
+
*
|
|
9
|
+
* An ID can for instance be something like `post-create-name, `${model.name}-${componentType}-${fieldName}`.
|
|
10
|
+
*
|
|
11
|
+
* Each code generator can instantiate an SelectorCollector - the constructor will require the current model & component type.
|
|
12
|
+
* All generated Ids will be stored in a global static Set so we can serialize them later.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SelectorCollector {
|
|
15
|
+
private _prefix;
|
|
16
|
+
/**
|
|
17
|
+
* We store all generated IDs in a global static Set so we can serialize them later.
|
|
18
|
+
*/
|
|
19
|
+
private static _ids;
|
|
20
|
+
constructor(_prefix: string);
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new instance of the SelectorCollector.
|
|
23
|
+
*/
|
|
24
|
+
static from(prefix: string): SelectorCollector;
|
|
25
|
+
/**
|
|
26
|
+
* Generates a new ID for an element and stores it in the collector
|
|
27
|
+
*/
|
|
28
|
+
idFor(
|
|
29
|
+
/**
|
|
30
|
+
* The name of the element, e.g. `age`, `submit`.
|
|
31
|
+
*/
|
|
32
|
+
elementName: string, options?: {
|
|
33
|
+
/**
|
|
34
|
+
* Optional prefix for the type of the element, e.g. `field` or `button`.
|
|
35
|
+
*/
|
|
36
|
+
typePrefix?: string;
|
|
37
|
+
}): string;
|
|
38
|
+
/**
|
|
39
|
+
* Returns all generated IDs and resets the stored IDs.
|
|
40
|
+
*/
|
|
41
|
+
static flush(): ElementId[];
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SelectorCollector = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The SelectorCollector is used to generate and track HTML element IDs.
|
|
6
|
+
* The idea is that it is instantiated once and then used to generate IDs throughout the generators.
|
|
7
|
+
* After the files are generated, all generated IDs can be serialized to a file.
|
|
8
|
+
*
|
|
9
|
+
* An ID can for instance be something like `post-create-name, `${model.name}-${componentType}-${fieldName}`.
|
|
10
|
+
*
|
|
11
|
+
* Each code generator can instantiate an SelectorCollector - the constructor will require the current model & component type.
|
|
12
|
+
* All generated Ids will be stored in a global static Set so we can serialize them later.
|
|
13
|
+
*/
|
|
14
|
+
class SelectorCollector {
|
|
15
|
+
constructor(_prefix) {
|
|
16
|
+
this._prefix = _prefix;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new instance of the SelectorCollector.
|
|
20
|
+
*/
|
|
21
|
+
static from(prefix) {
|
|
22
|
+
return new SelectorCollector(prefix);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generates a new ID for an element and stores it in the collector
|
|
26
|
+
*/
|
|
27
|
+
idFor(
|
|
28
|
+
/**
|
|
29
|
+
* The name of the element, e.g. `age`, `submit`.
|
|
30
|
+
*/
|
|
31
|
+
elementName, options) {
|
|
32
|
+
const { typePrefix } = options !== null && options !== void 0 ? options : {};
|
|
33
|
+
const id = [this._prefix, typePrefix, elementName].filter((x) => x !== undefined && x !== '').join('-');
|
|
34
|
+
if (SelectorCollector._ids.has(id)) {
|
|
35
|
+
throw new Error(`ID ${id} already exists.`);
|
|
36
|
+
}
|
|
37
|
+
SelectorCollector._ids.add(id);
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns all generated IDs and resets the stored IDs.
|
|
42
|
+
*/
|
|
43
|
+
static flush() {
|
|
44
|
+
const result = [...SelectorCollector._ids.values()];
|
|
45
|
+
SelectorCollector._ids.clear();
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.SelectorCollector = SelectorCollector;
|
|
50
|
+
/**
|
|
51
|
+
* We store all generated IDs in a global static Set so we can serialize them later.
|
|
52
|
+
*/
|
|
53
|
+
SelectorCollector._ids = new Set();
|
package/dist/lib/imports.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as Types from './schema/types';
|
|
|
6
6
|
* Example:
|
|
7
7
|
* ```
|
|
8
8
|
* {
|
|
9
|
-
* [meta.data.importPath]: meta.data.
|
|
9
|
+
* [meta.data.importPath]: meta.data.repository.className,
|
|
10
10
|
* [meta.types.importPath]: [model.brandedIdType, meta.types.typeName],
|
|
11
11
|
* }
|
|
12
12
|
* ```
|