@postxl/generator 0.27.1 → 0.27.3
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/generators/indices/businesslogicmodule.generator.js +1 -0
- package/dist/generators/indices/businesslogicservice.generator.js +7 -6
- package/dist/generators/indices/datamockmodule.generator.js +1 -0
- package/dist/generators/indices/datamodule.generator.js +1 -0
- package/dist/generators/indices/repositories.generator.d.ts +1 -1
- package/dist/generators/indices/repositories.generator.js +1 -1
- package/dist/generators/indices/seed-template-decoder.generator.d.ts +1 -1
- package/dist/generators/indices/seed-template-decoder.generator.js +1 -1
- package/dist/generators/models/businesslogic.generator.js +6 -3
- package/dist/generators/models/repository.generator.d.ts +31 -11
- package/dist/generators/models/repository.generator.js +177 -107
- package/package.json +6 -6
|
@@ -6,6 +6,7 @@ const meta_1 = require("../../lib/meta");
|
|
|
6
6
|
/**
|
|
7
7
|
* Generates a business Logic module class.
|
|
8
8
|
*/
|
|
9
|
+
// TODO: https://github.com/PostXL/PostXL/issues/347
|
|
9
10
|
function generateBusinessLogicModule({ models, meta }) {
|
|
10
11
|
const mm = models
|
|
11
12
|
.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }))
|
|
@@ -6,6 +6,7 @@ const meta_1 = require("../../lib/meta");
|
|
|
6
6
|
/**
|
|
7
7
|
* Generates the business logic service class.
|
|
8
8
|
*/
|
|
9
|
+
// TODO: https://github.com/PostXL/PostXL/issues/347
|
|
9
10
|
function generateBusinessLogicService({ models, meta }) {
|
|
10
11
|
const mm = models
|
|
11
12
|
.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }))
|
|
@@ -23,12 +24,12 @@ function generateBusinessLogicService({ models, meta }) {
|
|
|
23
24
|
return `
|
|
24
25
|
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
25
26
|
|
|
26
|
-
${imports.generate()}
|
|
27
|
+
${imports.generate()}
|
|
27
28
|
|
|
28
|
-
@Injectable()
|
|
29
|
-
export class ${meta.businessLogic.serviceClassName} {
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
`;
|
|
29
|
+
@Injectable()
|
|
30
|
+
export class ${meta.businessLogic.serviceClassName} {
|
|
31
|
+
constructor(${constructor}) {}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
33
34
|
}
|
|
34
35
|
exports.generateBusinessLogicService = generateBusinessLogicService;
|
|
@@ -30,6 +30,7 @@ const Types = __importStar(require("../../lib/schema/types"));
|
|
|
30
30
|
/**
|
|
31
31
|
* Generates a mocking class
|
|
32
32
|
*/
|
|
33
|
+
// TODO: https://github.com/PostXL/PostXL/issues/347
|
|
33
34
|
function generateDataMockModule({ models, meta }) {
|
|
34
35
|
const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
35
36
|
const imports = imports_1.ImportsGenerator.from(meta.data.dataMockModuleFilePath)
|
|
@@ -30,6 +30,7 @@ const Types = __importStar(require("../../lib/schema/types"));
|
|
|
30
30
|
/**
|
|
31
31
|
* Generates a data module class.
|
|
32
32
|
*/
|
|
33
|
+
// TODO: https://github.com/PostXL/PostXL/issues/347
|
|
33
34
|
function generateDataModule({ models, meta }) {
|
|
34
35
|
const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
35
36
|
const imports = imports_1.ImportsGenerator.from(meta.data.dataModuleFilePath)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SchemaMetaData } from '../../lib/meta';
|
|
2
2
|
import { Model } from '../../lib/schema/schema';
|
|
3
3
|
/**
|
|
4
|
-
* Generates an index file that exports all stubs.
|
|
4
|
+
* Generates an index file that exports all repository stubs.
|
|
5
5
|
*/
|
|
6
6
|
export declare function generateRepositoriesIndex({ models, meta }: {
|
|
7
7
|
models: Model[];
|
|
@@ -5,7 +5,7 @@ const exports_1 = require("../../lib/exports");
|
|
|
5
5
|
const imports_1 = require("../../lib/imports");
|
|
6
6
|
const meta_1 = require("../../lib/meta");
|
|
7
7
|
/**
|
|
8
|
-
* Generates an index file that exports all stubs.
|
|
8
|
+
* Generates an index file that exports all repository stubs.
|
|
9
9
|
*/
|
|
10
10
|
function generateRepositoriesIndex({ models, meta }) {
|
|
11
11
|
const exports = exports_1.ExportsGenerator.from(meta.data.repositoriesIndexFilePath);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SchemaMetaData } from '../../lib/meta';
|
|
2
2
|
import { Model } from '../../lib/schema/schema';
|
|
3
3
|
/**
|
|
4
|
-
* Creates a decoder for the Seed Excel template
|
|
4
|
+
* Creates a decoder for the Seed Excel template.
|
|
5
5
|
*/
|
|
6
6
|
export declare function generateSeedTemplateDecoder({ models, meta }: {
|
|
7
7
|
models: Model[];
|
|
@@ -8,7 +8,7 @@ const types_2 = require("../../lib/types");
|
|
|
8
8
|
// TODO: Remove hardcoded path that seems to be reused in multiple places!
|
|
9
9
|
const PXL_COMMON = (0, types_1.toPath)('@pxl/common');
|
|
10
10
|
/**
|
|
11
|
-
* Creates a decoder for the Seed Excel template
|
|
11
|
+
* Creates a decoder for the Seed Excel template.
|
|
12
12
|
*/
|
|
13
13
|
function generateSeedTemplateDecoder({ models, meta }) {
|
|
14
14
|
const imports = imports_1.ImportsGenerator.from(meta.seed.templateDecoderFilePath);
|
|
@@ -28,9 +28,11 @@ const imports_1 = require("../../lib/imports");
|
|
|
28
28
|
const meta_1 = require("../../lib/meta");
|
|
29
29
|
const fields_1 = require("../../lib/schema/fields");
|
|
30
30
|
const Types = __importStar(require("../../lib/schema/types"));
|
|
31
|
+
const repository_generator_1 = require("./repository.generator");
|
|
31
32
|
/**
|
|
32
33
|
* Generates business logic for a given model.
|
|
33
34
|
*/
|
|
35
|
+
// TODO: https://github.com/PostXL/PostXL/issues/347
|
|
34
36
|
function generateModelBusinessLogic({ model, meta }) {
|
|
35
37
|
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
36
38
|
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.serviceFilePath);
|
|
@@ -114,6 +116,7 @@ function generateModelBusinessLogic({ model, meta }) {
|
|
|
114
116
|
return item
|
|
115
117
|
}
|
|
116
118
|
`;
|
|
119
|
+
const methodTypeSignatures = (0, repository_generator_1.getRepositoryMethodsTypeSignatures)({ model, meta });
|
|
117
120
|
// prettier-ignore
|
|
118
121
|
return `
|
|
119
122
|
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
@@ -170,14 +173,14 @@ export class ${meta.businessLogic.serviceClassName} {
|
|
|
170
173
|
/**
|
|
171
174
|
* Creates a new ${meta.userFriendlyName}.
|
|
172
175
|
*/
|
|
173
|
-
public async create(item:
|
|
176
|
+
public async create(item: ${methodTypeSignatures.create.parameters[0]}): ${methodTypeSignatures.create.returnType} {
|
|
174
177
|
return this.${modelRepositoryVariableName}.create(item)
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
/**
|
|
178
181
|
* Updates the given ${meta.userFriendlyName}.
|
|
179
182
|
*/
|
|
180
|
-
public async update(item:
|
|
183
|
+
public async update(item: ${methodTypeSignatures.update.parameters[0]}): ${methodTypeSignatures.update.returnType} {
|
|
181
184
|
return this.${modelRepositoryVariableName}.update(item)
|
|
182
185
|
}
|
|
183
186
|
|
|
@@ -187,7 +190,7 @@ export class ${meta.businessLogic.serviceClassName} {
|
|
|
187
190
|
* Note: This does NOT delete any linked items.
|
|
188
191
|
* If the items is a dependency of another item, the deletion will fail!
|
|
189
192
|
*/
|
|
190
|
-
public async delete(id: ${
|
|
193
|
+
public async delete(id: ${methodTypeSignatures.delete.parameters[0]}): ${methodTypeSignatures.delete.returnType} {
|
|
191
194
|
return this.${modelRepositoryVariableName}.delete(id)
|
|
192
195
|
}
|
|
193
196
|
}
|
|
@@ -2,25 +2,45 @@ import { ModelMetaData } from '../../lib/meta';
|
|
|
2
2
|
import { Model } from '../../lib/schema/schema';
|
|
3
3
|
/**
|
|
4
4
|
* Generates repository data structure for a given model.
|
|
5
|
-
* Based on the model, the repository is generated slightly differently, based on:
|
|
6
|
-
* - if the model has a default field, the repository will have a public variable "defaultValue"
|
|
7
|
-
* that is set and verified during init
|
|
8
|
-
* - if the model has a generated id, the repository will have a function "generateNextId" that
|
|
9
|
-
* is used to generate the next id. The `create` and `createMany` functions will use this function
|
|
10
|
-
* and allow being called with an id.
|
|
11
|
-
* - unique string fields are ensured to be unique
|
|
12
|
-
* - max length string fields are ensured to not exceed their max length
|
|
13
|
-
* - index for fields marked with index attribute
|
|
14
|
-
* - relations are indexed by the foreign key
|
|
15
5
|
*/
|
|
16
6
|
export declare function generateRepository({ model, meta }: {
|
|
17
7
|
model: Model;
|
|
18
8
|
meta: ModelMetaData;
|
|
19
9
|
}): string;
|
|
20
10
|
/**
|
|
21
|
-
* Generates a mock repository data structure for a given model: same a repository, but in memory only
|
|
11
|
+
* Generates a mock repository data structure for a given model: same a repository, but in memory only.
|
|
22
12
|
*/
|
|
23
13
|
export declare function generateMockRepository({ model: modelSource, meta: metaSource, }: {
|
|
24
14
|
model: Model;
|
|
25
15
|
meta: ModelMetaData;
|
|
26
16
|
}): string;
|
|
17
|
+
type FnSignature = {
|
|
18
|
+
/**
|
|
19
|
+
* A list of ordered TypeScript types where the first type in the list corresponds to the type of the
|
|
20
|
+
* first parameter and so on. Note that the parameters don't contain names, only types.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
*
|
|
24
|
+
* ```
|
|
25
|
+
* function foo(a: string, b: number, c: boolean) {}
|
|
26
|
+
* // ['string', 'number', 'boolean']
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
parameters: string[];
|
|
30
|
+
/**
|
|
31
|
+
* The return type of the function.
|
|
32
|
+
*/
|
|
33
|
+
returnType: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Returns a collection of type signatures for the repository methods of a given model.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getRepositoryMethodsTypeSignatures({ model, meta }: {
|
|
39
|
+
model: Model;
|
|
40
|
+
meta: ModelMetaData;
|
|
41
|
+
}): {
|
|
42
|
+
create: FnSignature;
|
|
43
|
+
update: FnSignature;
|
|
44
|
+
delete: FnSignature;
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateMockRepository = exports.generateRepository = void 0;
|
|
3
|
+
exports.getRepositoryMethodsTypeSignatures = exports.generateMockRepository = exports.generateRepository = void 0;
|
|
4
4
|
const imports_1 = require("../../lib/imports");
|
|
5
5
|
const meta_1 = require("../../lib/meta");
|
|
6
6
|
const fields_1 = require("../../lib/schema/fields");
|
|
@@ -10,16 +10,6 @@ const jsdoc_1 = require("../../lib/utils/jsdoc");
|
|
|
10
10
|
const string_1 = require("../../lib/utils/string");
|
|
11
11
|
/**
|
|
12
12
|
* Generates repository data structure for a given model.
|
|
13
|
-
* Based on the model, the repository is generated slightly differently, based on:
|
|
14
|
-
* - if the model has a default field, the repository will have a public variable "defaultValue"
|
|
15
|
-
* that is set and verified during init
|
|
16
|
-
* - if the model has a generated id, the repository will have a function "generateNextId" that
|
|
17
|
-
* is used to generate the next id. The `create` and `createMany` functions will use this function
|
|
18
|
-
* and allow being called with an id.
|
|
19
|
-
* - unique string fields are ensured to be unique
|
|
20
|
-
* - max length string fields are ensured to not exceed their max length
|
|
21
|
-
* - index for fields marked with index attribute
|
|
22
|
-
* - relations are indexed by the foreign key
|
|
23
13
|
*/
|
|
24
14
|
function generateRepository({ model, meta }) {
|
|
25
15
|
const { idField } = model;
|
|
@@ -30,13 +20,63 @@ function generateRepository({ model, meta }) {
|
|
|
30
20
|
})
|
|
31
21
|
.addImport({
|
|
32
22
|
items: [(0, types_1.toClassName)('Repository')],
|
|
23
|
+
// TODO: Unify DataLib Imports https://github.com/PostXL/PostXL/issues/344!
|
|
33
24
|
from: (0, types_1.toFileName)(model.schemaConfig.paths.dataLibPath + 'repository.type'),
|
|
25
|
+
})
|
|
26
|
+
.addImport({
|
|
27
|
+
items: [meta.types.toBrandedIdTypeFnName],
|
|
28
|
+
from: meta.types.importPath,
|
|
34
29
|
});
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
// NOTE: We first generate different parts of the code responisble for a particular task
|
|
31
|
+
// and then we combine them into the final code block.
|
|
32
|
+
//
|
|
33
|
+
// Based on the model, the repository is generated slightly differently:
|
|
34
|
+
// 1.) if the model has a default field, the repository will have a public variable "defaultValue"
|
|
35
|
+
// that is set and verified during init,
|
|
36
|
+
// 2.) if the model has a generated id, the repository will have a function "generateNextId" that
|
|
37
|
+
// is used to generate the next id. The `create` and `createMany` functions will use this function
|
|
38
|
+
// and allow being called with an id,
|
|
39
|
+
// 3.) unique string fields are ensured to be unique,
|
|
40
|
+
// 4.) max length string fields are ensured to not exceed their max length,
|
|
41
|
+
// 5.) index for fields marked with index attribute,
|
|
42
|
+
// 6.) relations are indexed by the foreign key.
|
|
43
|
+
const idBlocks = generateIdBlocks({ model, meta });
|
|
44
|
+
const defaultValueBlocks = generateDefaultBlocks({ model, meta });
|
|
45
|
+
const uniqueStringFieldsBlocks = generateUniqueFieldsBlocks({ model, meta });
|
|
46
|
+
const maxLengthBlocks = generateMaxLengthBlocks({ model, meta });
|
|
47
|
+
const indexBlocks = generateIndexBlocks({ model, meta, imports });
|
|
48
|
+
const relationsBlocks = generateRelationsBlocks({ model, meta, imports });
|
|
49
|
+
let mainBlocks;
|
|
50
|
+
if (model.attributes.inMemoryOnly) {
|
|
51
|
+
mainBlocks = _generateMainBuildingBlocks_InMemoryOnly({
|
|
52
|
+
model,
|
|
53
|
+
meta,
|
|
54
|
+
blocks: {
|
|
55
|
+
uniqueStringFieldsBlocks,
|
|
56
|
+
defaultValueBlocks,
|
|
57
|
+
idBlocks,
|
|
58
|
+
indexBlocks,
|
|
59
|
+
maxLengthBlocks,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
mainBlocks = generateMainBuildingBlocks_InDatabase({
|
|
65
|
+
model,
|
|
66
|
+
meta,
|
|
67
|
+
imports,
|
|
68
|
+
blocks: {
|
|
69
|
+
uniqueStringFieldsBlocks,
|
|
70
|
+
defaultValueBlocks,
|
|
71
|
+
idBlocks,
|
|
72
|
+
indexBlocks,
|
|
73
|
+
maxLengthBlocks,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
37
77
|
return `
|
|
38
78
|
import { Injectable, Logger } from '@nestjs/common'
|
|
39
|
-
${
|
|
79
|
+
${idBlocks.libraryImports}
|
|
40
80
|
${imports.generate()}
|
|
41
81
|
|
|
42
82
|
@Injectable()
|
|
@@ -44,17 +84,17 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
44
84
|
protected data: Map<${model.brandedIdType}, ${model.typeName}> = new Map()
|
|
45
85
|
protected logger = new Logger(${meta.data.repositoryClassName}.name)
|
|
46
86
|
|
|
47
|
-
${
|
|
87
|
+
${relationsBlocks.mapDeclarations.join('\n')}
|
|
48
88
|
|
|
49
|
-
${
|
|
89
|
+
${defaultValueBlocks.publicVariableDeclaration}
|
|
50
90
|
|
|
51
|
-
${
|
|
91
|
+
${idBlocks.generateNextIdFunctionName}
|
|
52
92
|
|
|
53
93
|
protected uniqueIds = {
|
|
54
|
-
${
|
|
94
|
+
${uniqueStringFieldsBlocks.mapDeclarations.join(',\n')}
|
|
55
95
|
}
|
|
56
96
|
|
|
57
|
-
${
|
|
97
|
+
${indexBlocks.nestedMapDeclarations.join('\n')}
|
|
58
98
|
|
|
59
99
|
${mainBlocks.constructorCode}
|
|
60
100
|
|
|
@@ -79,7 +119,7 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
79
119
|
return Array.from(this.data.values())
|
|
80
120
|
}
|
|
81
121
|
|
|
82
|
-
${
|
|
122
|
+
${indexBlocks.getterFunctions.join('\n')}
|
|
83
123
|
|
|
84
124
|
public filter(predicate: (item: ${model.typeName}) => boolean): ${model.typeName}[] {
|
|
85
125
|
return this.getAllAsArray().filter(predicate)
|
|
@@ -95,17 +135,18 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
95
135
|
|
|
96
136
|
/**${(0, jsdoc_1.convertToJsDocComments)([
|
|
97
137
|
`Checks that item has the ${idField.name} field.`,
|
|
98
|
-
`In case none exists, ${
|
|
99
|
-
|
|
100
|
-
|
|
138
|
+
`In case none exists, ${idBlocks.verifyFunctionComment}`,
|
|
139
|
+
uniqueStringFieldsBlocks.verifyFunctionComment,
|
|
140
|
+
maxLengthBlocks.verifyFunctionComment,
|
|
101
141
|
])}
|
|
102
142
|
*/
|
|
103
|
-
private verifyItem(item: ${blocks.id.verifyFunctionParameterType}): ${model.typeName} {
|
|
104
|
-
${blocks.id.verifyCode}
|
|
105
143
|
|
|
106
|
-
|
|
144
|
+
private verifyItem(item: ${idBlocks.verifyFunctionParameterType}): ${model.typeName} {
|
|
145
|
+
${idBlocks.verifyCode}
|
|
107
146
|
|
|
108
|
-
${
|
|
147
|
+
${maxLengthBlocks.verifyCode.join('\n')}
|
|
148
|
+
|
|
149
|
+
${uniqueStringFieldsBlocks.verifyCode.join('\n')}
|
|
109
150
|
|
|
110
151
|
return {
|
|
111
152
|
${idField.name},
|
|
@@ -130,25 +171,25 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
130
171
|
|
|
131
172
|
${mainBlocks.deleteCode}
|
|
132
173
|
|
|
133
|
-
${
|
|
174
|
+
${relationsBlocks.getterFunctions.join('\n')}
|
|
134
175
|
|
|
135
|
-
${
|
|
176
|
+
${maxLengthBlocks.ensureMaxLengthFunctions.join('\n')}
|
|
136
177
|
|
|
137
|
-
${
|
|
178
|
+
${uniqueStringFieldsBlocks.ensureUniqueFunctions.join('\n\n')}
|
|
138
179
|
|
|
139
180
|
/**
|
|
140
181
|
* Function that adds/updates a given item to the internal data store, indexes, etc.
|
|
141
182
|
*/
|
|
142
183
|
private set(item: ${model.typeName}): void {
|
|
143
|
-
${
|
|
184
|
+
${idBlocks.setCode}
|
|
144
185
|
|
|
145
186
|
this.data.set(item.id, item)
|
|
146
187
|
|
|
147
|
-
${
|
|
188
|
+
${uniqueStringFieldsBlocks.setCode.join('\n')}
|
|
148
189
|
|
|
149
|
-
${
|
|
190
|
+
${relationsBlocks.setCode.join('\n')}
|
|
150
191
|
|
|
151
|
-
${
|
|
192
|
+
${indexBlocks.setCode.join('\n')}
|
|
152
193
|
}
|
|
153
194
|
|
|
154
195
|
/**
|
|
@@ -156,11 +197,11 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
156
197
|
*/
|
|
157
198
|
private remove(item: ${model.typeName}): void {
|
|
158
199
|
this.data.delete(item.id)
|
|
159
|
-
${
|
|
200
|
+
${uniqueStringFieldsBlocks.removeCode.join('\n')}
|
|
160
201
|
|
|
161
|
-
${
|
|
202
|
+
${relationsBlocks.removeCode.join('\n')}
|
|
162
203
|
|
|
163
|
-
${
|
|
204
|
+
${indexBlocks.removeCode.join('\n')}
|
|
164
205
|
}
|
|
165
206
|
|
|
166
207
|
${mainBlocks.databaseDecoderCode}
|
|
@@ -169,7 +210,7 @@ export class ${meta.data.repositoryClassName} implements Repository<${model.type
|
|
|
169
210
|
}
|
|
170
211
|
exports.generateRepository = generateRepository;
|
|
171
212
|
/**
|
|
172
|
-
* Generates a mock repository data structure for a given model: same a repository, but in memory only
|
|
213
|
+
* Generates a mock repository data structure for a given model: same a repository, but in memory only.
|
|
173
214
|
*/
|
|
174
215
|
function generateMockRepository({ model: modelSource, meta: metaSource, }) {
|
|
175
216
|
// 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
|
|
@@ -178,26 +219,21 @@ function generateMockRepository({ model: modelSource, meta: metaSource, }) {
|
|
|
178
219
|
return generateRepository({ model, meta });
|
|
179
220
|
}
|
|
180
221
|
exports.generateMockRepository = generateMockRepository;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks });
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
190
|
-
const { idField } = model;
|
|
222
|
+
/**
|
|
223
|
+
* Generates the main building blocks of the repository for in-memory model.
|
|
224
|
+
*/
|
|
225
|
+
function _generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
226
|
+
const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
|
|
191
227
|
return {
|
|
192
228
|
constructorCode: '',
|
|
193
229
|
initCode: `
|
|
194
230
|
public async init() {
|
|
195
231
|
this.data.clear()
|
|
196
232
|
|
|
197
|
-
${blocks.
|
|
198
|
-
${blocks.
|
|
233
|
+
${blocks.uniqueStringFieldsBlocks.clearCode.join('\n')}
|
|
234
|
+
${blocks.defaultValueBlocks.init.resetCode}
|
|
199
235
|
|
|
200
|
-
${blocks.
|
|
236
|
+
${blocks.indexBlocks.initCode.join('\n')}
|
|
201
237
|
|
|
202
238
|
return Promise.resolve()
|
|
203
239
|
}`,
|
|
@@ -210,18 +246,17 @@ function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
210
246
|
public async deleteAll(): Promise<void> {
|
|
211
247
|
return this.init()
|
|
212
248
|
}`,
|
|
213
|
-
// prettier-ignore
|
|
214
249
|
createCode: `
|
|
215
250
|
// Non-mocked version is async - so we keep type-compatible signatures for create() and createWithId()
|
|
216
251
|
// eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-unused-vars
|
|
217
|
-
public async create(item:
|
|
252
|
+
public async create(item: ${methodTypeSignatures.create.parameters[0]}): ${methodTypeSignatures.create.returnType} {
|
|
218
253
|
const newItem = await Promise.resolve(this.verifyItem(item))
|
|
219
254
|
|
|
220
255
|
this.set(newItem)
|
|
221
256
|
return newItem
|
|
222
257
|
}`,
|
|
223
258
|
createManyCode: `
|
|
224
|
-
public async createMany(items: ${blocks.
|
|
259
|
+
public async createMany(items: ${blocks.idBlocks.verifyFunctionParameterType}[]) {
|
|
225
260
|
const newItems = items.map((item) => this.verifyItem(item))
|
|
226
261
|
|
|
227
262
|
await Promise.resolve()
|
|
@@ -232,10 +267,9 @@ function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
232
267
|
|
|
233
268
|
return newItems
|
|
234
269
|
}`,
|
|
270
|
+
// prettier-ignore
|
|
235
271
|
updateCode: `
|
|
236
|
-
public async update(item:
|
|
237
|
-
id: ${model.brandedIdType}
|
|
238
|
-
}): Promise<${model.typeName}> {
|
|
272
|
+
public async update(item: ${methodTypeSignatures.update.parameters[0]}): ${methodTypeSignatures.update.returnType} {
|
|
239
273
|
const existingItem = this.get(item.id)
|
|
240
274
|
|
|
241
275
|
if (!existingItem) {
|
|
@@ -243,9 +277,9 @@ function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
243
277
|
}
|
|
244
278
|
|
|
245
279
|
|
|
246
|
-
${blocks.
|
|
280
|
+
${blocks.maxLengthBlocks.updateCode.join('\n')}
|
|
247
281
|
|
|
248
|
-
${blocks.
|
|
282
|
+
${blocks.uniqueStringFieldsBlocks.updateCode.join('\n')}
|
|
249
283
|
|
|
250
284
|
const newItem = await Promise.resolve({ ...existingItem, ...item })
|
|
251
285
|
|
|
@@ -255,7 +289,7 @@ function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
255
289
|
return newItem
|
|
256
290
|
}`,
|
|
257
291
|
deleteCode: `
|
|
258
|
-
public async delete(id: ${
|
|
292
|
+
public async delete(id: ${methodTypeSignatures.delete.parameters[0]}): ${methodTypeSignatures.delete.returnType} {
|
|
259
293
|
const existingItem = this.get(id)
|
|
260
294
|
if (!existingItem) {
|
|
261
295
|
throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
|
|
@@ -268,6 +302,9 @@ function generateMainBuildingBlocks_InMemoryOnly({ model, meta, blocks, }) {
|
|
|
268
302
|
databaseDecoderCode: ``,
|
|
269
303
|
};
|
|
270
304
|
}
|
|
305
|
+
/**
|
|
306
|
+
* Generates the methods of the repository for a model that is stored in the database.
|
|
307
|
+
*/
|
|
271
308
|
function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }) {
|
|
272
309
|
const decoderFunctionName = meta.data.repository.decoderFnName;
|
|
273
310
|
const { idField } = model;
|
|
@@ -281,16 +318,22 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
281
318
|
items: [`format`, `pluralize`].map(types_1.toTypeName),
|
|
282
319
|
from: (0, types_1.toFileName)('@pxl/common'),
|
|
283
320
|
});
|
|
321
|
+
const dbTableName = [model.sourceSchemaName, model.sourceName]
|
|
322
|
+
.filter((s) => s != null)
|
|
323
|
+
.map((part) => `"${part}"`)
|
|
324
|
+
.join('.');
|
|
325
|
+
const methodTypeSignatures = getRepositoryMethodsTypeSignatures({ model, meta });
|
|
284
326
|
return {
|
|
285
327
|
constructorCode: `constructor(protected db: DbService) {}`,
|
|
286
328
|
initCode: `
|
|
287
329
|
public async init() {
|
|
288
330
|
this.data.clear()
|
|
289
331
|
|
|
290
|
-
${blocks.
|
|
291
|
-
|
|
332
|
+
${blocks.uniqueStringFieldsBlocks.clearCode.join('\n')}
|
|
333
|
+
|
|
334
|
+
${blocks.defaultValueBlocks.init.resetCode}
|
|
292
335
|
|
|
293
|
-
${blocks.
|
|
336
|
+
${blocks.indexBlocks.initCode.join('\n')}
|
|
294
337
|
|
|
295
338
|
const data = await this.db.${meta.data.repository.getMethodFnName}.findMany({})
|
|
296
339
|
|
|
@@ -298,15 +341,15 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
298
341
|
const item = this.${decoderFunctionName}(rawItem)
|
|
299
342
|
this.set(item)
|
|
300
343
|
|
|
301
|
-
${blocks.
|
|
344
|
+
${blocks.defaultValueBlocks.init.setCode}
|
|
302
345
|
}
|
|
303
346
|
|
|
304
|
-
${blocks.
|
|
347
|
+
${blocks.idBlocks.initCode}
|
|
305
348
|
|
|
306
|
-
${blocks.
|
|
349
|
+
${blocks.defaultValueBlocks.init.checkCode}
|
|
307
350
|
|
|
308
351
|
this.logger.log(\`\${format(this.data.size)} \${pluralize('${model.typeName}', this.data.size)} loaded\`)
|
|
309
|
-
${blocks.
|
|
352
|
+
${blocks.indexBlocks.initLogCode.join('\n')}
|
|
310
353
|
}`,
|
|
311
354
|
reInitCode: `
|
|
312
355
|
public async reInit(data: ${model.typeName}[]): Promise<void> {
|
|
@@ -316,19 +359,20 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
316
359
|
this.logger.error(errorMsg)
|
|
317
360
|
throw new Error(errorMsg)
|
|
318
361
|
}
|
|
362
|
+
|
|
319
363
|
await this.db.runOnlyOnTestDb(() => this.db.${meta.data.repository.getMethodFnName}.createMany({ data: data.map((i) => this.toCreateItem(i)) }))
|
|
364
|
+
|
|
320
365
|
return this.init()
|
|
321
366
|
}`,
|
|
322
367
|
deleteAllCode: `
|
|
323
368
|
public async deleteAll(): Promise<void> {
|
|
324
|
-
await this.db.runOnlyOnTestDb(() => this.db.$executeRaw\`DELETE FROM ${
|
|
325
|
-
|
|
369
|
+
await this.db.runOnlyOnTestDb(() => this.db.$executeRaw\`DELETE FROM ${dbTableName}\`)
|
|
370
|
+
|
|
326
371
|
return this.init()
|
|
327
372
|
}
|
|
328
373
|
`,
|
|
329
|
-
// prettier-ignore
|
|
330
374
|
createCode: `
|
|
331
|
-
public async create(item:
|
|
375
|
+
public async create(item: ${methodTypeSignatures.create.parameters[0]}): ${methodTypeSignatures.create.returnType} {
|
|
332
376
|
const newItem = this.${decoderFunctionName}(
|
|
333
377
|
await this.db.${meta.data.repository.getMethodFnName}.create({
|
|
334
378
|
data: this.toCreateItem(this.verifyItem(item)),
|
|
@@ -339,7 +383,7 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
339
383
|
return newItem
|
|
340
384
|
}`,
|
|
341
385
|
createManyCode: `
|
|
342
|
-
public async createMany(items: ${blocks.
|
|
386
|
+
public async createMany(items: ${blocks.idBlocks.verifyFunctionParameterType}[]) {
|
|
343
387
|
const newItems = items.map((item) => this.verifyItem(item))
|
|
344
388
|
|
|
345
389
|
await this.db.${meta.data.repository.getMethodFnName}.createMany({ data: newItems.map(i => this.toCreateItem(i)) })
|
|
@@ -352,16 +396,15 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
352
396
|
}`,
|
|
353
397
|
// prettier-ignore
|
|
354
398
|
updateCode: `
|
|
355
|
-
public async update(item:
|
|
356
|
-
const existingItem = this.get(item.
|
|
357
|
-
|
|
399
|
+
public async update(item: ${methodTypeSignatures.update.parameters[0]}): ${methodTypeSignatures.update.returnType} {
|
|
400
|
+
const existingItem = this.get(item.${idField.name})
|
|
358
401
|
if (!existingItem) {
|
|
359
402
|
throw new Error(\`Could not update ${meta.userFriendlyName} with id \${item.id}. Not found!\`)
|
|
360
403
|
}
|
|
361
404
|
|
|
362
|
-
${blocks.
|
|
405
|
+
${blocks.maxLengthBlocks.updateCode.join('\n')}
|
|
363
406
|
|
|
364
|
-
${blocks.
|
|
407
|
+
${blocks.uniqueStringFieldsBlocks.updateCode.join('\n')}
|
|
365
408
|
|
|
366
409
|
const newItem = this.${decoderFunctionName}(
|
|
367
410
|
await this.db.${meta.data.repository.getMethodFnName}.update({
|
|
@@ -385,7 +428,7 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
385
428
|
return newItem
|
|
386
429
|
}`,
|
|
387
430
|
deleteCode: `
|
|
388
|
-
public async delete(id: ${
|
|
431
|
+
public async delete(id: ${methodTypeSignatures.delete.parameters[0]}): ${methodTypeSignatures.delete.returnType} {
|
|
389
432
|
const existingItem = this.get(id)
|
|
390
433
|
if (!existingItem) {
|
|
391
434
|
throw new Error(\`Could not delete ${model.typeName} with id \${id}. Not found!\`)
|
|
@@ -395,48 +438,69 @@ function generateMainBuildingBlocks_InDatabase({ model, meta, imports, blocks, }
|
|
|
395
438
|
|
|
396
439
|
this.remove(existingItem)
|
|
397
440
|
}`,
|
|
441
|
+
// prettier-ignore
|
|
398
442
|
databaseDecoderCode: `
|
|
399
443
|
/**
|
|
400
444
|
* Utility function that converts a given Database object to a TypeScript model instance
|
|
401
445
|
*/
|
|
402
|
-
private ${decoderFunctionName}(item: Pick<DbType, ${
|
|
403
|
-
.map((f) => `'${f.sourceName}'`)
|
|
404
|
-
.join(' | ')}>): ${model.typeName} {
|
|
446
|
+
private ${decoderFunctionName}(item: Pick<DbType, ${Array.from(model.fields.values()).map((f) => `'${f.sourceName}'`).join(' | ')}>): ${model.typeName} {
|
|
405
447
|
return ${meta.types.zodDecoderFnName}.parse({
|
|
406
|
-
${
|
|
448
|
+
${Array.from(model.fields.values()).map((f) => `${f.name}: item.${f.sourceName}`).join(',\n')}
|
|
407
449
|
})
|
|
408
450
|
}`,
|
|
409
451
|
};
|
|
410
452
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
maxLength: generateMaxLengthBlocks({ model, meta }),
|
|
417
|
-
index: generateIndexBlocks({ model, meta, imports }),
|
|
418
|
-
relations: generateRelationsBlocks({ model, meta, imports }),
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
function generateIdBlocks({ model, meta, imports, }) {
|
|
453
|
+
/**
|
|
454
|
+
* Generates code chunks responsible for verifying the ID validity of a model instance and generating the id
|
|
455
|
+
* value of a model with auto-generated id.
|
|
456
|
+
*/
|
|
457
|
+
function generateIdBlocks({ model, meta }) {
|
|
422
458
|
const idField = model.idField;
|
|
423
459
|
if (!idField.isGenerated) {
|
|
424
|
-
return
|
|
460
|
+
return _generateIdBlocks_NoGeneration({ idField, model, meta });
|
|
425
461
|
}
|
|
426
462
|
if (idField.schemaType === 'Int') {
|
|
427
|
-
return
|
|
463
|
+
return _generateIdBlock_Int({ idField, model, meta });
|
|
428
464
|
}
|
|
429
465
|
if (idField.schemaType === 'String') {
|
|
430
|
-
return
|
|
466
|
+
return _generateIdBlock_UUID({ idField, model, meta });
|
|
431
467
|
}
|
|
432
468
|
throw new Error(`Repository block only supports Id generation for number and strings! Found ${idField.schemaType} for model ${model.name} instead!`);
|
|
433
469
|
}
|
|
434
|
-
|
|
470
|
+
/**
|
|
471
|
+
* Returns a collection of type signatures for the repository methods of a given model.
|
|
472
|
+
*/
|
|
473
|
+
// NOTE: We export this function as an interface simplification to the repository generator. Internally, we
|
|
474
|
+
// use the same functions as the ones used in this function which we don't want to expose.
|
|
475
|
+
function getRepositoryMethodsTypeSignatures({ model, meta }) {
|
|
476
|
+
const { verifyFunctionParameterType } = generateIdBlocks({ model, meta });
|
|
477
|
+
return {
|
|
478
|
+
create: {
|
|
479
|
+
parameters: [verifyFunctionParameterType],
|
|
480
|
+
returnType: `Promise<${model.typeName}>`,
|
|
481
|
+
},
|
|
482
|
+
update: {
|
|
483
|
+
parameters: [`Partial<${model.typeName}> & { ${model.idField.name}: ${model.brandedIdType} }`],
|
|
484
|
+
returnType: `Promise<${model.typeName}>`,
|
|
485
|
+
},
|
|
486
|
+
delete: {
|
|
487
|
+
parameters: [model.brandedIdType],
|
|
488
|
+
returnType: `Promise<void>`,
|
|
489
|
+
},
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
exports.getRepositoryMethodsTypeSignatures = getRepositoryMethodsTypeSignatures;
|
|
493
|
+
/**
|
|
494
|
+
* Generates the id block code chunks for a model that requires an ID field to be manually
|
|
495
|
+
* supplied to the create function.
|
|
496
|
+
*/
|
|
497
|
+
function _generateIdBlocks_NoGeneration({ idField, model, meta, }) {
|
|
435
498
|
return {
|
|
436
499
|
libraryImports: '',
|
|
437
500
|
generateNextIdFunctionName: '',
|
|
438
501
|
initCode: '',
|
|
439
502
|
verifyFunctionComment: `an error is thrown as field has no default setting in schema.`,
|
|
503
|
+
// TODO: This creates a bug!
|
|
440
504
|
verifyFunctionParameterType: model.typeName,
|
|
441
505
|
verifyCode: `
|
|
442
506
|
if (item.${idField.name} === undefined) {
|
|
@@ -446,11 +510,11 @@ function generateIdBlocks_NoGeneration({ idField, model, meta, }) {
|
|
|
446
510
|
setCode: '',
|
|
447
511
|
};
|
|
448
512
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Generates the id block code chunks for a model that has an integer id field.
|
|
515
|
+
* Given chunks make sure that the id is unique if provided or generate a new one if not.
|
|
516
|
+
*/
|
|
517
|
+
function _generateIdBlock_Int({ idField, model, meta, }) {
|
|
454
518
|
return {
|
|
455
519
|
libraryImports: '',
|
|
456
520
|
generateNextIdFunctionName: `
|
|
@@ -465,11 +529,11 @@ function generateIdBlock_Int({ idField, model, meta, imports, }) {
|
|
|
465
529
|
setCode: `if (item.id > this.currentMaxId) { this.currentMaxId = item.id }`,
|
|
466
530
|
};
|
|
467
531
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
532
|
+
/**
|
|
533
|
+
* Generates the id block code chunks for a model that has a UUID id field.
|
|
534
|
+
* It allows you to provide a custom id or generates a new one if not.
|
|
535
|
+
*/
|
|
536
|
+
function _generateIdBlock_UUID({ idField, model, meta, }) {
|
|
473
537
|
return {
|
|
474
538
|
libraryImports: `import { randomUUID } from 'crypto'`,
|
|
475
539
|
generateNextIdFunctionName: `
|
|
@@ -483,6 +547,9 @@ function generateIdBlock_UUID({ idField, model, meta, imports, }) {
|
|
|
483
547
|
setCode: '',
|
|
484
548
|
};
|
|
485
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Returns the code chunks that define the default value property and its initialization.
|
|
552
|
+
*/
|
|
486
553
|
function generateDefaultBlocks({ model, meta }) {
|
|
487
554
|
const defaultField = model.defaultField;
|
|
488
555
|
if (!defaultField) {
|
|
@@ -520,6 +587,9 @@ function generateDefaultBlocks({ model, meta }) {
|
|
|
520
587
|
`,
|
|
521
588
|
};
|
|
522
589
|
}
|
|
590
|
+
/**
|
|
591
|
+
* Generates code chunks that enforce the uniqueness of a given field.
|
|
592
|
+
*/
|
|
523
593
|
function generateUniqueFieldsBlocks({ model }) {
|
|
524
594
|
const fields = model.fields.filter(fields_1.isUniqueStringField);
|
|
525
595
|
const result = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postxl/generator",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.3",
|
|
4
4
|
"main": "./dist/generator.js",
|
|
5
5
|
"typings": "./dist/generator.d.ts",
|
|
6
6
|
"bin": {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@faker-js/faker": "7.6.0",
|
|
18
|
-
"@prisma/generator-helper": "
|
|
19
|
-
"@prisma/internals": "^
|
|
18
|
+
"@prisma/generator-helper": "5.1.0",
|
|
19
|
+
"@prisma/internals": "^5.1.0",
|
|
20
20
|
"exceljs": "^4.3.0",
|
|
21
21
|
"fast-glob": "^3.2.12",
|
|
22
22
|
"prettier": "^2.8.7",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"@postxl/lock": "0.4.7"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@prisma/client": "
|
|
28
|
+
"@prisma/client": "5.1.0",
|
|
29
29
|
"@types/jest": "^29.5.0",
|
|
30
30
|
"@types/node": "18.15.10",
|
|
31
31
|
"jest": "29.5.0",
|
|
32
|
-
"prisma": "
|
|
32
|
+
"prisma": "5.1.0",
|
|
33
33
|
"ts-jest": "29.0.5",
|
|
34
34
|
"ts-node": "10.9.1",
|
|
35
35
|
"ts-toolbelt": "^9.6.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"build": "tsc -p tsconfig.build.json",
|
|
47
47
|
"prepublish": "tsc -p tsconfig.build.json",
|
|
48
48
|
"dev": "tsc -p tsconfig.build.json -w",
|
|
49
|
-
"test": "./scripts/test.sh",
|
|
49
|
+
"test:generation": "./scripts/test.sh",
|
|
50
50
|
"test:jest": "jest",
|
|
51
51
|
"test:watch": "jest --watch",
|
|
52
52
|
"test:types": "tsc --noEmit"
|