@postxl/generator 0.14.0 → 0.15.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 +16 -0
- package/dist/generators/indices/businesslogicindex.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicindex.generator.js +19 -0
- package/dist/generators/indices/businesslogicmodule.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicmodule.generator.js +43 -0
- package/dist/generators/indices/businesslogicservice.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogicservice.generator.js +32 -0
- package/dist/generators/indices/datamockmodule.generator.js +1 -1
- package/dist/generators/indices/datamodule.generator.js +22 -21
- package/dist/generators/indices/dataservice.generator.js +1 -1
- package/dist/generators/indices/seed-template-decoder.generator.js +32 -11
- package/dist/generators/models/businesslogic.generator.d.ts +9 -0
- package/dist/generators/models/businesslogic.generator.js +172 -0
- package/dist/generators/models/react.generator/context.generator.js +5 -3
- package/dist/generators/models/react.generator/library.generator.js +1 -1
- package/dist/generators/models/react.generator/lookup.generator.js +1 -1
- package/dist/generators/models/react.generator/modals.generator.d.ts +1 -1
- package/dist/generators/models/react.generator/modals.generator.js +118 -60
- package/dist/generators/models/repository.generator.js +18 -2
- package/dist/generators/models/route.generator.js +6 -6
- package/dist/generators/models/seed.generator.js +5 -2
- package/dist/generators/models/stub.generator.js +11 -9
- package/dist/generators/models/types.generator.js +32 -2
- package/dist/lib/imports.js +12 -3
- package/dist/lib/meta.d.ts +101 -1
- package/dist/lib/meta.js +21 -0
- package/dist/lib/schema/fields.d.ts +5 -1
- package/dist/lib/schema/schema.d.ts +26 -1
- package/dist/lib/schema/schema.js +1 -1
- package/dist/prisma/parse.js +15 -3
- package/package.json +2 -2
package/dist/generator.js
CHANGED
|
@@ -61,6 +61,10 @@ const meta_1 = require("./lib/meta");
|
|
|
61
61
|
const types_1 = require("./lib/schema/types");
|
|
62
62
|
const client_path_1 = require("./prisma/client-path");
|
|
63
63
|
const parse_1 = require("./prisma/parse");
|
|
64
|
+
const businesslogicservice_generator_1 = require("./generators/indices/businesslogicservice.generator");
|
|
65
|
+
const businesslogicindex_generator_1 = require("./generators/indices/businesslogicindex.generator");
|
|
66
|
+
const businesslogicmodule_generator_1 = require("./generators/indices/businesslogicmodule.generator");
|
|
67
|
+
const businesslogic_generator_1 = require("./generators/models/businesslogic.generator");
|
|
64
68
|
const seed_template_decoder_generator_1 = require("./generators/indices/seed-template-decoder.generator");
|
|
65
69
|
const seed_template_generator_1 = require("./generators/indices/seed-template.generator");
|
|
66
70
|
const CONFIG_SCHEMA = zod_1.z
|
|
@@ -68,6 +72,7 @@ const CONFIG_SCHEMA = zod_1.z
|
|
|
68
72
|
project: zod_1.z.string(),
|
|
69
73
|
pathToTypes: zod_1.z.string().optional(),
|
|
70
74
|
pathToDataLib: zod_1.z.string().optional(),
|
|
75
|
+
pathToBusinessLogic: zod_1.z.string().optional(),
|
|
71
76
|
pathToSeedLib: zod_1.z.string().optional(),
|
|
72
77
|
trpcRoutesFolder: zod_1.z.string().optional(),
|
|
73
78
|
reactFolderOutput: zod_1.z.string().optional(),
|
|
@@ -86,6 +91,7 @@ const CONFIG_SCHEMA = zod_1.z
|
|
|
86
91
|
project: s.project,
|
|
87
92
|
paths: {
|
|
88
93
|
dataLibPath: (0, types_1.toPath)(s.pathToDataLib || 'repos'),
|
|
94
|
+
businessLogicPath: (0, types_1.toPath)(s.pathToBusinessLogic || 'repos'),
|
|
89
95
|
reactFolderPath: (0, types_1.toPath)(s.reactFolderOutput || 'react'),
|
|
90
96
|
modelTypeDefinitionsPath: (0, types_1.toPath)(s.pathToTypes || 'types'),
|
|
91
97
|
seedPath: (0, types_1.toPath)(s.pathToSeedLib || 'seed'),
|
|
@@ -97,6 +103,7 @@ const CONFIG_SCHEMA = zod_1.z
|
|
|
97
103
|
disableGenerators: {
|
|
98
104
|
types: s.pathToTypes === undefined,
|
|
99
105
|
data: s.pathToDataLib === undefined,
|
|
106
|
+
businessLogic: s.pathToBusinessLogic === undefined,
|
|
100
107
|
seed: s.pathToSeedLib === undefined,
|
|
101
108
|
trpc: s.trpcRoutesFolder === undefined,
|
|
102
109
|
react: s.reactFolderOutput === undefined,
|
|
@@ -156,6 +163,10 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
|
|
|
156
163
|
generated.write(`/${meta.data.repoFilePath}.ts`, (0, repository_generator_1.generateRepository)({ model, meta }));
|
|
157
164
|
generated.write(`/${meta.data.mockRepoFilePath}.ts`, (0, repository_generator_1.generateMockRepository)({ model, meta }));
|
|
158
165
|
}
|
|
166
|
+
// Business Logic
|
|
167
|
+
if (!config.disableGenerators.businessLogic) {
|
|
168
|
+
generated.write(`/${meta.businessLogic.serviceFilePath}.ts`, (0, businesslogic_generator_1.generateModelBusinessLogic)({ model, meta }));
|
|
169
|
+
}
|
|
159
170
|
// Routes
|
|
160
171
|
if (!config.disableGenerators.trpc) {
|
|
161
172
|
generated.write(`/${meta.trpc.routerFilePath}.ts`, (0, route_generator_1.generateRoute)({ model, meta }));
|
|
@@ -188,6 +199,11 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
|
|
|
188
199
|
generated.write(`/${meta.data.stubIndexFilePath}.ts`, (0, stubs_generator_1.generateStubsIndex)({ models, meta }));
|
|
189
200
|
generated.write(`/${meta.migrationsPath}/emptyDatabase.template.sql`, (0, emptydatabasemigration_generator_1.generateEmptyDatabaseStoredProcedure)({ models, meta }));
|
|
190
201
|
}
|
|
202
|
+
if (!config.disableGenerators.businessLogic) {
|
|
203
|
+
generated.write(`/${meta.businessLogic.indexFilePath}.ts`, (0, businesslogicindex_generator_1.generateBusinessLogicIndex)({ models, meta }));
|
|
204
|
+
generated.write(`/${meta.businessLogic.moduleFilePath}.ts`, (0, businesslogicmodule_generator_1.generateBusinessLogicModule)({ models, meta }));
|
|
205
|
+
generated.write(`/${meta.businessLogic.serviceFilePath}.ts`, (0, businesslogicservice_generator_1.generateBusinessLogicService)({ models, meta }));
|
|
206
|
+
}
|
|
191
207
|
if (!config.disableGenerators.seed) {
|
|
192
208
|
generated.write(`/${meta.seed.indexFilePath}.ts`, (0, seed_generator_1.generateSeedIndex)({ models, meta }));
|
|
193
209
|
generated.write(`/${meta.seed.templateExcelFilePath}`, yield (0, seed_template_generator_1.generateSeedExcelTemplate)({ models }));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchemaMetaData } from '../../lib/meta';
|
|
2
|
+
import { Model } from '../../lib/schema/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Generates index file for all businessLogic files.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateBusinessLogicIndex({ models, meta }: {
|
|
7
|
+
models: Model[];
|
|
8
|
+
meta: SchemaMetaData;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateBusinessLogicIndex = void 0;
|
|
4
|
+
const exports_1 = require("../../lib/exports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
|
+
/**
|
|
7
|
+
* Generates index file for all businessLogic files.
|
|
8
|
+
*/
|
|
9
|
+
function generateBusinessLogicIndex({ models, meta }) {
|
|
10
|
+
const exports = exports_1.ExportsGenerator.from(meta.businessLogic.indexFilePath);
|
|
11
|
+
exports.exportEverythingFromPath(meta.businessLogic.serviceFilePath);
|
|
12
|
+
exports.exportEverythingFromPath(meta.businessLogic.moduleFilePath);
|
|
13
|
+
for (const model of models) {
|
|
14
|
+
const meta = (0, meta_1.getModelMetadata)({ model });
|
|
15
|
+
exports.exportEverythingFromPath(meta.businessLogic.serviceFilePath);
|
|
16
|
+
}
|
|
17
|
+
return exports.generate();
|
|
18
|
+
}
|
|
19
|
+
exports.generateBusinessLogicIndex = generateBusinessLogicIndex;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchemaMetaData } from '../../lib/meta';
|
|
2
|
+
import { Model } from '../../lib/schema/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Generates a business Logic module class.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateBusinessLogicModule({ models, meta }: {
|
|
7
|
+
models: Model[];
|
|
8
|
+
meta: SchemaMetaData;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateBusinessLogicModule = void 0;
|
|
4
|
+
const imports_1 = require("../../lib/imports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
|
+
/**
|
|
7
|
+
* Generates a business Logic module class.
|
|
8
|
+
*/
|
|
9
|
+
function generateBusinessLogicModule({ models, meta }) {
|
|
10
|
+
const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
11
|
+
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.moduleFilePath)
|
|
12
|
+
.addImport({
|
|
13
|
+
items: [meta.data.moduleName],
|
|
14
|
+
from: meta.data.importPath,
|
|
15
|
+
})
|
|
16
|
+
.addImport({
|
|
17
|
+
items: [meta.businessLogic.serviceClassName],
|
|
18
|
+
from: meta.businessLogic.serviceFilePath,
|
|
19
|
+
});
|
|
20
|
+
const providers = [meta.businessLogic.serviceClassName];
|
|
21
|
+
for (const { meta } of mm) {
|
|
22
|
+
imports.addImport({
|
|
23
|
+
items: [meta.businessLogic.serviceClassName],
|
|
24
|
+
from: meta.businessLogic.serviceFilePath,
|
|
25
|
+
});
|
|
26
|
+
providers.push(meta.businessLogic.serviceClassName);
|
|
27
|
+
}
|
|
28
|
+
return `
|
|
29
|
+
import { Module } from '@nestjs/common'
|
|
30
|
+
|
|
31
|
+
${imports.generate()}
|
|
32
|
+
|
|
33
|
+
const providers = [${providers.join(', ')}]
|
|
34
|
+
@Module({
|
|
35
|
+
imports: [${meta.data.moduleName}],
|
|
36
|
+
providers,
|
|
37
|
+
exports: providers,
|
|
38
|
+
})
|
|
39
|
+
export class BusinessLogicModule {}
|
|
40
|
+
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
exports.generateBusinessLogicModule = generateBusinessLogicModule;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SchemaMetaData } from '../../lib/meta';
|
|
2
|
+
import { Model } from '../../lib/schema/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Generates the business logic service class.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateBusinessLogicService({ models, meta }: {
|
|
7
|
+
models: Model[];
|
|
8
|
+
meta: SchemaMetaData;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateBusinessLogicService = void 0;
|
|
4
|
+
const imports_1 = require("../../lib/imports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
|
+
/**
|
|
7
|
+
* Generates the business logic service class.
|
|
8
|
+
*/
|
|
9
|
+
function generateBusinessLogicService({ models, meta }) {
|
|
10
|
+
const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
|
|
11
|
+
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.serviceFilePath);
|
|
12
|
+
for (const { meta } of mm) {
|
|
13
|
+
imports.addImport({
|
|
14
|
+
items: [meta.businessLogic.serviceClassName],
|
|
15
|
+
from: meta.businessLogic.serviceFilePath,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
const constructor = mm
|
|
19
|
+
.map(({ meta }) => `public ${meta.businessLogic.serviceVariableName} :${meta.businessLogic.serviceClassName}`)
|
|
20
|
+
.join(',\n');
|
|
21
|
+
return `
|
|
22
|
+
import { Injectable } from '@nestjs/common'
|
|
23
|
+
|
|
24
|
+
${imports.generate()}
|
|
25
|
+
|
|
26
|
+
@Injectable()
|
|
27
|
+
export class ${meta.businessLogic.serviceClassName} {
|
|
28
|
+
constructor(${constructor}) {}
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
exports.generateBusinessLogicService = generateBusinessLogicService;
|
|
@@ -24,9 +24,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.generateDataMockModule = void 0;
|
|
27
|
+
const imports_1 = require("../../lib/imports");
|
|
27
28
|
const meta_1 = require("../../lib/meta");
|
|
28
29
|
const Types = __importStar(require("../../lib/schema/types"));
|
|
29
|
-
const imports_1 = require("../../lib/imports");
|
|
30
30
|
/**
|
|
31
31
|
* Generates a mocking class
|
|
32
32
|
*/
|
|
@@ -24,9 +24,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.generateDataModule = void 0;
|
|
27
|
+
const imports_1 = require("../../lib/imports");
|
|
27
28
|
const meta_1 = require("../../lib/meta");
|
|
28
29
|
const Types = __importStar(require("../../lib/schema/types"));
|
|
29
|
-
const imports_1 = require("../../lib/imports");
|
|
30
30
|
/**
|
|
31
31
|
* Generates a data module class.
|
|
32
32
|
*/
|
|
@@ -47,6 +47,7 @@ function generateDataModule({ models, meta }) {
|
|
|
47
47
|
from: meta.data.repoFilePath,
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
+
const moduleName = meta.data.moduleName;
|
|
50
51
|
return `
|
|
51
52
|
import { DynamicModule, Provider, Type } from '@nestjs/common'
|
|
52
53
|
import { DbModule, DbService } from '@${meta.config.project}/db'
|
|
@@ -68,43 +69,43 @@ const createRepositoryProvider = <T extends AsyncInit>(t: Type<T>, loadData: boo
|
|
|
68
69
|
},
|
|
69
70
|
})
|
|
70
71
|
|
|
71
|
-
export class
|
|
72
|
+
export class ${moduleName} {
|
|
72
73
|
private static cachedModule: DynamicModule | undefined = undefined
|
|
73
74
|
|
|
74
75
|
static isInstantiated(): boolean {
|
|
75
|
-
return
|
|
76
|
+
return !!${moduleName}.cachedModule
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
static getInstance():
|
|
79
|
-
if (
|
|
80
|
-
return
|
|
79
|
+
static getInstance(): ${moduleName} {
|
|
80
|
+
if (!${moduleName}.cachedModule) throw new Error('${moduleName} must be called via .provide first!')
|
|
81
|
+
return ${moduleName}.cachedModule
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
static provide({ loadData }: { loadData: boolean }): DynamicModule {
|
|
84
|
-
if (
|
|
85
|
-
console.warn('
|
|
86
|
-
return
|
|
85
|
+
if (${moduleName}.cachedModule) {
|
|
86
|
+
console.warn('${moduleName} is already instantiated, skipping...')
|
|
87
|
+
return ${moduleName}.cachedModule
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
const repositoryProviders
|
|
90
|
-
${mm.map(({ meta }) => meta.data.repositoryClassName).join(',\n')}
|
|
91
|
-
]
|
|
90
|
+
const repositoryProviders = [
|
|
91
|
+
${mm.map(({ meta }) => `createRepositoryProvider(${meta.data.repositoryClassName}, loadData)`).join(',\n')}
|
|
92
|
+
]
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
module:
|
|
94
|
+
${moduleName}.cachedModule = {
|
|
95
|
+
module: ${moduleName},
|
|
95
96
|
global: true,
|
|
96
97
|
imports: [DbModule.provide()],
|
|
97
98
|
providers: [DataService, ...repositoryProviders],
|
|
98
99
|
exports: [DataService, ...repositoryProviders],
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
return
|
|
102
|
+
return ${moduleName}.cachedModule
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
static provideE2E(): DynamicModule {
|
|
105
|
-
if (
|
|
106
|
-
console.warn('
|
|
107
|
-
return
|
|
106
|
+
if (${moduleName}.cachedModule) {
|
|
107
|
+
console.warn('${moduleName} is already instantiated, skipping...')
|
|
108
|
+
return ${moduleName}.cachedModule
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
const providers: Provider<Repository<any, any>>[] = [
|
|
@@ -112,15 +113,15 @@ export class DataModule {
|
|
|
112
113
|
TestDataService,
|
|
113
114
|
]
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
module:
|
|
116
|
+
${moduleName}.cachedModule = {
|
|
117
|
+
module: ${moduleName},
|
|
117
118
|
global: true,
|
|
118
119
|
imports: [DbModule.provide()],
|
|
119
120
|
providers: [...providers],
|
|
120
121
|
exports: providers,
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
return
|
|
124
|
+
return ${moduleName}.cachedModule
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateDataService = void 0;
|
|
4
|
-
const meta_1 = require("../../lib/meta");
|
|
5
4
|
const imports_1 = require("../../lib/imports");
|
|
5
|
+
const meta_1 = require("../../lib/meta");
|
|
6
6
|
/**
|
|
7
7
|
* Generates a generic data service object that may be used on the server to access database.
|
|
8
8
|
*/
|
|
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateSeedTemplateDecoder = void 0;
|
|
4
4
|
const imports_1 = require("../../lib/imports");
|
|
5
5
|
const meta_1 = require("../../lib/meta");
|
|
6
|
-
const types_1 = require("../../lib/types");
|
|
6
|
+
const types_1 = require("../../lib/schema/types");
|
|
7
|
+
const types_2 = require("../../lib/types");
|
|
8
|
+
// TODO: Remove hardcoded path that seems to be reused in multiple places!
|
|
9
|
+
const PXL_COMMON = (0, types_1.toPath)('@pxl/common');
|
|
7
10
|
/**
|
|
8
11
|
* Creates a decoder for the Seed Excel template
|
|
9
12
|
*/
|
|
@@ -20,7 +23,6 @@ function generateSeedTemplateDecoder({ models, meta }) {
|
|
|
20
23
|
}
|
|
21
24
|
return `
|
|
22
25
|
import * as z from 'zod'
|
|
23
|
-
import { excelStringDecoder, excelStringNullableDecoder, excelBooleanDecoder, excelDateNullableDecoder, excelDateDecoder } from '@pxl/common'
|
|
24
26
|
|
|
25
27
|
${imports.generate()}
|
|
26
28
|
|
|
@@ -42,11 +44,12 @@ function generateTableDecoder({ model, meta, imports, }) {
|
|
|
42
44
|
case 'id': {
|
|
43
45
|
imports.addImport({
|
|
44
46
|
items: [meta.types.toBrandedIdTypeFnName],
|
|
45
|
-
from: meta.types.
|
|
47
|
+
from: meta.types.importPath,
|
|
46
48
|
});
|
|
47
49
|
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
48
50
|
typeName: field.unbrandedTypeName,
|
|
49
51
|
nullable: false,
|
|
52
|
+
imports,
|
|
50
53
|
})}.transform((id: ${field.unbrandedTypeName}) => ${meta.types.toBrandedIdTypeFnName}(id))`);
|
|
51
54
|
break;
|
|
52
55
|
}
|
|
@@ -54,6 +57,7 @@ function generateTableDecoder({ model, meta, imports, }) {
|
|
|
54
57
|
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
55
58
|
typeName: field.typeName,
|
|
56
59
|
nullable: !field.isRequired,
|
|
60
|
+
imports,
|
|
57
61
|
})}`);
|
|
58
62
|
break;
|
|
59
63
|
}
|
|
@@ -62,11 +66,12 @@ function generateTableDecoder({ model, meta, imports, }) {
|
|
|
62
66
|
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
63
67
|
imports.addImport({
|
|
64
68
|
items: [refMeta.types.toBrandedIdTypeFnName],
|
|
65
|
-
from: refMeta.types.
|
|
69
|
+
from: refMeta.types.importPath,
|
|
66
70
|
});
|
|
67
71
|
fieldDecoders.push(`${fieldMeta.excelColumnName}: ${toExcelDecoder({
|
|
68
72
|
typeName: field.unbrandedTypeName,
|
|
69
73
|
nullable: !field.isRequired,
|
|
74
|
+
imports,
|
|
70
75
|
})}.transform((id: ${field.unbrandedTypeName}${field.isRequired ? '' : '| null'}) => ${field.isRequired ? '' : ' id === null ? null : '}${refMeta.types.toBrandedIdTypeFnName}(id))`);
|
|
71
76
|
break;
|
|
72
77
|
}
|
|
@@ -74,13 +79,13 @@ function generateTableDecoder({ model, meta, imports, }) {
|
|
|
74
79
|
const refEnumMeta = (0, meta_1.getEnumMetadata)({ enumerator: field.enumerator });
|
|
75
80
|
imports.addImport({
|
|
76
81
|
items: [field.enumerator.typeName],
|
|
77
|
-
from: refEnumMeta.types.
|
|
82
|
+
from: refEnumMeta.types.importPath,
|
|
78
83
|
});
|
|
79
84
|
fieldDecoders.push(`${fieldMeta.excelColumnName}: z.enum([${field.enumerator.values.map((v) => `'${v}'`).join(', ')}])${field.isRequired ? '' : '.nullable()'}`);
|
|
80
85
|
break;
|
|
81
86
|
}
|
|
82
87
|
default: {
|
|
83
|
-
throw new
|
|
88
|
+
throw new types_2.ExhaustiveSwitchCheck(field);
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -100,16 +105,32 @@ export type ${meta.seed.decoder.decoderTypeName} = z.infer<typeof ${meta.seed.de
|
|
|
100
105
|
export const ${meta.seed.decoder.decoderName} = z.array(${meta.seed.decoder.schemaName})
|
|
101
106
|
`;
|
|
102
107
|
}
|
|
103
|
-
function toExcelDecoder({ typeName, nullable }) {
|
|
108
|
+
function toExcelDecoder({ typeName, nullable, imports, }) {
|
|
104
109
|
switch (typeName) {
|
|
105
|
-
case 'string':
|
|
106
|
-
|
|
110
|
+
case 'string': {
|
|
111
|
+
const decoder = (0, types_1.toFunction)(nullable ? 'excelStringNullableDecoder' : 'excelStringDecoder');
|
|
112
|
+
imports.addImport({
|
|
113
|
+
items: [decoder],
|
|
114
|
+
from: PXL_COMMON,
|
|
115
|
+
});
|
|
116
|
+
return decoder;
|
|
117
|
+
}
|
|
107
118
|
case 'boolean':
|
|
119
|
+
imports.addImport({
|
|
120
|
+
items: [(0, types_1.toFunction)('excelBooleanDecoder')],
|
|
121
|
+
from: PXL_COMMON,
|
|
122
|
+
});
|
|
108
123
|
return 'excelBooleanDecoder';
|
|
109
124
|
case 'number':
|
|
110
125
|
return `z.number()${nullable ? '.nullable()' : ''}`;
|
|
111
|
-
case 'Date':
|
|
112
|
-
|
|
126
|
+
case 'Date': {
|
|
127
|
+
const decoder = (0, types_1.toFunction)(nullable ? 'excelDateNullableDecoder' : 'excelDateDecoder');
|
|
128
|
+
imports.addImport({
|
|
129
|
+
items: [decoder],
|
|
130
|
+
from: PXL_COMMON,
|
|
131
|
+
});
|
|
132
|
+
return decoder;
|
|
133
|
+
}
|
|
113
134
|
default:
|
|
114
135
|
throw new Error('Unknown type');
|
|
115
136
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ModelMetaData } from '../../lib/meta';
|
|
2
|
+
import { Model } from '../../lib/schema/schema';
|
|
3
|
+
/**
|
|
4
|
+
* Generates business logic for a given model.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateModelBusinessLogic({ model, meta }: {
|
|
7
|
+
model: Model;
|
|
8
|
+
meta: ModelMetaData;
|
|
9
|
+
}): string;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.generateModelBusinessLogic = void 0;
|
|
27
|
+
const imports_1 = require("../../lib/imports");
|
|
28
|
+
const meta_1 = require("../../lib/meta");
|
|
29
|
+
const fields_1 = require("../../lib/schema/fields");
|
|
30
|
+
const Types = __importStar(require("../../lib/schema/types"));
|
|
31
|
+
/**
|
|
32
|
+
* Generates business logic for a given model.
|
|
33
|
+
*/
|
|
34
|
+
function generateModelBusinessLogic({ model, meta }) {
|
|
35
|
+
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.serviceFilePath);
|
|
36
|
+
const repos = new Map();
|
|
37
|
+
imports.addImport({
|
|
38
|
+
items: [meta.data.repositoryClassName],
|
|
39
|
+
from: meta.data.importPath,
|
|
40
|
+
});
|
|
41
|
+
imports.addImport({
|
|
42
|
+
items: [model.brandedIdType, meta.types.typeName],
|
|
43
|
+
from: meta.types.importPath,
|
|
44
|
+
});
|
|
45
|
+
const dataRepo = Types.toVariableName('data');
|
|
46
|
+
repos.set(meta.data.repositoryClassName, { name: dataRepo, repoName: meta.data.repositoryClassName });
|
|
47
|
+
const linkedItems = new Map();
|
|
48
|
+
for (const relation of (0, fields_1.getRelationFields)(model)) {
|
|
49
|
+
if (relation.relationToModel.typeName === model.typeName) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const refModel = relation.relationToModel;
|
|
53
|
+
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
54
|
+
imports.addImport({
|
|
55
|
+
items: [refModel.brandedIdType, refMeta.types.typeName],
|
|
56
|
+
from: refMeta.types.importPath,
|
|
57
|
+
});
|
|
58
|
+
imports.addImport({
|
|
59
|
+
items: [refMeta.data.repositoryClassName],
|
|
60
|
+
from: refMeta.data.importPath,
|
|
61
|
+
});
|
|
62
|
+
repos.set(refMeta.data.repositoryClassName, {
|
|
63
|
+
name: refMeta.internalPluralName,
|
|
64
|
+
repoName: refMeta.data.repositoryClassName,
|
|
65
|
+
});
|
|
66
|
+
linkedItems.set(relation.name, {
|
|
67
|
+
fieldName: relation.relatedModelBacklinkFieldName,
|
|
68
|
+
variableDefinition: `
|
|
69
|
+
const ${relation.relatedModelBacklinkFieldName} = this.${refMeta.internalPluralName}.get(itemRaw.${relation.name})
|
|
70
|
+
${!relation.isRequired
|
|
71
|
+
? ''
|
|
72
|
+
: `
|
|
73
|
+
if (!${relation.relatedModelBacklinkFieldName}) {
|
|
74
|
+
throw new Error(\`Could not find ${refMeta.types.typeName} with id \${itemRaw.${relation.name}} for ${model.typeName}.${relation.name}!\`)
|
|
75
|
+
}`}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const hasLinkedItems = linkedItems.size > 0;
|
|
79
|
+
if (hasLinkedItems) {
|
|
80
|
+
imports.addImport({
|
|
81
|
+
items: [meta.types.linkedTypeName],
|
|
82
|
+
from: meta.types.importPath,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
for (const f of (0, fields_1.getEnumFields)(model)) {
|
|
86
|
+
const refEnumMeta = (0, meta_1.getEnumMetadata)({ enumerator: f.enumerator });
|
|
87
|
+
imports.addImport({
|
|
88
|
+
items: [f.enumerator.typeName],
|
|
89
|
+
from: refEnumMeta.types.importPath,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return `
|
|
93
|
+
import { Injectable } from '@nestjs/common'
|
|
94
|
+
${imports.generate()}
|
|
95
|
+
|
|
96
|
+
@Injectable()
|
|
97
|
+
export class ${meta.businessLogic.serviceClassName} {
|
|
98
|
+
constructor(
|
|
99
|
+
${[...repos.values()].map(({ name, repoName }) => `private readonly ${name}: ${repoName}`).join(',\n')}
|
|
100
|
+
) {}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Returns the raw ${meta.userFriendlyName} with the given id or null if it does not exist.
|
|
104
|
+
* Raw: The ${meta.userFriendlyName} only contains linked Ids, not the linked items themselves.
|
|
105
|
+
*/
|
|
106
|
+
public get(id: ${model.brandedIdType}): ${meta.types.typeName} | null {
|
|
107
|
+
return this.${dataRepo}.get(id)
|
|
108
|
+
}
|
|
109
|
+
${!hasLinkedItems
|
|
110
|
+
? ''
|
|
111
|
+
: `
|
|
112
|
+
/**
|
|
113
|
+
* Returns the linked ${meta.userFriendlyName} with the given id or null if it does not exist.
|
|
114
|
+
* Linked: The ${meta.userFriendlyName} contains the linked (raw) items themselves, not only the ids.
|
|
115
|
+
*/
|
|
116
|
+
public getLinkedItem(id: ${model.brandedIdType}): ${meta.types.linkedTypeName} | null {
|
|
117
|
+
const itemRaw = this.${dataRepo}.get(id)
|
|
118
|
+
if (!itemRaw) return null
|
|
119
|
+
${[...linkedItems.values()].map(({ variableDefinition }) => variableDefinition).join('\n')}
|
|
120
|
+
const item: ${meta.types.linkedTypeName} = {
|
|
121
|
+
${model.fields
|
|
122
|
+
.map((f) => {
|
|
123
|
+
if (f.kind !== 'relation') {
|
|
124
|
+
return `${f.name}: itemRaw.${f.name}`;
|
|
125
|
+
}
|
|
126
|
+
const linked = linkedItems.get(f.name);
|
|
127
|
+
if (!linked) {
|
|
128
|
+
throw new Error(`Could not find linked item for ${model.typeName}.${f.name}`);
|
|
129
|
+
}
|
|
130
|
+
return `${linked.fieldName}`;
|
|
131
|
+
})
|
|
132
|
+
.join(',\n')}
|
|
133
|
+
}
|
|
134
|
+
return item
|
|
135
|
+
}`}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Returns a map of all ${meta.userFriendlyName}s.
|
|
139
|
+
*/
|
|
140
|
+
public getAll(): Map<${meta.types.brandedIdType}, ${model.typeName}> {
|
|
141
|
+
return this.${dataRepo}.getAll()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Creates a new ${meta.userFriendlyName}.
|
|
146
|
+
*/
|
|
147
|
+
public async create(item: Omit<${model.typeName}, 'id'>): Promise<${model.typeName}> {
|
|
148
|
+
return this.${dataRepo}.create(item)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Updates the given ${meta.userFriendlyName}.
|
|
153
|
+
*/
|
|
154
|
+
public async update(item: Partial<${model.typeName}> & {
|
|
155
|
+
id: ${model.brandedIdType}
|
|
156
|
+
}): Promise<${model.typeName}> {
|
|
157
|
+
return this.${dataRepo}.update(item)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Deletes the ${meta.userFriendlyName} with the given id.
|
|
162
|
+
*
|
|
163
|
+
* Note: This does NOT delete any linked items.
|
|
164
|
+
* If the items is a dependency of another item, the deletion will fail!
|
|
165
|
+
*/
|
|
166
|
+
public async delete(id: ${model.brandedIdType}): Promise<void> {
|
|
167
|
+
return this.${dataRepo}.delete(id)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
exports.generateModelBusinessLogic = generateModelBusinessLogic;
|
|
@@ -14,7 +14,9 @@ function generateModelContext({ model, meta }) {
|
|
|
14
14
|
items: [model.typeName, model.brandedIdType],
|
|
15
15
|
from: meta.types.importPath,
|
|
16
16
|
});
|
|
17
|
+
const resultMapTypeDefinition = `Map<${model.brandedIdType}, ${model.typeName}>`;
|
|
17
18
|
return `
|
|
19
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
18
20
|
import React, { useMemo } from 'react'
|
|
19
21
|
|
|
20
22
|
import { createUseContext } from '@lib/react'
|
|
@@ -25,7 +27,7 @@ ${imports.generate()}
|
|
|
25
27
|
|
|
26
28
|
type Context = {
|
|
27
29
|
ready: boolean
|
|
28
|
-
map:
|
|
30
|
+
map: ${resultMapTypeDefinition}
|
|
29
31
|
list: ${model.typeName}[]
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -34,11 +36,11 @@ const ReactContext = React.createContext<Context | null>(null)
|
|
|
34
36
|
/**
|
|
35
37
|
* Context provider to fetch the ${meta.userFriendlyName} data and use it in componenets.
|
|
36
38
|
*/
|
|
37
|
-
export const ${meta.react.context.contextProviderName} = ({ children }: React.PropsWithChildren
|
|
39
|
+
export const ${meta.react.context.contextProviderName} = ({ children }: React.PropsWithChildren) => {
|
|
38
40
|
const ${queryName} = trpc.${meta.trpc.getMap.reactQueryMethod}.useQuery()
|
|
39
41
|
|
|
40
42
|
const context = useMemo<Context>(() => {
|
|
41
|
-
const data = ${queryName}.data ?? new
|
|
43
|
+
const data: ${resultMapTypeDefinition} = ${queryName}.data ?? new ${resultMapTypeDefinition}()
|
|
42
44
|
|
|
43
45
|
return {
|
|
44
46
|
ready: ${queryName}.isLoading === false,
|
|
@@ -47,7 +47,7 @@ function generateModelLibraryComponents({ model, meta }) {
|
|
|
47
47
|
const { ready, list } = ${context.hookFnName}()
|
|
48
48
|
|
|
49
49
|
return (
|
|
50
|
-
<CardList>
|
|
50
|
+
<CardList loading={!ready}>
|
|
51
51
|
{list.map(item => <${components.cardComponentName} key={item.id} item={item} />)}
|
|
52
52
|
</CardList>
|
|
53
53
|
)
|
|
@@ -23,7 +23,7 @@ function generateModelLookupComponents({ model, meta }) {
|
|
|
23
23
|
const tsOmittedFields = hasNameField ? `'label' | 'options' | 'loading'` : `'options' | 'loading'`;
|
|
24
24
|
const reactLabelField = hasNameField ? `label={(l) => l.name}` : '';
|
|
25
25
|
return `
|
|
26
|
-
import React
|
|
26
|
+
import React from 'react'
|
|
27
27
|
|
|
28
28
|
import { MenuSelectInput, MenuSelectField } from '@components/atoms/MenuSelect'
|
|
29
29
|
import { SelectInput, SelectField } from '@components/atoms/SelectInput'
|