diff --git a/README.md b/README.md index de7d9f469b..dfb4c8d1ab 100644 --- a/README.md +++ b/README.md @@ -470,7 +470,7 @@ import { validate } from 'class-validator'; class MyClass { @MinLength(32, { - message: "EIC code must be at least 32 charatcers", + message: "EIC code must be at least 32 characters", context: { errorCode: 1003, developerNote: "The validated string must contain 32 or more characters." @@ -922,7 +922,10 @@ validator.isInstance(value, target); // Checks value is an instance of the targe | `@IsISIN()` | Checks if the string is an ISIN (stock/security identifier). | | `@IsISO8601()` | Checks if the string is a valid ISO 8601 date. | | `@IsJSON()` | Checks if the string is valid JSON. | -| `@IsLowercase()` | Checks if the string is lowercase. | +| `@IsLowercase()` | Checks if the string is lowercase. +| `@IsLatLong()` | check if the string is a valid latitude-longitude coordinate in the format lat,long +| `@IsLatitude()` | check if the string or number is a valid latitude coordinate +| `@IsLongitude()` | check if the string or number is a valid longitude coordinate | `@IsMobilePhone(locale: string)` | Checks if the string is a mobile phone number. | | `@IsISO31661Alpha2()` | Check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code. | | `@IsISO31661Alpha3()` | Check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code. | diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts index 33b627fe41..f2463ad0c7 100644 --- a/src/decorator/decorators.ts +++ b/src/decorator/decorators.ts @@ -260,6 +260,51 @@ export function IsBoolean(validationOptions?: ValidationOptions) { }; } +/** + * Checks if a value is a latitude,longitude. + */ +export function IsLatLong(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.IS_LATLONG, + target: object.constructor, + propertyName: propertyName, + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} + +/** + * Checks if a value is a latitude,longitude. + */ +export function IsLatitude(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.IS_LONGITUDE, + target: object.constructor, + propertyName: propertyName, + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} + +/** + * Checks if a value is a latitude,longitude. + */ +export function IsLongitude(validationOptions?: ValidationOptions) { + return function (object: Object, propertyName: string) { + const args: ValidationMetadataArgs = { + type: ValidationTypes.IS_LATITUDE, + target: object.constructor, + propertyName: propertyName, + validationOptions: validationOptions + }; + getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args)); + }; +} + /** * Checks if a value is a date. */ diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts index dc2fa1ab34..5ac6b3a750 100644 --- a/src/validation/ValidationTypes.ts +++ b/src/validation/ValidationTypes.ts @@ -25,6 +25,9 @@ export class ValidationTypes { static IS_BOOLEAN = "isBoolean"; static IS_DATE = "isDate"; static IS_NUMBER = "isNumber"; + static IS_LATLONG = "isLatLong"; + static IS_LATITUDE = "isLatitude"; + static IS_LONGITUDE = "isLongitude"; static IS_STRING = "isString"; static IS_DATE_STRING = "isDateString"; static IS_ARRAY = "isArray"; @@ -232,6 +235,12 @@ export class ValidationTypes { return eachPrefix + "$property must be a valid ISO31661 Alpha2 code"; case this.IS_ISO31661_ALPHA_3: return eachPrefix + "$property must be a valid ISO31661 Alpha3 code"; + case this.IS_LATLONG: + return eachPrefix + "$property must be a latitude,longitude string"; + case this.IS_LATITUDE: + return eachPrefix + "$property must be a latitude string or number"; + case this.IS_LONGITUDE: + return eachPrefix + "$property must be a longitude string or number"; case this.IS_MONGO_ID: return eachPrefix + "$property must be a mongodb id"; case this.IS_MULTIBYTE: diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts index 7126c52163..fe7f5ee423 100644 --- a/src/validation/Validator.ts +++ b/src/validation/Validator.ts @@ -127,6 +127,12 @@ export class Validator { return this.isNotIn(value, metadata.constraints[0]); /* type checkers */ + case ValidationTypes.IS_LATLONG: + return this.isLatLong(value); + case ValidationTypes.IS_LATITUDE: + return this.isLatitude(value); + case ValidationTypes.IS_LONGITUDE: + return this.isLongitude(value); case ValidationTypes.IS_BOOLEAN: return this.isBoolean(value); case ValidationTypes.IS_DATE: @@ -332,6 +338,29 @@ export class Validator { return value instanceof Boolean || typeof value === "boolean"; } + + /** + * Checks if a given value is a latitude. + */ + isLatLong(value: any): boolean { + + return this.validatorJs.isLatLong(value); + } + + /** + * Checks if a given value is a latitude. + */ + isLatitude(value: any): boolean { + return (typeof value === "number" || this.isString(value)) && this.isLatLong(`0,${value}`); + } + + /** + * Checks if a given value is a longitude. + */ + isLongitude(value: any): boolean { + return (typeof value === "number" || this.isString(value)) && this.isLatLong(`${value},0`); + } + /** * Checks if a given value is a real date. */ diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts index e7f6dd2ec2..915b0def58 100644 --- a/test/functional/validation-functions-and-decorators.spec.ts +++ b/test/functional/validation-functions-and-decorators.spec.ts @@ -3,6 +3,9 @@ import {expect} from "chai"; import { IsBooleanString, IsPositive, + IsLatLong, + IsLongitude, + IsLatitude, IsNegative, Contains, Equals, @@ -441,6 +444,68 @@ describe("IsBoolean", function() { checkReturnedError(new MyClass(), invalidValues, validationType, message, done); }); +}); +// ------------------------------------------------------------------------- +// Specifications: type check +// ------------------------------------------------------------------------- + +describe("IsLatLong", function () { + + const validValues = ["27.6945311,85.3446311", "27.675509,85.2100893"]; + const invalidValues = [ "276945311,853446311" , "asas,as.as12" ]; + + class MyClass { + @IsLatLong() + someProperty: any; + } + + it("should not fail if validator.validate said that its valid", function (done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function (done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + +}); +describe("IsLatitude", function () { + + const validValues = ["27.6945311", "27.675509", 27.675509]; + const invalidValues = ["276945311", "asas", 1234222, 5678921]; + + class MyClass { + @IsLatitude() + someProperty: any; + } + + it("should not fail if validator.validate said that its valid", function (done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function (done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + +}); + +describe("IsLongitude", function () { + + const validValues = ["85.3446311", "85.2100893", 85.2100893]; + const invalidValues = ["853446311", "as.as12", 12345 , 737399]; + + class MyClass { + @IsLongitude() + someProperty: any; + } + + it("should not fail if validator.validate said that its valid", function (done) { + checkValidValues(new MyClass(), validValues, done); + }); + + it("should fail if validator.validate said that its invalid", function (done) { + checkInvalidValues(new MyClass(), invalidValues, done); + }); + }); describe("IsDate", function() {