@postxl/generator 0.39.0 → 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 +37 -21
- package/dist/generators/indices/businesslogic-update-module.generator.js +1 -1
- package/dist/generators/indices/businesslogic-view-module.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 +7 -7
- package/dist/generators/indices/datamodule.generator.js +13 -34
- package/dist/generators/indices/dataservice.generator.js +201 -8
- package/dist/generators/indices/dispatcher-service.generator.js +14 -5
- 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/{seed-template-decoder.generator.d.ts → importexport-exporter-class.generator.d.ts} +2 -2
- 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 +7 -7
- package/dist/generators/indices/seed-template.generator.js +1 -1
- package/dist/generators/indices/testdata-service.generator.js +5 -4
- package/dist/generators/models/businesslogic-update.generator.js +5 -5
- package/dist/generators/models/businesslogic-view.generator.js +3 -3
- 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/repository.generator.js +50 -21
- package/dist/lib/imports.d.ts +1 -1
- package/dist/lib/meta.d.ts +468 -134
- package/dist/lib/meta.js +187 -80
- package/dist/lib/schema/schema.d.ts +54 -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 +1 -1
- package/dist/generators/indices/seed-service.generator.js +0 -354
- package/dist/generators/indices/seed-template-decoder.generator.js +0 -151
- package/dist/generators/indices/seeddata-type.generator.js +0 -42
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateImportExportTypes = void 0;
|
|
4
|
+
const imports_1 = require("../../lib/imports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
|
+
/**
|
|
7
|
+
* Generates types for import export module.
|
|
8
|
+
*/
|
|
9
|
+
function generateImportExportTypes({ models, meta }) {
|
|
10
|
+
const { types } = meta.importExport;
|
|
11
|
+
const imports = imports_1.ImportsGenerator.from(types.filePath);
|
|
12
|
+
const dto = meta.types.dto;
|
|
13
|
+
imports.addImports({
|
|
14
|
+
[meta.types.importPath]: [dto.create, dto.update, dto.genericModel, dto.idType],
|
|
15
|
+
[meta.data.importPath]: [meta.data.types.bulkMutation],
|
|
16
|
+
});
|
|
17
|
+
const deltaTypes = [];
|
|
18
|
+
const errorTypes = [];
|
|
19
|
+
for (const model of models) {
|
|
20
|
+
const modelMeta = (0, meta_1.getModelMetadata)({ model });
|
|
21
|
+
imports.addImport({
|
|
22
|
+
items: [modelMeta.types.typeName, modelMeta.types.brandedIdType],
|
|
23
|
+
from: modelMeta.types.importPath,
|
|
24
|
+
});
|
|
25
|
+
const missingFields = [];
|
|
26
|
+
const invalidReferenceFieldErrors = [];
|
|
27
|
+
const nonUniqueFieldErrors = [];
|
|
28
|
+
const invalidTypeFieldErrors = [];
|
|
29
|
+
const isRequiredDependencyErrors = [];
|
|
30
|
+
// Prepare field specific error types
|
|
31
|
+
for (const field of model.fields) {
|
|
32
|
+
if (field.attributes.ignore || field.kind === 'id') {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (field.isRequired) {
|
|
36
|
+
missingFields.push(`"${field.name}"`);
|
|
37
|
+
}
|
|
38
|
+
if (field.kind === 'relation') {
|
|
39
|
+
invalidReferenceFieldErrors.push(`
|
|
40
|
+
${types.delta_Model.errors.invalidReference.type}<"${field.relationToModel.name}", "${field.name}", ${field.relationToModel.brandedIdType}>
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
if (field.kind === 'scalar' && field.isUnique) {
|
|
44
|
+
nonUniqueFieldErrors.push(`
|
|
45
|
+
${types.delta_Model.errors.nonUnique.type}<"${field.name}", ${field.tsTypeName}>
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
if (field.kind === 'scalar' && field.validation) {
|
|
49
|
+
invalidTypeFieldErrors.push(`
|
|
50
|
+
${types.delta_Model.errors.invalidType.type}<"${field.name}", "${field.schemaType}", ${field.tsTypeName}>
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Prepare isRequiredDependency errors
|
|
55
|
+
for (const relatedModel of models) {
|
|
56
|
+
if (relatedModel.name === model.name) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
for (const relatedField of relatedModel.fields) {
|
|
60
|
+
if (relatedField.kind !== 'relation' ||
|
|
61
|
+
relatedField.relationToModel.name !== model.name ||
|
|
62
|
+
!relatedField.isRequired) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
isRequiredDependencyErrors.push(`
|
|
66
|
+
${types.delta_Model.errors.isRequiredDependency.type}<
|
|
67
|
+
'${relatedModel.name}',
|
|
68
|
+
'${relatedField.name}',
|
|
69
|
+
${relatedModel.typeName},
|
|
70
|
+
${relatedModel.brandedIdType}
|
|
71
|
+
>
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const missingFieldError = missingFields.length > 0
|
|
76
|
+
? `${types.delta_Model.errors.missingField.type}<${missingFields.join(' | ')}> `
|
|
77
|
+
: undefined;
|
|
78
|
+
const modelErrorTypes = [
|
|
79
|
+
missingFieldError,
|
|
80
|
+
...invalidReferenceFieldErrors,
|
|
81
|
+
...nonUniqueFieldErrors,
|
|
82
|
+
...invalidTypeFieldErrors,
|
|
83
|
+
...isRequiredDependencyErrors,
|
|
84
|
+
].filter((t) => t !== undefined);
|
|
85
|
+
if (modelErrorTypes.length === 0) {
|
|
86
|
+
modelErrorTypes.push(`never`);
|
|
87
|
+
}
|
|
88
|
+
errorTypes.push(`export type ${modelMeta.importExport.delta_Model_Errors} = ${modelErrorTypes.join('\n| ')}`);
|
|
89
|
+
deltaTypes.push(`${modelMeta.seed.constantName}?: ${types.delta_Model.type}<
|
|
90
|
+
${modelMeta.types.typeName},
|
|
91
|
+
${modelMeta.types.brandedIdType},
|
|
92
|
+
${modelMeta.importExport.delta_Model_Errors}
|
|
93
|
+
>[]`);
|
|
94
|
+
}
|
|
95
|
+
return /* ts */ `
|
|
96
|
+
${imports.generate()}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Generic type that contains all changes between an existing item and an updated item.
|
|
100
|
+
*/
|
|
101
|
+
export type ${types.delta_Fields}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> = Partial<{
|
|
102
|
+
[K in keyof Omit<Model, 'id'>]?: { old: Model[K]; new: Model[K] }
|
|
103
|
+
}>
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* For a given imported item of a model, this type contains the determined action to take - create, update, delete or unchanged.
|
|
107
|
+
*/
|
|
108
|
+
export type ${types.delta_Model.type}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}, ModelErrors> =
|
|
109
|
+
| ${types.delta_Model.unchanged.type}<Model, ID>
|
|
110
|
+
| ${types.delta_Model.create.type}<Model, ID>
|
|
111
|
+
| ${types.delta_Model.update.type}<Model, ID>
|
|
112
|
+
| ${types.delta_Model.delete.type}<Model, ID>
|
|
113
|
+
| ${types.delta_Model.errors.type}<Model, ID, ModelErrors>
|
|
114
|
+
|
|
115
|
+
export type ${types.delta_Model.unchanged.type}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> = {
|
|
116
|
+
type: '${types.delta_Model.unchanged.discriminant}'
|
|
117
|
+
input: Model
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function ${types.delta_Model.unchanged.typeGuard}<Model extends ${dto.genericModel}<ID>, ID extends IDType>(
|
|
121
|
+
delta: Delta_Model<Model, ID, unknown>,
|
|
122
|
+
): delta is ${types.delta_Model.unchanged.type}<Model, ID> {
|
|
123
|
+
return delta.type === 'unchanged'
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export type ${types.delta_Model.create.type}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> = {
|
|
127
|
+
type: '${types.delta_Model.create.discriminant}'
|
|
128
|
+
input: Model
|
|
129
|
+
createDTO: ${dto.create}<Model, ID>
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function ${types.delta_Model.create.typeGuard}<Model extends ${dto.genericModel}<ID>, ID extends IDType>(
|
|
133
|
+
delta: Delta_Model<Model, ID, unknown>,
|
|
134
|
+
): delta is ${types.delta_Model.create.type}<Model, ID> {
|
|
135
|
+
return delta.type === 'create'
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export type ${types.delta_Model.update.type}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> = {
|
|
139
|
+
type: '${types.delta_Model.update.discriminant}'
|
|
140
|
+
input: Model
|
|
141
|
+
updateDTO: ${dto.update}<Model, ID>
|
|
142
|
+
delta: ${types.delta_Fields}<Model, ID>
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function ${types.delta_Model.update.typeGuard}<Model extends ${dto.genericModel}<ID>, ID extends IDType>(
|
|
146
|
+
delta: Delta_Model<Model, ID, unknown>,
|
|
147
|
+
): delta is ${types.delta_Model.update.type}<Model, ID> {
|
|
148
|
+
return delta.type === 'update'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type ${types.delta_Model.delete.type}<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> = {
|
|
152
|
+
type: '${types.delta_Model.delete.discriminant}'
|
|
153
|
+
input: Model
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function ${types.delta_Model.delete.typeGuard}<Model extends ${dto.genericModel}<ID>, ID extends IDType>(
|
|
157
|
+
delta: Delta_Model<Model, ID, unknown>,
|
|
158
|
+
): delta is ${types.delta_Model.delete.type}<Model, ID> {
|
|
159
|
+
return delta.type === 'delete'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type ${types.delta_Model.errors.type}<Model extends GenericModel<ID>, ID extends IDType, ModelErrors> = {
|
|
163
|
+
type: '${types.delta_Model.errors.discriminant}'
|
|
164
|
+
input: Model
|
|
165
|
+
errors: ModelErrors[]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function ${types.delta_Model.errors.typeGuard}<Model extends GenericModel<ID>, ID extends IDType, ModelErrors>(
|
|
169
|
+
delta: Delta_Model<Model, ID, unknown>,
|
|
170
|
+
): delta is ${types.delta_Model.errors.type}<Model, ID, ModelErrors> {
|
|
171
|
+
return delta.type === 'errors'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export type ${types.delta_Model.errors.missingField.type}<FieldName extends string> = {
|
|
175
|
+
error: '${types.delta_Model.errors.missingField.discriminant}'
|
|
176
|
+
fieldName: FieldName
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export type ${types.delta_Model.errors.invalidReference.type}<
|
|
180
|
+
RelatedModel extends string, FieldName extends string, Value
|
|
181
|
+
> = {
|
|
182
|
+
error: '${types.delta_Model.errors.invalidReference.discriminant}'
|
|
183
|
+
relatedModel: RelatedModel
|
|
184
|
+
fieldName: FieldName
|
|
185
|
+
value: Value
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type ${types.delta_Model.errors.nonUnique.type}<FieldName extends string, Value> = {
|
|
189
|
+
error: '${types.delta_Model.errors.nonUnique.discriminant}'
|
|
190
|
+
fieldName: FieldName
|
|
191
|
+
value: Value
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export type ${types.delta_Model.errors.invalidType.type}<FieldName extends string, TypeName extends string, Value> = {
|
|
195
|
+
error: '${types.delta_Model.errors.invalidType.discriminant}'
|
|
196
|
+
fieldName: FieldName
|
|
197
|
+
typeExpected: TypeName
|
|
198
|
+
value: Value
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type ${types.delta_Model.errors.isRequiredDependency.type}<
|
|
202
|
+
RelatedModelName extends string,
|
|
203
|
+
RelatedField extends string,
|
|
204
|
+
RelatedModel extends GenericModel<ID>,
|
|
205
|
+
ID extends IDType
|
|
206
|
+
> = {
|
|
207
|
+
error: '${types.delta_Model.errors.isRequiredDependency.discriminant}'
|
|
208
|
+
relatedModel: RelatedModelName
|
|
209
|
+
relatedField: RelatedField
|
|
210
|
+
relatedItems: RelatedModel[]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
${errorTypes.join('\n')}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* The delta of for all models.
|
|
217
|
+
*/
|
|
218
|
+
export type ${types.delta} = {
|
|
219
|
+
${deltaTypes.join('\n')}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export type DataChanges = {
|
|
223
|
+
/**
|
|
224
|
+
* The delta of all models.
|
|
225
|
+
*/
|
|
226
|
+
delta: ${types.delta}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The bulk mutations derived from the delta.
|
|
230
|
+
*/
|
|
231
|
+
bulkMutations: ${meta.data.types.bulkMutation}[]
|
|
232
|
+
}`;
|
|
233
|
+
}
|
|
234
|
+
exports.generateImportExportTypes = generateImportExportTypes;
|
|
@@ -8,12 +8,12 @@ const meta_1 = require("../../lib/meta");
|
|
|
8
8
|
* Generates an index file that exports all repository stubs.
|
|
9
9
|
*/
|
|
10
10
|
function generateRepositoriesIndex({ models, meta }) {
|
|
11
|
-
const exports = exports_1.ExportsGenerator.from(meta.data.
|
|
11
|
+
const exports = exports_1.ExportsGenerator.from(meta.data.repository.indexFilePath);
|
|
12
12
|
for (const model of models) {
|
|
13
13
|
const meta = (0, meta_1.getModelMetadata)({ model });
|
|
14
|
-
exports.exportEverythingFromPath(meta.data.
|
|
14
|
+
exports.exportEverythingFromPath(meta.data.repository.filePath);
|
|
15
15
|
}
|
|
16
|
-
exports.exportEverythingFromPath(meta.data.
|
|
16
|
+
exports.exportEverythingFromPath(meta.data.repository.constFilePath);
|
|
17
17
|
return exports.generate();
|
|
18
18
|
}
|
|
19
19
|
exports.generateRepositoriesIndex = generateRepositoriesIndex;
|
|
@@ -22,18 +22,18 @@ exports.generateRepositoriesIndex = generateRepositoriesIndex;
|
|
|
22
22
|
*/
|
|
23
23
|
function generateRepositoriesArray({ models, meta }) {
|
|
24
24
|
const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
25
|
-
const imports = imports_1.ImportsGenerator.from(meta.data.
|
|
25
|
+
const imports = imports_1.ImportsGenerator.from(meta.data.repository.constFilePath);
|
|
26
26
|
for (const { meta } of mm) {
|
|
27
27
|
imports.addImport({
|
|
28
|
-
items: [meta.data.
|
|
29
|
-
from: meta.data.
|
|
28
|
+
items: [meta.data.repository.className],
|
|
29
|
+
from: meta.data.repository.filePath,
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
return /* ts */ `
|
|
33
33
|
${imports.generate()}
|
|
34
34
|
|
|
35
35
|
export const repositories = [${models
|
|
36
|
-
.map((model) => (0, meta_1.getModelMetadata)({ model }).data.
|
|
36
|
+
.map((model) => (0, meta_1.getModelMetadata)({ model }).data.repository.className)
|
|
37
37
|
.join(', ')}]`;
|
|
38
38
|
}
|
|
39
39
|
exports.generateRepositoriesArray = generateRepositoriesArray;
|
|
@@ -62,7 +62,7 @@ function initializeWorkbook() {
|
|
|
62
62
|
function addModel({ model, meta, wb }) {
|
|
63
63
|
const ws = wb.addWorksheet(model.name);
|
|
64
64
|
const table = ws.addTable({
|
|
65
|
-
name: meta.
|
|
65
|
+
name: meta.importExport.tableName,
|
|
66
66
|
ref: 'A1',
|
|
67
67
|
headerRow: true,
|
|
68
68
|
totalsRow: false,
|
|
@@ -11,8 +11,9 @@ function generateTestDataService({ models, meta: schemaMeta, }) {
|
|
|
11
11
|
const imports = imports_1.ImportsGenerator.from(schemaMeta.data.testDataServiceFilePath);
|
|
12
12
|
imports.addImports({
|
|
13
13
|
[schemaMeta.actions.importPath]: [(0, types_1.toClassName)('ActionExecutionFactory')],
|
|
14
|
-
[schemaMeta.data.importPath]: [schemaMeta.data.
|
|
15
|
-
[schemaMeta.
|
|
14
|
+
[schemaMeta.data.importPath]: [schemaMeta.data.dataService.class, schemaMeta.data.dataMockDataType],
|
|
15
|
+
[schemaMeta.importExport.importPath]: [schemaMeta.importExport.converterFunctions.mockDataToBulkMutations],
|
|
16
|
+
[schemaMeta.seed.importPath]: [(0, types_1.toClassName)('createActionSeedData')],
|
|
16
17
|
});
|
|
17
18
|
const reInitCalls = [];
|
|
18
19
|
const modelMetas = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
@@ -38,7 +39,7 @@ export class TestDataService {
|
|
|
38
39
|
|
|
39
40
|
constructor(
|
|
40
41
|
private db: DbService,
|
|
41
|
-
private dataService: ${schemaMeta.data.
|
|
42
|
+
private dataService: ${schemaMeta.data.dataService.class},
|
|
42
43
|
private actionExecutionFactory: ActionExecutionFactory,
|
|
43
44
|
) {}
|
|
44
45
|
|
|
@@ -48,7 +49,7 @@ export class TestDataService {
|
|
|
48
49
|
// We need to init the user repository first so the root user is created
|
|
49
50
|
await this.dataService.users.init()
|
|
50
51
|
|
|
51
|
-
const mockData = ${schemaMeta.
|
|
52
|
+
const mockData = ${schemaMeta.importExport.converterFunctions.mockDataToBulkMutations}(data)
|
|
52
53
|
const action = createActionSeedData({ name: 'E2E', order: 0, data: [] })
|
|
53
54
|
const actionExecution = await this.actionExecutionFactory.create({
|
|
54
55
|
action,
|
|
@@ -13,12 +13,12 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
13
13
|
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
14
14
|
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.update.serviceFilePath);
|
|
15
15
|
imports.addImports({
|
|
16
|
-
[meta.data.importPath]: meta.data.
|
|
17
|
-
[schemaMeta.actions.importPath]: schemaMeta.actions.
|
|
16
|
+
[meta.data.importPath]: meta.data.repository.className,
|
|
17
|
+
[schemaMeta.actions.importPath]: schemaMeta.actions.actionExecution.interface,
|
|
18
18
|
[meta.types.importPath]: [model.brandedIdType, meta.types.typeName],
|
|
19
19
|
[schemaMeta.businessLogic.update.serviceFilePath]: schemaMeta.businessLogic.update.serviceClassName,
|
|
20
20
|
[schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
|
|
21
|
-
[meta.data.importPath]: [meta.data.
|
|
21
|
+
[meta.data.importPath]: [meta.data.repository.className],
|
|
22
22
|
});
|
|
23
23
|
/**
|
|
24
24
|
* The name of the variable that holds the repository instance for the current model
|
|
@@ -36,7 +36,7 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
36
36
|
const actionBlocks = generateActionsBuildingBlocks({ model, meta });
|
|
37
37
|
imports.addImport({ from: meta.types.importPath, items: actionBlocks.importTypes });
|
|
38
38
|
const constructorParameters = [
|
|
39
|
-
`public readonly ${modelRepositoryVariableName}: ${meta.data.
|
|
39
|
+
`public readonly ${modelRepositoryVariableName}: ${meta.data.repository.className}`,
|
|
40
40
|
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly ${updateServiceClassName}: ${schemaMeta.businessLogic.update.serviceClassName}`,
|
|
41
41
|
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly ${viewServiceClassName}: ${schemaMeta.businessLogic.view.serviceClassName}`,
|
|
42
42
|
];
|
|
@@ -145,7 +145,7 @@ function generateActionsBuildingBlocks({ model, meta }) {
|
|
|
145
145
|
dispatcher: `
|
|
146
146
|
public async dispatch<A extends Action_${meta.businessLogic.update.actionNameModelPart}>({ action, execution }: {
|
|
147
147
|
action: A;
|
|
148
|
-
execution: ${schemaMeta.actions.
|
|
148
|
+
execution: ${schemaMeta.actions.actionExecution.interface}
|
|
149
149
|
}) {
|
|
150
150
|
switch (action.type) {
|
|
151
151
|
${dispatcher.join('\n')}
|
|
@@ -13,10 +13,10 @@ function generateModelBusinessLogicView({ model, meta }) {
|
|
|
13
13
|
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
14
14
|
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.view.serviceFilePath);
|
|
15
15
|
imports.addImports({
|
|
16
|
-
[meta.data.importPath]: meta.data.
|
|
16
|
+
[meta.data.importPath]: meta.data.repository.className,
|
|
17
17
|
[meta.types.importPath]: [model.brandedIdType, meta.types.typeName],
|
|
18
18
|
[schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
|
|
19
|
-
[meta.data.importPath]: [meta.data.
|
|
19
|
+
[meta.data.importPath]: [meta.data.repository.className],
|
|
20
20
|
});
|
|
21
21
|
/**
|
|
22
22
|
* The name of the variable that holds the repository instance for the current model
|
|
@@ -31,7 +31,7 @@ function generateModelBusinessLogicView({ model, meta }) {
|
|
|
31
31
|
*/
|
|
32
32
|
const viewServiceClassName = 'viewService';
|
|
33
33
|
const constructorParameters = [
|
|
34
|
-
`public readonly ${modelRepositoryVariableName}: ${meta.data.
|
|
34
|
+
`public readonly ${modelRepositoryVariableName}: ${meta.data.repository.className}`,
|
|
35
35
|
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly ${viewServiceClassName}: ${schemaMeta.businessLogic.view.serviceClassName}`,
|
|
36
36
|
];
|
|
37
37
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ModelMetaData, SchemaMetaData } from '../../lib/meta';
|
|
2
|
+
import { Model } from '../../lib/schema/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a decoder for the Seed Excel template.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateModelImportExportDecoder({ model, meta }: {
|
|
7
|
+
model: Model;
|
|
8
|
+
meta: ModelMetaData;
|
|
9
|
+
}): string;
|
|
10
|
+
/**
|
|
11
|
+
* Generates the data decoder, aggregating all the models.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateImportExportDecoder({ models, meta }: {
|
|
14
|
+
models: Model[];
|
|
15
|
+
meta: SchemaMetaData;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Generates the index file for all the routes.
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateImportExportDecoderIndex({ models, meta }: {
|
|
21
|
+
models: Model[];
|
|
22
|
+
meta: SchemaMetaData;
|
|
23
|
+
}): string;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateImportExportDecoderIndex = exports.generateImportExportDecoder = exports.generateModelImportExportDecoder = void 0;
|
|
4
|
+
const exports_1 = require("../../lib/exports");
|
|
5
|
+
const imports_1 = require("../../lib/imports");
|
|
6
|
+
const meta_1 = require("../../lib/meta");
|
|
7
|
+
const types_1 = require("../../lib/schema/types");
|
|
8
|
+
const types_2 = require("../../lib/types");
|
|
9
|
+
// TODO: Remove hardcoded path that seems to be reused in multiple places!
|
|
10
|
+
const PXL_COMMON = (0, types_1.toPath)('@pxl/common');
|
|
11
|
+
/**
|
|
12
|
+
* Creates a decoder for the Seed Excel template.
|
|
13
|
+
*/
|
|
14
|
+
function generateModelImportExportDecoder({ model, meta }) {
|
|
15
|
+
const { filePath: decoderFilePath, itemEncoderFunctionName: rowExportFunctionName, encodedExcelType: excelType, arrayEncoderFunctionName: tableExportFunctionName, tableDecoder: tableImportDecoder, } = meta.importExport.decoder;
|
|
16
|
+
const imports = imports_1.ImportsGenerator.from(decoderFilePath);
|
|
17
|
+
imports.addImports({
|
|
18
|
+
[PXL_COMMON]: [
|
|
19
|
+
(0, types_1.toFunctionName)('uncapitalizeKeys'),
|
|
20
|
+
(0, types_1.toFunctionName)('capitalizeKeys'),
|
|
21
|
+
(0, types_1.toFunctionName)('nullOrBlankDecoder'),
|
|
22
|
+
],
|
|
23
|
+
[meta.types.importPath]: [meta.types.typeName],
|
|
24
|
+
});
|
|
25
|
+
const { userFriendlyName: userFriendly, userFriendlyNamePlural: userFriendlyPlural, internalSingularName: singular, internalSingularNameCapitalized: singularCapitalized, } = meta;
|
|
26
|
+
const { fieldDecoders, blankFieldDecoders } = generateFieldDecoders({ model, meta, imports });
|
|
27
|
+
return `
|
|
28
|
+
import * as z from 'zod'
|
|
29
|
+
${imports.generate()}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The decoder for an Excel row containing a ${userFriendly} entry
|
|
33
|
+
*/
|
|
34
|
+
const ${singular}ExcelRowImportDecoderInput = z.object({
|
|
35
|
+
${fieldDecoders.join(',\n')}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The type for rows in the ${userFriendly} table
|
|
41
|
+
*/
|
|
42
|
+
export type ${excelType} = z.infer<typeof ${singular}ExcelRowImportDecoderInput>
|
|
43
|
+
|
|
44
|
+
const ${singular}ExcelRowImportDecoder = ${singular}ExcelRowImportDecoderInput.transform(uncapitalizeKeys)
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The decoder to identify blank rows in the ${userFriendly} table
|
|
48
|
+
*/
|
|
49
|
+
const blank${singularCapitalized}ExcelRowImportDecoderInput = z
|
|
50
|
+
.object({
|
|
51
|
+
${blankFieldDecoders.join(',\n')}
|
|
52
|
+
})
|
|
53
|
+
.transform(() => undefined)
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The decoder for an Excel table that contains ${userFriendly} entries
|
|
57
|
+
*/
|
|
58
|
+
export const ${tableImportDecoder} = z
|
|
59
|
+
.array(${singular}ExcelRowImportDecoder.or(blank${singularCapitalized}ExcelRowImportDecoderInput))
|
|
60
|
+
.transform((items) => items.filter(Boolean) as ${model.typeName}[])
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Converts a ${userFriendly} to an Excel row
|
|
64
|
+
*/
|
|
65
|
+
export const ${rowExportFunctionName} = (item: ${model.typeName}): ${excelType} => capitalizeKeys(item)
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Converts a list of ${userFriendlyPlural} to an Excel table
|
|
69
|
+
*/
|
|
70
|
+
export const ${tableExportFunctionName} = (items: ${model.typeName}[]): ${excelType}[] => items.map(${rowExportFunctionName})
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
exports.generateModelImportExportDecoder = generateModelImportExportDecoder;
|
|
74
|
+
function generateFieldDecoders({ model, meta, imports, }) {
|
|
75
|
+
const fieldDecoders = [];
|
|
76
|
+
const blankFieldDecoders = [];
|
|
77
|
+
for (const field of model.fields) {
|
|
78
|
+
const fieldMeta = (0, meta_1.getFieldMetadata)({ field });
|
|
79
|
+
blankFieldDecoders.push(`${fieldMeta.excelColumnName}: nullOrBlankDecoder`);
|
|
80
|
+
switch (field.kind) {
|
|
81
|
+
case 'id': {
|
|
82
|
+
imports.addImport({ items: [meta.types.toBrandedIdTypeFnName], from: meta.types.importPath });
|
|
83
|
+
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
84
|
+
tsTypeName: field.unbrandedTypeName,
|
|
85
|
+
dbTypeName: field.schemaType,
|
|
86
|
+
nullable: false,
|
|
87
|
+
imports,
|
|
88
|
+
})}.transform((id: ${field.unbrandedTypeName}) => ${meta.types.toBrandedIdTypeFnName}(id))`);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case 'scalar': {
|
|
92
|
+
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
93
|
+
tsTypeName: field.tsTypeName,
|
|
94
|
+
dbTypeName: field.schemaType,
|
|
95
|
+
nullable: !field.isRequired,
|
|
96
|
+
imports,
|
|
97
|
+
})}`);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case 'relation': {
|
|
101
|
+
const refModel = field.relationToModel;
|
|
102
|
+
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
103
|
+
imports.addImport({ items: [refMeta.types.toBrandedIdTypeFnName], from: refMeta.types.importPath });
|
|
104
|
+
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
105
|
+
tsTypeName: field.unbrandedTypeName,
|
|
106
|
+
dbTypeName: field.schemaType,
|
|
107
|
+
nullable: !field.isRequired,
|
|
108
|
+
imports,
|
|
109
|
+
})}
|
|
110
|
+
.transform(
|
|
111
|
+
(id: ${field.unbrandedTypeName}${field.isRequired ? '' : '| null'}) =>
|
|
112
|
+
${field.isRequired ? '' : ' id === null ? null : '}${refMeta.types.toBrandedIdTypeFnName}(id)
|
|
113
|
+
)`);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case 'enum': {
|
|
117
|
+
fieldDecoders.push(`${fieldMeta.excelColumnName}: z.enum([
|
|
118
|
+
${field.enumerator.values.map((v) => `'${v}'`).join(', ')}
|
|
119
|
+
])${field.isRequired ? '' : '.nullable()'}`);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
default: {
|
|
123
|
+
throw new types_2.ExhaustiveSwitchCheck(field);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { fieldDecoders, blankFieldDecoders };
|
|
128
|
+
}
|
|
129
|
+
function toExcelDecoder({ tsTypeName, dbTypeName: typeName, nullable, imports, }) {
|
|
130
|
+
switch (tsTypeName) {
|
|
131
|
+
case 'string': {
|
|
132
|
+
const decoder = (0, types_1.toFunctionName)(nullable ? 'excelStringNullableDecoder' : 'excelStringDecoder');
|
|
133
|
+
imports.addImport({
|
|
134
|
+
items: [decoder],
|
|
135
|
+
from: PXL_COMMON,
|
|
136
|
+
});
|
|
137
|
+
return decoder;
|
|
138
|
+
}
|
|
139
|
+
case 'boolean':
|
|
140
|
+
imports.addImport({
|
|
141
|
+
items: [(0, types_1.toFunctionName)('excelBooleanDecoder')],
|
|
142
|
+
from: PXL_COMMON,
|
|
143
|
+
});
|
|
144
|
+
return 'excelBooleanDecoder';
|
|
145
|
+
case 'number':
|
|
146
|
+
switch (typeName) {
|
|
147
|
+
case 'Int':
|
|
148
|
+
case 'BigInt':
|
|
149
|
+
return `z.number().int()${nullable ? '.nullable()' : ''}`;
|
|
150
|
+
default:
|
|
151
|
+
return `z.number()${nullable ? '.nullable()' : ''}`;
|
|
152
|
+
}
|
|
153
|
+
case 'Date': {
|
|
154
|
+
const decoder = (0, types_1.toFunctionName)(nullable ? 'excelDateNullableDecoder' : 'excelDateDecoder');
|
|
155
|
+
imports.addImport({
|
|
156
|
+
items: [decoder],
|
|
157
|
+
from: PXL_COMMON,
|
|
158
|
+
});
|
|
159
|
+
return decoder;
|
|
160
|
+
}
|
|
161
|
+
default:
|
|
162
|
+
throw new Error('Unknown type');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Generates the data decoder, aggregating all the models.
|
|
167
|
+
*/
|
|
168
|
+
function generateImportExportDecoder({ models, meta }) {
|
|
169
|
+
const { decodedPXLModelDataTypeName, encodedExcelDataTypeName, fullDecoderName, fullEncoderFunctionName } = meta.importExport.decoder;
|
|
170
|
+
const imports = imports_1.ImportsGenerator.from(meta.importExport.decoder.fullDecoderFilePath);
|
|
171
|
+
imports.addImports({
|
|
172
|
+
[PXL_COMMON]: (0, types_1.toFunctionName)('uncapitalizeKeys'),
|
|
173
|
+
});
|
|
174
|
+
const importTypes = [];
|
|
175
|
+
const decoderEntries = [];
|
|
176
|
+
const exportFields = [];
|
|
177
|
+
for (const model of models) {
|
|
178
|
+
const modelMeta = (0, meta_1.getModelMetadata)({ model });
|
|
179
|
+
imports.addImport({
|
|
180
|
+
from: modelMeta.importExport.decoder.filePath,
|
|
181
|
+
items: [
|
|
182
|
+
modelMeta.importExport.decoder.tableDecoder,
|
|
183
|
+
modelMeta.importExport.decoder.arrayEncoderFunctionName,
|
|
184
|
+
modelMeta.importExport.decoder.encodedExcelType,
|
|
185
|
+
],
|
|
186
|
+
});
|
|
187
|
+
importTypes.push(`${modelMeta.importExport.tableName}?: ${modelMeta.importExport.decoder.encodedExcelType}[]`);
|
|
188
|
+
decoderEntries.push(`${modelMeta.importExport.tableName}: ${modelMeta.importExport.decoder.tableDecoder}.optional()`);
|
|
189
|
+
exportFields.push(`${modelMeta.importExport.tableName}:
|
|
190
|
+
data.${modelMeta.importExport.exportDataFullPropertyName} !== undefined ?
|
|
191
|
+
${modelMeta.importExport.decoder.arrayEncoderFunctionName}(data.${modelMeta.importExport.exportDataFullPropertyName})
|
|
192
|
+
: undefined`);
|
|
193
|
+
}
|
|
194
|
+
return `
|
|
195
|
+
import * as z from 'zod'
|
|
196
|
+
${imports.generate()}
|
|
197
|
+
|
|
198
|
+
export type ${encodedExcelDataTypeName} = {
|
|
199
|
+
${importTypes.join(',\n')}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Decoder that converts Excel data to model data
|
|
204
|
+
*/
|
|
205
|
+
export const ${fullDecoderName} = z
|
|
206
|
+
.object({
|
|
207
|
+
${decoderEntries.join(',\n')}
|
|
208
|
+
})
|
|
209
|
+
.transform(uncapitalizeKeys)
|
|
210
|
+
|
|
211
|
+
export type ${decodedPXLModelDataTypeName} = z.infer<typeof excelDataDecoder>
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Converts the model data to Excel format
|
|
215
|
+
*/
|
|
216
|
+
export const ${fullEncoderFunctionName} = (data: ${decodedPXLModelDataTypeName}): ${encodedExcelDataTypeName} => ({
|
|
217
|
+
${exportFields.join(',\n')}
|
|
218
|
+
})
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
exports.generateImportExportDecoder = generateImportExportDecoder;
|
|
222
|
+
/**
|
|
223
|
+
* Generates the index file for all the routes.
|
|
224
|
+
*/
|
|
225
|
+
function generateImportExportDecoderIndex({ models, meta }) {
|
|
226
|
+
const exports = exports_1.ExportsGenerator.from(meta.importExport.decoder.indexFilePath);
|
|
227
|
+
exports.exportEverythingFromPath(meta.importExport.decoder.fullDecoderFilePath);
|
|
228
|
+
for (const model of models) {
|
|
229
|
+
const modelMeta = (0, meta_1.getModelMetadata)({ model });
|
|
230
|
+
exports.exportEverythingFromPath(modelMeta.importExport.decoder.filePath);
|
|
231
|
+
}
|
|
232
|
+
return exports.generate();
|
|
233
|
+
}
|
|
234
|
+
exports.generateImportExportDecoderIndex = generateImportExportDecoderIndex;
|