Skip to content

Commit

Permalink
fix "context" for custom validators
Browse files Browse the repository at this point in the history
  • Loading branch information
Christoph Linder committed Nov 13, 2018
1 parent 3907863 commit 86079d8
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/metadata/ValidationMetadataArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,10 @@ export interface ValidationMetadataArgs {
* Extra options specific to validation type.
*/
validationTypeOptions?: any;

/**
* A transient set of data passed through to the validation result for response mapping
*/
context?: any;

}
12 changes: 10 additions & 2 deletions src/register-decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,18 @@ export interface ValidationDecoratorOptions {
*/
export function registerDecorator(options: ValidationDecoratorOptions): void {

let name;
let constraintCls: Function;
if (options.validator instanceof Function) {
constraintCls = options.validator as Function;
const constraintClasses = getFromContainer(MetadataStorage).getTargetValidatorConstraints(options.validator);
if (constraintClasses.length !== 1) {
throw `More than one implementation of ValidatorConstraintInterface found for validator on: ${options.target}:${options.propertyName}`;
}
name = options.name || constraintClasses[0].name;
} else {
const validator = options.validator as ValidatorConstraintInterface;
name = options.name;
constraintCls = class CustomConstraint implements ValidatorConstraintInterface {
validate(value: any, validationArguments?: ValidationArguments): Promise<boolean>|boolean {
return validator.validate(value, validationArguments);
Expand All @@ -73,12 +80,13 @@ export function registerDecorator(options: ValidationDecoratorOptions): void {
}

const validationMetadataArgs: ValidationMetadataArgs = {
type: ValidationTypes.CUSTOM_VALIDATION,
type: name || ValidationTypes.CUSTOM_VALIDATION,
target: options.target,
propertyName: options.propertyName,
validationOptions: options.options,
constraintCls: constraintCls,
constraints: options.constraints
constraints: options.constraints,
context: (options.options || {}).context
};
getFromContainer(MetadataStorage).addValidationMetadata(new ValidationMetadata(validationMetadataArgs));
}
24 changes: 17 additions & 7 deletions src/validation/ValidationExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class ValidationExecutor {
/**
* If there is no metadata registered it means possibly the dependencies are not flatterned and
* more than one instance is used.
*
*
* TODO: This needs proper handling, forcing to use the same container or some other proper solution.
*/
if (!this.metadataStorage.hasValidationMetaData) {
Expand All @@ -60,29 +60,39 @@ export class ValidationExecutor {
if (!this.validatorOptions ||
!this.validatorOptions.validationError ||
this.validatorOptions.validationError.target === undefined ||
this.validatorOptions.validationError.target === true)
this.validatorOptions.validationError.target === true) {
validationError.target = object;
}

validationError.value = undefined;
validationError.property = undefined;
validationError.children = [];
validationError.constraints = { unknownValue: "an unknown value was passed to the validate function" };
validationError.constraints = {unknownValue: "an unknown value was passed to the validate function"};

validationErrors.push(validationError);

return;
}

if (this.validatorOptions && this.validatorOptions.whitelist)
if (this.validatorOptions && this.validatorOptions.whitelist) {
this.whitelist(object, groupedMetadatas, validationErrors);
}

const PREDEFINED_VALIDATION_TYPES = [
ValidationTypes.NESTED_VALIDATION,
ValidationTypes.CONDITIONAL_VALIDATION,
ValidationTypes.WHITELIST,
ValidationTypes.IS_DEFINED
];

// General validation
Object.keys(groupedMetadatas).forEach(propertyName => {

const value = (object as any)[propertyName];
const definedMetadatas = groupedMetadatas[propertyName].filter(metadata => metadata.type === ValidationTypes.IS_DEFINED);
const metadatas = groupedMetadatas[propertyName].filter(
metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST);
const customValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CUSTOM_VALIDATION);
metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST);
const customValidationMetadatas = metadatas.filter(metadata => PREDEFINED_VALIDATION_TYPES.indexOf(metadata.type) === -1);
const nestedValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.NESTED_VALIDATION);
const conditionalValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CONDITIONAL_VALIDATION);

Expand Down Expand Up @@ -128,7 +138,7 @@ export class ValidationExecutor {
notAllowedProperties.forEach(property => {
validationErrors.push({
target: object, property, value: (object as any)[property], children: undefined,
constraints: { [ValidationTypes.WHITELIST]: `property ${property} should not exist` }
constraints: {[ValidationTypes.WHITELIST]: `property ${property} should not exist`}
});
});

Expand Down
7 changes: 6 additions & 1 deletion src/validation/ValidatorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ export interface ValidatorOptions {
*/
forbidUnknownValues?: boolean;

}
/**
* A transient set of data passed through to the validation result for response mapping
*/
context?: any;

}

0 comments on commit 86079d8

Please sign in to comment.