Skip to content

Commit 8704de3

Browse files
author
Angelo Manganiello
authored
Merge pull request #192 from jhipster/feature/dto-validation-issue182
Feature/dto validation issue182
2 parents 850cb7c + a64b4af commit 8704de3

File tree

9 files changed

+73
-45
lines changed

9 files changed

+73
-45
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
# [1.4.0](https://github.com/jhipster/generator-jhipster-nodejs/tree/v1.4.0)
1515

16-
- Dto implementation in the rest nestjs api[issue #181](https://github.com/jhipster/generator-jhipster-nodejs/issues/181)
16+
- Add validation in dto nestjs controllers [issue #182](https://github.com/jhipster/generator-jhipster-nodejs/issues/182)
17+
- Dto implementation in the rest nestjs api [issue #181](https://github.com/jhipster/generator-jhipster-nodejs/issues/181)
1718
- Protractor or another tool for client e2e tests [issue #101](https://github.com/jhipster/generator-jhipster-nodejs/issues/101)
1819
- Support the account management with user registration, delete, creation and changes password with settings [issue #166](https://github.com/jhipster/generator-jhipster-nodejs/issues/166)
1920
- NestJS migration from 6 to 7 version [issue #183](https://github.com/jhipster/generator-jhipster-nodejs/issues/183)

ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ To contribute for the next featues, fork the repo and open a pull request regard
5151
- [x] Jhipster client e2e protractor tests integrated
5252
- [x] Other core/admin jhipster management api
5353
- [x] DTOs based rest api
54+
- [x] Validation
5455

5556
## To DO for next release
5657

5758
- [ ] Add MongoDB support
58-
- [ ] Validation
5959
- [ ] Export json/yaml for swagger to integrate with jhipster gateway
6060
- [ ] pagination options in client
6161
- [ ] Elastic Search support

generators/entity-server/templates/server/src/common/field_validators.ejs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
See the License for the specific language governing permissions and
1717
limitations under the License.
1818
-%>
19-
<%# Returns a string of all validator annotations for the entity field. -%>
19+
<%# Returns a string of all validator annotations for the entity field. -%>
2020
<%
2121
const field = fields[idx];
2222
let result = '';
@@ -28,16 +28,16 @@ if (field.fieldValidate === true) {
2828
const isBlob = field.fieldType === 'byte[]';
2929
3030
if (rules.includes('required') && !isBlob) {
31-
validators.push('@NotNull');
31+
validators.push('@IsNotEmpty()');
3232
}
3333
if (rules.includes('minlength') && !rules.includes('maxlength')) {
34-
validators.push('@Size(min = ' + field.fieldValidateRulesMinlength + ')');
34+
validators.push('@MinLength(' + field.fieldValidateRulesMinlength + ')');
3535
}
3636
if (rules.includes('maxlength') && !rules.includes('minlength')) {
37-
validators.push('@Size(max = ' + field.fieldValidateRulesMaxlength + ')');
37+
validators.push('@MaxLength(' + field.fieldValidateRulesMaxlength + ')');
3838
}
3939
if (rules.includes('minlength') && rules.includes('maxlength')) {
40-
validators.push('@Size(min = ' + field.fieldValidateRulesMinlength + ', max = ' + field.fieldValidateRulesMaxlength + ')');
40+
validators.push('@Length(' + field.fieldValidateRulesMinlength + ', ' + field.fieldValidateRulesMaxlength + ')');
4141
}
4242
// Not supported anymore because the server can't check the size of the blob before downloading it completely.
4343
// if (rules.includes('minbytes') && !rules.includes('maxbytes')) {
@@ -50,25 +50,15 @@ if (field.fieldValidate === true) {
5050
// validators.push('@Size(min = ' + field.fieldValidateRulesMinbytes + ', max = ' + field.fieldValidateRulesMaxbytes + ')');
5151
// }
5252
if (rules.includes('min')) {
53-
if (field.fieldType === 'Float' || field.fieldType === 'Double' || field.fieldType === 'BigDecimal') {
54-
validators.push('@DecimalMin(value = "' + field.fieldValidateRulesMin + '")');
55-
} else {
56-
const isLong = (field.fieldValidateRulesMin > MAX_VALUE || field.fieldType == 'Long') ? 'L' : '';
57-
validators.push('@Min(value = ' + field.fieldValidateRulesMin + isLong + ')');
58-
}
53+
validators.push('@Min(' + field.fieldValidateRulesMin + ')');
5954
}
6055
if (rules.includes('max')) {
61-
if (field.fieldType === 'Float' || field.fieldType === 'Double' || field.fieldType === 'BigDecimal') {
62-
validators.push('@DecimalMax(value = "' + field.fieldValidateRulesMax + '")');
63-
} else {
64-
const isLong = (field.fieldValidateRulesMax > MAX_VALUE || field.fieldType == 'Long') ? 'L' : '';
65-
validators.push('@Max(value = ' + field.fieldValidateRulesMax + isLong + ')');
66-
}
56+
validators.push('@Max(' + field.fieldValidateRulesMax + ')');
6757
}
6858
if (rules.includes('pattern')) {
69-
validators.push('@Pattern(regexp = "' + field.fieldValidateRulesPatternJava + '")');
59+
validators.push('@Matches("' + field.fieldValidateRulesPatternJava + '")');
7060
}
7161
result = validators.join('\n ');
7262
result += '\n';
7363
} -%>
74-
<%# WIP: todo - result -%>
64+
<%- result -%>

generators/entity-server/templates/server/src/domain/entity.ts.ejs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export class <%= asEntity(entityClass) %> extends BaseEntity {
5353
if (fieldValidateRules.includes('unique')) {
5454
unique = true;
5555
} _%>
56-
<%- include ../common/field_validators -%>
56+
5757
<%_ } _%>
5858
<%_ if (fields[idx].fieldIsEnum) { _%>
5959
@Column({type: 'simple-enum', name: '<%-fieldNameAsDatabaseColumn %>', enum: <%= fieldType %>})

generators/entity-server/templates/server/src/service/dto/entity.dto.ts.ejs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
import { ApiModelProperty } from '@nestjs/swagger';
33
<%_ if (validation) { _%>
4-
import { validate, Contains, IsString, IsInt, Length, IsEmail, Min, Max } from 'class-validator';
4+
import { IsNotEmpty, MinLength, MaxLength, Length, Min, Max, Matches } from 'class-validator';
55
<%_ } _%>
66
import { BaseDTO } from './base.dto';
77

@@ -34,10 +34,8 @@ export class <%= asEntity(entityClass) %>DTO extends BaseDTO {
3434
<%- formatAsFieldJavadoc(fields[idx].javadoc) %>
3535
<%_ }
3636
let required = false;
37-
let unique = false;
3837
const fieldValidate = fields[idx].fieldValidate;
3938
const fieldValidateRules = fields[idx].fieldValidateRules;
40-
const fieldValidateRulesMaxlength = fields[idx].fieldValidateRulesMaxlength;
4139
const fieldType = fields[idx].fieldType;
4240
const fieldTypeBlobContent = fields[idx].fieldTypeBlobContent;
4341
const fieldName = fields[idx].fieldName;
@@ -48,17 +46,11 @@ export class <%= asEntity(entityClass) %>DTO extends BaseDTO {
4846
if (fieldValidateRules.includes('required')) {
4947
required = true;
5048
}
51-
if (fieldValidateRules.includes('unique')) {
52-
unique = true;
53-
} _%>
54-
<%- include ../../common/field_validators -%>
49+
_%>
50+
<%- include ../../common/field_validators -%>
5551
<%_ } _%>
5652
<%_ if (fields[idx].fieldIsEnum) { _%>
5753
@ApiModelProperty({ enum: <%= fieldType %>, <%_ if (typeof fields[idx].javadoc != 'undefined') { _%> description: '<%- formatAsApiDescription(fields[idx].javadoc) %>' <%_ } else { _%> description: '<%= fieldName %> enum field' <%_ } if (!required) { _%>, required: false <%_ } _%>})
58-
<%_ } else if (['Instant', 'ZonedDateTime', 'LocalDate'].includes(fieldType)) { _%>
59-
60-
<%_ } else if (fieldType === 'BigDecimal') { _%>
61-
6254
<%_ } else { _%>
6355
@ApiModelProperty({ <%_ if (typeof fields[idx].javadoc != 'undefined') { _%> description: '<%- formatAsApiDescription(fields[idx].javadoc) %>' <%_ } else { _%> description: '<%= fieldName %> field' <%_ } if (!required) { _%>, required: false <%_ } _%>})
6456
<%_ } _%>

test-integration/samples/monolith-client-auth-i18n-template-jdl/monolith-client-auth-i18n-template-jdl.jdl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ entity BloodPressure {
3535
}
3636
entity Weight {
3737
timestamp ZonedDateTime required
38-
weight Double
38+
weight Double
3939
}
4040
entity Points {
4141
date LocalDate required
@@ -45,7 +45,7 @@ entity Points {
4545
notes String maxlength(140)
4646
}
4747
entity Preferences {
48-
weeklyGoal Integer required max(21)
48+
weeklyGoal Integer
4949
weightUnits Units required
5050
}
5151

test-integration/samples/monolith-client-auth-template-jdl/monolith-client-auth-template-jdl.jdl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ TEACHER
4343

4444
entity DemetraUser {
4545
gender Gender required,
46-
address String required,
46+
address String minlength(1) maxlength(100) required,
4747
borndate LocalDate required,
4848
cf String required unique,
4949
usertype UserType required,
@@ -52,7 +52,7 @@ entity DemetraUser {
5252

5353
entity SingleCourse {
5454
title String required unique,
55-
description String,
55+
description String pattern(/^[A-Z]$/),
5656
isnotonlyfordegree Boolean required,
5757
cfu Integer,
5858
courseimage Blob,
@@ -64,7 +64,6 @@ entity Activity {
6464
description String,
6565
mynumber Double,
6666
creationtime ZonedDateTime
67-
6867
}
6968

7069
relationship OneToOne {

test/entity.spec.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,36 @@ describe('Subgenerator entity of nodejs JHipster blueprint', () => {
9797
assert.fileContent(greatEntityPath, "@Column({ name: 'name', nullable: true, unique: true })");
9898
assert.fileContent(greatEntityPath, 'name: string;');
9999

100+
// name UUID with validation and swagger annotation
101+
assert.fileContent(greatEntityDTOPath, 'name: string;');
102+
assert.fileContent(greatEntityDTOPath, '@MinLength(5)');
103+
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ description: 'name field', required: false })");
104+
100105
// Gender enum field with swagger annotation
101106
assert.fileContent(greatEntityPath, "@Column({ type: 'simple-enum', name: 'gender', enum: Gender })");
102107
assert.fileContent(greatEntityPath, 'gender: Gender;');
103108
assert.fileContent(greatEntityDTOPath, 'gender: Gender;');
104109
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ enum: Gender, description: 'gender enum field' })");
105110

106-
// address String required field with swagger annotation
107-
assert.fileContent(greatEntityPath, "@Column({ name: 'address' })");
111+
// address string required field
112+
assert.fileContent(greatEntityPath, "@Column({ name: 'address', length: 100 })");
108113
assert.fileContent(greatEntityPath, 'address: string;');
114+
115+
// address string with validation and swagger annotation
109116
assert.fileContent(greatEntityDTOPath, 'address: string;');
117+
assert.fileContent(greatEntityDTOPath, '@IsNotEmpty()');
118+
assert.fileContent(greatEntityDTOPath, '@Length(1, 100)');
110119
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ description: 'address field' })");
111120

121+
// description string field
122+
assert.fileContent(greatEntityPath, "@Column({ name: 'description', nullable: true })");
123+
assert.fileContent(greatEntityPath, 'description: string;');
124+
125+
// description string with validation and swagger annotation
126+
assert.fileContent(greatEntityDTOPath, 'description: string;');
127+
assert.fileContent(greatEntityDTOPath, "@Matches('^[A-Z]$')");
128+
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ description: 'description field', required: false })");
129+
112130
// istrue Boolean field with swagger annotation
113131
assert.fileContent(greatEntityPath, "@Column({ type: 'boolean', name: 'istrue', nullable: true })");
114132
assert.fileContent(greatEntityPath, 'istrue: boolean;');
@@ -119,6 +137,8 @@ describe('Subgenerator entity of nodejs JHipster blueprint', () => {
119137
assert.fileContent(greatEntityPath, "@Column({ type: 'date', name: 'borndate' })");
120138
assert.fileContent(greatEntityPath, 'borndate: any;');
121139

140+
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ description: 'borndate field' })");
141+
122142
// profileimage Blob field
123143
assert.fileContent(greatEntityPath, "@Column({ type: 'blob', name: 'profileimage', nullable: true })");
124144
assert.fileContent(greatEntityPath, 'profileimage: any;');
@@ -147,6 +167,12 @@ describe('Subgenerator entity of nodejs JHipster blueprint', () => {
147167
assert.fileContent(greatEntityPath, "@Column({ type: 'double', name: 'mynumber', nullable: true })");
148168
assert.fileContent(greatEntityPath, 'mynumber: number;');
149169

170+
// mynumber with validation and swagger annotation
171+
assert.fileContent(greatEntityDTOPath, 'mynumber: number;');
172+
assert.fileContent(greatEntityDTOPath, '@Min(1)');
173+
assert.fileContent(greatEntityDTOPath, '@Max(100)');
174+
assert.fileContent(greatEntityDTOPath, "@ApiModelProperty({ description: 'mynumber field', required: false })");
175+
150176
// count Long field
151177
assert.fileContent(greatEntityPath, "@Column({ type: 'long', name: 'count', nullable: true })");
152178
assert.fileContent(greatEntityPath, 'count: number;');

test/templates/.jhipster/GreatEntity.json

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@
55
"fieldName": "name",
66
"fieldType": "UUID",
77
"fieldValidateRules": [
8-
"unique"
9-
]
8+
"unique",
9+
"minlength"
10+
],
11+
"fieldValidateRulesMinlength": "5"
12+
},
13+
{
14+
"fieldName": "description",
15+
"fieldType": "String",
16+
"fieldValidateRules": [
17+
"pattern"
18+
],
19+
"fieldValidateRulesPattern": "^[A-Z]$"
1020
},
1121
{
1222
"fieldName": "gender",
@@ -20,8 +30,12 @@
2030
"fieldName": "address",
2131
"fieldType": "String",
2232
"fieldValidateRules": [
33+
"minlength",
34+
"maxlength",
2335
"required"
24-
]
36+
],
37+
"fieldValidateRulesMinlength": "1",
38+
"fieldValidateRulesMaxlength": "100"
2539
},
2640
{
2741
"fieldName": "istrue",
@@ -64,7 +78,13 @@
6478
},
6579
{
6680
"fieldName": "mynumber",
67-
"fieldType": "Double"
81+
"fieldType": "Double",
82+
"fieldValidateRules": [
83+
"min",
84+
"max"
85+
],
86+
"fieldValidateRulesMin": "1",
87+
"fieldValidateRulesMax": "100"
6888
},
6989
{
7090
"fieldName": "count",
@@ -92,4 +112,4 @@
92112
"jpaMetamodelFiltering": false,
93113
"fluentMethods": true,
94114
"readOnly": false
95-
}
115+
}

0 commit comments

Comments
 (0)