@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.
Files changed (31) hide show
  1. package/dist/generator.js +16 -0
  2. package/dist/generators/indices/businesslogicindex.generator.d.ts +9 -0
  3. package/dist/generators/indices/businesslogicindex.generator.js +19 -0
  4. package/dist/generators/indices/businesslogicmodule.generator.d.ts +9 -0
  5. package/dist/generators/indices/businesslogicmodule.generator.js +43 -0
  6. package/dist/generators/indices/businesslogicservice.generator.d.ts +9 -0
  7. package/dist/generators/indices/businesslogicservice.generator.js +32 -0
  8. package/dist/generators/indices/datamockmodule.generator.js +1 -1
  9. package/dist/generators/indices/datamodule.generator.js +22 -21
  10. package/dist/generators/indices/dataservice.generator.js +1 -1
  11. package/dist/generators/indices/seed-template-decoder.generator.js +32 -11
  12. package/dist/generators/models/businesslogic.generator.d.ts +9 -0
  13. package/dist/generators/models/businesslogic.generator.js +172 -0
  14. package/dist/generators/models/react.generator/context.generator.js +5 -3
  15. package/dist/generators/models/react.generator/library.generator.js +1 -1
  16. package/dist/generators/models/react.generator/lookup.generator.js +1 -1
  17. package/dist/generators/models/react.generator/modals.generator.d.ts +1 -1
  18. package/dist/generators/models/react.generator/modals.generator.js +118 -60
  19. package/dist/generators/models/repository.generator.js +18 -2
  20. package/dist/generators/models/route.generator.js +6 -6
  21. package/dist/generators/models/seed.generator.js +5 -2
  22. package/dist/generators/models/stub.generator.js +11 -9
  23. package/dist/generators/models/types.generator.js +32 -2
  24. package/dist/lib/imports.js +12 -3
  25. package/dist/lib/meta.d.ts +101 -1
  26. package/dist/lib/meta.js +21 -0
  27. package/dist/lib/schema/fields.d.ts +5 -1
  28. package/dist/lib/schema/schema.d.ts +26 -1
  29. package/dist/lib/schema/schema.js +1 -1
  30. package/dist/prisma/parse.js +15 -3
  31. 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 DataModule {
72
+ export class ${moduleName} {
72
73
  private static cachedModule: DynamicModule | undefined = undefined
73
74
 
74
75
  static isInstantiated(): boolean {
75
- return !!DataModule.cachedModule
76
+ return !!${moduleName}.cachedModule
76
77
  }
77
78
 
78
- static getInstance(): DataModule {
79
- if (!DataModule.cachedModule) throw new Error('DataModule must be called via .provide first!')
80
- return DataModule.cachedModule
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 (DataModule.cachedModule) {
85
- console.warn('DataModule is already instantiated, skipping...')
86
- return DataModule.cachedModule
85
+ if (${moduleName}.cachedModule) {
86
+ console.warn('${moduleName} is already instantiated, skipping...')
87
+ return ${moduleName}.cachedModule
87
88
  }
88
89
 
89
- const repositoryProviders: Provider<Repository<any, any>>[] = [
90
- ${mm.map(({ meta }) => meta.data.repositoryClassName).join(',\n')}
91
- ].map((r) => createRepositoryProvider(r as any, loadData))
90
+ const repositoryProviders = [
91
+ ${mm.map(({ meta }) => `createRepositoryProvider(${meta.data.repositoryClassName}, loadData)`).join(',\n')}
92
+ ]
92
93
 
93
- DataModule.cachedModule = {
94
- module: DataModule,
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 DataModule.cachedModule
102
+ return ${moduleName}.cachedModule
102
103
  }
103
104
 
104
105
  static provideE2E(): DynamicModule {
105
- if (DataModule.cachedModule) {
106
- console.warn('DataModule is already instantiated, skipping...')
107
- return DataModule.cachedModule
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
- DataModule.cachedModule = {
116
- module: DataModule,
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 DataModule.cachedModule
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.filePath,
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.filePath,
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.filePath,
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 types_1.ExhaustiveSwitchCheck(field);
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
- return nullable ? 'excelStringNullableDecoder' : 'excelStringDecoder';
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
- return nullable ? 'excelDateNullableDecoder' : 'excelDateDecoder';
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: Map<${model.brandedIdType}, ${model.typeName}>
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 Map()
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, { useMemo } from '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'
@@ -1,5 +1,5 @@
1
- import { Model } from '../../../lib/schema/schema';
2
1
  import { ModelMetaData } from '../../../lib/meta';
2
+ import { Model } from '../../../lib/schema/schema';
3
3
  /**
4
4
  * Utility generator that creates a create modal component for a given model.
5
5
  */