Skip to content

Commit b345a61

Browse files
authored
feat: add validator for string integer
1 parent f47f2ca commit b345a61

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ yarn add @byndyusoft/class-validator-extended class-validator class-transformer
3232

3333
- [AtLeastOneDefined](./src/decorators/validators/atLeastOneDefined.ts)
3434
- [IsNullable](./src/decorators/validators/isNullable.ts)
35+
- [IsIntString](./src/decorators/validators/math/isIntString.ts)
3536
- [LessThan](./src/decorators/validators/math/lessThan.ts)
3637
- [LessThanOrEqualTo](./src/decorators/validators/math/lessThanOrEqualTo.ts)
3738
- [GreaterThan](./src/decorators/validators/math/greaterThan.ts)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2023 Byndyusoft
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { validate, ValidationError } from "class-validator";
18+
19+
import { IsIntString } from "~/src";
20+
21+
class Box {
22+
@IsIntString()
23+
public readonly height!: string;
24+
25+
public constructor(height: string) {
26+
this.height = height;
27+
}
28+
}
29+
30+
describe("decorators/validators/IsIntString", () => {
31+
describe("when values are valid", () => {
32+
const height = "99";
33+
const box = new Box(height);
34+
35+
it("does not have validation errors", async () => {
36+
const validationErrors = await validate(box);
37+
38+
expect(validationErrors).toHaveLength(0);
39+
});
40+
});
41+
42+
describe("when values are invalid", () => {
43+
const cases: Array<{
44+
description: string;
45+
height: string | number;
46+
}> = [
47+
{
48+
description: "for number",
49+
height: 100,
50+
},
51+
{
52+
description: "for string number",
53+
height: "100.1",
54+
},
55+
{
56+
description: "for wrong types",
57+
height: "abc",
58+
},
59+
];
60+
61+
it.each(cases)(
62+
"returns validation errors $description",
63+
async ({ height }) => {
64+
// @ts-expect-error for validation tests
65+
const box = new Box(height);
66+
67+
const validationErrors = await validate(box);
68+
69+
expect(validationErrors).toBeArrayOfSize(1);
70+
71+
expect(validationErrors).toSatisfyAll((error: ValidationError) => {
72+
if (!error.constraints) {
73+
return false;
74+
}
75+
76+
return "isIntString" in error.constraints;
77+
});
78+
},
79+
);
80+
});
81+
});

src/decorators/validators/math/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616

1717
export * from "./greaterThan";
1818
export * from "./greaterThanOrEqualTo";
19+
export * from "./isIntString";
1920
export * from "./lessThan";
2021
export * from "./lessThanOrEqualTo";
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2023 Byndyusoft
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {
18+
buildMessage,
19+
isString,
20+
ValidateBy,
21+
ValidationOptions,
22+
} from "class-validator";
23+
import { Decimal } from "decimal.js";
24+
25+
const isIntString = (value: unknown): boolean => {
26+
try {
27+
return isString(value) && new Decimal(value).isInt();
28+
} catch {
29+
return false;
30+
}
31+
};
32+
33+
export function IsIntString(
34+
validationOptions?: ValidationOptions,
35+
): PropertyDecorator {
36+
return ValidateBy(
37+
{
38+
name: "isIntString",
39+
validator: {
40+
validate: (value): boolean => isIntString(value),
41+
defaultMessage: buildMessage(
42+
(eachPrefix) => `${eachPrefix}$property must be a string integer`,
43+
validationOptions,
44+
),
45+
},
46+
},
47+
validationOptions,
48+
);
49+
}

0 commit comments

Comments
 (0)