@postxl/generator 0.54.0 → 0.56.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 +1 -1
- package/dist/generators/indices/businesslogic-actiontypes.generator.js +18 -7
- package/dist/generators/indices/businesslogic-update-index.generator.js +3 -1
- package/dist/generators/indices/dispatcher-service.generator.js +2 -2
- package/dist/generators/indices/importexport-exporter-class.generator.js +41 -4
- package/dist/generators/indices/importexport-import-service.generator.js +2 -2
- package/dist/generators/indices/seed-migration.generator.js +9 -7
- package/dist/generators/indices/testdata-service.generator.js +9 -3
- package/dist/generators/models/businesslogic-update.generator.js +162 -218
- package/dist/generators/models/businesslogic-view.generator.js +47 -10
- package/dist/generators/models/route.generator.js +28 -31
- package/dist/generators/models/types.generator.js +18 -99
- package/dist/lib/exports.d.ts +4 -0
- package/dist/lib/exports.js +38 -8
- package/dist/lib/meta.d.ts +15 -52
- package/dist/lib/meta.js +6 -15
- package/dist/lib/schema/schema.d.ts +10 -6
- package/dist/lib/schema/types.d.ts +5 -5
- package/dist/lib/utils/jsdoc.d.ts +5 -0
- package/dist/lib/utils/jsdoc.js +22 -1
- package/dist/prisma/parse.js +49 -25
- package/package.json +1 -1
|
@@ -3,9 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateModelBusinessLogicUpdate = void 0;
|
|
4
4
|
const imports_1 = require("../../lib/imports");
|
|
5
5
|
const meta_1 = require("../../lib/meta");
|
|
6
|
+
const fields_1 = require("../../lib/schema/fields");
|
|
6
7
|
const types_1 = require("../../lib/schema/types");
|
|
8
|
+
const zod_1 = require("../../lib/schema/zod");
|
|
7
9
|
const jsdoc_1 = require("../../lib/utils/jsdoc");
|
|
8
|
-
const repository_generator_1 = require("./repository.generator");
|
|
9
10
|
/**
|
|
10
11
|
* Generates update business logic for a given model.
|
|
11
12
|
* The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
|
|
@@ -15,239 +16,182 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
15
16
|
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.update.serviceFilePath);
|
|
16
17
|
imports.addImports({
|
|
17
18
|
[meta.data.importPath]: meta.data.repository.className,
|
|
18
|
-
[
|
|
19
|
-
|
|
19
|
+
[meta.types.importPath]: [
|
|
20
|
+
(0, types_1.toAnnotatedTypeName)(model.brandedIdType),
|
|
21
|
+
(0, types_1.toAnnotatedTypeName)(meta.types.typeName),
|
|
22
|
+
meta.types.toBrandedIdTypeFnName,
|
|
23
|
+
],
|
|
20
24
|
[meta.businessLogic.view.serviceFilePath]: [meta.businessLogic.view.serviceClassName],
|
|
25
|
+
[schemaMeta.actions.importPath]: [
|
|
26
|
+
schemaMeta.actions.actionExecution.interface,
|
|
27
|
+
schemaMeta.actions.dispatcher.interface,
|
|
28
|
+
schemaMeta.actions.dispatcher.actionMethod,
|
|
29
|
+
],
|
|
21
30
|
[schemaMeta.businessLogic.update.serviceFilePath]: schemaMeta.businessLogic.update.serviceClassName,
|
|
22
31
|
[schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
|
|
23
|
-
[meta.data.importPath]: [meta.data.repository.className],
|
|
24
32
|
});
|
|
33
|
+
const { dispatcher } = schemaMeta.actions;
|
|
34
|
+
for (const relation of (0, fields_1.getRelationFields)(model)) {
|
|
35
|
+
// NOTE: We add branded id type and type name imports only for foreign models.
|
|
36
|
+
if (relation.relationToModel.typeName === model.typeName) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const refMeta = (0, meta_1.getModelMetadata)({ model: relation.relationToModel });
|
|
40
|
+
imports.addImport({
|
|
41
|
+
items: [refMeta.types.toBrandedIdTypeFnName],
|
|
42
|
+
from: refMeta.types.filePath,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
25
45
|
/**
|
|
26
46
|
* The name of the variable that holds the repository instance for the current model
|
|
27
47
|
* (e.g. when we generate business logic service for Aggregation, the AggregationRepository
|
|
28
48
|
* would be referenced using `this.data` variable).
|
|
29
49
|
*/
|
|
30
50
|
const modelRepositoryVariableName = meta.businessLogic.dataRepositoryVariableName;
|
|
31
|
-
/**
|
|
32
|
-
* The name of the variable that holds the central business logic service instance.
|
|
33
|
-
* Instead of injecting a repository instance for each model, we inject this single instance
|
|
34
|
-
* which then provides access to all models' business logic.
|
|
35
|
-
*/
|
|
36
|
-
const updateServiceClassName = 'updateService';
|
|
37
|
-
const viewServiceClassName = 'viewService';
|
|
38
|
-
const actionBlocks = generateActionsBuildingBlocks({ model, meta });
|
|
39
|
-
imports.addImport({ from: meta.types.importPath, items: actionBlocks.importTypes });
|
|
40
51
|
const constructorParameters = [
|
|
41
52
|
`public readonly ${modelRepositoryVariableName}: ${meta.data.repository.className}`,
|
|
42
|
-
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly
|
|
43
|
-
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly
|
|
53
|
+
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly updateService: ${schemaMeta.businessLogic.update.serviceClassName}`,
|
|
54
|
+
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly viewService: ${schemaMeta.businessLogic.view.serviceClassName}`,
|
|
44
55
|
];
|
|
45
|
-
const
|
|
56
|
+
const { zodCreateObject, zodUpdateObject, zodUpsertObject } = meta.businessLogic.update;
|
|
46
57
|
return /* ts */ `
|
|
47
|
-
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
48
|
-
import { ExhaustiveSwitchCheck } from '@backend/common'
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
|
|
132
|
-
function generateActionsBuildingBlocks({ model, meta }) {
|
|
133
|
-
const actionTypeDefinition = [];
|
|
134
|
-
const resultMap = [];
|
|
135
|
-
const typeDefinitionWithCreateFunction = [];
|
|
136
|
-
const importTypes = [];
|
|
137
|
-
const dispatcher = [];
|
|
138
|
-
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
139
|
-
const actionDefinitions = prepareActionDefinitions({ model, meta });
|
|
140
|
-
for (const [type, config] of Object.entries(actionDefinitions)) {
|
|
141
|
-
const def = generateAction({ model, meta, type: type, config });
|
|
142
|
-
actionTypeDefinition.push(def.actionName),
|
|
143
|
-
resultMap.push(def.resultMap),
|
|
144
|
-
typeDefinitionWithCreateFunction.push(def.typeDefinition, def.createFunction, ''),
|
|
145
|
-
importTypes.push(...def.importTypes),
|
|
146
|
-
dispatcher.push(def.dispatchCaseExpression);
|
|
58
|
+
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
59
|
+
import { ExhaustiveSwitchCheck, UnionOmit } from '@backend/common'
|
|
60
|
+
import { z } from 'zod'
|
|
61
|
+
|
|
62
|
+
${imports.generate()}
|
|
63
|
+
|
|
64
|
+
export type Scope = "${meta.actions.actionScopeConstType}"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Zod decoder for validating the create input of a ${meta.userFriendlyName}.
|
|
70
|
+
*/
|
|
71
|
+
export const ${zodCreateObject} = z.object({
|
|
72
|
+
${model.fields
|
|
73
|
+
.filter((f) => !f.attributes.isReadonly)
|
|
74
|
+
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f })}`)
|
|
75
|
+
.join(',')}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Zod decoder for validating the update input of a ${meta.userFriendlyName} .
|
|
80
|
+
*/
|
|
81
|
+
export const ${zodUpdateObject} = z.object({
|
|
82
|
+
${model.fields
|
|
83
|
+
.filter((f) => !f.attributes.isReadonly || f.kind === 'id')
|
|
84
|
+
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
|
|
85
|
+
.join(',')}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
|
|
90
|
+
*/
|
|
91
|
+
export const ${zodUpsertObject} = z.union([${zodUpdateObject}, ${zodCreateObject}])
|
|
92
|
+
|
|
93
|
+
export type Actions = {
|
|
94
|
+
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
|
|
95
|
+
create: {
|
|
96
|
+
payload: z.infer<typeof ${zodCreateObject}>
|
|
97
|
+
result: ${meta.types.typeName}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
${(0, jsdoc_1.toJsDocComment)([`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
101
|
+
createMany: {
|
|
102
|
+
payload: z.infer<typeof ${zodCreateObject}>[]
|
|
103
|
+
result: ${meta.types.typeName}[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
|
|
107
|
+
update: {
|
|
108
|
+
payload: z.infer<typeof ${zodUpdateObject}>
|
|
109
|
+
result: ${meta.types.typeName}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
${(0, jsdoc_1.toJsDocComment)([`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
113
|
+
updateMany: {
|
|
114
|
+
payload: z.infer<typeof ${zodUpdateObject}>[]
|
|
115
|
+
result: ${meta.types.typeName}[]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
|
|
119
|
+
upsert: {
|
|
120
|
+
payload: z.infer<typeof ${zodUpsertObject}>
|
|
121
|
+
result: ${meta.types.typeName}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
${(0, jsdoc_1.toJsDocComment)([`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
125
|
+
upsertMany: {
|
|
126
|
+
payload: z.infer<typeof ${zodUpsertObject}>[]
|
|
127
|
+
result: ${meta.types.typeName}[]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} and returns its id.`])}
|
|
131
|
+
delete: {
|
|
132
|
+
payload: ${model.brandedIdType}
|
|
133
|
+
result: ${model.brandedIdType}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
${(0, jsdoc_1.toJsDocComment)([`Deletes multiple ${meta.userFriendlyNamePlural} and returns their ids.`])}
|
|
137
|
+
deleteMany: {
|
|
138
|
+
payload: ${model.brandedIdType}[]
|
|
139
|
+
result: ${model.brandedIdType}[]
|
|
140
|
+
}
|
|
147
141
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
142
|
+
|
|
143
|
+
@Injectable()
|
|
144
|
+
export class ${meta.businessLogic.update.serviceClassName} implements ${dispatcher.interface}<Scope, Actions> {
|
|
145
|
+
/**
|
|
146
|
+
* Instance of the ${meta.userFriendlyName} view service for convenience.
|
|
147
|
+
*/
|
|
148
|
+
private view: ${meta.businessLogic.view.serviceClassName}
|
|
149
|
+
|
|
150
|
+
constructor(${constructorParameters.join(',\n')}) {
|
|
151
|
+
this.view = this.viewService.${meta.businessLogic.view.serviceVariableName}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Dispatches an action to the appropriate method of the repository.
|
|
156
|
+
*/
|
|
157
|
+
public async dispatch<A extends ${dispatcher.actionMethod}<Scope, Actions>>({
|
|
158
|
+
action,
|
|
159
|
+
execution,
|
|
160
|
+
}: {
|
|
161
|
+
action: UnionOmit<A, 'result'>
|
|
162
|
+
execution: ${schemaMeta.actions.actionExecution.interface}
|
|
163
|
+
}): Promise<A['result']> {
|
|
160
164
|
switch (action.type) {
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
case 'create':
|
|
166
|
+
return this.data.create({ item: action.payload, execution })
|
|
167
|
+
|
|
168
|
+
case 'createMany':
|
|
169
|
+
return this.data.createMany({ items: action.payload, execution })
|
|
170
|
+
|
|
171
|
+
case 'update':
|
|
172
|
+
return this.data.update({ item: action.payload, execution })
|
|
173
|
+
|
|
174
|
+
case 'updateMany':
|
|
175
|
+
return this.data.updateMany({ items: action.payload, execution })
|
|
176
|
+
|
|
177
|
+
case 'upsert':
|
|
178
|
+
return this.data.upsert({ item: action.payload, execution })
|
|
179
|
+
|
|
180
|
+
case 'upsertMany':
|
|
181
|
+
return this.data.upsertMany({ items: action.payload, execution })
|
|
182
|
+
|
|
183
|
+
case 'delete':
|
|
184
|
+
return this.data.delete({ id: action.payload, execution })
|
|
185
|
+
|
|
186
|
+
case 'deleteMany':
|
|
187
|
+
return this.data.deleteMany({ ids: action.payload, execution })
|
|
188
|
+
|
|
189
|
+
default:
|
|
163
190
|
throw new ExhaustiveSwitchCheck(action)
|
|
164
|
-
|
|
191
|
+
|
|
165
192
|
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function prepareActionDefinitions({ model, meta, }) {
|
|
170
|
-
return {
|
|
171
|
-
create: {
|
|
172
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Create`,
|
|
173
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameCreate,
|
|
174
|
-
payload: meta.types.dto.create,
|
|
175
|
-
resultType: meta.types.typeName,
|
|
176
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.create)],
|
|
177
|
-
dispatcherParameterName: 'item',
|
|
178
|
-
},
|
|
179
|
-
createMany: {
|
|
180
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_CreateMany`,
|
|
181
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameCreateMany,
|
|
182
|
-
payload: `${meta.types.dto.create}[]`,
|
|
183
|
-
resultType: `${meta.types.typeName}[]`,
|
|
184
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.create)],
|
|
185
|
-
dispatcherParameterName: 'items',
|
|
186
|
-
},
|
|
187
|
-
update: {
|
|
188
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Update`,
|
|
189
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameUpdate,
|
|
190
|
-
payload: meta.types.dto.update,
|
|
191
|
-
resultType: meta.types.typeName,
|
|
192
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.update)],
|
|
193
|
-
dispatcherParameterName: 'item',
|
|
194
|
-
},
|
|
195
|
-
updateMany: {
|
|
196
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_UpdateMany`,
|
|
197
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameUpdateMany,
|
|
198
|
-
payload: `${meta.types.dto.update}[]`,
|
|
199
|
-
resultType: `${meta.types.typeName}[]`,
|
|
200
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.update)],
|
|
201
|
-
dispatcherParameterName: 'items',
|
|
202
|
-
},
|
|
203
|
-
upsert: {
|
|
204
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Upsert`,
|
|
205
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameUpsert,
|
|
206
|
-
payload: meta.types.dto.upsert,
|
|
207
|
-
resultType: meta.types.typeName,
|
|
208
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.upsert)],
|
|
209
|
-
dispatcherParameterName: 'item',
|
|
210
|
-
},
|
|
211
|
-
upsertMany: {
|
|
212
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_UpsertMany`,
|
|
213
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameUpsertMany,
|
|
214
|
-
payload: `${meta.types.dto.upsert}[]`,
|
|
215
|
-
resultType: `${meta.types.typeName}[]`,
|
|
216
|
-
imports: [(0, types_1.toAnnotatedTypeName)(meta.types.dto.upsert)],
|
|
217
|
-
dispatcherParameterName: 'items',
|
|
218
|
-
},
|
|
219
|
-
delete: {
|
|
220
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_Delete`,
|
|
221
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameDelete,
|
|
222
|
-
payload: model.brandedIdType,
|
|
223
|
-
resultType: model.brandedIdType,
|
|
224
|
-
imports: [(0, types_1.toAnnotatedTypeName)(model.brandedIdType)],
|
|
225
|
-
dispatcherParameterName: 'id',
|
|
226
|
-
},
|
|
227
|
-
deleteMany: {
|
|
228
|
-
actionName: `Action_${meta.businessLogic.update.actionNameModelPart}_DeleteMany`,
|
|
229
|
-
createFunctionName: meta.businessLogic.update.createActionFunctionNameDeleteMany,
|
|
230
|
-
payload: `${model.brandedIdType}[]`,
|
|
231
|
-
resultType: `${model.brandedIdType}[]`,
|
|
232
|
-
imports: [(0, types_1.toAnnotatedTypeName)(model.brandedIdType)],
|
|
233
|
-
dispatcherParameterName: 'ids',
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
function generateAction({ meta, type, config: { imports, actionName, payload, createFunctionName, resultType, dispatcherParameterName }, }) {
|
|
238
|
-
return {
|
|
239
|
-
actionName,
|
|
240
|
-
actionType: type,
|
|
241
|
-
importTypes: imports,
|
|
242
|
-
resultMap: `${type}: ${resultType}`,
|
|
243
|
-
typeDefinition: `
|
|
244
|
-
export type ${actionName} = { scope: '${meta.actions.actionScopeConstType}'; type: '${type}'; payload: ${payload} }`,
|
|
245
|
-
createFunction: `
|
|
246
|
-
export function ${createFunctionName}(payload: ${payload}): ${actionName} {
|
|
247
|
-
return { scope: '${meta.actions.actionScopeConstType}', type: '${type}', payload }
|
|
248
|
-
}`,
|
|
249
|
-
dispatchCaseExpression: `
|
|
250
|
-
case '${type}':
|
|
251
|
-
return this.${type}({ ${dispatcherParameterName}: action.payload, execution })`,
|
|
252
|
-
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
253
196
|
}
|
|
197
|
+
exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
|
|
@@ -5,7 +5,9 @@ const imports_1 = require("../../lib/imports");
|
|
|
5
5
|
const meta_1 = require("../../lib/meta");
|
|
6
6
|
const fields_1 = require("../../lib/schema/fields");
|
|
7
7
|
const types_1 = require("../../lib/schema/types");
|
|
8
|
+
const types_2 = require("../../lib/types");
|
|
8
9
|
const ast_1 = require("../../lib/utils/ast");
|
|
10
|
+
const jsdoc_1 = require("../../lib/utils/jsdoc");
|
|
9
11
|
/**
|
|
10
12
|
* Generates view business logic for a given model.
|
|
11
13
|
* The view logic exposes all information and links of a model. See template's readme for more info.
|
|
@@ -44,24 +46,30 @@ function generateModelBusinessLogicView({ model, meta }) {
|
|
|
44
46
|
const refMeta = (0, meta_1.getModelMetadata)({ model: refModel });
|
|
45
47
|
const variableGetter = `await this.${viewServiceClassName}.${refMeta.businessLogic.view.serviceVariableName}.get(itemRaw.${relation.name})`;
|
|
46
48
|
const variablePresenceCheck = `
|
|
47
|
-
if (!${relation.
|
|
49
|
+
if (!${relation.relationFieldName}) {
|
|
48
50
|
throw new Error(\`Could not find ${refMeta.types.typeName} with id \${itemRaw.${relation.name}} for ${model.typeName}.${relation.name}!\`)
|
|
49
51
|
}
|
|
50
52
|
`;
|
|
51
|
-
const relationVariableName = relation.
|
|
53
|
+
const relationVariableName = relation.relationFieldName;
|
|
54
|
+
const relationVariableDefinition = relation.isRequired
|
|
55
|
+
? `${variableGetter};${variablePresenceCheck}`
|
|
56
|
+
: `itemRaw.${relation.name} !== null ? ${variableGetter} : null`;
|
|
52
57
|
variables.set(relation.name, {
|
|
53
58
|
variableName: relationVariableName,
|
|
54
|
-
variableDefinition: `
|
|
55
|
-
const ${relationVariableName} = ${relation.isRequired
|
|
56
|
-
? `${variableGetter};${variablePresenceCheck}`
|
|
57
|
-
: `itemRaw.${relation.name} !== null ? ${variableGetter} : null`}
|
|
58
|
-
`,
|
|
59
|
+
variableDefinition: `const ${relationVariableName} = ${relationVariableDefinition}`,
|
|
59
60
|
});
|
|
61
|
+
if (relation.relationToModel.typeName !== model.typeName) {
|
|
62
|
+
imports.addImport({
|
|
63
|
+
items: [refMeta.types.toBrandedIdTypeFnName],
|
|
64
|
+
from: refMeta.types.filePath,
|
|
65
|
+
});
|
|
66
|
+
imports.addTypeImport({
|
|
67
|
+
items: [refModel.brandedIdType, refMeta.types.typeName],
|
|
68
|
+
from: refMeta.types.filePath,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
60
71
|
}
|
|
61
72
|
const hasLinkedItems = variables.size > 0;
|
|
62
|
-
if (hasLinkedItems) {
|
|
63
|
-
imports.addTypeImport({ from: meta.types.importPath, items: [meta.types.linkedTypeName] });
|
|
64
|
-
}
|
|
65
73
|
const linkedItemsGetterFn = `
|
|
66
74
|
/**
|
|
67
75
|
* Returns the linked ${meta.userFriendlyName} with the given id or null if it does not exist.
|
|
@@ -92,6 +100,16 @@ function generateModelBusinessLogicView({ model, meta }) {
|
|
|
92
100
|
|
|
93
101
|
return item
|
|
94
102
|
}
|
|
103
|
+
`;
|
|
104
|
+
const linkedTypeDefinition = `
|
|
105
|
+
export type ${meta.types.linkedTypeName} = {
|
|
106
|
+
${model.fields
|
|
107
|
+
.map((f) => `
|
|
108
|
+
${(0, jsdoc_1.getFieldComment)(f)}
|
|
109
|
+
${getLinkedFieldType(f)}${f.isRequired ? '' : ' | null'}
|
|
110
|
+
`)
|
|
111
|
+
.join('\n')}
|
|
112
|
+
}
|
|
95
113
|
`;
|
|
96
114
|
return /* ts */ `
|
|
97
115
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
@@ -100,6 +118,8 @@ import { FilterOperator } from '@backend/common'
|
|
|
100
118
|
|
|
101
119
|
${imports.generate()}
|
|
102
120
|
|
|
121
|
+
${hasLinkedItems ? linkedTypeDefinition : ''}
|
|
122
|
+
|
|
103
123
|
@Injectable()
|
|
104
124
|
export class ${meta.businessLogic.view.serviceClassName} {
|
|
105
125
|
constructor(${constructorParameters.join(',\n')}) {}
|
|
@@ -253,3 +273,20 @@ function compare(a: ${model.typeName}, b: ${model.typeName}, field: keyof ${mode
|
|
|
253
273
|
|
|
254
274
|
`;
|
|
255
275
|
}
|
|
276
|
+
/**
|
|
277
|
+
* Converts a field to a TypeScript type definition with linked fields.
|
|
278
|
+
*/
|
|
279
|
+
function getLinkedFieldType(f) {
|
|
280
|
+
switch (f.kind) {
|
|
281
|
+
case 'enum':
|
|
282
|
+
return `${f.name}: ${f.typeName}`;
|
|
283
|
+
case 'relation':
|
|
284
|
+
return `${f.relationFieldName}: ${f.relationToModel.typeName}`;
|
|
285
|
+
case 'id':
|
|
286
|
+
return `${f.name}: ${f.model.brandedIdType}`;
|
|
287
|
+
case 'scalar':
|
|
288
|
+
return `${f.name}: ${f.tsTypeName}`;
|
|
289
|
+
default:
|
|
290
|
+
throw new types_2.ExhaustiveSwitchCheck(f);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -9,28 +9,18 @@ const types_1 = require("../../lib/schema/types");
|
|
|
9
9
|
*/
|
|
10
10
|
function generateRoute({ model, meta }) {
|
|
11
11
|
const { idField, defaultField } = model;
|
|
12
|
+
const { scopeName, dataRepositoryVariableName } = meta.businessLogic;
|
|
12
13
|
const defaultValueMethod = `
|
|
13
|
-
getDefault: procedure.query(({ ctx }) => ctx.view.${meta.data.dataServiceName}.${
|
|
14
|
+
getDefault: procedure.query(({ ctx }) => ctx.view.${meta.data.dataServiceName}.${dataRepositoryVariableName}.defaultValue),
|
|
14
15
|
`;
|
|
16
|
+
const { zodCreateObject, zodUpdateObject, zodUpsertObject } = meta.businessLogic.update;
|
|
15
17
|
const imports = imports_1.ImportsGenerator.from(meta.trpc.routerFilePath).addImports({
|
|
16
18
|
[meta.types.importPath]: [
|
|
17
19
|
(0, types_1.toAnnotatedTypeName)(model.typeName),
|
|
18
20
|
meta.types.toBrandedIdTypeFnName,
|
|
19
|
-
meta.types.zodDecoderFnNames.createObject,
|
|
20
|
-
meta.types.zodDecoderFnNames.updateObject,
|
|
21
|
-
meta.types.zodDecoderFnNames.upsertObject,
|
|
22
21
|
meta.types.zodDecoderFnNames.id,
|
|
23
22
|
],
|
|
24
|
-
[meta.businessLogic.
|
|
25
|
-
meta.businessLogic.update.createActionFunctionNameCreate,
|
|
26
|
-
meta.businessLogic.update.createActionFunctionNameCreateMany,
|
|
27
|
-
meta.businessLogic.update.createActionFunctionNameUpdate,
|
|
28
|
-
meta.businessLogic.update.createActionFunctionNameUpdateMany,
|
|
29
|
-
meta.businessLogic.update.createActionFunctionNameUpsert,
|
|
30
|
-
meta.businessLogic.update.createActionFunctionNameUpsertMany,
|
|
31
|
-
meta.businessLogic.update.createActionFunctionNameDelete,
|
|
32
|
-
meta.businessLogic.update.createActionFunctionNameDeleteMany,
|
|
33
|
-
],
|
|
23
|
+
[meta.businessLogic.update.serviceFilePath]: [zodCreateObject, zodUpdateObject, zodUpsertObject],
|
|
34
24
|
});
|
|
35
25
|
return /* ts */ `
|
|
36
26
|
import { z } from 'zod'
|
|
@@ -71,30 +61,37 @@ export const ${meta.trpc.routerName} = router({
|
|
|
71
61
|
return ctx.view.${meta.data.dataServiceName}.getList(input)
|
|
72
62
|
}),
|
|
73
63
|
|
|
74
|
-
create: procedure
|
|
75
|
-
.
|
|
64
|
+
create: procedure
|
|
65
|
+
.input(${zodCreateObject})
|
|
66
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "create", payload: input})),
|
|
76
67
|
|
|
77
|
-
createMany: procedure
|
|
78
|
-
.
|
|
68
|
+
createMany: procedure
|
|
69
|
+
.input(z.array(${zodCreateObject}))
|
|
70
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "createMany", payload: input})),
|
|
79
71
|
|
|
80
|
-
update: procedure
|
|
81
|
-
.
|
|
72
|
+
update: procedure
|
|
73
|
+
.input(${zodUpdateObject})
|
|
74
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "update", payload: input})),
|
|
82
75
|
|
|
83
|
-
updateMany: procedure
|
|
84
|
-
.
|
|
76
|
+
updateMany: procedure
|
|
77
|
+
.input(z.array(${zodUpdateObject}))
|
|
78
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "updateMany", payload: input})),
|
|
85
79
|
|
|
86
|
-
upsert: procedure
|
|
87
|
-
.
|
|
80
|
+
upsert: procedure
|
|
81
|
+
.input(${zodUpsertObject})
|
|
82
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "upsert", payload: input})),
|
|
88
83
|
|
|
89
|
-
upsertMany: procedure
|
|
90
|
-
.
|
|
84
|
+
upsertMany: procedure
|
|
85
|
+
.input(z.array(${zodUpsertObject}))
|
|
86
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "upsertMany", payload: input})),
|
|
91
87
|
|
|
92
|
-
delete: procedure
|
|
93
|
-
.
|
|
88
|
+
delete: procedure
|
|
89
|
+
.input(${meta.types.zodDecoderFnNames.id})
|
|
90
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "delete", payload: input})),
|
|
94
91
|
|
|
95
|
-
deleteMany: procedure
|
|
96
|
-
.
|
|
97
|
-
|
|
92
|
+
deleteMany: procedure
|
|
93
|
+
.input(z.array(${meta.types.zodDecoderFnNames.id}))
|
|
94
|
+
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "deleteMany", payload: input})),
|
|
98
95
|
})
|
|
99
96
|
`;
|
|
100
97
|
}
|