@postxl/generator 0.56.3 → 0.56.5

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 CHANGED
@@ -60,6 +60,7 @@ const importexport_exporter_class_generator_1 = require("./generators/indices/im
60
60
  const importexport_import_service_generator_1 = require("./generators/indices/importexport-import-service.generator");
61
61
  const importexport_types_generator_1 = require("./generators/indices/importexport-types.generator");
62
62
  const repositories_generator_1 = require("./generators/indices/repositories.generator");
63
+ const routes_index_generator_1 = require("./generators/indices/routes-index.generator");
63
64
  const seed_migration_generator_1 = require("./generators/indices/seed-migration.generator");
64
65
  const seed_template_generator_1 = require("./generators/indices/seed-template.generator");
65
66
  const selectors_generator_1 = require("./generators/indices/selectors.generator");
@@ -234,7 +235,7 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
234
235
  generated.write(`/${meta.seedData.initialMigrationFilePath}.ts`, (0, seed_migration_generator_1.generateSeedMigration)({ models, meta }));
235
236
  generated.write(`/${meta.seedData.templateExcelFilePath}`, yield (0, seed_template_generator_1.generateSeedExcelTemplate)({ models }));
236
237
  // Routes
237
- generated.write(`/${meta.trpc.routesFilePath}.ts`, (0, route_generator_1.generateRoutesIndex)({ models, meta }));
238
+ generated.write(`/${meta.trpc.routesFilePath}.ts`, (0, routes_index_generator_1.generateRoutesIndex)({ models, meta }));
238
239
  // Types
239
240
  generated.write(`/${meta.types.indexFilePath}.ts`, (0, types_generator_2.generateTypesIndex)({ models, enums, meta }));
240
241
  // -------------------------------------------------------------------------
@@ -54,7 +54,7 @@ export class ${meta.actions.dispatcher.class} {
54
54
  const execution = await this.actionExecutionFactory.create({ action, dbService: this.dbService, user })
55
55
 
56
56
  try {
57
- const result = await (this.execute({ action, execution }) as Promise<ResultOfAction<A>>)
57
+ const result = await this.execute({ action, execution })
58
58
 
59
59
  await execution.success(result)
60
60
 
@@ -65,22 +65,36 @@ export class ${meta.actions.dispatcher.class} {
65
65
  }
66
66
  }
67
67
 
68
- private async execute({ action, execution }: { action: Action; execution: IActionExecution }) {
68
+ private async execute<A extends Action>({
69
+ action,
70
+ execution,
71
+ }: {
72
+ action: A
73
+ execution: IActionExecution
74
+ }): Promise<ResultOfAction<A>> {
69
75
  switch (action.scope) {
70
76
  ${models
71
77
  .map((model) => {
72
78
  const modelMeta = (0, meta_1.getModelMetadata)({ model });
73
79
  return `
74
- case '${modelMeta.businessLogic.scopeName}':
75
- return this.updateService.${modelMeta.businessLogic.update.serviceVariableName}.dispatch({ action, execution })
80
+ case '${modelMeta.businessLogic.scopeName}': {
81
+ const method = this.updateService.${modelMeta.businessLogic.update.serviceVariableName}[action.type] as (params: {
82
+ data: A['payload']
83
+ execution: IActionExecution
84
+ }) => Promise<ResultOfAction<A>>
85
+
86
+ // NOTE: We need to bind the method to the service instance, as it is a method of the service and not a standalone function.
87
+ return method.bind(this.updateService.${modelMeta.businessLogic.update.serviceVariableName})({ data: action.payload, execution })
88
+ }
76
89
  `;
77
90
  })
78
91
  .join('\n')}
92
+
79
93
  case 'seed':
80
- return this.seedService.dispatch({ action, execution })
94
+ return this.seedService.dispatch({ action, execution }) as Promise<ResultOfAction<A>>
81
95
 
82
96
  case 'import':
83
- return this.importService.dispatch({ action, execution })
97
+ return this.importService.dispatch({ action, execution }) as Promise<ResultOfAction<A>>
84
98
 
85
99
  default:
86
100
  throw new ExhaustiveSwitchCheck(action)
@@ -9,7 +9,6 @@ const types_1 = require("../../lib/schema/types");
9
9
  */
10
10
  function generateImportExportExporterClass({ models, meta }) {
11
11
  const imports = imports_1.ImportsGenerator.from(meta.importExport.exporterClass.filePath);
12
- const modelsMap = new Map(models.map((model) => [model.name, model]));
13
12
  imports.addImports({
14
13
  [meta.businessLogic.view.importPath]: [meta.businessLogic.view.serviceClassName],
15
14
  [meta.importExport.decoder.fullDecoderFilePath]: [
@@ -50,27 +49,15 @@ function generateImportExportExporterClass({ models, meta }) {
50
49
  }
51
50
  }
52
51
  const childItemCalls = [];
53
- for (const relatedModelCore of model.relatedModels) {
54
- const relatedModel = modelsMap.get(relatedModelCore.name);
55
- // This should not happen as the related models are always present
56
- if (!relatedModel) {
57
- continue;
58
- }
59
- for (const field of relatedModel.fields) {
60
- if (field.kind !== 'relation') {
61
- continue;
62
- }
63
- if (field.relationToModel.name !== model.name) {
64
- continue;
65
- }
66
- const linkedModelMeta = (0, meta_1.getModelMetadata)({ model: relatedModel });
67
- const linkedFieldMeta = (0, meta_1.getFieldMetadata)({ field: field });
68
- childItemCalls.push(`
69
- // Add all ${linkedModelMeta.userFriendlyNamePlural} that are related to the ${modelMeta.userFriendlyName} via ${field.name}
70
- for (const ${field.name} of await this.viewService.${linkedModelMeta.businessLogic.view.serviceVariableName}.data.${linkedFieldMeta.getByForeignKeyIdsMethodFnName}(id)) {
71
- await this.${linkedModelMeta.importExport.exportAddFunctionName}({id: ${field.name}, includeChildren})
72
- }`);
73
- }
52
+ for (const { referencingField, referencingModel } of model.references) {
53
+ const linkedModelMeta = (0, meta_1.getModelMetadata)({ model: referencingModel });
54
+ const linkedFieldMeta = (0, meta_1.getFieldMetadata)({ field: referencingField });
55
+ childItemCalls.push(`
56
+ // Add all ${linkedModelMeta.userFriendlyNamePlural} that are related to the ${modelMeta.userFriendlyName} via ${referencingField.name}
57
+ for (const ${referencingField.name} of await this.viewService.${linkedModelMeta.businessLogic.view.serviceVariableName}.data.${linkedFieldMeta.getByForeignKeyIdsMethodFnName}(id)) {
58
+ await this.${linkedModelMeta.importExport.exportAddFunctionName}({id: ${referencingField.name}, includeChildren})
59
+ }
60
+ `);
74
61
  }
75
62
  const childItems = childItemCalls.length > 0
76
63
  ? `
@@ -0,0 +1,9 @@
1
+ import { SchemaMetaData } from '../../lib/meta';
2
+ import { Model } from '../../lib/schema/schema';
3
+ /**
4
+ * Generates the index file for all the routes.
5
+ */
6
+ export declare function generateRoutesIndex({ models, meta }: {
7
+ models: Model[];
8
+ meta: SchemaMetaData;
9
+ }): string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateRoutesIndex = void 0;
4
+ const imports_1 = require("../../lib/imports");
5
+ const meta_1 = require("../../lib/meta");
6
+ /**
7
+ * Generates the index file for all the routes.
8
+ */
9
+ function generateRoutesIndex({ models, meta }) {
10
+ const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
11
+ const imports = imports_1.ImportsGenerator.from(meta.trpc.routesFilePath);
12
+ for (const { meta } of mm) {
13
+ imports.addImport({ items: [meta.trpc.routerName], from: meta.trpc.routerFilePath });
14
+ }
15
+ return /* ts */ `
16
+ ${imports.generate()}
17
+
18
+ /**
19
+ * Object with all generated routes.
20
+ */
21
+ export const routes = {
22
+ ${mm.map(({ meta }) => `${meta.trpc.routerName}`).join(',\n')}
23
+ }
24
+ `;
25
+ }
26
+ exports.generateRoutesIndex = generateRoutesIndex;
@@ -13,21 +13,45 @@ const jsdoc_1 = require("../../lib/utils/jsdoc");
13
13
  */
14
14
  function generateModelBusinessLogicUpdate({ model, meta }) {
15
15
  const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
16
+ /**
17
+ * Shorthand variable for relevant metadata.
18
+ */
19
+ const m = {
20
+ /**
21
+ * The name of the interface that handles the action execution.
22
+ */
23
+ iExecution: schemaMeta.actions.execution.interface,
24
+ /**
25
+ * The name of the type that represents a fully typed, flat object, e.g. `Aggregation`
26
+ */
27
+ typeName: meta.types.typeName,
28
+ /**
29
+ * Type of the ID field that is specific to this model, e.g. `AggregationId`
30
+ */
31
+ brandedId: model.brandedIdType,
32
+ /**
33
+ * Internal type name for create payload, e.g. `CreateAggregation`
34
+ */
35
+ createType: `Create${meta.internalSingularNameCapitalized}`,
36
+ /**
37
+ * Internal type name for update payload, e.g. `UpdateAggregation`
38
+ */
39
+ updateType: `Update${meta.internalSingularNameCapitalized}`,
40
+ /**
41
+ * Internal type name for upsert payload, e.g. `UpsertAggregation`
42
+ */
43
+ upsertType: `Upsert${meta.internalSingularNameCapitalized}`,
44
+ };
16
45
  const imports = imports_1.ImportsGenerator.from(meta.businessLogic.update.serviceFilePath);
17
46
  imports.addImports({
18
47
  [meta.data.importPath]: meta.data.repository.className,
19
48
  [meta.types.importPath]: [
20
- (0, types_1.toAnnotatedTypeName)(model.brandedIdType),
21
- (0, types_1.toAnnotatedTypeName)(meta.types.typeName),
49
+ (0, types_1.toAnnotatedTypeName)(m.brandedId),
50
+ (0, types_1.toAnnotatedTypeName)(m.typeName),
22
51
  meta.types.toBrandedIdTypeFnName,
23
52
  ],
24
53
  [meta.businessLogic.view.serviceFilePath]: [meta.businessLogic.view.serviceClassName],
25
- [schemaMeta.actions.importPath]: [
26
- schemaMeta.actions.execution.interface,
27
- schemaMeta.actions.dispatcher.interface,
28
- schemaMeta.actions.definition.payload,
29
- schemaMeta.actions.definition.result,
30
- ],
54
+ [schemaMeta.actions.importPath]: [schemaMeta.actions.execution.interface, schemaMeta.actions.dispatcher.definition],
31
55
  [schemaMeta.businessLogic.update.serviceFilePath]: schemaMeta.businessLogic.update.serviceClassName,
32
56
  [schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
33
57
  });
@@ -49,28 +73,70 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
49
73
  */
50
74
  const modelRepositoryVariableName = meta.businessLogic.dataRepositoryVariableName;
51
75
  const constructorParameters = [
52
- `public readonly ${modelRepositoryVariableName}: ${meta.data.repository.className}`,
76
+ `private readonly ${modelRepositoryVariableName}: ${meta.data.repository.className}`,
53
77
  `@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly updateService: ${schemaMeta.businessLogic.update.serviceClassName}`,
54
78
  `@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly viewService: ${schemaMeta.businessLogic.view.serviceClassName}`,
55
79
  ];
56
80
  const { zodCreateObject, zodUpdateObject, zodUpsertObject } = meta.businessLogic.update;
57
- const { dispatcher, definition } = schemaMeta.actions;
58
- /**
59
- * A return value of the dispatcher.
60
- *
61
- * NOTE: We need to cast to the return value every time so that the function correctly determines the return type.
62
- */
63
- const dispatcherReturnValue = `Promise<${definition.result}<Actions, A>>`;
81
+ const { view, update } = meta.businessLogic;
82
+ /* prettier-ignore */
64
83
  return /* ts */ `
65
84
  import { Inject, Injectable, forwardRef } from '@nestjs/common'
66
- import { ExhaustiveSwitchCheck } from '@backend/common'
67
85
  import { z } from 'zod'
68
86
 
69
87
  ${imports.generate()}
70
88
 
71
89
  export type Scope = "${meta.actions.actionScopeConstType}"
72
90
 
73
-
91
+ export type Actions = {
92
+ ${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
93
+ create: {
94
+ payload: ${m.createType}
95
+ result: ${m.typeName}
96
+ }
97
+
98
+ ${(0, jsdoc_1.toJsDocComment)([`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`])}
99
+ createMany: {
100
+ payload: ${m.createType}[]
101
+ result: ${m.typeName}[]
102
+ }
103
+
104
+ ${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
105
+ update: {
106
+ payload: ${m.updateType}
107
+ result: ${m.typeName}
108
+ }
109
+
110
+ ${(0, jsdoc_1.toJsDocComment)([`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
111
+ updateMany: {
112
+ payload: ${m.updateType}[]
113
+ result: ${m.typeName}[]
114
+ }
115
+
116
+ ${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
117
+ upsert: {
118
+ payload: ${m.upsertType}
119
+ result: ${m.typeName}
120
+ }
121
+
122
+ ${(0, jsdoc_1.toJsDocComment)([`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
123
+ upsertMany: {
124
+ payload: ${m.upsertType}[]
125
+ result: ${m.typeName}[]
126
+ }
127
+
128
+ ${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} and returns its id.`])}
129
+ delete: {
130
+ payload: ${m.brandedId}
131
+ result: ${m.brandedId}
132
+ }
133
+
134
+ ${(0, jsdoc_1.toJsDocComment)([`Deletes multiple ${meta.userFriendlyNamePlural} and returns their ids.`])}
135
+ deleteMany: {
136
+ payload: ${m.brandedId}[]
137
+ result: ${m.brandedId}[]
138
+ }
139
+ }
74
140
 
75
141
  /**
76
142
  * Zod decoder for validating the create input of a ${meta.userFriendlyName}.
@@ -82,6 +148,8 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
82
148
  .join(',')}
83
149
  })
84
150
 
151
+ type ${m.createType} = z.infer<typeof ${zodCreateObject}>
152
+
85
153
  /**
86
154
  * Zod decoder for validating the update input of a ${meta.userFriendlyName} .
87
155
  */
@@ -92,112 +160,68 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
92
160
  .join(',')}
93
161
  })
94
162
 
163
+ type ${m.updateType} = z.infer<typeof ${zodUpdateObject}>
164
+
95
165
  /**
96
166
  * Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
97
167
  */
98
168
  export const ${zodUpsertObject} = z.union([${zodUpdateObject}, ${zodCreateObject}])
169
+
170
+ type ${m.upsertType} = z.infer<typeof ${zodUpsertObject}>
171
+
172
+ export type ${update.serviceInterfaceName} = ${schemaMeta.actions.dispatcher.definition}<Actions>
173
+
174
+ @Injectable()
175
+ export class ${update.serviceClassName} implements ${update.serviceInterfaceName} {
176
+
177
+ /**
178
+ * Instance of the ${meta.userFriendlyName} view service for convenience.
179
+ */
180
+ private view: ${view.serviceClassName}
181
+
182
+ constructor(${constructorParameters.join(',\n')}) {
183
+ this.view = this.viewService.${view.serviceVariableName}
184
+ }
99
185
 
100
- export type Actions = {
101
186
  ${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
102
- create: {
103
- payload: z.infer<typeof ${zodCreateObject}>
104
- result: ${meta.types.typeName}
187
+ public async create({ data, execution }: { data: ${m.createType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
188
+ return this.data.create({ item: data, execution })
105
189
  }
106
190
 
107
191
  ${(0, jsdoc_1.toJsDocComment)([`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`])}
108
- createMany: {
109
- payload: z.infer<typeof ${zodCreateObject}>[]
110
- result: ${meta.types.typeName}[]
192
+ public async createMany({ data, execution }: { data: ${m.createType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
193
+ return this.data.createMany({ items: data, execution })
111
194
  }
112
195
 
113
196
  ${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
114
- update: {
115
- payload: z.infer<typeof ${zodUpdateObject}>
116
- result: ${meta.types.typeName}
197
+ public async update({ data, execution }: { data: ${m.updateType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
198
+ return this.data.update({ item: data, execution })
117
199
  }
118
200
 
119
201
  ${(0, jsdoc_1.toJsDocComment)([`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
120
- updateMany: {
121
- payload: z.infer<typeof ${zodUpdateObject}>[]
122
- result: ${meta.types.typeName}[]
202
+ public async updateMany({ data, execution }: { data: ${m.updateType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
203
+ return this.data.updateMany({ items: data, execution })
123
204
  }
124
205
 
125
206
  ${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
126
- upsert: {
127
- payload: z.infer<typeof ${zodUpsertObject}>
128
- result: ${meta.types.typeName}
207
+ public async upsert({ data, execution }: { data: ${m.upsertType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
208
+ return this.data.upsert({ item: data, execution })
129
209
  }
130
210
 
131
211
  ${(0, jsdoc_1.toJsDocComment)([`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
132
- upsertMany: {
133
- payload: z.infer<typeof ${zodUpsertObject}>[]
134
- result: ${meta.types.typeName}[]
212
+ public async upsertMany({ data, execution }: { data: ${m.upsertType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
213
+ return this.data.upsertMany({ items: data, execution })
135
214
  }
136
-
215
+
137
216
  ${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} and returns its id.`])}
138
- delete: {
139
- payload: ${model.brandedIdType}
140
- result: ${model.brandedIdType}
217
+ public async delete({ data, execution }: { data: ${m.brandedId}; execution: ${m.iExecution} }): Promise<${m.brandedId}> {
218
+ return this.data.delete({ id: data, execution })
141
219
  }
142
220
 
143
221
  ${(0, jsdoc_1.toJsDocComment)([`Deletes multiple ${meta.userFriendlyNamePlural} and returns their ids.`])}
144
- deleteMany: {
145
- payload: ${model.brandedIdType}[]
146
- result: ${model.brandedIdType}[]
147
- }
148
- }
149
-
150
- @Injectable()
151
- export class ${meta.businessLogic.update.serviceClassName} implements ${dispatcher.interface}<Scope, Actions> {
152
- /**
153
- * Instance of the ${meta.userFriendlyName} view service for convenience.
154
- */
155
- private view: ${meta.businessLogic.view.serviceClassName}
156
-
157
- constructor(${constructorParameters.join(',\n')}) {
158
- this.view = this.viewService.${meta.businessLogic.view.serviceVariableName}
159
- }
160
-
161
- /**
162
- * Dispatches an action to the appropriate method of the repository.
163
- */
164
- public async dispatch<A extends ${definition.payload}<Scope, Actions>>({
165
- action,
166
- execution,
167
- }: {
168
- action: A
169
- execution: ${schemaMeta.actions.execution.interface}
170
- }): ${dispatcherReturnValue} {
171
- switch (action.type) {
172
- case 'create':
173
- return this.data.create({ item: action.payload, execution }) as ${dispatcherReturnValue}
174
-
175
- case 'createMany':
176
- return this.data.createMany({ items: action.payload, execution }) as ${dispatcherReturnValue}
177
-
178
- case 'update':
179
- return this.data.update({ item: action.payload, execution }) as ${dispatcherReturnValue}
180
-
181
- case 'updateMany':
182
- return this.data.updateMany({ items: action.payload, execution }) as ${dispatcherReturnValue}
183
-
184
- case 'upsert':
185
- return this.data.upsert({ item: action.payload, execution }) as ${dispatcherReturnValue}
186
-
187
- case 'upsertMany':
188
- return this.data.upsertMany({ items: action.payload, execution }) as ${dispatcherReturnValue}
189
-
190
- case 'delete':
191
- return this.data.delete({ id: action.payload, execution }) as ${dispatcherReturnValue}
192
-
193
- case 'deleteMany':
194
- return this.data.deleteMany({ ids: action.payload, execution }) as ${dispatcherReturnValue}
195
-
196
- default:
197
- throw new ExhaustiveSwitchCheck(action)
198
-
199
- }
200
- }
222
+ public async deleteMany({ data, execution }: { data: ${m.brandedId}[]; execution: ${m.iExecution} }): Promise<${m.brandedId}[]> {
223
+ return this.data.deleteMany({ ids: data, execution })
224
+ }
201
225
  }
202
226
  `;
203
227
  }
@@ -1,4 +1,4 @@
1
- import { ModelMetaData, SchemaMetaData } from '../../lib/meta';
1
+ import { ModelMetaData } from '../../lib/meta';
2
2
  import { Model } from '../../lib/schema/schema';
3
3
  /**
4
4
  * Generates TRPC route for a given model.
@@ -7,10 +7,3 @@ export declare function generateRoute({ model, meta }: {
7
7
  model: Model;
8
8
  meta: ModelMetaData;
9
9
  }): string;
10
- /**
11
- * Generates the index file for all the routes.
12
- */
13
- export declare function generateRoutesIndex({ models, meta }: {
14
- models: Model[];
15
- meta: SchemaMetaData;
16
- }): string;
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateRoutesIndex = exports.generateRoute = void 0;
3
+ exports.generateRoute = void 0;
4
4
  const imports_1 = require("../../lib/imports");
5
- const meta_1 = require("../../lib/meta");
6
5
  const types_1 = require("../../lib/schema/types");
7
6
  /**
8
7
  * Generates TRPC route for a given model.
@@ -96,24 +95,3 @@ export const ${meta.trpc.routerName} = router({
96
95
  `;
97
96
  }
98
97
  exports.generateRoute = generateRoute;
99
- /**
100
- * Generates the index file for all the routes.
101
- */
102
- function generateRoutesIndex({ models, meta }) {
103
- const mm = models.map((model) => ({ model, meta: (0, meta_1.getModelMetadata)({ model }) }));
104
- const imports = imports_1.ImportsGenerator.from(meta.trpc.routesFilePath);
105
- for (const { meta } of mm) {
106
- imports.addImport({ items: [meta.trpc.routerName], from: meta.trpc.routerFilePath });
107
- }
108
- return /* ts */ `
109
- ${imports.generate()}
110
-
111
- /**
112
- * Object with all generated routes.
113
- */
114
- export const routes = {
115
- ${mm.map(({ meta }) => `${meta.trpc.routerName}`).join(',\n')}
116
- }
117
- `;
118
- }
119
- exports.generateRoutesIndex = generateRoutesIndex;
@@ -117,9 +117,9 @@ export type SchemaMetaData = {
117
117
  */
118
118
  class: Types.ClassName;
119
119
  /**
120
- * The name of the interface that indicates a service can dispatch actions.
120
+ * The definition type that may be used to create a dispatcher conforming class.
121
121
  */
122
- interface: Types.ClassName;
122
+ definition: Types.TypeName;
123
123
  };
124
124
  definition: {
125
125
  /**
@@ -919,9 +919,13 @@ export type ModelMetaData = {
919
919
  */
920
920
  update: {
921
921
  /**
922
- * The name by which the model's update class is exposed in the updateService/context. (e.g. aggregations)
922
+ * The name by which the model's update class is exposed in the updateService/context. (e.g. AggregationUpdateService)
923
923
  */
924
924
  serviceClassName: Types.ClassName;
925
+ /**
926
+ * The name of the interface that represents the update service for this model. (e.g. IAggregationUpdateService)
927
+ */
928
+ serviceInterfaceName: Types.TypeName;
925
929
  /**
926
930
  * The name by which the model's service is exposed in the updateService/context. (e.g. aggregations)
927
931
  */
package/dist/lib/meta.js CHANGED
@@ -89,7 +89,7 @@ function getSchemaMetadata({ config }) {
89
89
  dispatcher: {
90
90
  filePath: Types.toPath(`${config.paths.actionsPath}dispatcher.service`),
91
91
  class: Types.toClassName(`DispatcherService`),
92
- interface: Types.toClassName(`IDispatcher`),
92
+ definition: Types.toTypeName('IDispatcherDefinition'),
93
93
  },
94
94
  definition: {
95
95
  schema: Types.toTypeName('ActionDef'),
@@ -338,6 +338,7 @@ function getModelMetadata({ model }) {
338
338
  },
339
339
  update: {
340
340
  serviceClassName: Types.toClassName(`${PascalCase}UpdateService`),
341
+ serviceInterfaceName: Types.toTypeName(`I${PascalCase}UpdateService`),
341
342
  serviceVariableName: Types.toVariableName(`${uncapitalizedPlural}`),
342
343
  serviceFileName: Types.toFileName(`${camelCase}.update.service`),
343
344
  serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}update/${camelCase}.update.service`),
@@ -173,7 +173,16 @@ export type ModelFields = {
173
173
  /**
174
174
  * A list of models that reference this model in their relations.
175
175
  */
176
- relatedModels: ModelCore[];
176
+ references: {
177
+ /**
178
+ * The name of the field in the referencing model that references this model.
179
+ */
180
+ referencingField: FieldRelation;
181
+ /**
182
+ * The model that references this model.
183
+ */
184
+ referencingModel: ModelCore;
185
+ }[];
177
186
  };
178
187
  /**
179
188
  * A field of a model.
@@ -41,9 +41,27 @@ function parsePrismaSchema({ datamodel: { enums: enumsRaw, models: modelsRaw },
41
41
  // NOTE: We preprocess models and enums so that we can populate relationships.
42
42
  const models = modelsRaw.map((dmmfModel) => parseModelCore({ dmmfModel, config }));
43
43
  const enums = enumsRaw.map((dmmfEnum) => parseEnum({ dmmfEnum, config }));
44
+ // NOTE: Then we parse the fields of the models.
44
45
  const modelsWithFields = modelsRaw
45
46
  .map((dmmfModel) => parseModel({ dmmfModel, models, enums, config }))
46
47
  .filter(isModelNotIgnored);
48
+ // NOTE: Lastly we link back-relations to models.
49
+ for (const mwf of modelsWithFields) {
50
+ for (const field of mwf.fields) {
51
+ if (field.kind !== 'relation') {
52
+ continue;
53
+ }
54
+ const referencedModel = modelsWithFields.find((m) => m.sourceName === field.relationToModel.sourceName);
55
+ if (!referencedModel) {
56
+ // NOTE: This should never happen because Prisma should validate the validity of the relation.
57
+ (0, error_1.throwError)(`Model ${highlight(mwf.name)} not found!`);
58
+ }
59
+ referencedModel.references.push({
60
+ referencingModel: mwf,
61
+ referencingField: field,
62
+ });
63
+ }
64
+ }
47
65
  return { models: modelsWithFields, enums };
48
66
  }
49
67
  exports.parsePrismaSchema = parsePrismaSchema;
@@ -144,10 +162,6 @@ function parseModel({ dmmfModel, enums, models, config, }) {
144
162
  // we need to preprocess relations and then figure out which scalar
145
163
  // fields are actually foreign-keys.
146
164
  const referencedModels = {};
147
- /**
148
- * A map of models that are referenced in any way in the relations.
149
- */
150
- const relatedModels = {};
151
165
  for (const dmmfField of dmmfModel.fields) {
152
166
  if (dmmfField.kind !== 'object' || !dmmfField.relationName) {
153
167
  continue;
@@ -158,7 +172,6 @@ function parseModel({ dmmfModel, enums, models, config, }) {
158
172
  }
159
173
  if (!dmmfField.relationFromFields || dmmfField.relationFromFields.length === 0) {
160
174
  // NOTE: This field has no foreign-key values in this model so it must be a back-relation.
161
- relatedModels[dmmfField.type] = referencedModel;
162
175
  continue;
163
176
  }
164
177
  if (dmmfField.relationFromFields.length > 1) {
@@ -172,11 +185,10 @@ function parseModel({ dmmfModel, enums, models, config, }) {
172
185
  referencedModels[dmmfField.relationFromFields[0]] = referencedModel;
173
186
  }
174
187
  const relationFields = dmmfModel.fields
175
- .filter((f) => { var _a; return f.kind === 'object' && ((_a = f.relationToFields) === null || _a === void 0 ? void 0 : _a.length) === 1; })
188
+ .filter((f) => { var _a, _b; return f.kind === 'object' && ((_a = f.relationToFields) === null || _a === void 0 ? void 0 : _a.length) === 1 && ((_b = f.relationFromFields) === null || _b === void 0 ? void 0 : _b.length) === 1; })
176
189
  .reduce((acc, f) => {
177
- if (f.relationFromFields && f.relationFromFields[0]) {
178
- acc[f.relationFromFields[0]] = f;
179
- }
190
+ // NOTE: It's safe to assume that `relationFromFields` and `relationToFields` are defined because of the filter above.
191
+ acc[f.relationFromFields[0]] = f;
180
192
  return acc;
181
193
  }, {});
182
194
  const fields = dmmfModel.fields
@@ -246,7 +258,9 @@ function parseModel({ dmmfModel, enums, models, config, }) {
246
258
  nameField,
247
259
  fields,
248
260
  createdAtField,
249
- updatedAtField, relatedModels: Object.values(relatedModels) });
261
+ updatedAtField,
262
+ // NOTE: This is only a stub because we link references after all models were parsed above.
263
+ references: [] });
250
264
  }
251
265
  /**
252
266
  * Checks that there is exactly one id field and that there is at most one default field.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.56.3",
3
+ "version": "0.56.5",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {