diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index d449e9301a..4efb17b9de 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -22,7 +22,7 @@ export * from './common/NotEquals'; export * from './common/IsEmpty'; export * from './common/IsNotEmpty'; export * from './common/IsIn'; -export * from './common/IsNotIn'; +export * from './common/IsNotIn';; // ------------------------------------------------------------------------- // Number checkers @@ -33,6 +33,8 @@ export * from './number/IsPositive'; export * from './number/IsNegative'; export * from './number/Max'; export * from './number/Min'; +export * from './number/IsNatural'; +export * from './number/IsNaturalNoZero'; // ------------------------------------------------------------------------- // Date checkers diff --git a/src/decorator/number/IsNatural.ts b/src/decorator/number/IsNatural.ts new file mode 100644 index 0000000000..d6acc54c13 --- /dev/null +++ b/src/decorator/number/IsNatural.ts @@ -0,0 +1,40 @@ +import {ValidationOptions} from '../ValidationOptions'; +import {buildMessage, ValidateBy} from '../common/ValidateBy'; + +export const IS_NATURAL = 'iSNatural'; + +/** + * Checks if the value is a natural number. + */ +export function isNatural(value: unknown): boolean { + + if (typeof value === 'number') { + return Number.isInteger(value) && value >= 0; + + } else if (typeof value === 'string') { + + return Number.isInteger(+value) && +value >= 0; + } + + return false; + +} + +/** + * Checks if the value is a natural number. + */ +export function IsNatural(validationOptions?: ValidationOptions): PropertyDecorator { + return ValidateBy( + { + name: IS_NATURAL, + validator: { + validate: (value, args): boolean => isNatural(value), + defaultMessage: buildMessage( + eachPrefix => eachPrefix + '$property must be a natural number', + validationOptions + ), + }, + }, + validationOptions + ); +} diff --git a/src/decorator/number/IsNaturalNoZero.ts b/src/decorator/number/IsNaturalNoZero.ts new file mode 100644 index 0000000000..0c3cf4a889 --- /dev/null +++ b/src/decorator/number/IsNaturalNoZero.ts @@ -0,0 +1,41 @@ +import {ValidationOptions} from '../ValidationOptions'; +import {buildMessage, ValidateBy} from '../common/ValidateBy'; + +export const IS_NATURAL_NO_ZERO = 'iSNaturalNoZero'; + +/** + * Checks if the value is a natural number and not zero. + */ +export function isNaturalNoZero(value: unknown): boolean { + + if (typeof value === 'number') { + + return Number.isInteger(value) && value > 0; + + } else if (typeof value === 'string') { + + return Number.isInteger(+value) && +value > 0; + } + + return false; + +} + +/** + * Checks if the value is a natural number and not zero. + */ +export function IsNaturalNoZero(validationOptions?: ValidationOptions): PropertyDecorator { + return ValidateBy( + { + name: IS_NATURAL_NO_ZERO, + validator: { + validate: (value, args): boolean => isNaturalNoZero(value), + defaultMessage: buildMessage( + eachPrefix => eachPrefix + '$property must be a natural number and must be greater than zero', + validationOptions + ), + }, + }, + validationOptions + ); +} diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index 5144a0db48..631b68c426 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -193,6 +193,11 @@ import { isTaxId, IsTaxId, IsISO4217CurrencyCode, + IsNatural, + isNatural, + IsNaturalNoZero, + iSNaturalNoZero, + iSNatural, } from '../../src/decorator/decorators'; import { Validator } from '../../src/validation/Validator'; import { ValidatorOptions } from '../../src/validation/ValidatorOptions'; @@ -4779,3 +4784,99 @@ describe('IsISO4217', () => { return checkInvalidValues(new MyClass(), invalidValues); }); }); + +describe('IsNatural', () => { + const validValues = [0, '01', '0', '11', 2, 4, 100, 1000]; + const invalidValues = ['-01', -11, '123.123', ' ', '', 2.5, -0.1]; + + class MyClass { + @IsNatural() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(isNatural(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(isNatural(value as any)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'isNatural'; + const message = 'someProperty must be a natural number'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +}); + +describe('IsNaturalNoZero', () => { + const validValues = [1, 2, 4, 6, 13, 100]; + const invalidValues = ['-1', 0, -11, '123.123', -10.6, ' ', '', 2.5, -0.1]; + + class MyClass { + @IsNaturalNoZero() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(iSNaturalNoZero(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(iSNaturalNoZero(value)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'iSNaturalNoZero'; + const message = 'someProperty must be a natural number and greater then zero'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +}); + +describe('IsNatural', () => { + const validValues = [0, 1, 11, 2, 4, 100]; + const invalidValues = ['-1', -11, '123.123', -10.6, ' ', '', 2.5, -0.1]; + + class MyClass { + @IsNatural() + someProperty: string; + } + + it('should not fail if validator.validate said that its valid', () => { + return checkValidValues(new MyClass(), validValues); + }); + + it('should fail if validator.validate said that its invalid', () => { + return checkInvalidValues(new MyClass(), invalidValues); + }); + + it('should not fail if method in validator said that its valid', () => { + validValues.forEach(value => expect(iSNatural(value)).toBeTruthy()); + }); + + it('should fail if method in validator said that its invalid', () => { + invalidValues.forEach(value => expect(iSNatural(value)).toBeFalsy()); + }); + + it('should return error object with proper data', () => { + const validationType = 'iSNatural'; + const message = 'someProperty must be a natural number'; + return checkReturnedError(new MyClass(), invalidValues, validationType, message); + }); +});