Skip to content

Commit 4eb1216

Browse files
authored
fix: pass context to ValidationError for async validations (#533)
1 parent 2012d72 commit 4eb1216

File tree

2 files changed

+62
-17
lines changed

2 files changed

+62
-17
lines changed

Diff for: src/validation/ValidationExecutor.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export class ValidationExecutor {
182182
}
183183

184184
this.defaultValidations(object, value, metadatas, validationError.constraints);
185-
this.customValidations(object, value, customValidationMetadatas, validationError.constraints);
185+
this.customValidations(object, value, customValidationMetadatas, validationError);
186186
this.nestedValidations(value, nestedValidationMetadatas, validationError.children);
187187

188188
this.mapContexts(object, value, metadatas, validationError);
@@ -244,7 +244,7 @@ export class ValidationExecutor {
244244
private customValidations(object: Object,
245245
value: any,
246246
metadatas: ValidationMetadata[],
247-
errorMap: { [key: string]: string }) {
247+
error: ValidationError) {
248248

249249
metadatas.forEach(metadata => {
250250
this.metadataStorage
@@ -267,14 +267,20 @@ export class ValidationExecutor {
267267
const promise = validatedValue.then(isValid => {
268268
if (!isValid) {
269269
const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
270-
errorMap[type] = message;
270+
error.constraints[type] = message;
271+
if (metadata.context) {
272+
if (!error.contexts) {
273+
error.contexts = {};
274+
}
275+
error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
276+
}
271277
}
272278
});
273279
this.awaitingPromises.push(promise);
274280
} else {
275281
if (!validatedValue) {
276282
const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
277-
errorMap[type] = message;
283+
error.constraints[type] = message;
278284
}
279285
}
280286

@@ -297,7 +303,13 @@ export class ValidationExecutor {
297303
const validationResult = flatValidatedValues.every((isValid: boolean) => isValid);
298304
if (!validationResult) {
299305
const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
300-
errorMap[type] = message;
306+
error.constraints[type] = message;
307+
if (metadata.context) {
308+
if (!error.contexts) {
309+
error.contexts = {};
310+
}
311+
error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
312+
}
301313
}
302314
});
303315

@@ -309,7 +321,7 @@ export class ValidationExecutor {
309321
const validationResult = validatedSubValues.every((isValid: boolean) => isValid);
310322
if (!validationResult) {
311323
const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
312-
errorMap[type] = message;
324+
error.constraints[type] = message;
313325
}
314326
});
315327
});

Diff for: test/functional/custom-decorators.spec.ts

+44-11
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,39 @@ describe("custom decorators", function() {
4141
const relatedValue = (args.object as any)[relatedPropertyName];
4242
if (relatedValue === undefined || relatedValue === null)
4343
return true;
44-
45-
return typeof value === "string" &&
44+
45+
const result = typeof value === "string" &&
4646
typeof relatedValue === "string" &&
4747
value.length > relatedValue.length;
48+
49+
const asPromise = validationOptions &&
50+
validationOptions.context &&
51+
validationOptions.context.promise;
52+
53+
return asPromise ? Promise.resolve(result) : result;
4854
}
4955
}
5056
});
5157
};
5258
}
53-
59+
5460
class MyClass {
5561
@IsLongerThan("lastName", {
62+
context: { foo: "bar"},
5663
message: "$property must be longer then $constraint1. Given value: $value"
5764
})
5865
firstName: string;
59-
66+
67+
lastName: string;
68+
}
69+
70+
class MyClassWithAsyncValidator {
71+
@IsLongerThan("lastName", {
72+
context: { foo: "bar", promise: true},
73+
message: "$property must be longer then $constraint1. Given value: $value"
74+
})
75+
firstName: string;
76+
6077
lastName: string;
6178
}
6279

@@ -87,9 +104,25 @@ describe("custom decorators", function() {
87104
errors[0].constraints.should.be.eql({ isLongerThan: "firstName must be longer then lastName. Given value: Li" });
88105
});
89106
});
90-
107+
108+
it("should include context", function() {
109+
const model = new MyClass();
110+
const asyncModel = new MyClassWithAsyncValidator();
111+
model.firstName = asyncModel.firstName = "Paul";
112+
model.lastName = asyncModel.lastName = "Walker";
113+
114+
return validator.validate(model).then(errors => {
115+
errors.length.should.be.equal(1);
116+
errors[0].contexts.should.be.eql({ isLongerThan: { foo: "bar" } });
117+
118+
return validator.validate(asyncModel).then(errors => {
119+
errors.length.should.be.equal(1);
120+
errors[0].contexts.should.have.nested.property("isLongerThan.foo", "bar");
121+
});
122+
});
123+
});
91124
});
92-
125+
93126
describe("decorator with default message", function() {
94127

95128
function IsLonger(property: string, validationOptions?: ValidationOptions) {
@@ -106,7 +139,7 @@ describe("custom decorators", function() {
106139
const relatedValue = (args.object as any)[relatedPropertyName];
107140
if (relatedValue === undefined || relatedValue === null)
108141
return true;
109-
142+
110143
return typeof value === "string" &&
111144
typeof relatedValue === "string" &&
112145
value.length > relatedValue.length;
@@ -118,11 +151,11 @@ describe("custom decorators", function() {
118151
});
119152
};
120153
}
121-
154+
122155
class SecondClass {
123156
@IsLonger("lastName")
124157
firstName: string;
125-
158+
126159
lastName: string;
127160
}
128161

@@ -153,7 +186,7 @@ describe("custom decorators", function() {
153186
errors[0].constraints.should.be.eql({ isLonger: "firstName must be longer then lastName" });
154187
});
155188
});
156-
189+
157190
});
158191

159192
describe("decorator with separate validation constraint class", function() {
@@ -166,7 +199,7 @@ describe("custom decorators", function() {
166199
const relatedValue = (args.object as any)[relatedPropertyName];
167200
if (value === null || value === undefined)
168201
return true;
169-
202+
170203
return typeof value === "string" &&
171204
typeof relatedValue === "string" &&
172205
value.length < relatedValue.length;

0 commit comments

Comments
 (0)