Skip to content
Draft
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
34 changes: 33 additions & 1 deletion docs/site/Relation-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ lb4 relation [options]
through model. For HasManyThrough relation only.
- `--targetKeyOnThrough`: Foreign key that references the target model on the
through model. For HasManyThrough relation only.
- `--customReferenceKeys`: Confrimation if there is any custom reference key to
source or target model. For HasManyThrough relation only.
- `--customSourceModelKey`: Custom key referencing in the source model. For
HasManyThrough relation only.
- `--customTargetModelKey`: Custom key referencing in the target model. For
HasManyThrough relation only.
- `-c`, `--config`: JSON file name or value to configure options.
- `-y`, `--yes`: Skip all confirmation prompts with default or provided value.
- `--format`: Format generated code using `npm run lint:fix`.
Expand Down Expand Up @@ -113,7 +119,11 @@ lb4 relation --sourceModel=<sourceModel>
[--sourceModelPrimaryKeyType=<sourceModelPrimaryKeyType>]
[--destinationModelPrimaryKey=<destinationModelPrimaryKey>]
[--destinationModelPrimaryKeyType=<destinationModelPrimaryKeyType>]
[--sourceKeyOnThrough=<sourceKeyOnThrough>] [--targetKeyOnThrough<targetKeyOnThrough>]
[--sourceKeyOnThrough=<sourceKeyOnThrough>]
[--targetKeyOnThrough<targetKeyOnThrough>]
[--customReferenceKeys=<customReferenceKeys>]
[--customSourceModelKey=<customSourceModelKey>]
[--customTargetModelKey<customTargetModelKey>]
[--format]
```

Expand All @@ -126,6 +136,15 @@ lb4 relation --sourceModel=<sourceModel>
- `<targetKeyOnThrough>` - Property on the through model that references the
primary key property of the target model.

- `<customReferenceKeys>` - Confirm if there is any custom reference key to
source or target model.

- `<customSourceModelKey>` - Property to that references the key in the source
model

- `<customTargetModelKey>` - Property to that references the key in the target
model

### Interactive Prompts

The tool will prompt you for:
Expand Down Expand Up @@ -165,6 +184,19 @@ The tool will prompt you for:
relation only. Default value: `<targetModel>` + `Id` in camelCase, e.g
`patientId`.

- Confirmation for any custom reference key(s) (`customReferenceKeys`). Prompts
to confirm if there is any custom reference keys to be defined referenceing
source or target model. For HasManyThrough relation only. The default value is
false

- Name of custom reference key in source model (`customSourceModelKey`). Prompts
a property name that references non-primary key in source model. Only prompts
if `customReferenceKeys` is true.For HasManyThrough relation only.

- Name of custom reference key in target model (`customTargetModelKey`). Prompts
a property name that references non-primary key in target model. Only prompts
if `customReferenceKeys` is true.For HasManyThrough relation only.

- Name of the relation (`relationName`). Prompts for the Source property name.
Note: Leave blank to use the default. Default values:
- plural form of `<targetModel>` for `hasMany` and `hasManyThrough` relations,
Expand Down
21 changes: 21 additions & 0 deletions packages/cli/.yo-rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,27 @@
"name": "registerInclusionResolver",
"hide": false
},
"customReferenceKeys": {
"type": "String",
"required": false,
"description": "Any Custom Reference Kyes",
"name": "customReferenceKeys",
"hide": false
},
"customSourceModelKey": {
"type": "String",
"required": false,
"description": "Custom Source model key",
"name": "customSourceModelKey",
"hide": false
},
"customTargetModelKey": {
"type": "String",
"required": false,
"description": "Custom Destination model",
"name": "customTargetModelKey",
"hide": false
},
"config": {
"type": "String",
"alias": "c",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module.exports = class HasManyThroughRelationGenerator extends (
options.destinationModel,
);
this.artifactInfo.targetRepositoryClassName =
this.artifactInfo.targetModelName + 'Repository';
this.artifactInfo.targetModelClassName + 'Repository';
this.artifactInfo.paramTargetRepository = utils.camelCase(
this.artifactInfo.targetModelName + 'Repository',
);
Expand Down Expand Up @@ -80,7 +80,22 @@ module.exports = class HasManyThroughRelationGenerator extends (
const dest = this.destinationPath(
path.join(this.artifactInfo.outDir, this.artifactInfo.outFile),
);

this.artifactInfo.idPath = 'id';
this.artifactInfo.customSourceModelKey = options.customSourceModelKey;
if (options.customSourceModelKey) {
this.artifactInfo.idPath = utils.camelCase(options.customSourceModelKey);
const customSourceModelKeyType = relationUtils.getModelPropertyType(
this.artifactInfo.modelDir,
options.sourceModel,
options.customSourceModelKey,
);
if (customSourceModelKeyType) {
this.artifactInfo.sourceModelPrimaryKeyType = customSourceModelKeyType;
}
}
this.artifactInfo.customTargetModelKey = options.customTargetModelKey;
this.artifactInfo.sourceKeyOnThrough = options.sourceKeyOnThrough;
this.artifactInfo.targetKeyOnThrough = options.targetKeyOnThrough;
this.copyTemplatedFiles(source, dest, this.artifactInfo);
await relationUtils.addExportController(
this,
Expand All @@ -104,8 +119,13 @@ module.exports = class HasManyThroughRelationGenerator extends (
const targetKey = options.targetKeyOnThrough;
const dftSourceKey = options.defaultSourceKeyOnThrough;
const dftTargetKey = options.defaultTargetKeyOnThrough;
const sourceKeyType = options.sourceModelPrimaryKeyType;
const targetKeyType = options.destinationModelPrimaryKeyType;
const customSourceModelKey = options.customSourceModelKey;
const customTargetModelKey = options.customTargetModelKey;
const sourceKeyType =
options.customSourceModelKeyType || options.sourceModelPrimaryKeyType;
const targetKeyType =
options.customTargetModelKeyType ||
options.destinationModelPrimaryKeyType;

// checks if both target and source key exist in through model
const project = new relationUtils.AstLoopBackProject();
Expand Down Expand Up @@ -145,6 +165,8 @@ module.exports = class HasManyThroughRelationGenerator extends (
sourceKey,
isDefaultTargetKey,
targetKey,
customSourceModelKey,
customTargetModelKey,
);
relationUtils.addProperty(sourceClass, modelProperty);
let imports;
Expand Down Expand Up @@ -200,21 +222,31 @@ module.exports = class HasManyThroughRelationGenerator extends (
sourceKey,
isDefaultTargetKey,
targetKey,
customSourceModelKey,
customTargetModelKey,
) {
let keyFrom = '';
let keyTo = '';
let customReferenceKeyFrom = '';
let customReferenceKeyTo = '';
if (!isDefaultSourceKey) {
keyFrom = `, keyFrom: '${sourceKey}'`;
}
if (!isDefaultTargetKey) {
keyTo = `, keyTo: '${targetKey}'`;
}
if (customSourceModelKey) {
customReferenceKeyFrom = `customReferenceKeyFrom: '${customSourceModelKey}', `;
}
if (customTargetModelKey) {
customReferenceKeyTo = `customReferenceKeyTo: '${customTargetModelKey}', `;
}

const relationDecorator = [
{
name: 'hasMany',
arguments: [
`() => ${targetClass}, {through: {model: () => ${throughModel}${keyFrom}${keyTo}}}`,
`() => ${targetClass}, {${customReferenceKeyFrom}${customReferenceKeyTo}through: {model: () => ${throughModel}${keyFrom}${keyTo}}}`,
],
},
];
Expand Down
127 changes: 127 additions & 0 deletions packages/cli/generators/relation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ module.exports = class RelationGenerator extends ArtifactGenerator {
required: false,
description: g.f('Relation name'),
});

this.option('defaultRelationName', {
type: String,
required: false,
Expand All @@ -151,6 +152,25 @@ module.exports = class RelationGenerator extends ArtifactGenerator {
'Allow <sourceModel> queries to include data from related <destinationModel>',
),
});

this.option('customReferenceKeys', {
type: String,
required: false,
description: g.f('Any Custom Reference Kyes'),
});

this.option('customSourceModelKey', {
type: String,
required: false,
description: g.f('Custom Source model key'),
});

this.option('customTargetModelKey', {
type: String,
required: false,
description: g.f('Custom Destination model'),
});

this.artifactInfo = {
type: 'relation',
rootDir: utils.sourceRootDir,
Expand Down Expand Up @@ -384,6 +404,113 @@ module.exports = class RelationGenerator extends ArtifactGenerator {
}
}

// Prompt a user for confirmation if they have custom reference keys
async promptCustomReferenceKeys() {
if (this.shouldExit()) return false;
if (this.options.customReferenceKeys) {
this.artifactInfo.customReferenceKeys = this.options.customReferenceKeys;
if (this.options.customSourceModelKey) {
this.artifactInfo.customSourceModelKey =
this.options.customSourceModelKey;
}
if (this.options.customTargetModelKey) {
this.artifactInfo.customTargetModelKey =
this.options.customTargetModelKey;
}
}

if (this.artifactInfo.relationType === 'hasManyThrough') {
const props = await this.prompt([
{
type: 'confirm',
name: 'customReferenceKeys',
message: g.f(
'Do you have custom reference keys for source and target models?',
),
when: this.artifactInfo.customReferenceKeys === undefined,
default: false,
},
]);
Object.assign(this.artifactInfo, props);
if (this.artifactInfo.customReferenceKeys) {
const answerSource = await this.prompt([
{
type: 'input',
name: 'customSourceModelKey',
message: g.f('What is the name of reference key in source model?'),
when: this.artifactInfo.customSourceModelKey === undefined,
},
]);
if (answerSource.customSourceModelKey) {
this.artifactInfo.customSourceModelKey =
answerSource.customSourceModelKey;
}
const answerTarget = await this.prompt([
{
type: 'input',
name: 'customTargetModelKey',
message: g.f('What is the name of reference key in target model?'),
when: this.artifactInfo.customTargetModelKey === undefined,
},
]);
if (answerTarget.customTargetModelKey) {
this.artifactInfo.customTargetModelKey =
answerTarget.customTargetModelKey;
}
const customSourceModelKeyType = relationUtils.getModelPropertyType(
this.artifactInfo.modelDir,
this.artifactInfo.sourceModel,
this.artifactInfo.customSourceModelKey,
);

const customTargetModelKeyType = relationUtils.getModelPropertyType(
this.artifactInfo.modelDir,
this.artifactInfo.destinationModel,
this.artifactInfo.customTargetModelKey,
);
if (customSourceModelKeyType) {
this.artifactInfo.customSourceModelKeyType = customSourceModelKeyType;
}
let answer = await this.prompt([
{
type: 'list',
name: 'customSourceModelKeyType',
message: g.f(
'What is the type of the custom reference key of source model?',
),
choices: ['number', 'string', 'object'],
when: this.artifactInfo.customSourceModelKeyType === undefined,
default: 'number',
},
]);
if (answer.customSourceModelKeyType) {
this.artifactInfo.customSourceModelKeyType =
answer.customSourceModelKeyType;
}

if (customTargetModelKeyType) {
this.artifactInfo.customTargetModelKeyType = customTargetModelKeyType;
}
answer = await this.prompt([
{
type: 'list',
name: 'customTargetModelKeyType',
message: g.f(
'What is the type of the custom reference key of source model?',
),
choices: ['number', 'string', 'object'],
when: this.artifactInfo.customTargetModelKeyType === undefined,
default: 'number',
},
]);
if (answer.customTargetModelKeyType) {
this.artifactInfo.customTargetModelKeyType =
answer.customTargetModelKeyType;
}
}
}
}

/**
* Prompt foreign key if not exist:
* 1. From source model get primary key. If primary key does not exist -
Expand Down
Loading
Loading