@neohm/nh-cli 1.1.5 → 1.2.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/README.md +146 -12
- package/package.json +1 -1
- package/src/commands/gen.flag.js +353 -0
- package/src/commands/gen.js +36 -78
- package/src/index.js +57 -2
- package/src/lib/collision.js +82 -0
- package/src/lib/format.js +54 -0
- package/src/lib/registry.js +120 -0
- package/src/lib/sync.engine.js +34 -7
- package/src/lib/templates.js +308 -42
package/src/lib/templates.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
|
+
toWords,
|
|
4
5
|
toDotCase,
|
|
5
6
|
toPascalCase,
|
|
6
7
|
toKebabCase,
|
|
@@ -16,6 +17,17 @@ const {
|
|
|
16
17
|
* across nestjs-boilerplate.
|
|
17
18
|
*/
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* A named import, wrapped the way prettier's 80-column printer would: one line
|
|
22
|
+
* while it fits, one member per line once it doesn't. Generated files are
|
|
23
|
+
* committed as-is, so they have to come out already formatted.
|
|
24
|
+
*/
|
|
25
|
+
function namedImport(members, from) {
|
|
26
|
+
const oneLine = `import { ${members.join(', ')} } from '${from}';`;
|
|
27
|
+
if (oneLine.length <= 80) return oneLine;
|
|
28
|
+
return `import {\n${members.map((m) => ` ${m},`).join('\n')}\n} from '${from}';`;
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
/** Build the canonical names for a given entity-ish base (e.g. "Shape"). */
|
|
20
32
|
function names(base) {
|
|
21
33
|
const dot = toDotCase(base);
|
|
@@ -32,6 +44,8 @@ function names(base) {
|
|
|
32
44
|
attributesDtoFile: `${dot}.attributes.dto.ts`,
|
|
33
45
|
controllerClass: `${pascal}Controller`,
|
|
34
46
|
controllerFile: `${dot}.controller.ts`,
|
|
47
|
+
serviceClass: `${pascal}Service`,
|
|
48
|
+
serviceFile: `${dot}.service.ts`,
|
|
35
49
|
dtoClass: `Add${pascal}DataDto`,
|
|
36
50
|
dtoFile: `add.${dot}.data.dto.ts`,
|
|
37
51
|
processorClass: `${pascal}DataProcessor`,
|
|
@@ -42,6 +56,17 @@ function names(base) {
|
|
|
42
56
|
subscriberFile: `${dot}.subscriber.ts`,
|
|
43
57
|
jobClass: `${pascal}Job`,
|
|
44
58
|
jobFile: `${dot}.job.ts`,
|
|
59
|
+
// External (API-key) surface. Mirrors the internal names with an
|
|
60
|
+
// `external.` filename prefix and an `External` class prefix, matching
|
|
61
|
+
// external/controllers/external.test.controller.ts in the boilerplate.
|
|
62
|
+
externalControllerClass: `External${pascal}Controller`,
|
|
63
|
+
externalControllerFile: `external.${dot}.controller.ts`,
|
|
64
|
+
externalServiceClass: `External${pascal}Service`,
|
|
65
|
+
externalServiceFile: `external.${dot}.service.ts`,
|
|
66
|
+
externalProcessorClass: `External${pascal}DataProcessor`,
|
|
67
|
+
externalProcessorFile: `external.${dot}.data.processor.ts`,
|
|
68
|
+
externalListProcessorClass: `External${pascal}ListProcessor`,
|
|
69
|
+
externalListProcessorFile: `external.${dot}.list.processor.ts`,
|
|
45
70
|
// Fed through naming.migrationFileName/migrationClassName so the migration
|
|
46
71
|
// `nh gen` writes is named exactly like one from `nh migration`.
|
|
47
72
|
migrationName: `Add${pascal}Table`,
|
|
@@ -50,14 +75,26 @@ function names(base) {
|
|
|
50
75
|
|
|
51
76
|
function entity(base, tableName) {
|
|
52
77
|
const n = names(base);
|
|
53
|
-
return `import { Column, Entity } from 'typeorm';
|
|
54
|
-
import { CommonEntity } from '@neohm/nestend';
|
|
78
|
+
return `import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
|
|
79
|
+
import { CommonEntity, TenantEntity } from '@neohm/nestend';
|
|
55
80
|
import { ${n.attributesDtoClass} } from '../dtos/${n.dot}.attributes.dto';
|
|
56
81
|
|
|
57
82
|
@Entity({ name: '${tableName}' })
|
|
58
83
|
export class ${n.entityClass} extends CommonEntity {
|
|
84
|
+
// Tenant scope — the service and the list processor both filter on it.
|
|
85
|
+
@Column()
|
|
86
|
+
tenant_id: string;
|
|
87
|
+
|
|
88
|
+
// TODO: declare the columns ${n.pascal} owns.
|
|
89
|
+
|
|
59
90
|
@Column({ type: 'jsonb' })
|
|
60
91
|
attributes: ${n.attributesDtoClass};
|
|
92
|
+
|
|
93
|
+
// Relations and methods
|
|
94
|
+
|
|
95
|
+
@ManyToOne(() => TenantEntity)
|
|
96
|
+
@JoinColumn({ name: 'tenant_id' })
|
|
97
|
+
tenant: TenantEntity;
|
|
61
98
|
}
|
|
62
99
|
`;
|
|
63
100
|
}
|
|
@@ -70,46 +107,259 @@ function attributesDto(base) {
|
|
|
70
107
|
`;
|
|
71
108
|
}
|
|
72
109
|
|
|
73
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Controllers hold no business logic. They authenticate the caller, then
|
|
112
|
+
* delegate to the module's service — so the HTTP surface stays readable and
|
|
113
|
+
* the same operation is reusable from a job, a subscriber or another service.
|
|
114
|
+
*/
|
|
115
|
+
function controller(base, { processor = false, listProcessor = false } = {}) {
|
|
74
116
|
const n = names(base);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
const svcProp = `${n.camel}Service`;
|
|
118
|
+
const hasPost = processor || listProcessor;
|
|
119
|
+
|
|
120
|
+
// @nestjs/common members, alphabetised the way prettier leaves them.
|
|
121
|
+
const nestCommon = ['Controller', 'Get', 'Param'];
|
|
122
|
+
if (hasPost) nestCommon.push('Body', 'Post');
|
|
123
|
+
nestCommon.sort();
|
|
124
|
+
|
|
125
|
+
const nestendImports = ['AuthService'];
|
|
126
|
+
if (listProcessor) nestendImports.push('CommonListFilterDto');
|
|
127
|
+
nestendImports.push('CommonParamsDto');
|
|
128
|
+
|
|
129
|
+
const imports = [
|
|
130
|
+
namedImport(nestCommon, '@nestjs/common'),
|
|
131
|
+
// @ApiBearerAuth() attaches the requirement to these operations. The
|
|
132
|
+
// DocumentBuilder call only registers the scheme (under its default name,
|
|
133
|
+
// 'bearer') and draws the Authorize button — without the decorator
|
|
134
|
+
// swagger-ui shows no padlock and never sends the Authorization header.
|
|
135
|
+
`import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';`,
|
|
136
|
+
namedImport(nestendImports, '@neohm/nestend'),
|
|
137
|
+
`import { ${n.serviceClass} } from '../services/${n.dot}.service';`,
|
|
138
|
+
];
|
|
139
|
+
if (processor) {
|
|
140
|
+
imports.push(
|
|
141
|
+
`import { ${n.dtoClass} } from '../dtos/add.${n.dot}.data.dto';`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
78
144
|
|
|
79
|
-
|
|
80
|
-
@
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
145
|
+
const methods = [
|
|
146
|
+
` @Get(':id')
|
|
147
|
+
async get${n.pascal}(@Param() params: CommonParamsDto) {
|
|
148
|
+
const { user } = await this.authService.validateAccess(
|
|
149
|
+
'add-scope',
|
|
150
|
+
'add-role',
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
return this.${svcProp}.get(user, params.id);
|
|
154
|
+
}`,
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
if (processor) {
|
|
158
|
+
methods.push(` @Post()
|
|
159
|
+
async upsert${n.pascal}(@Body() body: ${n.dtoClass}) {
|
|
160
|
+
await this.authService.validateAccess('add-scope', 'add-role');
|
|
161
|
+
|
|
162
|
+
return this.${svcProp}.upsert(body);
|
|
163
|
+
}`);
|
|
85
164
|
}
|
|
86
|
-
return `import { Body, Controller, Post } from '@nestjs/common';
|
|
87
|
-
import { ApiTags } from '@nestjs/swagger';
|
|
88
|
-
import {
|
|
89
|
-
AuthService,
|
|
90
|
-
CommonListFilterDto,
|
|
91
|
-
ListFilterService,
|
|
92
|
-
} from '@neohm/nestend';
|
|
93
|
-
import { ${n.listProcessorClass} } from '../libraries/${n.dot}.list.processor';
|
|
94
165
|
|
|
166
|
+
if (listProcessor) {
|
|
167
|
+
methods.push(` @Post('list')
|
|
168
|
+
async list(@Body() body: CommonListFilterDto) {
|
|
169
|
+
const { user } = await this.authService.validateAccess(
|
|
170
|
+
'add-scope',
|
|
171
|
+
'add-role',
|
|
172
|
+
);
|
|
173
|
+
return this.${svcProp}.list(user, body);
|
|
174
|
+
}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return `${imports.join('\n')}
|
|
178
|
+
|
|
179
|
+
// TODO: replace 'add-scope' / 'add-role' with this module's scope and role.
|
|
95
180
|
@ApiTags('${n.kebab}')
|
|
181
|
+
@ApiBearerAuth()
|
|
96
182
|
@Controller('api/v1/${n.kebab}')
|
|
97
183
|
export class ${n.controllerClass} {
|
|
98
184
|
constructor(
|
|
99
|
-
private readonly
|
|
185
|
+
private readonly ${svcProp}: ${n.serviceClass},
|
|
100
186
|
private readonly authService: AuthService,
|
|
101
187
|
) {}
|
|
102
188
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
189
|
+
${methods.join('\n\n')}
|
|
190
|
+
}
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The module's service layer, always generated: single-record reads live here,
|
|
196
|
+
* and write / list work is handed to the processors. Injected into the
|
|
197
|
+
* controller, so nothing downstream has to know how a record is fetched.
|
|
198
|
+
*
|
|
199
|
+
* `get()` is unconditional — it is the one operation that needs no processor.
|
|
200
|
+
* `upsert()` appears with a data processor, `list()` with a listing processor.
|
|
201
|
+
*/
|
|
202
|
+
function service(base, { processor = false, listProcessor = false } = {}) {
|
|
203
|
+
const n = names(base);
|
|
204
|
+
const label = toWords(base).join(' ');
|
|
205
|
+
|
|
206
|
+
const nestendImports = [];
|
|
207
|
+
if (listProcessor) {
|
|
208
|
+
nestendImports.push('CommonListFilterDto', 'ListFilterService');
|
|
209
|
+
}
|
|
210
|
+
nestendImports.push('NotFoundException', 'UserEntity');
|
|
211
|
+
|
|
212
|
+
const imports = [
|
|
213
|
+
namedImport(nestendImports, '@neohm/nestend'),
|
|
214
|
+
`import { Injectable } from '@nestjs/common';`,
|
|
215
|
+
];
|
|
216
|
+
if (listProcessor) {
|
|
217
|
+
imports.push(
|
|
218
|
+
`import { ${n.listProcessorClass} } from '../libraries/${n.dot}.list.processor';`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (processor) {
|
|
222
|
+
imports.push(
|
|
223
|
+
`import { ${n.dtoClass} } from '../dtos/add.${n.dot}.data.dto';`,
|
|
224
|
+
`import { ${n.processorClass} } from '../libraries/${n.dot}.data.processor';`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
imports.push(
|
|
228
|
+
`import { ${n.entityClass} } from '../entities/${n.dot}.entity';`,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
const members = [];
|
|
232
|
+
if (listProcessor) {
|
|
233
|
+
members.push(
|
|
234
|
+
` constructor(protected readonly listFilterService: ListFilterService) {}`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// The tenant scope is part of the lookup, not a check after it: a row
|
|
239
|
+
// belonging to another tenant must read as "not found", never as "forbidden".
|
|
240
|
+
members.push(` async get(user: UserEntity, id: string) {
|
|
241
|
+
const ${n.camel} = await ${n.entityClass}.findOne({
|
|
242
|
+
where: { id, tenant_id: user.organization_id },
|
|
243
|
+
});
|
|
244
|
+
if (!${n.camel}) throw new NotFoundException('Invalid ${label} id');
|
|
245
|
+
|
|
246
|
+
return ${n.camel};
|
|
247
|
+
}`);
|
|
248
|
+
|
|
249
|
+
if (processor) {
|
|
250
|
+
// Insert or update: CommonDataDto carries an optional `id`, and the data
|
|
251
|
+
// processor decides which of the two the payload asks for.
|
|
252
|
+
members.push(` async upsert(data: ${n.dtoClass}) {
|
|
253
|
+
return new ${n.processorClass}().process(data);
|
|
254
|
+
}`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (listProcessor) {
|
|
258
|
+
// Emit the call already wrapped the way prettier's 80-column printer
|
|
259
|
+
// would, so a long entity name doesn't leave the generated file dirty.
|
|
260
|
+
// Prettier's three tiers: keep the fluent one-liner; else break the
|
|
261
|
+
// .process() argument; else break the constructor arguments too.
|
|
262
|
+
const call = `new ${n.listProcessorClass}(this.listFilterService, user)`;
|
|
263
|
+
const oneLine = ` return ${call}.process(data);`;
|
|
264
|
+
const brokenArg = ` return ${call}.process(`;
|
|
265
|
+
let body;
|
|
266
|
+
if (oneLine.length <= 80) {
|
|
267
|
+
body = oneLine;
|
|
268
|
+
} else if (brokenArg.length <= 80) {
|
|
269
|
+
body = `${brokenArg}\n data,\n );`;
|
|
270
|
+
} else {
|
|
271
|
+
body = ` return new ${n.listProcessorClass}(\n this.listFilterService,\n user,\n ).process(data);`;
|
|
272
|
+
}
|
|
273
|
+
members.push(` async list(user: UserEntity, data: CommonListFilterDto) {
|
|
274
|
+
${body}
|
|
275
|
+
}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return `${imports.join('\n')}
|
|
279
|
+
|
|
280
|
+
@Injectable()
|
|
281
|
+
export class ${n.serviceClass} {
|
|
282
|
+
${members.join('\n\n')}
|
|
283
|
+
}
|
|
284
|
+
`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Bare controller for `nh gen -c`: swagger tag, the caller-supplied route
|
|
289
|
+
* under api/v1, AuthService on hand, and one empty `check()` to build on.
|
|
290
|
+
*/
|
|
291
|
+
function bareController(base, routePath) {
|
|
292
|
+
const n = names(base);
|
|
293
|
+
return `import { Controller, Get } from '@nestjs/common';
|
|
294
|
+
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
|
295
|
+
import { AuthService } from '@neohm/nestend';
|
|
296
|
+
|
|
297
|
+
@ApiTags('${routePath}')
|
|
298
|
+
@ApiBearerAuth()
|
|
299
|
+
@Controller('api/v1/${routePath}')
|
|
300
|
+
export class ${n.controllerClass} {
|
|
301
|
+
constructor(private readonly authService: AuthService) {}
|
|
302
|
+
|
|
303
|
+
@Get('check')
|
|
304
|
+
async check() {}
|
|
305
|
+
}
|
|
306
|
+
`;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Bare external controller for `nh gen -x -c`. The API-key surface differs
|
|
311
|
+
* from the internal one in three ways, all of them load-bearing: the route is
|
|
312
|
+
* api/e/v1, the key is declared to swagger with @ApiSecurity('api-key'), and
|
|
313
|
+
* access is checked through ApiKeyService rather than AuthService.
|
|
314
|
+
*/
|
|
315
|
+
function bareExternalController(base, routePath) {
|
|
316
|
+
const n = names(base);
|
|
317
|
+
return `import { Controller, Get } from '@nestjs/common';
|
|
318
|
+
import { ApiSecurity, ApiTags } from '@nestjs/swagger';
|
|
319
|
+
import { ApiKeyService } from '@neohm/nestend';
|
|
320
|
+
|
|
321
|
+
@ApiTags('external-${routePath} (Api key)')
|
|
322
|
+
@ApiSecurity('api-key')
|
|
323
|
+
@Controller('api/e/v1/${routePath}')
|
|
324
|
+
export class ${n.externalControllerClass} {
|
|
325
|
+
constructor(private readonly apiKeyService: ApiKeyService) {}
|
|
326
|
+
|
|
327
|
+
@Get('check')
|
|
328
|
+
async check() {}
|
|
329
|
+
}
|
|
330
|
+
`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Bare injectable service for `nh gen -s` / `nh gen -x -s`. */
|
|
334
|
+
function bareService(base, { external = false } = {}) {
|
|
335
|
+
const n = names(base);
|
|
336
|
+
const cls = external ? n.externalServiceClass : n.serviceClass;
|
|
337
|
+
return `import { Injectable } from '@nestjs/common';
|
|
338
|
+
|
|
339
|
+
@Injectable()
|
|
340
|
+
export class ${cls} {}
|
|
341
|
+
`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Standalone job for `nh gen -j`. Unlike the entity job the wizard scaffolds,
|
|
346
|
+
* this one is not driven by a subscriber, so it takes no DatabaseEventDto and
|
|
347
|
+
* references no entity — whatever `dispatch()` was handed arrives as `data`.
|
|
348
|
+
*/
|
|
349
|
+
function additionalJob(base) {
|
|
350
|
+
const n = names(base);
|
|
351
|
+
return `import { CommonJob, QueueService } from '@neohm/nestend';
|
|
352
|
+
import { Injectable } from '@nestjs/common';
|
|
353
|
+
import { JobConstants } from '../../constants/job.constants';
|
|
354
|
+
|
|
355
|
+
@Injectable()
|
|
356
|
+
export class ${n.jobClass} extends CommonJob {
|
|
357
|
+
constructor(protected readonly queueService: QueueService) {
|
|
358
|
+
super(JobConstants.${n.camel}Job);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async handle(data: unknown): Promise<void> {
|
|
362
|
+
return;
|
|
113
363
|
}
|
|
114
364
|
}
|
|
115
365
|
`;
|
|
@@ -125,12 +375,16 @@ export class ${n.dtoClass} extends CommonDataDto {
|
|
|
125
375
|
`;
|
|
126
376
|
}
|
|
127
377
|
|
|
128
|
-
function processor(base) {
|
|
378
|
+
function processor(base, { external = false } = {}) {
|
|
129
379
|
const n = names(base);
|
|
380
|
+
// An external processor sits one level deeper (external/libraries/), so its
|
|
381
|
+
// reach back into the module's dtos/ gains a segment.
|
|
382
|
+
const up = external ? '../..' : '..';
|
|
383
|
+
const cls = external ? n.externalProcessorClass : n.processorClass;
|
|
130
384
|
return `import { CommonDataProcessor } from '@neohm/nestend';
|
|
131
|
-
import { ${n.dtoClass} } from '
|
|
385
|
+
import { ${n.dtoClass} } from '${up}/dtos/add.${n.dot}.data.dto';
|
|
132
386
|
|
|
133
|
-
export class ${
|
|
387
|
+
export class ${cls} extends CommonDataProcessor {
|
|
134
388
|
protected payload: ${n.dtoClass};
|
|
135
389
|
|
|
136
390
|
async process(data: ${n.dtoClass}) {
|
|
@@ -153,8 +407,9 @@ export class ${n.processorClass} extends CommonDataProcessor {
|
|
|
153
407
|
`;
|
|
154
408
|
}
|
|
155
409
|
|
|
156
|
-
function listProcessor(base, tableName) {
|
|
410
|
+
function listProcessor(base, tableName, { external = false } = {}) {
|
|
157
411
|
const n = names(base);
|
|
412
|
+
const cls = external ? n.externalListProcessorClass : n.listProcessorClass;
|
|
158
413
|
return `import {
|
|
159
414
|
CommonListFilterConfig,
|
|
160
415
|
CommonListFilterDto,
|
|
@@ -183,7 +438,7 @@ function listProcessor(base, tableName) {
|
|
|
183
438
|
* \`columns\`. Standing literal clauses go in \`predicates\`; anything
|
|
184
439
|
* carrying a value goes in the method, where add() binds it.
|
|
185
440
|
*/
|
|
186
|
-
export class ${
|
|
441
|
+
export class ${cls} extends CommonListProcessor {
|
|
187
442
|
protected config: CommonListFilterConfig = {
|
|
188
443
|
query: '${tableName} a',
|
|
189
444
|
columns: [
|
|
@@ -219,11 +474,8 @@ export class ${n.listProcessorClass} extends CommonListProcessor {
|
|
|
219
474
|
}
|
|
220
475
|
|
|
221
476
|
protected applyCustomPredicates() {
|
|
222
|
-
|
|
223
|
-
this.predicates.add(
|
|
224
|
-
'a.organization_id = :organization_id',
|
|
225
|
-
this.user.organization_id,
|
|
226
|
-
);
|
|
477
|
+
// Filter for the caller's tenant/organization
|
|
478
|
+
this.predicates.add('a.tenant_id = :tenant_id', this.user.organization_id);
|
|
227
479
|
}
|
|
228
480
|
}
|
|
229
481
|
`;
|
|
@@ -292,10 +544,19 @@ export class ${className} extends MigrationUtility {
|
|
|
292
544
|
|
|
293
545
|
process() {
|
|
294
546
|
this.rootPrimary();
|
|
547
|
+
|
|
548
|
+
this.foreign({ name: 'tenant_id', foreignTable: 'sys_tenants' });
|
|
295
549
|
this.foreign({ name: 'created_by', foreignTable: 'sys_users' });
|
|
296
|
-
|
|
550
|
+
this.foreign({ name: 'updated_by', foreignTable: 'sys_users' });
|
|
551
|
+
|
|
552
|
+
// TODO: add columns matching ${n.entityClass}.
|
|
553
|
+
|
|
297
554
|
this.json('attributes');
|
|
298
555
|
this.timestamps();
|
|
556
|
+
|
|
557
|
+
this.index('tenant_id');
|
|
558
|
+
this.index('created_by');
|
|
559
|
+
this.index('updated_by');
|
|
299
560
|
}
|
|
300
561
|
}
|
|
301
562
|
`;
|
|
@@ -435,6 +696,11 @@ module.exports = {
|
|
|
435
696
|
entity,
|
|
436
697
|
attributesDto,
|
|
437
698
|
controller,
|
|
699
|
+
service,
|
|
700
|
+
bareController,
|
|
701
|
+
bareExternalController,
|
|
702
|
+
bareService,
|
|
703
|
+
additionalJob,
|
|
438
704
|
dto,
|
|
439
705
|
processor,
|
|
440
706
|
listProcessor,
|