Skip to content

Commit

Permalink
feat: add IsObject and IsNotEmptyObject new decorators (#334)
Browse files Browse the repository at this point in the history
Co-authored-by: Yogev Lahyani <yogev.lahyani@autodesk.com>
  • Loading branch information
2 people authored and vlapo committed Oct 2, 2019
1 parent 47172f5 commit 0a41aeb
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,8 @@ validator.isISBN(str, version); // Checks if the string is an ISBN (version 10 o
validator.isISIN(str); // Checks if the string is an ISIN (stock/security identifier).
validator.isISO8601(str); // Checks if the string is a valid ISO 8601 date.
validator.isJSON(str); // Checks if the string is valid JSON (note: uses JSON.parse).
validator.isObject(object); // Checks if the object is valid Object (null, functions, arrays will return false)
validator.isNotEmptyObject(object); // Checks if the object is not empty
validator.isLowercase(str); // Checks if the string is lowercase.
validator.isLatLong(str); // Checks if the string is lowercase.
validator.isLatitude(str); // Checks if the string is lowercase.
Expand Down Expand Up @@ -925,6 +927,8 @@ 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. |
| `@IsObject()` | Checks if the object is valid Object (null, functions, arrays will return false). |
| `@IsNotEmptyObject()` | Checks if the object is not empty. |
| `@IsLowercase()` | Checks if the string is lowercase. |
| `@IsLatLong()` | Checks if the string is a valid latitude-longitude coordinate in the format lat,long |
| `@IsLatitude()` | Checks if the string or number is a valid latitude coordinate |
Expand Down
30 changes: 30 additions & 0 deletions src/decorator/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,36 @@ export function IsJSON(validationOptions?: ValidationOptions) {
};
}

/**
* Checks if the value is a valid object.
*/
export function IsObject(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
const args: ValidationMetadataArgs = {
type: ValidationTypes.IS_OBJECT,
target: object.constructor,
propertyName: propertyName,
validationOptions: validationOptions
};
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
};
}

/**
* Checks if the value is a valid object & not empty.
*/
export function IsNotEmptyObject(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
const args: ValidationMetadataArgs = {
type: ValidationTypes.IS_NOT_EMPTY_OBJECT,
target: object.constructor,
propertyName: propertyName,
validationOptions: validationOptions
};
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
};
}

/**
* Checks if the string is lowercase.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/validation/ValidationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export class ValidationTypes {
static IS_ISIN = "isIsin";
static IS_ISO8601 = "isIso8601";
static IS_JSON = "isJson";
static IS_OBJECT = "isObject";
static IS_NOT_EMPTY_OBJECT = "isNotEmptyObject";
static IS_LOWERCASE = "isLowercase";
static IS_MOBILE_PHONE = "isMobilePhone";
static IS_PHONE_NUMBER = "isPhoneNumber";
Expand Down Expand Up @@ -225,6 +227,10 @@ export class ValidationTypes {
return eachPrefix + "$property must be a valid ISO 8601 date string";
case this.IS_JSON:
return eachPrefix + "$property must be a json string";
case this.IS_OBJECT:
return eachPrefix + "$property must be an object";
case this.IS_NOT_EMPTY_OBJECT:
return eachPrefix + "$property must be a non-empty object";
case this.IS_LOWERCASE:
return eachPrefix + "$property must be a lowercase string";
case this.IS_MOBILE_PHONE:
Expand Down
29 changes: 29 additions & 0 deletions src/validation/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ export class Validator {
private libPhoneNumber = {
phoneUtil: require("google-libphonenumber").PhoneNumberUtil.getInstance(),
};
private _isEmptyObject = function(object: object) {
for (const key in object) {
if (object.hasOwnProperty(key)) {
return false;
}
}

return true;
};

/**
* Performs validation of the given object based on decorators or validation schema.
Expand Down Expand Up @@ -221,6 +230,10 @@ export class Validator {
return this.isISO8601(value);
case ValidationTypes.IS_JSON:
return this.isJSON(value);
case ValidationTypes.IS_OBJECT:
return this.isObject(value);
case ValidationTypes.IS_NOT_EMPTY_OBJECT:
return this.isNotEmptyObject(value);
case ValidationTypes.IS_LOWERCASE:
return this.isLowercase(value);
case ValidationTypes.IS_MOBILE_PHONE:
Expand Down Expand Up @@ -687,6 +700,22 @@ export class Validator {
return typeof value === "string" && this.validatorJs.isJSON(value);
}

/**
* Checks if the value is valid Object.
* Returns false if the value is not an object.
*/
isObject(value: any): boolean {
return value != null && (typeof value === "object" || typeof value === "function") && !Array.isArray(value);
}

/**
* Checks if the value is valid Object & not empty.
* Returns false if the value is not an object or an empty valid object.
*/
isNotEmptyObject(value: any): boolean {
return this.isObject(value) && !this._isEmptyObject(value);
}

/**
* Checks if the string is lowercase.
* If given value is not a string, then it returns false.
Expand Down
70 changes: 70 additions & 0 deletions test/functional/validation-functions-and-decorators.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
IsIn,
IsInt,
IsJSON,
IsObject,
IsNotEmptyObject,
Length,
IsLowercase,
IsMongoId,
Expand Down Expand Up @@ -2312,6 +2314,74 @@ describe("IsJSON", function() {

});

describe("IsObject", function() {

const validValues = [{ "key": "value" }, { key: "value" }, {}];
const invalidValues: any[] = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, "[]", [], [{ key: "value" }]];

class MyClass {
@IsObject()
someProperty: object;
}

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);
});

it("should not fail if method in validator said that its valid", function() {
validValues.forEach(value => validator.isObject(value).should.be.true);
});

it("should fail if method in validator said that its invalid", function() {
invalidValues.forEach(value => validator.isObject(value).should.be.false);
});

it("should return error object with proper data", function(done) {
const validationType = "isObject";
const message = "someProperty must be an object";
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
});

});

describe("IsNotEmptyObject", function() {

const validValues = [{ "key": "value" }, { key: "value" }];
const invalidValues = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, {}, [], [{ key: "value" }]];

class MyClass {
@IsNotEmptyObject()
someProperty: object;
}

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);
});

it("should not fail if method in validator said that its valid", function() {
validValues.forEach(value => validator.isNotEmptyObject(value).should.be.true);
});

it("should fail if method in validator said that its invalid", function() {
invalidValues.forEach(value => validator.isNotEmptyObject(value).should.be.false);
});

it("should return error object with proper data", function(done) {
const validationType = "isNotEmptyObject";
const message = "someProperty must be a non-empty object";
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
});

});

describe("IsLowercase", function() {

const validValues = [
Expand Down

1 comment on commit 0a41aeb

@or109
Copy link

@or109 or109 commented on 0a41aeb Dec 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good job :)

Please sign in to comment.