Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): add option to create relations in cli discover command #8461

Merged
merged 1 commit into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/site/Discovering-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Models can be discovered from a supported datasource by running the

`--views`: Choose whether to discover views. Default is true

`--relations`: Choose whether to create relations. Default is false

`--all`: Skips the model prompt and discovers all of them

`--outDir`: Specify the directory into which the `model.model.ts` files will be
Expand Down
7 changes: 7 additions & 0 deletions packages/cli/.yo-rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,13 @@
"name": "views",
"hide": false
},
"relations": {
"type": "Boolean",
"description": "Discover and create relations",
"default": false,
"name": "relations",
"hide": false
},
"schema": {
"type": "String",
"description": "Schema to discover",
Expand Down
47 changes: 47 additions & 0 deletions packages/cli/generators/discover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
default: true,
});

this.option('relations', {
type: Boolean,
description: g.f('Discover and create relations'),
default: false,
});

this.option('schema', {
type: String,
description: g.f('Schema to discover'),
Expand Down Expand Up @@ -289,6 +295,7 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
{
schema: modelInfo.owner,
disableCamelCase: this.artifactInfo.disableCamelCase,
associations: this.options.relations,
},
);
if (this.options.optionalId) {
Expand Down Expand Up @@ -336,6 +343,46 @@ module.exports = class DiscoveryGenerator extends ArtifactGenerator {
);
debug(`Writing: ${fullPath}`);

if (this.options.relations) {
const relationImports = [];
const relationDestinationImports = [];
const foreignKeys = {};
for (const relationName in templateData.settings.relations) {
const relation = templateData.settings.relations[relationName];
const targetModel = this.artifactInfo.modelDefinitions.find(
model => model.name === relation.model,
);
// If targetModel is not in discovered models, skip creating relation
if (targetModel) {
Object.assign(templateData.properties[relation.foreignKey], {
relation,
});
relationImports.push(relation.type);
relationDestinationImports.push(relation.model);

foreignKeys[relationName] = {};
Object.assign(foreignKeys[relationName], {
name: relationName,
entity: relation.model,
entityKey: Object.entries(targetModel.properties).find(
x => x?.[1].id === 1,
)?.[0],
foreignKey: relation.foreignKey,
Comment on lines +368 to +370
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note for myself: We'll need to figure out how to handle composite foreign keys in the future.

});
}
}
templateData.relationImports = relationImports;
templateData.relationDestinationImports = relationDestinationImports;
// Delete relation from modelSettings
delete templateData.settings.relations;
Comment on lines +376 to +377
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some connectors support "strong relations" (i.e. Constraints enforced by the database engine) through @model({settings: {foreignKeys: {/* ... */}}). Can we populate that field as well?

See https://github.com/loopbackio/loopback-connector-mysql/tree/f8f40a1199b6ed63ba01d6d173a9314004c08c93#auto-migrateauto-update-models-with-foreign-keys for an example of the syntax.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@achrinza Thank you for the review. and sure we can do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@achrinza, we have updated the code to populate foreignKeys in model settings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @achrinza,
The Soap-calculator example uses a soap service link https://calculator-webservice.mybluemix.net/ for sending HTTP requests. This link is now returning 404 on all requests and because of that related tests are failing. We are unable to get our PRs merged because of these failed tests.
This is the link for datasource of soap-service.
https://github.com/loopbackio/loopback-next/blob/master/examples/soap-calculator/src/datasources/calculator.datasource.ts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sohaibahsan007, we're aware of the issue and looking into it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

if (Object.keys(foreignKeys)?.length > 0) {
Object.assign(templateData.settings, {foreignKeys});
}
templateData.modelSettings = utils.stringifyModelSettings(
templateData.settings,
);
}

this.copyTemplatedFiles(
modelDiscoverer.MODEL_TEMPLATE_PATH,
fullPath,
Expand Down
15 changes: 11 additions & 4 deletions packages/cli/generators/model/templates/model.ts.ejs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<% if (isModelBaseBuiltin) { -%>
import {<%= modelBaseClass %>, model, property} from '@loopback/repository';
import {<%= modelBaseClass %>, model, property<%if (locals.relationImports) {%><% relationImports.forEach((relation) => {-%>, <%= relation %> <%_})-%><%}%>} from '@loopback/repository';
<% } else { -%>
import {model, property} from '@loopback/repository';
import {model, property<%if (locals.relationImports) {%><% relationImports.forEach((relation) => {-%> , <%= relation %> <%_})-%><%}%>} from '@loopback/repository';
import {<%= modelBaseClass %>} from '.';
<% } -%>
<%_ if (locals.relationDestinationImports && locals.relationDestinationImports.length > 0) { -%>
import {<% relationDestinationImports.forEach((model, index) => {-%><%= model %><%if (index!==relationDestinationImports.length-1) {%>,<% } %> <%_}) -%>} from '.';
<%_ } -%>

<% if (modelSettings) { -%>
@model(<%- modelSettings %>)
Expand All @@ -12,13 +15,17 @@ import {<%= modelBaseClass %>} from '.';
<% } -%>
export class <%= className %> extends <%= modelBaseClass %> {
<% Object.entries(properties).forEach(([key, val]) => { -%>
<% if (val.relation) { -%>
@<%= val.relation.type %>(() => <%= val.relation.model %>)
<% } else { -%>
@property({
<%_ Object.entries(val).forEach(([propKey, propVal]) => { -%>
<%_ if (!['tsType'].includes(propKey)) { -%>
<%_ if (!['tsType', 'relation'].includes(propKey)) { -%>
<%= propKey %>: <%- propVal %>,
<%_ } -%>
<%_ } -%>
<%_ }) -%>
})
<% } -%>
<%= key %><%if (!val.required) {%>?<% } %>: <%= val.tsType %>;

<% }) -%>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,13 @@ exports[`cli saves command metadata to .yo-rc.json 1`] = `
"name": "views",
"hide": false
},
"relations": {
"type": "Boolean",
"description": "Discover and create relations",
"default": false,
"name": "relations",
"hide": false
},
"schema": {
"type": "String",
"description": "Schema to discover",
Expand Down