@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
|
@@ -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
|
-
return `
|
|
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;
|
|
@@ -17,7 +17,7 @@ function generateSeedMigration({ models, meta }) {
|
|
|
17
17
|
});
|
|
18
18
|
modelTypes.push(`${modelMeta.seed.constantName}: { create: ${modelMeta.seed.constantName} }`);
|
|
19
19
|
}
|
|
20
|
-
return `
|
|
20
|
+
return /* ts */ `
|
|
21
21
|
import { createActionSeedData } from '${meta.seed.importPath}'
|
|
22
22
|
${imports.generate()}
|
|
23
23
|
|
|
@@ -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,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates list of component selectors for Cypress tests.
|
|
3
|
+
*
|
|
4
|
+
* Note: This generator does not need the models or meta data passed in.
|
|
5
|
+
* Instead it uses the SelectorCollector singleton that already collected all ids during the generation process of the individual models.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateSelectors(): string;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSelectors = void 0;
|
|
4
|
+
const id_collector_1 = require("../../lib/id-collector");
|
|
5
|
+
/**
|
|
6
|
+
* List of ids that are not generated but hardcoded across the template.
|
|
7
|
+
*/
|
|
8
|
+
const HARDCODED_IDS = [
|
|
9
|
+
'indexPage-buttons-create',
|
|
10
|
+
'confirmationModal-buttons-confirm',
|
|
11
|
+
'confirmationModal-buttons-cancel',
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Generates list of component selectors for Cypress tests.
|
|
15
|
+
*
|
|
16
|
+
* Note: This generator does not need the models or meta data passed in.
|
|
17
|
+
* Instead it uses the SelectorCollector singleton that already collected all ids during the generation process of the individual models.
|
|
18
|
+
*/
|
|
19
|
+
function generateSelectors() {
|
|
20
|
+
// SelectorCollector is a static singleton that collects all ids during the generation process. We flush it here to get all ids.
|
|
21
|
+
const collectedIds = id_collector_1.SelectorCollector.flush();
|
|
22
|
+
const object = {};
|
|
23
|
+
const ids = [...HARDCODED_IDS, ...collectedIds];
|
|
24
|
+
ids.sort();
|
|
25
|
+
ids.map((id) => {
|
|
26
|
+
addCypressSelectorToNestedObject({ object, id });
|
|
27
|
+
});
|
|
28
|
+
const selectors = JSON.stringify(object, null, 2);
|
|
29
|
+
return /* ts */ `
|
|
30
|
+
export const SELECTORS =
|
|
31
|
+
${selectors}
|
|
32
|
+
`;
|
|
33
|
+
}
|
|
34
|
+
exports.generateSelectors = generateSelectors;
|
|
35
|
+
/**
|
|
36
|
+
* Converts an id like `post-create-name` to a nested object like `{post: {create: {name: '[data-cy=post-create-name]'}}}`.
|
|
37
|
+
*/
|
|
38
|
+
function addCypressSelectorToNestedObject({ object, id, }) {
|
|
39
|
+
const keys = id.split('-');
|
|
40
|
+
extendObject(object, keys, `[data-cy=${id}]`);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Recursively traverses the keys and adds the value to the object in a nested way.
|
|
44
|
+
* E.g. `{object, keys: ['post', 'create', 'name'], value}` will extend `object` with `{post: {create: {name: value}}}`.
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
function extendObject(object, keys, value) {
|
|
48
|
+
const key = keys.shift();
|
|
49
|
+
// no item left -> we are at the end of the recursion
|
|
50
|
+
if (!key) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// create the nested object if it does not exist yet
|
|
54
|
+
object[key] = object[key] || {};
|
|
55
|
+
// In case the object already has a value, we check if it is a string (and not a nested object).
|
|
56
|
+
// If it is a string, it we check if the value is the same as the new value. In this case is is a duplicate and hence fine.
|
|
57
|
+
// However, if it is a string and a different value, it means we have an inconsistent ID structure.
|
|
58
|
+
// E.g. this can happen when we have three entries: "post-create", "post-create-name", "post-create-description".
|
|
59
|
+
// In this case, the "post-create" entry will be a string - and we cannot nest `{name: ..., description: ...}` in it.
|
|
60
|
+
if (key in object && typeof object[key] === 'string') {
|
|
61
|
+
if (keys.length !== 0) {
|
|
62
|
+
throw new Error(`Key ${key} already exists with value: ${object[key]} but we are trying to nest ${keys.join('-')}`);
|
|
63
|
+
}
|
|
64
|
+
if (object[key] !== value) {
|
|
65
|
+
throw new Error(`Duplicate key ${key} with different values: ${object[key]} and ${value}`);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// If there are still keys left, we recursively call this function with the nested object and the remaining keys.
|
|
70
|
+
if (keys.length !== 0) {
|
|
71
|
+
extendObject(object[key], keys, value);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// If there are no keys left, we need to verify that the object might not already have a nested object.
|
|
75
|
+
// This can happen, e.g. when we have two entries: "post-create-name" and "post-create".
|
|
76
|
+
// In this case, the `post.create` entry will be a nested object`{name: ...}`.
|
|
77
|
+
// If we would set `post.create` to a string, we would lose the nested object.
|
|
78
|
+
if (key in object && typeof object[key] !== 'string' && Object.keys(object[key]).length !== 0) {
|
|
79
|
+
throw new Error(`Key ${key} already has nested object ${JSON.stringify(object[key])} but we are trying to set it to ${value}`);
|
|
80
|
+
}
|
|
81
|
+
object[key] = value;
|
|
82
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SchemaMetaData } from '../../lib/meta';
|
|
2
2
|
import { Model } from '../../lib/schema/schema';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Generates the TestDataService class.
|
|
5
5
|
*/
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function generateTestDataService({ models, meta: schemaMeta, }: {
|
|
7
7
|
models: Model[];
|
|
8
8
|
meta: SchemaMetaData;
|
|
9
9
|
}): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTestDataService = void 0;
|
|
4
|
+
const imports_1 = require("../../lib/imports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
|
+
const types_1 = require("../../lib/schema/types");
|
|
7
|
+
/**
|
|
8
|
+
* Generates the TestDataService class.
|
|
9
|
+
*/
|
|
10
|
+
function generateTestDataService({ models, meta: schemaMeta, }) {
|
|
11
|
+
const imports = imports_1.ImportsGenerator.from(schemaMeta.data.testDataServiceFilePath);
|
|
12
|
+
imports.addImports({
|
|
13
|
+
[schemaMeta.actions.importPath]: [(0, types_1.toClassName)('ActionExecutionFactory')],
|
|
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')],
|
|
17
|
+
});
|
|
18
|
+
const reInitCalls = [];
|
|
19
|
+
const modelMetas = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
20
|
+
for (const { model, meta } of modelMetas) {
|
|
21
|
+
if (model.defaultField) {
|
|
22
|
+
imports.addImport({ items: [meta.data.stubGenerationFnName], from: meta.data.importPath });
|
|
23
|
+
const stubDefault = `${meta.data.stubGenerationFnName}({ ${model.defaultField.name}: true })`;
|
|
24
|
+
reInitCalls.push(`await this.dataService.${meta.data.dataServiceName}.reInit({ items: mockData.${meta.seed.constantName}?.create ?? [${stubDefault}], execution: actionExecution })`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
reInitCalls.push(`await this.dataService.${meta.data.dataServiceName}.reInit({ items: mockData.${meta.seed.constantName}?.create ?? [], execution: actionExecution })`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return /* ts */ `
|
|
31
|
+
import { Injectable, Logger } from '@nestjs/common'
|
|
32
|
+
|
|
33
|
+
import { DbService } from '@pxl/db'
|
|
34
|
+
${imports.generate()}
|
|
35
|
+
|
|
36
|
+
@Injectable()
|
|
37
|
+
export class TestDataService {
|
|
38
|
+
private logger = new Logger(TestDataService.name)
|
|
39
|
+
|
|
40
|
+
constructor(
|
|
41
|
+
private db: DbService,
|
|
42
|
+
private dataService: ${schemaMeta.data.dataService.class},
|
|
43
|
+
private actionExecutionFactory: ActionExecutionFactory,
|
|
44
|
+
) {}
|
|
45
|
+
|
|
46
|
+
public async resetTestData(data: MockData) {
|
|
47
|
+
await this.db.emptyDatabase()
|
|
48
|
+
|
|
49
|
+
// We need to init the user repository first so the root user is created
|
|
50
|
+
await this.dataService.users.init()
|
|
51
|
+
|
|
52
|
+
const mockData = ${schemaMeta.importExport.converterFunctions.mockDataToBulkMutations}(data)
|
|
53
|
+
const action = createActionSeedData({ name: 'E2E', order: 0, data: [] })
|
|
54
|
+
const actionExecution = await this.actionExecutionFactory.create({
|
|
55
|
+
action,
|
|
56
|
+
dbService: this.db,
|
|
57
|
+
user: this.dataService.users.rootUser,
|
|
58
|
+
})
|
|
59
|
+
try {
|
|
60
|
+
${reInitCalls.join('\n')}
|
|
61
|
+
|
|
62
|
+
await actionExecution.success()
|
|
63
|
+
this.logger.log(\`✅ Reset test data\`)
|
|
64
|
+
} catch (e) {
|
|
65
|
+
await actionExecution.error(e)
|
|
66
|
+
throw e
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}`;
|
|
70
|
+
}
|
|
71
|
+
exports.generateTestDataService = generateTestDataService;
|
|
@@ -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,12 +36,12 @@ 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
|
];
|
|
43
43
|
const methodTypeSignatures = (0, repository_generator_1.getRepositoryMethodsTypeSignatures)({ model, meta });
|
|
44
|
-
return `
|
|
44
|
+
return /* ts */ `
|
|
45
45
|
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
46
46
|
import { ExhaustiveSwitchCheck } from '@pxl/common'
|
|
47
47
|
|
|
@@ -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
|
/**
|
|
@@ -92,7 +92,7 @@ function generateModelBusinessLogicView({ model, meta }) {
|
|
|
92
92
|
return item
|
|
93
93
|
}
|
|
94
94
|
`;
|
|
95
|
-
return `
|
|
95
|
+
return /* ts */ `
|
|
96
96
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
97
97
|
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
98
98
|
import { FilterOperator } from '@pxl/common'
|
|
@@ -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;
|