Skip to content

Commit 8e6937a

Browse files
committed
feat(cli): generate relations while discovering models
Signed-off-by: Muhammad Aaqil <[email protected]>
1 parent 3cb4841 commit 8e6937a

File tree

9 files changed

+140
-88
lines changed

9 files changed

+140
-88
lines changed

packages/cli/generators/discover/index.js

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
331331
{
332332
schema: modelInfo.owner,
333333
disableCamelCase: this.artifactInfo.disableCamelCase,
334-
associations: this.options.relations,
334+
// associations: this.options.relations,
335335
...discoveryOptions,
336336
},
337337
);
@@ -463,6 +463,7 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
463463
// end message to output something nice, before it was "Discover undefined was created in src/models/"
464464
this.artifactInfo.type = 'Models';
465465
this.artifactInfo.relationConfigs = relations;
466+
repositoryConfigs['relations'] = JSON.stringify(relations);
466467
this.artifactInfo.repositoryConfigs = repositoryConfigs;
467468
this.artifactInfo.name = this.artifactInfo.modelDefinitions
468469
.map(d => d.name)
@@ -471,5 +472,47 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
471472

472473
async end() {
473474
await super.end();
475+
await this._generateRepositories();
476+
}
477+
478+
async _generateRepositories() {
479+
if (
480+
!this.artifactInfo.repositoryConfigs ||
481+
!this.artifactInfo.repositoryConfigs.repositories ||
482+
this.artifactInfo.repositoryConfigs.repositories.size === 0
483+
) {
484+
debug(
485+
'No repository configurations found, skipping repository generation',
486+
);
487+
return;
488+
}
489+
const {repositories, datasource, repositoryBaseClass, relations} =
490+
this.artifactInfo.repositoryConfigs;
491+
// Convert Set to Array and iterate
492+
const modelList = Array.from(repositories);
493+
for (let index = 0; index < modelList.length; index++) {
494+
const model = modelList[index];
495+
const repoGenOptions = {
496+
name: model,
497+
model,
498+
datasource,
499+
repositoryBaseClass,
500+
yes: true,
501+
skipInstall: true,
502+
skipCache: true,
503+
};
504+
if (index === modelList.length - 1) {
505+
repoGenOptions.relations = relations;
506+
}
507+
// Use composeWith to invoke the repository generator
508+
const repoGen = require('../repository');
509+
this.composeWith(
510+
{
511+
Generator: repoGen,
512+
path: require.resolve('../repository'),
513+
},
514+
repoGenOptions,
515+
);
516+
}
474517
}
475518
};

packages/cli/generators/repository/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,5 +571,37 @@ module.exports = class RepositoryGenerator extends ArtifactGenerator {
571571
);
572572
this.artifactInfo.name = `${this.artifactInfo.className}Repository`;
573573
await super.end();
574+
await this._generateRelations();
575+
}
576+
577+
async _generateRelations() {
578+
if (!this.artifactInfo.relations) {
579+
debug('No relation configurations found, skipping relation generation');
580+
return;
581+
}
582+
this.artifactInfo.relations = JSON.parse(this.artifactInfo.relations);
583+
if (!this.artifactInfo.relations.length) {
584+
debug('No relation configurations found, skipping relation generation');
585+
return;
586+
}
587+
this.artifactInfo.relations.forEach(relation => {
588+
const repoGen = require('../relation');
589+
this.composeWith(
590+
{
591+
Generator: repoGen,
592+
path: require.resolve('../relation'),
593+
},
594+
{
595+
sourceModel: relation.sourceModel,
596+
destinationModel: relation.destinationModel,
597+
foreignKeyName: relation.foreignKeyName,
598+
relationType: relation.relationType,
599+
registerInclusionResolver: relation.registerInclusionResolver,
600+
yes: true,
601+
skipInstall: true,
602+
skipCache: true,
603+
},
604+
);
605+
});
574606
}
575607
};

packages/cli/lib/artifact-generator.js

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -128,53 +128,6 @@ module.exports = class ArtifactGenerator extends BaseGenerator {
128128
.split(this.classNameSeparator)
129129
.map(utils.toClassName);
130130
const classesOutput = classes.join(this.classNameSeparator);
131-
if (
132-
this.artifactInfo.repositoryConfigs &&
133-
this.artifactInfo.repositoryConfigs.repositories.size
134-
) {
135-
const {repositories, datasource, repositoryBaseClass} =
136-
this.artifactInfo.repositoryConfigs;
137-
for (const model of repositories) {
138-
const config = {repositoryBaseClass, datasource, model, name: model};
139-
try {
140-
const {execSync} = require('child_process');
141-
const cmd =
142-
"lb4 repository --config='" + JSON.stringify(config) + "' --yes";
143-
execSync(cmd, {
144-
cwd: process.cwd(),
145-
stdio: ['ignore', 'pipe', 'pipe'],
146-
encoding: 'utf8',
147-
});
148-
} catch (error) {
149-
console.log(error);
150-
}
151-
}
152-
} else {
153-
debug(
154-
'No repository configurations found, skipping repository generation',
155-
);
156-
}
157-
if (
158-
this.artifactInfo.relationConfigs &&
159-
this.artifactInfo.relationConfigs.length
160-
) {
161-
for (const configs of this.artifactInfo.relationConfigs) {
162-
try {
163-
const {execSync} = require('child_process');
164-
const cmd =
165-
"lb4 relation --config='" + JSON.stringify(configs) + "' --yes";
166-
execSync(cmd, {
167-
cwd: process.cwd(),
168-
stdio: ['ignore', 'pipe', 'pipe'],
169-
encoding: 'utf8',
170-
});
171-
} catch (error) {
172-
console.log(error);
173-
}
174-
}
175-
} else {
176-
debug('No relation configurations found, skipping relation generation');
177-
}
178131
// User Output
179132
this.log();
180133
this.log(

packages/cli/lib/base-generator.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,6 @@ module.exports = class BaseGenerator extends Generator {
461461
);
462462
}
463463
}
464-
process.exit(0);
465464
}
466465

467466
/**

packages/cli/snapshots/integration/generators/discover.integration.snapshots.js

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,7 @@ export type ViewWithRelations = View & ViewRelations;
6060
exports[`lb4 discover integration model discovery discovers models with --relations 1`] = `
6161
import {Entity, model, property, belongsTo} from '@loopback/repository';
6262
63-
@model({
64-
settings: {
65-
foreignKeys: {
66-
doctorRel: {name: 'doctorRel', entity: 'Doctor', entityKey: 'id', foreignKey: 'reportsTo'}
67-
}
68-
}
69-
})
63+
@model()
7064
export class Doctor extends Entity {
7165
@property({
7266
type: 'number',
@@ -82,8 +76,7 @@ export class Doctor extends Entity {
8276
name?: string;
8377
8478
@belongsTo(() => Doctor)
85-
reportsTo?: number;
86-
79+
reportsTo: number;
8780
// Define well-known properties here
8881
8982
// Indexer property to allow additional data
@@ -163,21 +156,10 @@ export type TestWithRelations = Test & TestRelations;
163156

164157
exports[`lb4 discover integration model discovery generate relations with --relations 1`] = `
165158
import {Entity, model, property, belongsTo} from '@loopback/repository';
166-
import {Doctor,Patient} from '.';
167-
168-
@model({
169-
settings: {
170-
foreignKeys: {
171-
doctorIdRel: {name: 'doctorIdRel', entity: 'Doctor', entityKey: 'id', foreignKey: 'doctorId'},
172-
patientIdRel: {
173-
name: 'patientIdRel',
174-
entity: 'Patient',
175-
entityKey: 'pid',
176-
foreignKey: 'patientId'
177-
}
178-
}
179-
}
180-
})
159+
import {Doctor} from './doctor.model';
160+
import {Patient} from './patient.model';
161+
162+
@model()
181163
export class Appointment extends Entity {
182164
@property({
183165
type: 'number',
@@ -188,13 +170,11 @@ export class Appointment extends Entity {
188170
mysql: {columnName: 'id', dataType: 'int', dataLength: null, dataPrecision: 10, dataScale: 0, nullable: 'N', generated: 1},
189171
})
190172
id?: number;
191-
192-
@belongsTo(() => Patient)
193-
patientId?: number;
194-
195173
@belongsTo(() => Doctor)
196-
doctorId?: number;
174+
doctorId: number;
197175
176+
@belongsTo(() => Patient)
177+
patientId: number;
198178
// Define well-known properties here
199179
200180
// Indexer property to allow additional data

packages/cli/test/fixtures/discover/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,14 @@ exports.SANDBOX_FILES = [
66
file: 'mem.datasource.js',
77
content: fs.readFileSync(require.resolve('./mem.datasource.js.txt')),
88
},
9+
{
10+
path: 'src/datasources',
11+
file: 'mem.datasource.ts',
12+
content: fs.readFileSync(require.resolve('./mem.datasource.ts.txt')),
13+
},
14+
{
15+
path: 'src/datasources',
16+
file: 'index.ts',
17+
content: `export * from './mem.datasource';\n`,
18+
},
919
];

packages/cli/test/fixtures/discover/mem.datasource.js.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,6 @@ const fullDefinitions = [
171171
modelSettings: {
172172
settings: {
173173
idInjection: false,
174-
relations: {
175-
doctorRel: {model: 'Doctor', type: 'belongsTo', foreignKey: 'reportsTo'},
176-
}
177174
}
178175
}
179176
},
@@ -239,10 +236,6 @@ const fullDefinitions = [
239236
modelSettings: {
240237
settings: {
241238
idInjection: false,
242-
relations: {
243-
doctorIdRel: {model: 'Doctor', type: 'belongsTo', foreignKey: 'doctorId'},
244-
patientIdRel: {model: 'Patient', type: 'belongsTo', foreignKey: 'patientId'}
245-
}
246239
}
247240
}
248241
},
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
2+
import {juggler} from '@loopback/repository';
3+
4+
const config = {
5+
name: 'mem',
6+
connector: 'memory',
7+
};
8+
9+
@lifeCycleObserver('datasource')
10+
export class MemDataSource extends juggler.DataSource
11+
implements LifeCycleObserver {
12+
static dataSourceName = 'mem';
13+
static readonly defaultConfig = config;
14+
15+
constructor(
16+
dsConfig: object = config,
17+
) {
18+
super(dsConfig);
19+
}
20+
}
21+
22+
export default MemDataSource;

packages/cli/test/integration/generators/discover.integration.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ const appointmentModel = path.join(
9797
'src/models/appointment.model.ts',
9898
);
9999
const doctorModel = path.join(sandbox.path, 'src/models/doctor.model.ts');
100+
const doctorRepository = path.join(
101+
sandbox.path,
102+
'src/repositories/doctor.repository.ts',
103+
);
104+
const appointmentRepository = path.join(
105+
sandbox.path,
106+
'src/repositories/appointment.repository.ts',
107+
);
108+
const patientRepository = path.join(
109+
sandbox.path,
110+
'src/repositories/patient.repository.ts',
111+
);
100112

101113
const defaultExpectedIndexFile = path.join(sandbox.path, 'src/models/index.ts');
102114
const movedExpectedTestModel = path.join(sandbox.path, 'src/test.model.ts');
@@ -111,8 +123,8 @@ describe('lb4 discover integration', () => {
111123
beforeEach('reset sandbox', async () => {
112124
await sandbox.reset();
113125
await sandbox.mkdir('dist/datasources');
126+
await sandbox.mkdir('src/datasources');
114127
});
115-
116128
it('generates all models without prompts using --all --dataSource', /** @this {Mocha.Context} */ async function () {
117129
this.timeout(10000);
118130
await testUtils
@@ -212,7 +224,8 @@ describe('lb4 discover integration', () => {
212224
assert.file(defaultExpectedTestModel);
213225
expectFileToMatchSnapshot(defaultExpectedTestModel);
214226
});
215-
it('generate relations with --relations', async () => {
227+
it('generate relations with --relations', /** @this {Mocha.Context} */ async function () {
228+
this.timeout(50000);
216229
await testUtils
217230
.executeGenerator(generator)
218231
.inDir(sandbox.path, () =>
@@ -221,10 +234,14 @@ describe('lb4 discover integration', () => {
221234
}),
222235
)
223236
.withOptions(relationsSetTrue);
237+
assert.file(appointmentRepository);
238+
assert.file(patientRepository);
239+
assert.file(doctorRepository);
224240
assert.file(appointmentModel);
225241
expectFileToMatchSnapshot(appointmentModel);
226242
});
227-
it('discovers models with --relations', async () => {
243+
it('discovers models with --relations', /** @this {Mocha.Context} */ async function () {
244+
this.timeout(50000);
228245
await testUtils
229246
.executeGenerator(generator)
230247
.inDir(sandbox.path, () =>
@@ -233,6 +250,9 @@ describe('lb4 discover integration', () => {
233250
}),
234251
)
235252
.withOptions(relationsSetTrue);
253+
assert.file(appointmentRepository);
254+
assert.file(patientRepository);
255+
assert.file(doctorRepository);
236256
assert.file(doctorModel);
237257
expectFileToMatchSnapshot(doctorModel);
238258
});

0 commit comments

Comments
 (0)