From e04661b85cb8940d3e9f4d7c5857951303a6803d Mon Sep 17 00:00:00 2001 From: isierra Date: Thu, 10 Nov 2016 19:02:48 +0100 Subject: [PATCH] fix: Renamed combineResults to collectResults fix: Added combineResults for objects --- package.json | 2 +- src/ValidationResult.spec.ts | 331 +++++------------------------------ src/ValidationResult.ts | 46 ++--- src/ValidatorBuilder.ts | 4 +- 4 files changed, 65 insertions(+), 318 deletions(-) diff --git a/package.json b/package.json index 92dd82c..5daa6b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rxvalidation", - "version": "0.1.3", + "version": "0.1.4", "description": "Async validation framework", "engines": { "node": ">=6.9", diff --git a/src/ValidationResult.spec.ts b/src/ValidationResult.spec.ts index f3864e4..e973861 100644 --- a/src/ValidationResult.spec.ts +++ b/src/ValidationResult.spec.ts @@ -9,7 +9,7 @@ import { successResult, messageResult, inconclusiveResult, errorResult, collectionResult, objectResult, propertiesResult, getWorstType, - reduceCollection, combineResults, + reduceCollection, collectResults, combineResults, } from "./index"; describe("successResult", () => { @@ -408,6 +408,45 @@ describe("reduceCollection", () => { [err], propertiesResult({ succ, msg, inc, err }), [err, propertiesResult({ succ, msg, inc, err })]); }); // reduceCollection +describe("collectResults", () => { + describe("Sanity checks", () => { + it("it should be a function", + () => expect(typeof collectResults).toBe("function")); + }); // Sanity checks + + const testCollectResults = ( + aname: string, bname: string, + a: ValidationResult[], b: ValidationResult) => + describe(`Given a ${aname} results`, () => { + describe(`When they are collected as results`, () => { + it(`it should be reduced to ${bname}`, + () => expect(collectResults(a)).toEqual(b)); + }); // When it is reduced with ${bname} result + }); + + const succ = successResult(); + const msg = messageResult("Hint"); + const msg2 = messageResult("Hint #2"); + const err = errorResult("Error"); + const err2 = errorResult("Error #2"); + const inc = inconclusiveResult("Inconclusive"); + const inc2 = inconclusiveResult("Inconclusive #2"); + const coll = collectionResult([err, msg]); + const coll2 = collectionResult([inc2, msg2]); + + testCollectResults("empty", "success", [], succ); + testCollectResults("[succ]", "success", [succ], succ); + testCollectResults("[succ, succ]", "success", [succ, succ], succ); + testCollectResults("[succ, message, succ]", "message", [succ, msg, succ], msg); + testCollectResults("[succ, inconclusive, succ]", "inconclusive", [succ, inc, succ], inc); + testCollectResults("[succ, error, succ]", "error", [succ, err, succ], err); + testCollectResults("[msg, msg]", "message", [msg, msg], msg); + testCollectResults("[msg, msg2]", "[msg, msg2]", [msg, msg2], collectionResult([msg, msg2])); + testCollectResults("[err, err]", "message", [err, err], err); + testCollectResults("[err, err2]", "[err, err2]", [err, err2], collectionResult([err, err2])); + testCollectResults("[msg, succ, err]", "[msg, err]", [msg, succ, err], collectionResult([msg, err])); +}); // reduceCollection + describe("combineResults", () => { describe("Sanity checks", () => { it("it should be a function", @@ -416,10 +455,11 @@ describe("combineResults", () => { const testCombineResults = ( aname: string, bname: string, - a: ValidationResult[], b: ValidationResult) => + a: { [key: string]: ValidationResult }, b: ValidationResult) => describe(`Given a ${aname} results`, () => { describe(`When it is combine as result`, () => { - it(`it should be reduced to ${bname}`, () => expect(combineResults(a)).toEqual(b)); + it(`it should be reduced to ${bname}`, + () => expect(combineResults(a)).toEqual(b)); }); // When it is reduced with ${bname} result }); @@ -433,284 +473,9 @@ describe("combineResults", () => { const coll = collectionResult([err, msg]); const coll2 = collectionResult([inc2, msg2]); - testCombineResults("empty", "success", [], succ); - testCombineResults("[succ]", "success", [succ], succ); - testCombineResults("[succ, succ]", "success", [succ, succ], succ); - testCombineResults("[succ, message, succ]", "message", [succ, msg, succ], msg); - testCombineResults("[succ, inconclusive, succ]", "inconclusive", [succ, inc, succ], inc); - testCombineResults("[succ, error, succ]", "error", [succ, err, succ], err); - testCombineResults("[msg, msg]", "message", [msg, msg], msg); - testCombineResults("[msg, msg2]", "[msg, msg2]", [msg, msg2], collectionResult([msg, msg2])); - testCombineResults("[err, err]", "message", [err, err], err); - testCombineResults("[err, err2]", "[err, err2]", [err, err2], collectionResult([err, err2])); - testCombineResults("[msg, succ, err]", "[msg, err]", [msg, succ, err], collectionResult([msg, err])); + testCombineResults("{}", "success", {}, succ); + testCombineResults("{field:success}", "{field:success}", { field: succ }, propertiesResult({ field: succ })); + testCombineResults("{field1...field4}", "{field1...field4}", + { field1: succ, field2: msg, field3: inc, field4: coll }, + propertiesResult({ field1: succ, field2: msg, field3: inc, field4: coll })); }); // reduceCollection - -// describe("combine", () => { -// describe("Sanity checks", () => { -// it("it should be a function", () => -// expect(typeof combine).toEqual("function")); -// }); // Sanity checks - -// const testCombine = ( -// aname: string, bname: string, cname: string, -// a: ValidationResult, b: ValidationResult, c: ValidationResult -// ) => -// describe(`Given a ${aname} result`, () => { -// describe(`When it is combined with a ${bname} result`, () => { -// it(`it should give a ${cname} result`, -// () => expect(combine(a, b)).toEqual(c)); -// }); // When it is combined with a success result -// }); // Given a success result - -// const succ = successResult(); -// const msg = messageResult("Hint"); -// const msg2 = messageResult("Hint #2"); -// const err = errorResult("Error"); -// const err2 = errorResult("Error #2"); -// const inc = inconclusiveResult("Inconclusive"); -// const inc2 = inconclusiveResult("Inconclusive #2"); -// const coll = collectionResult([err, msg]); -// const coll2 = collectionResult([inc2, msg2]); - -// // Atom + Atom -// testCombine("success", "success", "success", succ, succ, succ); -// testCombine("success", "message", "message", succ, msg, msg); -// testCombine("success", "inconclusive", "inconclusive", succ, inc, inc); -// testCombine("success", "error", "error", succ, err, err); - -// testCombine("message", "success", "message", msg, succ, msg); -// testCombine("message", "message", "message", msg, msg, msg); -// testCombine("message", "message 2", "collection", msg, msg2, collectionResult([msg, msg2])); -// testCombine("message 2", "message", "collection", msg2, msg, collectionResult([msg2, msg])); -// testCombine("message", "inconclusive", "collection", msg, inc, collectionResult([msg, inc])); -// testCombine("message", "error", "collection", msg, err, collectionResult([msg, err])); - -// testCombine("inconclusive", "success", "inconclusive", inc, succ, inc); -// testCombine("inconclusive", "message", "collection", inc, msg, collectionResult([inc, msg])); -// testCombine("inconclusive", "inconclusive", "inconclusive", inc, inc, inc); -// testCombine("inconclusive", "inconclusive 2", "collection", inc, inc2, collectionResult([inc, inc2])); -// testCombine("inconclusive 2", "inconclusive", "collection", inc2, inc, collectionResult([inc2, inc])); -// testCombine("inconclusive", "error", "collection", inc, err, collectionResult([inc, err])); - -// testCombine("error", "success", "error", err, succ, err); -// testCombine("error", "message", "collection", err, msg, collectionResult([err, msg])); -// testCombine("error", "inconclusive", "collection", err, inc, collectionResult([err, inc])); -// testCombine("error", "error", "error", err, err, err); -// testCombine("error", "error 2", "collection", err, err2, collectionResult([err, err2])); -// testCombine("error 2", "error", "collection", err2, err, collectionResult([err2, err])); - -// // Collection + (Atom | Collection) -// testCombine("success", "collection", "collection", succ, coll, coll); -// testCombine("collection", "success", "collection", coll, succ, coll); - -// testCombine("message", "collection", "collection", msg, coll, collectionResult([msg, err])); -// testCombine("message 2", "collection", "combined collection", msg2, coll, collectionResult([msg2, err, msg])); -// testCombine("collection", "message", "collection", coll, msg, coll); -// testCombine("collection", "message 2", "combined collection", coll, msg2, collectionResult([err, msg, msg2])); - -// testCombine("collection", "collection", "collection", coll, coll, coll); -// testCombine("collection", "collection2", "combined collection", coll, coll2, -// collectionResult([err, msg, inc2, msg2])); - -// }); // combine - -// describe("keepErrorsOnly", () => { -// describe("Sanity checks", () => { -// it("it should be a function", () => expect(typeof keepErrorsOnly).toBe("function")); -// }); // Sanity checks - -// describe("Keeping only errors from successful result", () => { -// const current = keepErrorsOnly(successResult()); -// const expected = successResult(); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from successful result - -// describe("Keeping only errors from message result", () => { -// const current = keepErrorsOnly(messageResult("message #1")); -// const expected = successResult(); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from message result - -// describe("Keeping only errors from warning result", () => { -// const current = keepErrorsOnly(messageResult("warning #1")); -// const expected = successResult(); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from warning result - -// describe("Keeping only errors from error result", () => { -// const current = keepErrorsOnly(errorResult("error #1")); -// const expected = errorResult("error #1"); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from error result - -// describe("Keeping only errors from successful collection result", () => { -// const current = keepErrorsOnly(collectionResult([ -// successResult(), -// messageResult("message #1"), -// messageResult("warning #2"), -// ])); -// const expected = successResult(); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from successful collection result - -// describe("Keeping only errors from error collection result", () => { -// describe("When the collection is flat", () => { -// const current = keepErrorsOnly(collectionResult([ -// errorResult("error #1"), -// successResult(), -// messageResult("message #1"), -// messageResult("warning #2"), -// errorResult("error #2"), -// ])); -// const expected = collectionResult([ -// errorResult("error #1"), -// errorResult("error #2"), -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the collection is flat -// describe("When the collection is deep", () => { -// const current = keepErrorsOnly(collectionResult([ -// collectionResult([ -// errorResult("error #1"), -// successResult(), -// messageResult("message #1"), -// messageResult("warning #2"), -// errorResult("error #2"), -// ]), -// successResult(), -// messageResult("message #3"), -// messageResult("warning #4"), -// errorResult("error #5"), -// collectionResult([ -// successResult(), -// messageResult("message #6"), -// messageResult("warning #7"), -// ]), -// ])); -// const expected = collectionResult([ -// collectionResult([ -// errorResult("error #1"), -// errorResult("error #2"), -// ]), -// errorResult("error #5"), -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the collection is flat -// describe("When the collection has only errors", () => { -// const current = keepErrorsOnly(collectionResult([ -// errorResult("error #1"), -// collectionResult([ -// errorResult("error #2"), -// errorResult("error #3"), -// ]), -// errorResult("error #4"), -// ])); -// const expected = collectionResult([ -// errorResult("error #1"), -// collectionResult([ -// errorResult("error #2"), -// errorResult("error #3"), -// ]), -// errorResult("error #4"), -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the collection is flat -// }); // Keeping only errors from error collection result - -// describe("Keeping only errors from successful object result", () => { -// const current = keepErrorsOnly(objectResult([ -// { property: "prop2", result: successResult() }, -// { property: "prop3", result: messageResult("message #1") }, -// { property: "prop4", result: messageResult("warning #2") }, -// ])); -// const expected = successResult(); -// it("it should give success", -// () => expect(current).toEqual(expected)); -// }); // Keeping only errors from successful object result - -// describe("Keeping only errors from error object result", () => { -// describe("When the object is flat", () => { -// const current = keepErrorsOnly(objectResult([ -// { property: "prop1", result: errorResult("error #1") }, -// { property: "prop2", result: successResult() }, -// { property: "prop3", result: messageResult("message #1") }, -// { property: "prop4", result: messageResult("warning #2") }, -// { property: "prop5", result: errorResult("error #2") }, -// ])); -// const expected = objectResult([ -// { property: "prop1", result: errorResult("error #1") }, -// { property: "prop5", result: errorResult("error #2") }, -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the object is flat -// describe("When the object is deep", () => { -// const current = keepErrorsOnly(objectResult([ -// { -// property: "prop1", result: objectResult([ -// { property: "prop2", result: errorResult("error #1") }, -// { property: "prop3", result: successResult() }, -// { property: "prop4", result: messageResult("message #1") }, -// { property: "prop5", result: messageResult("warning #2") }, -// { property: "prop6", result: errorResult("error #2") }, -// ]), -// }, -// { property: "prop7", result: successResult() }, -// { property: "prop8", result: messageResult("message #3") }, -// { property: "prop9", result: messageResult("warning #4") }, -// { property: "prop10", result: errorResult("error #5") }, -// { -// property: "prop11", result: objectResult([ -// { property: "prop12", result: successResult() }, -// { property: "prop13", result: messageResult("message #6") }, -// { property: "prop14", result: messageResult("warning #7") }, -// ]), -// }, -// ])); -// const expected = objectResult([ -// { -// property: "prop1", result: objectResult([ -// { property: "prop2", result: errorResult("error #1") }, -// { property: "prop6", result: errorResult("error #2") }, -// ]), -// }, -// { property: "prop10", result: errorResult("error #5") }, -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the object is flat -// describe("When the object has only errors", () => { -// const current = keepErrorsOnly(objectResult([ -// { property: "prop1", result: errorResult("error #1") }, -// { -// property: "prop2", result: objectResult([ -// { property: "prop3", result: errorResult("error #2") }, -// { property: "prop4", result: errorResult("error #3") }, -// ]), -// }, -// { property: "prop5", result: errorResult("error #4") }, -// ])); -// const expected = objectResult([ -// { property: "prop1", result: errorResult("error #1") }, -// { -// property: "prop2", result: objectResult([ -// { property: "prop3", result: errorResult("error #2") }, -// { property: "prop4", result: errorResult("error #3") }, -// ]), -// }, -// { property: "prop5", result: errorResult("error #4") }, -// ]); -// it("it should give error", -// () => expect(current).toEqual(expected)); -// }); // When the object is flat -// }); // Keeping only errors from error object result -// }); // keepErrorsOnly diff --git a/src/ValidationResult.ts b/src/ValidationResult.ts index 4dd1ee1..7aa6431 100644 --- a/src/ValidationResult.ts +++ b/src/ValidationResult.ts @@ -136,7 +136,9 @@ export const reduceCollection = (results: ValidationResult[], result: Validation } }; -export const combineResults = (results: ValidationResult[]): ValidationResult => { +export const collectResults = ( + results: ValidationResult[] +): ValidationResult => { const reduced = results.reduce(reduceCollection, []); if (reduced.length === 0) { return successResult(); } if (reduced.length === 1) { @@ -145,34 +147,14 @@ export const combineResults = (results: ValidationResult[]): ValidationResult => return collectionResult(reduced); }; -// export const combineWorst = (a: ValidationResult, b: ValidationResult): ValidationResult => { -// return a; -// }; - -// export const keepErrorsOnly = -// (result: ValidationResult): ValidationResult => { -// if (!result.isError) { -// return successResult(); -// } -// if (result.kind === "collection") { -// const errorResults = result.results -// .filter(r => r.isError) -// .map(r => keepErrorsOnly(r)); -// if (errorResults.length === result.results.length) { -// return result; -// } else { -// return collectionResult(errorResults); -// } -// } else if (result.kind === "object") { -// const errorProperties = result.properties -// .filter(p => p.result.isError) -// .map(p => ({ property: p.property, result: keepErrorsOnly(p.result) })); -// if (errorProperties.length === result.properties.length) { -// return result; -// } else { -// return objectResult(errorProperties); -// } -// } else { -// return result; -// } -// }; +export const combineResults = ( + results: { [key: string]: ValidationResult } +): ValidationResult => { + const keys = Object.keys(results); + if (keys.length === 0) { return successResult(); } + const result = objectResult(keys.map(property => { + const vr = results[property]; + return { property, result: vr }; + })); + return result; +}; diff --git a/src/ValidatorBuilder.ts b/src/ValidatorBuilder.ts index b1983bb..5267410 100644 --- a/src/ValidatorBuilder.ts +++ b/src/ValidatorBuilder.ts @@ -13,7 +13,7 @@ import { ValidationResult, PropertyValidation, successResult, messageResult, errorResult, inconclusiveResult, propertiesResult, objectResult, - combineResults, + collectResults, } from "./ValidationResult"; import * as utils from "./internalValidators"; @@ -46,7 +46,7 @@ export const collect = (...validators: Validator[]): Validator => { if (validators.length === 1) { return validators[0]; } return (value: any) => { const validations = validators.map(v => v(value)); - const mapper = (...results: ValidationResult[]) => combineResults(results); + const mapper = (...results: ValidationResult[]) => collectResults(results); return Observable.combineLatest(...validations, mapper); }; };