@postxl/generator 0.34.0 → 0.35.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 (58) hide show
  1. package/dist/generator.js +40 -22
  2. package/dist/generators/indices/businesslogic-actiontypes.generator.d.ts +9 -0
  3. package/dist/generators/indices/businesslogic-actiontypes.generator.js +39 -0
  4. package/dist/generators/indices/businesslogic-update-index.generator.d.ts +9 -0
  5. package/dist/generators/indices/businesslogic-update-index.generator.js +20 -0
  6. package/dist/generators/indices/businesslogic-update-module.generator.d.ts +9 -0
  7. package/dist/generators/indices/businesslogic-update-module.generator.js +69 -0
  8. package/dist/generators/indices/businesslogic-update-service.generator.d.ts +9 -0
  9. package/dist/generators/indices/businesslogic-update-service.generator.js +34 -0
  10. package/dist/generators/indices/businesslogic-view-index.generator.d.ts +9 -0
  11. package/dist/generators/indices/businesslogic-view-index.generator.js +19 -0
  12. package/dist/generators/indices/{businesslogicindex.generator.d.ts → businesslogic-view-module.generator.d.ts} +2 -2
  13. package/dist/generators/indices/{businesslogicmodule.generator.js → businesslogic-view-module.generator.js} +22 -26
  14. package/dist/generators/indices/{businesslogicservice.generator.d.ts → businesslogic-view-service.generator.d.ts} +1 -1
  15. package/dist/generators/indices/{businesslogicservice.generator.js → businesslogic-view-service.generator.js} +9 -10
  16. package/dist/generators/indices/{datamockmodule.generator.js → datamock-module.generator.js} +8 -16
  17. package/dist/generators/indices/datamocker.generator.js +3 -7
  18. package/dist/generators/indices/datamodule.generator.js +7 -13
  19. package/dist/generators/indices/{businesslogicmodule.generator.d.ts → dispatcher-service.generator.d.ts} +2 -2
  20. package/dist/generators/indices/dispatcher-service.generator.js +81 -0
  21. package/dist/generators/indices/seed-migration.generator.d.ts +9 -0
  22. package/dist/generators/indices/seed-migration.generator.js +35 -0
  23. package/dist/generators/indices/seed-service.generator.d.ts +1 -1
  24. package/dist/generators/indices/seed-service.generator.js +327 -123
  25. package/dist/generators/indices/seed-template-decoder.generator.js +22 -6
  26. package/dist/generators/indices/{seed.generator.d.ts → seeddata-type.generator.d.ts} +2 -2
  27. package/dist/generators/indices/seeddata-type.generator.js +42 -0
  28. package/dist/generators/indices/types.generator.d.ts +1 -1
  29. package/dist/generators/indices/types.generator.js +8 -6
  30. package/dist/generators/models/businesslogic-update.generator.d.ts +10 -0
  31. package/dist/generators/models/businesslogic-update.generator.js +243 -0
  32. package/dist/generators/models/businesslogic-view.generator.d.ts +10 -0
  33. package/dist/generators/models/{businesslogic.generator.js → businesslogic-view.generator.js} +23 -72
  34. package/dist/generators/models/react.generator/modals.generator.js +2 -2
  35. package/dist/generators/models/repository.generator.d.ts +9 -0
  36. package/dist/generators/models/repository.generator.js +420 -131
  37. package/dist/generators/models/route.generator.js +45 -55
  38. package/dist/generators/models/seed.generator.js +6 -2
  39. package/dist/generators/models/types.generator.js +60 -13
  40. package/dist/lib/attributes.d.ts +5 -0
  41. package/dist/lib/imports.d.ts +23 -2
  42. package/dist/lib/imports.js +19 -1
  43. package/dist/lib/meta.d.ts +287 -34
  44. package/dist/lib/meta.js +87 -16
  45. package/dist/lib/schema/schema.d.ts +24 -6
  46. package/dist/lib/schema/types.d.ts +4 -0
  47. package/dist/lib/utils/jsdoc.d.ts +1 -1
  48. package/dist/lib/utils/jsdoc.js +8 -6
  49. package/dist/lib/utils/string.js +2 -1
  50. package/dist/prisma/attributes.js +7 -3
  51. package/dist/prisma/parse.js +25 -5
  52. package/package.json +1 -1
  53. package/dist/generators/indices/businesslogicindex.generator.js +0 -19
  54. package/dist/generators/indices/seed.generator.js +0 -17
  55. package/dist/generators/indices/testdataservice.generator.d.ts +0 -9
  56. package/dist/generators/indices/testdataservice.generator.js +0 -78
  57. package/dist/generators/models/businesslogic.generator.d.ts +0 -9
  58. /package/dist/generators/indices/{datamockmodule.generator.d.ts → datamock-module.generator.d.ts} +0 -0
@@ -5,20 +5,21 @@ const imports_1 = require("../../lib/imports");
5
5
  const meta_1 = require("../../lib/meta");
6
6
  const types_1 = require("../../lib/schema/types");
7
7
  const types_2 = require("../../lib/types");
8
+ const string_1 = require("../../lib/utils/string");
8
9
  // TODO: Remove hardcoded path that seems to be reused in multiple places!
9
10
  const PXL_COMMON = (0, types_1.toPath)('@pxl/common');
10
11
  /**
11
12
  * Creates a decoder for the Seed Excel template.
12
13
  */
13
14
  function generateSeedTemplateDecoder({ models, meta }) {
14
- const imports = imports_1.ImportsGenerator.from(meta.seed.templateDecoderFilePath);
15
+ const imports = imports_1.ImportsGenerator.from(meta.seedData.templateDecoderFilePath);
15
16
  const decoders = [];
16
17
  const tableDecoders = [];
17
18
  const renameTransforms = [];
18
19
  for (const model of [...models].sort((a, b) => a.name.localeCompare(b.name))) {
19
20
  const modelMeta = (0, meta_1.getModelMetadata)({ model });
20
21
  decoders.push(generateTableDecoder({ model, meta: modelMeta, imports }));
21
- tableDecoders.push(`${modelMeta.seed.excel.tableName}: z.array(${modelMeta.seed.decoder.schemaName})`);
22
+ tableDecoders.push(`${modelMeta.seed.excel.tableName}: ${modelMeta.seed.decoder.decoderName}`);
22
23
  renameTransforms.push(`${modelMeta.seed.decoder.dataName}: item['${modelMeta.seed.excel.tableName}']`);
23
24
  }
24
25
  return `
@@ -26,9 +27,14 @@ function generateSeedTemplateDecoder({ models, meta }) {
26
27
 
27
28
  ${imports.generate()}
28
29
 
30
+ /**
31
+ * Helper schema to identify blank Excel cells
32
+ */
33
+ const nullOrBlankSchema = z.union([z.null(), z.literal('')])
34
+
29
35
  ${decoders.join('\n')}
30
36
 
31
- export const ${meta.seed.templateDecoderName} = z
37
+ export const ${meta.seedData.templateDecoderName} = z
32
38
  .object({${tableDecoders.join(',\n')}})
33
39
  .transform((item) => ({${renameTransforms.join(',\n')}}))
34
40
  `;
@@ -36,10 +42,12 @@ function generateSeedTemplateDecoder({ models, meta }) {
36
42
  exports.generateSeedTemplateDecoder = generateSeedTemplateDecoder;
37
43
  function generateTableDecoder({ model, meta, imports, }) {
38
44
  const fieldDecoders = [];
45
+ const blankFieldDecoders = [];
39
46
  const renameTransforms = [];
40
47
  for (const field of model.fields) {
41
48
  const fieldMeta = (0, meta_1.getFieldMetadata)({ field });
42
49
  renameTransforms.push(`${field.name}: item['${fieldMeta.excelColumnName}']`);
50
+ blankFieldDecoders.push(`${fieldMeta.excelColumnName}: nullOrBlankSchema`);
43
51
  switch (field.kind) {
44
52
  case 'id': {
45
53
  imports.addImport({ items: [meta.types.toBrandedIdTypeFnName], from: meta.types.importPath });
@@ -81,6 +89,7 @@ function generateTableDecoder({ model, meta, imports, }) {
81
89
  }
82
90
  }
83
91
  }
92
+ const blankSchemaName = `blank${(0, string_1.capitalize)(meta.seed.decoder.schemaName)}`;
84
93
  return `
85
94
  /**
86
95
  * The schema for the ${model.name} table
@@ -88,13 +97,20 @@ function generateTableDecoder({ model, meta, imports, }) {
88
97
  const ${meta.seed.decoder.schemaName} = z
89
98
  .object({${fieldDecoders.join(',\n')}})
90
99
  .transform((item) => ({${renameTransforms.join(',\n')}}))
91
-
92
- /**
100
+
101
+ /** The schema to identify blank rows in the ${model.name} table */
102
+ const ${blankSchemaName} = z
103
+ .object({${blankFieldDecoders.join(',\n')}})
104
+ .transform(() => undefined)
105
+
106
+ /**
93
107
  * The type of the ${model.name} table
94
108
  */
95
109
  export type ${meta.seed.decoder.decoderTypeName} = z.infer<typeof ${meta.seed.decoder.schemaName}>
96
110
 
97
- export const ${meta.seed.decoder.decoderName} = z.array(${meta.seed.decoder.schemaName})
111
+ export const ${meta.seed.decoder.decoderName} = z
112
+ .array(${meta.seed.decoder.schemaName}.or(${blankSchemaName}))
113
+ .transform((items) => items.filter(Boolean) as ${meta.seed.decoder.decoderTypeName}[])
98
114
  `;
99
115
  }
100
116
  function toExcelDecoder({ tsTypeName, dbTypeName: typeName, nullable, imports, }) {
@@ -1,9 +1,9 @@
1
1
  import { SchemaMetaData } from '../../lib/meta';
2
2
  import { Model } from '../../lib/schema/schema';
3
3
  /**
4
- * Generates index file for all seed files.
4
+ * Generates a type for all SeedData.
5
5
  */
6
- export declare function generateSeedIndex({ models, meta }: {
6
+ export declare function generateSeedDataType({ models, meta }: {
7
7
  models: Model[];
8
8
  meta: SchemaMetaData;
9
9
  }): string;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateSeedDataType = void 0;
4
+ const imports_1 = require("../../lib/imports");
5
+ const meta_1 = require("../../lib/meta");
6
+ const types_1 = require("../../lib/schema/types");
7
+ /**
8
+ * Generates a type for all SeedData.
9
+ */
10
+ function generateSeedDataType({ models, meta }) {
11
+ const imports = imports_1.ImportsGenerator.from(meta.types.importPath);
12
+ imports.addImport({ from: meta.data.importPath, items: [(0, types_1.toClassName)('MockData')] });
13
+ const modelTypes = [];
14
+ const mockConverters = [];
15
+ for (const model of models) {
16
+ const modelMeta = (0, meta_1.getModelMetadata)({ model });
17
+ imports.addImport({
18
+ items: [modelMeta.types.dto.create, modelMeta.types.dto.update, modelMeta.types.dto.upsert],
19
+ from: modelMeta.types.importPath,
20
+ });
21
+ modelTypes.push(`${modelMeta.seed.constantName}?: {
22
+ create?: ${modelMeta.types.dto.create}[]
23
+ update?: ${modelMeta.types.dto.update}[]
24
+ upsert?: ${modelMeta.types.dto.upsert}[]
25
+ delete?: string[]
26
+ }`);
27
+ mockConverters.push(`${modelMeta.seed.constantName}: { create: data.${modelMeta.seed.constantName} }`);
28
+ }
29
+ return `
30
+ ${imports.generate()}
31
+
32
+ export type SeedData = {
33
+ ${modelTypes.join('\n')}
34
+ }
35
+
36
+ export function mockDataToCreate(data: MockData): SeedData {
37
+ return {
38
+ ${mockConverters.join(',\n')}
39
+ }
40
+ }`;
41
+ }
42
+ exports.generateSeedDataType = generateSeedDataType;
@@ -3,7 +3,7 @@ import { Enum, Model } from '../../lib/schema/schema';
3
3
  /**
4
4
  * Generates an index file that exports all types.
5
5
  */
6
- export declare function generateTypesIndex({ models, enums, meta, }: {
6
+ export declare function generateTypesIndex({ models, enums, meta: schemaMeta, }: {
7
7
  models: Model[];
8
8
  enums: Enum[];
9
9
  meta: SchemaMetaData;
@@ -6,16 +6,18 @@ const meta_1 = require("../../lib/meta");
6
6
  /**
7
7
  * Generates an index file that exports all types.
8
8
  */
9
- function generateTypesIndex({ models, enums, meta, }) {
10
- const exports = exports_1.ExportsGenerator.from(meta.types.indexFilePath);
9
+ function generateTypesIndex({ models, enums, meta: schemaMeta, }) {
10
+ const exports = exports_1.ExportsGenerator.from(schemaMeta.types.indexFilePath);
11
11
  for (const model of models) {
12
- const meta = (0, meta_1.getModelMetadata)({ model });
13
- exports.exportEverythingFromPath(meta.types.filePath);
12
+ const modelMeta = (0, meta_1.getModelMetadata)({ model });
13
+ exports.exportEverythingFromPath(modelMeta.types.filePath);
14
14
  }
15
15
  for (const enumerator of enums) {
16
- const meta = (0, meta_1.getEnumMetadata)({ enumerator });
17
- exports.exportEverythingFromPath(meta.types.filePath);
16
+ const enumMeta = (0, meta_1.getEnumMetadata)({ enumerator });
17
+ exports.exportEverythingFromPath(enumMeta.types.filePath);
18
18
  }
19
+ // dto.types contains generic types that are used by all models
20
+ exports.exportEverythingFromPath(schemaMeta.types.dto.path);
19
21
  return exports.generate();
20
22
  }
21
23
  exports.generateTypesIndex = generateTypesIndex;
@@ -0,0 +1,10 @@
1
+ import { ModelMetaData } from '../../lib/meta';
2
+ import { Model } from '../../lib/schema/schema';
3
+ /**
4
+ * Generates update business logic for a given model.
5
+ * The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
6
+ */
7
+ export declare function generateModelBusinessLogicUpdate({ model, meta }: {
8
+ model: Model;
9
+ meta: ModelMetaData;
10
+ }): string;
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateModelBusinessLogicUpdate = void 0;
4
+ const imports_1 = require("../../lib/imports");
5
+ const meta_1 = require("../../lib/meta");
6
+ const jsdoc_1 = require("../../lib/utils/jsdoc");
7
+ const repository_generator_1 = require("./repository.generator");
8
+ /**
9
+ * Generates update business logic for a given model.
10
+ * The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
11
+ */
12
+ function generateModelBusinessLogicUpdate({ model, meta }) {
13
+ const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
14
+ const imports = imports_1.ImportsGenerator.from(meta.businessLogic.update.serviceFilePath);
15
+ imports.addImports({
16
+ [meta.data.importPath]: meta.data.repositoryClassName,
17
+ [schemaMeta.actions.importPath]: schemaMeta.actions.actionExecutionInterface,
18
+ [meta.types.importPath]: [model.brandedIdType, meta.types.typeName],
19
+ [schemaMeta.businessLogic.update.serviceFilePath]: schemaMeta.businessLogic.update.serviceClassName,
20
+ [schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
21
+ [meta.data.importPath]: [meta.data.repositoryClassName],
22
+ });
23
+ /**
24
+ * The name of the variable that holds the repository instance for the current model
25
+ * (e.g. when we generate business logic service for Aggregation, the AggregationRepository
26
+ * would be referenced using `this.data` variable).
27
+ */
28
+ const modelRepositoryVariableName = meta.businessLogic.dataRepositoryVariableName;
29
+ /**
30
+ * The name of the variable that holds the central business logic service instance.
31
+ * Instead of injecting a repository instance for each model, we inject this single instance
32
+ * which then provides access to all models' business logic.
33
+ */
34
+ const updateServiceClassName = 'updateService';
35
+ const viewServiceClassName = 'viewService';
36
+ const actionBlocks = generateActionsBuildingBlocks({ model, meta });
37
+ imports.addImport({ from: meta.types.importPath, items: actionBlocks.importTypes });
38
+ const constructorParameters = [
39
+ `public readonly ${modelRepositoryVariableName}: ${meta.data.repositoryClassName}`,
40
+ `@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly ${updateServiceClassName}: ${schemaMeta.businessLogic.update.serviceClassName}`,
41
+ `@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly ${viewServiceClassName}: ${schemaMeta.businessLogic.view.serviceClassName}`,
42
+ ];
43
+ const methodTypeSignatures = (0, repository_generator_1.getRepositoryMethodsTypeSignatures)({ model, meta });
44
+ return `
45
+ import { Inject, Injectable, forwardRef } from '@nestjs/common'
46
+ import { ExhaustiveSwitchCheck } from '@pxl/common'
47
+
48
+ ${imports.generate()}
49
+
50
+ ${actionBlocks.actionTypeDefinition}
51
+
52
+ ${actionBlocks.resultMap}
53
+
54
+ ${actionBlocks.typeDefinitionWithCreateFunction}
55
+
56
+ @Injectable()
57
+ export class ${meta.businessLogic.update.serviceClassName} {
58
+ constructor(${constructorParameters.join(',\n')}) {}
59
+
60
+ ${actionBlocks.dispatcher}
61
+
62
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.create.jsDoc)}
63
+ public async create(
64
+ { item, execution }: ${methodTypeSignatures.create.parameters[0]}
65
+ ): ${methodTypeSignatures.create.returnType} {
66
+ return this.${modelRepositoryVariableName}.create({ item, execution })
67
+ }
68
+
69
+
70
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.createMany.jsDoc)}
71
+ public async createMany(
72
+ { items, execution }: ${methodTypeSignatures.createMany.parameters[0]}
73
+ ): ${methodTypeSignatures.createMany.returnType} {
74
+ return this.${modelRepositoryVariableName}.createMany({ items, execution })
75
+ }
76
+
77
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.update.jsDoc)}
78
+ public async update(
79
+ { item, execution }: ${methodTypeSignatures.update.parameters[0]}
80
+ ): ${methodTypeSignatures.update.returnType} {
81
+ return this.${modelRepositoryVariableName}.update({ item, execution })
82
+ }
83
+
84
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.updateMany.jsDoc)}
85
+ public async updateMany(
86
+ { items, execution }: ${methodTypeSignatures.updateMany.parameters[0]}
87
+ ): ${methodTypeSignatures.updateMany.returnType} {
88
+ return this.${modelRepositoryVariableName}.updateMany({ items, execution })
89
+ }
90
+
91
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsert.jsDoc)}
92
+ public async upsert(
93
+ { item, execution }: ${methodTypeSignatures.upsert.parameters[0]}
94
+ ): ${methodTypeSignatures.upsert.returnType} {
95
+ return this.${modelRepositoryVariableName}.upsert({ item, execution })
96
+ }
97
+
98
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.upsertMany.jsDoc)}
99
+ public async upsertMany(
100
+ { items, execution }: ${methodTypeSignatures.upsertMany.parameters[0]}
101
+ ): ${methodTypeSignatures.upsertMany.returnType} {
102
+ return this.${modelRepositoryVariableName}.upsertMany({ items, execution })
103
+ }
104
+
105
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.delete.jsDoc)}
106
+ public async delete(
107
+ { id, execution }: ${methodTypeSignatures.delete.parameters[0]}
108
+ ): ${methodTypeSignatures.delete.returnType} {
109
+ return this.${modelRepositoryVariableName}.delete({ id, execution })
110
+ }
111
+
112
+ ${(0, jsdoc_1.toJsDocComment)(methodTypeSignatures.deleteMany.jsDoc)}
113
+ public async deleteMany(
114
+ { ids, execution }: ${methodTypeSignatures.deleteMany.parameters[0]}
115
+ ): ${methodTypeSignatures.deleteMany.returnType} {
116
+ return this.${modelRepositoryVariableName}.deleteMany({ ids, execution })
117
+ }
118
+
119
+ }`;
120
+ }
121
+ exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
122
+ function generateActionsBuildingBlocks({ model, meta }) {
123
+ const actionTypeDefinition = [];
124
+ const resultMap = [];
125
+ const typeDefinitionWithCreateFunction = [];
126
+ const importTypes = [];
127
+ const dispatcher = [];
128
+ const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
129
+ const actionDefinitions = prepareActionDefinitions({ model, meta });
130
+ for (const [type, config] of Object.entries(actionDefinitions)) {
131
+ const def = generateAction({ model, meta, type: type, config });
132
+ actionTypeDefinition.push(def.actionName),
133
+ resultMap.push(def.resultMap),
134
+ typeDefinitionWithCreateFunction.push(def.typeDefinition, def.createFunction, ''),
135
+ importTypes.push(...def.importTypes),
136
+ dispatcher.push(def.dispatchCaseExpression);
137
+ }
138
+ return {
139
+ importTypes,
140
+ actionTypeDefinition: `export type Action_${meta.businessLogic.update.actionNameModelPart} = ${actionTypeDefinition.join(' | ')}`,
141
+ resultMap: `export type ActionResult_${meta.businessLogic.update.actionNameModelPart} = {
142
+ ${resultMap.join('\n')}
143
+ }`,
144
+ typeDefinitionWithCreateFunction: `${typeDefinitionWithCreateFunction.join('\n')}`,
145
+ dispatcher: `
146
+ public async dispatch<A extends Action_${meta.businessLogic.update.actionNameModelPart}>({ action, execution }: {
147
+ action: A;
148
+ execution: ${schemaMeta.actions.actionExecutionInterface}
149
+ }) {
150
+ switch (action.type) {
151
+ ${dispatcher.join('\n')}
152
+ default: {
153
+ throw new ExhaustiveSwitchCheck(action)
154
+ }
155
+ }
156
+ }`,
157
+ };
158
+ }
159
+ function prepareActionDefinitions({ model, meta, }) {
160
+ return {
161
+ create: {
162
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Create`,
163
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameCreate,
164
+ payload: meta.types.dto.create,
165
+ resultType: meta.types.typeName,
166
+ imports: [meta.types.dto.create],
167
+ dispatcherParameterName: 'item',
168
+ },
169
+ createMany: {
170
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_CreateMany`,
171
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameCreateMany,
172
+ payload: `${meta.types.dto.create}[]`,
173
+ resultType: `${meta.types.typeName}[]`,
174
+ imports: [meta.types.dto.create],
175
+ dispatcherParameterName: 'items',
176
+ },
177
+ update: {
178
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Update`,
179
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameUpdate,
180
+ payload: meta.types.dto.update,
181
+ resultType: meta.types.typeName,
182
+ imports: [meta.types.dto.update],
183
+ dispatcherParameterName: 'item',
184
+ },
185
+ updateMany: {
186
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_UpdateMany`,
187
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameUpdateMany,
188
+ payload: `${meta.types.dto.update}[]`,
189
+ resultType: `${meta.types.typeName}[]`,
190
+ imports: [meta.types.dto.update],
191
+ dispatcherParameterName: 'items',
192
+ },
193
+ upsert: {
194
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Upsert`,
195
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameUpsert,
196
+ payload: meta.types.dto.upsert,
197
+ resultType: meta.types.typeName,
198
+ imports: [meta.types.dto.upsert],
199
+ dispatcherParameterName: 'item',
200
+ },
201
+ upsertMany: {
202
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_UpsertMany`,
203
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameUpsertMany,
204
+ payload: `${meta.types.dto.upsert}[]`,
205
+ resultType: `${meta.types.typeName}[]`,
206
+ imports: [meta.types.dto.upsert],
207
+ dispatcherParameterName: 'items',
208
+ },
209
+ delete: {
210
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Delete`,
211
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameDelete,
212
+ payload: model.brandedIdType,
213
+ resultType: model.brandedIdType,
214
+ imports: [model.brandedIdType],
215
+ dispatcherParameterName: 'id',
216
+ },
217
+ deleteMany: {
218
+ actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_DeleteMany`,
219
+ createFunctionName: meta.businessLogic.update.createActionFunctionNameDeleteMany,
220
+ payload: `${model.brandedIdType}[]`,
221
+ resultType: `${model.brandedIdType}[]`,
222
+ imports: [model.brandedIdType],
223
+ dispatcherParameterName: 'ids',
224
+ },
225
+ };
226
+ }
227
+ function generateAction({ meta, type, config: { imports, actionName, payload, createFunctionName, resultType, dispatcherParameterName }, }) {
228
+ return {
229
+ actionName,
230
+ actionType: type,
231
+ importTypes: imports,
232
+ resultMap: `${type}: ${resultType}`,
233
+ typeDefinition: `
234
+ export type ${actionName} = { scope: '${meta.actions.actionScopeConstType}'; type: '${type}'; payload: ${payload} }`,
235
+ createFunction: `
236
+ export function ${createFunctionName}(payload: ${payload}): ${actionName} {
237
+ return { scope: '${meta.actions.actionScopeConstType}', type: '${type}', payload }
238
+ }`,
239
+ dispatchCaseExpression: `
240
+ case '${type}':
241
+ return this.${type}({ ${dispatcherParameterName}: action.payload, execution })`,
242
+ };
243
+ }
@@ -0,0 +1,10 @@
1
+ import { ModelMetaData } from '../../lib/meta';
2
+ import { Model } from '../../lib/schema/schema';
3
+ /**
4
+ * Generates view business logic for a given model.
5
+ * The view logic exposes all information and links of a model. See template's readme for more info.
6
+ */
7
+ export declare function generateModelBusinessLogicView({ model, meta }: {
8
+ model: Model;
9
+ meta: ModelMetaData;
10
+ }): string;
@@ -1,44 +1,23 @@
1
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
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.generateModelBusinessLogic = void 0;
3
+ exports.generateModelBusinessLogicView = void 0;
27
4
  const imports_1 = require("../../lib/imports");
28
5
  const meta_1 = require("../../lib/meta");
29
6
  const fields_1 = require("../../lib/schema/fields");
30
- const Types = __importStar(require("../../lib/schema/types"));
31
7
  const ast_1 = require("../../lib/utils/ast");
32
- const repository_generator_1 = require("./repository.generator");
33
8
  /**
34
- * Generates business logic for a given model.
9
+ * Generates view business logic for a given model.
10
+ * The view logic exposes all information and links of a model. See template's readme for more info.
35
11
  */
36
- // TODO: https://github.com/PostXL/PostXL/issues/347
37
- function generateModelBusinessLogic({ model, meta }) {
12
+ function generateModelBusinessLogicView({ model, meta }) {
38
13
  const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
39
- const imports = imports_1.ImportsGenerator.from(meta.businessLogic.serviceFilePath);
40
- imports.addImport({ from: meta.data.importPath, items: [meta.data.repositoryClassName] });
41
- imports.addImport({ from: meta.types.importPath, items: [model.brandedIdType, meta.types.typeName] });
14
+ const imports = imports_1.ImportsGenerator.from(meta.businessLogic.view.serviceFilePath);
15
+ imports.addImports({
16
+ [meta.data.importPath]: meta.data.repositoryClassName,
17
+ [meta.types.importPath]: [model.brandedIdType, meta.types.typeName],
18
+ [schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
19
+ [meta.data.importPath]: [meta.data.repositoryClassName],
20
+ });
42
21
  /**
43
22
  * The name of the variable that holds the repository instance for the current model
44
23
  * (e.g. when we generate business logic service for Aggregation, the AggregationRepository
@@ -50,16 +29,11 @@ function generateModelBusinessLogic({ model, meta }) {
50
29
  * Instead of injecting a repository instance for each model, we inject this single instance
51
30
  * which then provides access to all models' business logic.
52
31
  */
53
- const businessLogicServiceClassName = Types.toVariableName('businessLogic');
32
+ const viewServiceClassName = 'viewService';
54
33
  const constructorParameters = [
55
34
  `public readonly ${modelRepositoryVariableName}: ${meta.data.repositoryClassName}`,
56
- `@Inject(forwardRef(() => ${schemaMeta.businessLogic.serviceClassName})) private readonly ${businessLogicServiceClassName}: ${schemaMeta.businessLogic.serviceClassName}`,
35
+ `@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly ${viewServiceClassName}: ${schemaMeta.businessLogic.view.serviceClassName}`,
57
36
  ];
58
- imports.addImport({
59
- from: schemaMeta.businessLogic.serviceFilePath,
60
- items: [schemaMeta.businessLogic.serviceClassName],
61
- });
62
- imports.addImport({ from: meta.data.importPath, items: [meta.data.repositoryClassName] });
63
37
  /**
64
38
  * Variable names and their definitions indexed by the name of the relation they represent.
65
39
  */
@@ -67,9 +41,9 @@ function generateModelBusinessLogic({ model, meta }) {
67
41
  for (const relation of (0, fields_1.getRelationFields)(model)) {
68
42
  const refModel = relation.relationToModel;
69
43
  const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
70
- const variableGetter = `this.${businessLogicServiceClassName}.${refMeta.businessLogic.serviceVariableName}.get(itemRaw.${relation.name})`;
44
+ const variableGetter = `this.${viewServiceClassName}.${refMeta.businessLogic.view.serviceVariableName}.get(itemRaw.${relation.name})`;
71
45
  const variablePresenceCheck = `
72
- if (!${relation.relatedModelBacklinkFieldName}) {
46
+ if (!${relation.relatedModelBacklinkFieldName}) {
73
47
  throw new Error(\`Could not find ${refMeta.types.typeName} with id \${itemRaw.${relation.name}} for ${model.typeName}.${relation.name}!\`)
74
48
  }
75
49
  `;
@@ -114,11 +88,10 @@ function generateModelBusinessLogic({ model, meta }) {
114
88
  })
115
89
  .join(',\n')}
116
90
  }
91
+
117
92
  return item
118
93
  }
119
94
  `;
120
- const methodTypeSignatures = (0, repository_generator_1.getRepositoryMethodsTypeSignatures)({ model, meta });
121
- // prettier-ignore
122
95
  return `
123
96
  import { Inject, Injectable, forwardRef } from '@nestjs/common'
124
97
  import { FilterOperator } from '@pxl/common'
@@ -126,7 +99,7 @@ import { FilterOperator } from '@pxl/common'
126
99
  ${imports.generate()}
127
100
 
128
101
  @Injectable()
129
- export class ${meta.businessLogic.serviceClassName} {
102
+ export class ${meta.businessLogic.view.serviceClassName} {
130
103
  constructor(${constructorParameters.join(',\n')}) {}
131
104
 
132
105
  /**
@@ -140,14 +113,14 @@ export class ${meta.businessLogic.serviceClassName} {
140
113
  ${hasLinkedItems ? linkedItemsGetterFn : ''}
141
114
 
142
115
  /**
143
- * Returns a map of all ${meta.userFriendlyName}s.
116
+ * Returns a map of all ${meta.userFriendlyNamePlural}.
144
117
  */
145
118
  public getAll(): Map<${meta.types.brandedIdType}, ${model.typeName}> {
146
119
  return this.${modelRepositoryVariableName}.getAll()
147
120
  }
148
121
 
149
- /**
150
- * Returns a list of filtered, sorted and paginated ${meta.userFriendlyName}s.
122
+ /**
123
+ * Returns a list of filtered, sorted and paginated ${meta.userFriendlyNamePlural}.
151
124
  */
152
125
  public getList({
153
126
  filter,
@@ -171,29 +144,6 @@ export class ${meta.businessLogic.serviceClassName} {
171
144
  return { rows: paginated, count: items.length }
172
145
  }
173
146
 
174
- /**
175
- * Creates a new ${meta.userFriendlyName}.
176
- */
177
- public async create(item: ${methodTypeSignatures.create.parameters[0]}): ${methodTypeSignatures.create.returnType} {
178
- return this.${modelRepositoryVariableName}.create(item)
179
- }
180
-
181
- /**
182
- * Updates the given ${meta.userFriendlyName}.
183
- */
184
- public async update(item: ${methodTypeSignatures.update.parameters[0]}): ${methodTypeSignatures.update.returnType} {
185
- return this.${modelRepositoryVariableName}.update(item)
186
- }
187
-
188
- /**
189
- * Deletes the ${meta.userFriendlyName} with the given id.
190
- *
191
- * Note: This does NOT delete any linked items.
192
- * If the item is a dependency of another item, the deletion will fail!
193
- */
194
- public async delete(id: ${methodTypeSignatures.delete.parameters[0]}): ${methodTypeSignatures.delete.returnType} {
195
- return this.${modelRepositoryVariableName}.delete(id)
196
- }
197
147
  }
198
148
 
199
149
  // Utility Functions
@@ -203,7 +153,7 @@ ${_createModelCompareFn({ model })}
203
153
  ${_createModelFilterFn({ model })}
204
154
  `;
205
155
  }
206
- exports.generateModelBusinessLogic = generateModelBusinessLogic;
156
+ exports.generateModelBusinessLogicView = generateModelBusinessLogicView;
207
157
  /**
208
158
  * Generates a utility filter function for the given model that can be used to filter out instances
209
159
  * of a model using a given operator on a given field.
@@ -221,8 +171,9 @@ function _createModelFilterFn({ model }) {
221
171
  case 'contains': {
222
172
  return (item[field] || '').toLowerCase().includes(value.toLowerCase())
223
173
  }
224
- default:
174
+ default: {
225
175
  return false
176
+ }
226
177
  }
227
178
  `,
228
179
  };
@@ -198,7 +198,7 @@ export const ${components.modals.editComponentName} = ({
198
198
  <Typed.Formik
199
199
  initialValues={{
200
200
  ${fields
201
- .filter((f) => !f.attributes.isReadonly)
201
+ .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
202
202
  .map((field) => {
203
203
  switch (field.kind) {
204
204
  case 'enum':
@@ -500,7 +500,7 @@ function getEditFormInputFields({ model }) {
500
500
  }
501
501
  function getEditFormikMutationData({ model: { fields } }) {
502
502
  return fields
503
- .filter((f) => !f.attributes.isReadonly)
503
+ .filter((f) => !f.attributes.isReadonly || f.kind === 'id')
504
504
  .map((field) => {
505
505
  const formikFieldName = getFormikFieldName(field.name);
506
506
  switch (field.kind) {
@@ -31,6 +31,10 @@ type FnSignature = {
31
31
  * The return type of the function.
32
32
  */
33
33
  returnType: string;
34
+ /**
35
+ * The JSDoc comment of the function.
36
+ */
37
+ jsDoc?: string[];
34
38
  };
35
39
  /**
36
40
  * Returns a collection of type signatures for the repository methods of a given model.
@@ -40,7 +44,12 @@ export declare function getRepositoryMethodsTypeSignatures({ model, meta }: {
40
44
  meta: ModelMetaData;
41
45
  }): {
42
46
  create: FnSignature;
47
+ createMany: FnSignature;
43
48
  update: FnSignature;
49
+ updateMany: FnSignature;
50
+ upsert: FnSignature;
51
+ upsertMany: FnSignature;
44
52
  delete: FnSignature;
53
+ deleteMany: FnSignature;
45
54
  };
46
55
  export {};