Skip to content

Commit 7f6de9a

Browse files
feat: add IsInstance decorator
1 parent 00c6a90 commit 7f6de9a

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

src/decorator/decorators.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,3 +1120,19 @@ export function ArrayUnique(validationOptions?: ValidationOptions) {
11201120
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
11211121
};
11221122
}
1123+
1124+
/**
1125+
* Checks if all array's values are unique. Comparison for objects is reference-based.
1126+
*/
1127+
export function IsInstance(targetType: new (...args: any[]) => any, validationOptions?: ValidationOptions) {
1128+
return function (object: Object, propertyName: string) {
1129+
const args: ValidationMetadataArgs = {
1130+
type: ValidationTypes.IS_INSTANCE,
1131+
target: object.constructor,
1132+
propertyName: propertyName,
1133+
constraints: [targetType],
1134+
validationOptions: validationOptions
1135+
};
1136+
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(args));
1137+
};
1138+
}

src/validation/ValidationTypes.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export class ValidationTypes {
8888
static ARRAY_MAX_SIZE = "arrayMaxSize";
8989
static ARRAY_UNIQUE = "arrayUnique";
9090

91+
/* object chekers */
92+
static IS_INSTANCE = "isInstance";
93+
9194
/**
9295
* Checks if validation type is valid.
9396
*/
@@ -252,6 +255,15 @@ export class ValidationTypes {
252255
return eachPrefix + "$property must contain not more than $constraint1 elements";
253256
case this.ARRAY_UNIQUE:
254257
return eachPrefix + "All $property's elements must be unique";
258+
259+
case this.IS_INSTANCE:
260+
return (args: ValidationArguments) => {
261+
if (args.constraints[0]) {
262+
return eachPrefix + `$property must be an instance of ${args.constraints[0].name}`;
263+
} else {
264+
return eachPrefix + `${this.IS_INSTANCE} decorator expects and object as value, but got falsy value.`;
265+
}
266+
};
255267
}
256268

257269
return "";

src/validation/Validator.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ export class Validator {
247247
return this.arrayMaxSize(value, metadata.constraints[0]);
248248
case ValidationTypes.ARRAY_UNIQUE:
249249
return this.arrayUnique(value);
250+
251+
case ValidationTypes.IS_INSTANCE:
252+
return this.isInstance(value, metadata.constraints[0]);
250253
}
251254
return true;
252255
}
@@ -798,4 +801,13 @@ export class Validator {
798801
return array.length === uniqueItems.length;
799802
}
800803

804+
/**
805+
* Checks if the value is an instance of the specified object.
806+
*/
807+
isInstance(object: any, targetTypeConstructor: new (...args: any[]) => any) {
808+
return targetTypeConstructor
809+
&& typeof targetTypeConstructor === "function"
810+
&& object instanceof targetTypeConstructor;
811+
}
812+
801813
}

test/functional/validation-functions-and-decorators.spec.ts

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ import {
6262
ArrayNotContains,
6363
ArrayUnique,
6464
IsArray,
65-
IsDateString
65+
IsDateString,
66+
IsInstance
6667
} from "../../src/decorator/decorators";
6768
import {Validator} from "../../src/validation/Validator";
6869
import {ValidatorOptions} from "../../src/validation/ValidatorOptions";
@@ -2989,7 +2990,7 @@ describe("ArrayMaxSize", function() {
29892990

29902991
});
29912992

2992-
describe("ArrayUnique", function() {
2993+
describe("ArrayUnique", function () {
29932994

29942995
const validValues = [["world", "hello", "superman"], ["world", "superman", "hello"], ["superman", "world", "hello"]];
29952996
const invalidValues: any[] = [null, undefined, ["world", "hello", "hello"], ["world", "hello", "world"], ["1", "1", "1"]];
@@ -2999,6 +3000,43 @@ describe("ArrayUnique", function() {
29993000
someProperty: string[];
30003001
}
30013002

3003+
it("should not fail if validator.validate said that its valid", function (done) {
3004+
checkValidValues(new MyClass(), validValues, done);
3005+
});
3006+
3007+
it("should fail if validator.validate said that its invalid", function (done) {
3008+
checkInvalidValues(new MyClass(), invalidValues, done);
3009+
});
3010+
3011+
it("should not fail if method in validator said that its valid", function () {
3012+
validValues.forEach(value => validator.arrayUnique(value).should.be.true);
3013+
});
3014+
3015+
it("should fail if method in validator said that its invalid", function () {
3016+
invalidValues.forEach(value => validator.arrayUnique(value).should.be.false);
3017+
});
3018+
3019+
it("should return error object with proper data", function (done) {
3020+
const validationType = "arrayUnique";
3021+
const message = "All someProperty's elements must be unique";
3022+
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
3023+
});
3024+
3025+
});
3026+
3027+
describe("isInstance", function () {
3028+
3029+
class MySubClass { }
3030+
class WrongSubClass {}
3031+
3032+
class MyClass {
3033+
@IsInstance(MySubClass)
3034+
someProperty: MySubClass;
3035+
}
3036+
3037+
const validValues = [new MySubClass()];
3038+
const invalidValues = [null, undefined, 15, "something", new WrongSubClass(), () => <any>null];
3039+
30023040
it("should not fail if validator.validate said that its valid", function(done) {
30033041
checkValidValues(new MyClass(), validValues, done);
30043042
});
@@ -3008,16 +3046,16 @@ describe("ArrayUnique", function() {
30083046
});
30093047

30103048
it("should not fail if method in validator said that its valid", function() {
3011-
validValues.forEach(value => validator.arrayUnique(value).should.be.true);
3049+
validValues.forEach(value => validator.isInstance(value, MySubClass).should.be.true);
30123050
});
30133051

30143052
it("should fail if method in validator said that its invalid", function() {
3015-
invalidValues.forEach(value => validator.arrayUnique(value).should.be.false);
3053+
invalidValues.forEach(value => validator.isInstance(value, MySubClass).should.be.false);
30163054
});
30173055

30183056
it("should return error object with proper data", function(done) {
3019-
const validationType = "arrayUnique";
3020-
const message = "All someProperty's elements must be unique";
3057+
const validationType = "isInstance";
3058+
const message = "someProperty must be an instance of MySubClass";
30213059
checkReturnedError(new MyClass(), invalidValues, validationType, message, done);
30223060
});
30233061

0 commit comments

Comments
 (0)