Skip to content

Commit 0a41aeb

Browse files
yogevlahyaniYogev Lahyani
authored andcommitted
feat: add IsObject and IsNotEmptyObject new decorators (#334)
Co-authored-by: Yogev Lahyani <yogev.lahyani@autodesk.com>
1 parent 47172f5 commit 0a41aeb

File tree

5 files changed

+139
-0
lines changed

5 files changed

+139
-0
lines changed

Diff for: README.md

+4
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,8 @@ validator.isISBN(str, version); // Checks if the string is an ISBN (version 10 o
836836
validator.isISIN(str); // Checks if the string is an ISIN (stock/security identifier).
837837
validator.isISO8601(str); // Checks if the string is a valid ISO 8601 date.
838838
validator.isJSON(str); // Checks if the string is valid JSON (note: uses JSON.parse).
839+
validator.isObject(object); // Checks if the object is valid Object (null, functions, arrays will return false)
840+
validator.isNotEmptyObject(object); // Checks if the object is not empty
839841
validator.isLowercase(str); // Checks if the string is lowercase.
840842
validator.isLatLong(str); // Checks if the string is lowercase.
841843
validator.isLatitude(str); // Checks if the string is lowercase.
@@ -925,6 +927,8 @@ validator.isInstance(value, target); // Checks value is an instance of the targe
925927
| `@IsISIN()` | Checks if the string is an ISIN (stock/security identifier). |
926928
| `@IsISO8601()` | Checks if the string is a valid ISO 8601 date. |
927929
| `@IsJSON()` | Checks if the string is valid JSON. |
930+
| `@IsObject()` | Checks if the object is valid Object (null, functions, arrays will return false). |
931+
| `@IsNotEmptyObject()` | Checks if the object is not empty. |
928932
| `@IsLowercase()` | Checks if the string is lowercase. |
929933
| `@IsLatLong()` | Checks if the string is a valid latitude-longitude coordinate in the format lat,long |
930934
| `@IsLatitude()` | Checks if the string or number is a valid latitude coordinate |

Diff for: src/decorator/decorators.ts

+30
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,36 @@ export function IsJSON(validationOptions?: ValidationOptions) {
923923
};
924924
}
925925

926+
/**
927+
* Checks if the value is a valid object.
928+
*/
929+
export function IsObject(validationOptions?: ValidationOptions) {
930+
return function (object: Object, propertyName: string) {
931+
const args: ValidationMetadataArgs = {
932+
type: ValidationTypes.IS_OBJECT,
933+
target: object.constructor,
934+
propertyName: propertyName,
935+
validationOptions: validationOptions
936+
};
937+
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
938+
};
939+
}
940+
941+
/**
942+
* Checks if the value is a valid object & not empty.
943+
*/
944+
export function IsNotEmptyObject(validationOptions?: ValidationOptions) {
945+
return function (object: Object, propertyName: string) {
946+
const args: ValidationMetadataArgs = {
947+
type: ValidationTypes.IS_NOT_EMPTY_OBJECT,
948+
target: object.constructor,
949+
propertyName: propertyName,
950+
validationOptions: validationOptions
951+
};
952+
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
953+
};
954+
}
955+
926956
/**
927957
* Checks if the string is lowercase.
928958
*/

Diff for: src/validation/ValidationTypes.ts

+6
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export class ValidationTypes {
7373
static IS_ISIN = "isIsin";
7474
static IS_ISO8601 = "isIso8601";
7575
static IS_JSON = "isJson";
76+
static IS_OBJECT = "isObject";
77+
static IS_NOT_EMPTY_OBJECT = "isNotEmptyObject";
7678
static IS_LOWERCASE = "isLowercase";
7779
static IS_MOBILE_PHONE = "isMobilePhone";
7880
static IS_PHONE_NUMBER = "isPhoneNumber";
@@ -225,6 +227,10 @@ export class ValidationTypes {
225227
return eachPrefix + "$property must be a valid ISO 8601 date string";
226228
case this.IS_JSON:
227229
return eachPrefix + "$property must be a json string";
230+
case this.IS_OBJECT:
231+
return eachPrefix + "$property must be an object";
232+
case this.IS_NOT_EMPTY_OBJECT:
233+
return eachPrefix + "$property must be a non-empty object";
228234
case this.IS_LOWERCASE:
229235
return eachPrefix + "$property must be a lowercase string";
230236
case this.IS_MOBILE_PHONE:

Diff for: src/validation/Validator.ts

+29
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ export class Validator {
2020
private libPhoneNumber = {
2121
phoneUtil: require("google-libphonenumber").PhoneNumberUtil.getInstance(),
2222
};
23+
private _isEmptyObject = function(object: object) {
24+
for (const key in object) {
25+
if (object.hasOwnProperty(key)) {
26+
return false;
27+
}
28+
}
29+
30+
return true;
31+
};
2332

2433
/**
2534
* Performs validation of the given object based on decorators or validation schema.
@@ -221,6 +230,10 @@ export class Validator {
221230
return this.isISO8601(value);
222231
case ValidationTypes.IS_JSON:
223232
return this.isJSON(value);
233+
case ValidationTypes.IS_OBJECT:
234+
return this.isObject(value);
235+
case ValidationTypes.IS_NOT_EMPTY_OBJECT:
236+
return this.isNotEmptyObject(value);
224237
case ValidationTypes.IS_LOWERCASE:
225238
return this.isLowercase(value);
226239
case ValidationTypes.IS_MOBILE_PHONE:
@@ -687,6 +700,22 @@ export class Validator {
687700
return typeof value === "string" && this.validatorJs.isJSON(value);
688701
}
689702

703+
/**
704+
* Checks if the value is valid Object.
705+
* Returns false if the value is not an object.
706+
*/
707+
isObject(value: any): boolean {
708+
return value != null && (typeof value === "object" || typeof value === "function") && !Array.isArray(value);
709+
}
710+
711+
/**
712+
* Checks if the value is valid Object & not empty.
713+
* Returns false if the value is not an object or an empty valid object.
714+
*/
715+
isNotEmptyObject(value: any): boolean {
716+
return this.isObject(value) && !this._isEmptyObject(value);
717+
}
718+
690719
/**
691720
* Checks if the string is lowercase.
692721
* If given value is not a string, then it returns false.

Diff for: test/functional/validation-functions-and-decorators.spec.ts

+70
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import {
3636
IsIn,
3737
IsInt,
3838
IsJSON,
39+
IsObject,
40+
IsNotEmptyObject,
3941
Length,
4042
IsLowercase,
4143
IsMongoId,
@@ -2312,6 +2314,74 @@ describe("IsJSON", function() {
23122314

23132315
});
23142316

2317+
describe("IsObject", function() {
2318+
2319+
const validValues = [{ "key": "value" }, { key: "value" }, {}];
2320+
const invalidValues: any[] = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, "[]", [], [{ key: "value" }]];
2321+
2322+
class MyClass {
2323+
@IsObject()
2324+
someProperty: object;
2325+
}
2326+
2327+
it("should not fail if validator.validate said that its valid", function(done) {
2328+
checkValidValues(new MyClass(), validValues, done);
2329+
});
2330+
2331+
it("should fail if validator.validate said that its invalid", function(done) {
2332+
checkInvalidValues(new MyClass(), invalidValues, done);
2333+
});
2334+
2335+
it("should not fail if method in validator said that its valid", function() {
2336+
validValues.forEach(value => validator.isObject(value).should.be.true);
2337+
});
2338+
2339+
it("should fail if method in validator said that its invalid", function() {
2340+
invalidValues.forEach(value => validator.isObject(value).should.be.false);
2341+
});
2342+
2343+
it("should return error object with proper data", function(done) {
2344+
const validationType = "isObject";
2345+
const message = "someProperty must be an object";
2346+
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
2347+
});
2348+
2349+
});
2350+
2351+
describe("IsNotEmptyObject", function() {
2352+
2353+
const validValues = [{ "key": "value" }, { key: "value" }];
2354+
const invalidValues = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, {}, [], [{ key: "value" }]];
2355+
2356+
class MyClass {
2357+
@IsNotEmptyObject()
2358+
someProperty: object;
2359+
}
2360+
2361+
it("should not fail if validator.validate said that its valid", function(done) {
2362+
checkValidValues(new MyClass(), validValues, done);
2363+
});
2364+
2365+
it("should fail if validator.validate said that its invalid", function(done) {
2366+
checkInvalidValues(new MyClass(), invalidValues, done);
2367+
});
2368+
2369+
it("should not fail if method in validator said that its valid", function() {
2370+
validValues.forEach(value => validator.isNotEmptyObject(value).should.be.true);
2371+
});
2372+
2373+
it("should fail if method in validator said that its invalid", function() {
2374+
invalidValues.forEach(value => validator.isNotEmptyObject(value).should.be.false);
2375+
});
2376+
2377+
it("should return error object with proper data", function(done) {
2378+
const validationType = "isNotEmptyObject";
2379+
const message = "someProperty must be a non-empty object";
2380+
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
2381+
});
2382+
2383+
});
2384+
23152385
describe("IsLowercase", function() {
23162386

23172387
const validValues = [

0 commit comments

Comments
 (0)