antonioru / antonioru/deep-waters

POC - Objectizing and enriching validation responses

Đang mở
#3 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
duplicate enhancement
Ngôn ngữ chính
JavaScript
Star
201
Fork
8
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

@antonioru I know your planning to tackle this this weekend. Couldn't get it off my mind and had some free time so heres a proof of concept script.

There's a lot of room for improvement and maybe some optimizations. Hope its helpful. Let me know what you think.
```javascript
/**
* All around functional helpers
*/
const compose = (...funcs) => (...args) => funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args))
const partial = (fn, ...args) => (...rest) => fn(...args, ...rest)

/**
* Function for converting validator function
* boolean results to an object
*/
const objectize = (doc, fn, value) => ({
...doc,
valid: fn(value),
value
})

/**
* When composing many validator function this will
* aggregate into passed and failed results
*/
const aggregateResults = (results) => ({
passed: results.filter(r => r.valid),
failed: results.filter(r => !r.valid)
})

/**
* Some more helpers for composing and/or validations
*/
const applyDoc = (doc) => (result) => ({ ...result, ...doc })
const applyValue = (value) => (result) => ({ ...result, value })
const runValidators = (validators) => (value) => validators.map(validator => validator(value))

/**
* Determines if a result of composed functions
* is valid or not
*/
const orValid = (result) => ({ ...result, valid: result.passed.length > 0 })
const andValid = (result) => ({ ...result, valid: result.failed.length === 0 })

/**
* HOF used to take simple bool validation functions and
* convert to full object style validators
*/
const validator = (fn) => (doc) => partial(objectize, doc, fn)

// const orValidator = (...validators) => (doc) => value => orValid(applyDoc(doc)(aggregateResults(runValidators(validators)(value))))
const orValidator = (...validators) => (doc) => (value) => compose(
runValidators(validators),
aggregateResults,
applyDoc(doc),
applyValue(value),
orValid)(value)

const andValidator = (...validators) => (doc) => (value) => compose(
runValidators(validators),
aggregateResults,
applyDoc(doc),
applyValue(value),
andValid)(value)

/**
* Same as before - bool validator functions. Some of these
* abbreviated for POC sake. Validators that were previously
* composed at this level would now be composed further
* below as validators
*/
const ofClass = (name, value) => Object.prototype.toString.call(value) === `[object ${name}]`
const isFalse = value => value === false
const isZero = value => value === 0
const isNumber = partial(ofClass, 'Number')
const biggerThan = number => value => value > number
const smallerThan = number => value => value < number

/**
* Object style validators composed with
* the core bool validators and descripting
* objects
*/
const isZeroValidator = validator(isZero)({
name: 'isZero'
})

const isFalseValidator = validator(isFalse)({
name: 'isFalse'
})

const isNumberValidator = validator(isNumber)({
name: 'isNumber'
})

const biggerThanValidator = (min) => validator(biggerThan(min))({
name: 'biggerThan',
expected: `number bigger than ${min}`
})

const smallerThanValidator = (max) => validator(smallerThan(max))({
name: 'smallerThan',
expected: `number smaller than ${max}`
})

const isFalsyValidator = orValidator(isZeroValidator, isFalseValidator)({
name: 'isFalsy'
})

const betweenValidator = (min) => (max) => andValidator(biggerThanValidator(min), smallerThanValidator(max))({
name: 'betweenValidator'
})

/**
*
* Some POC Tests :smile:
*
*/

const assert = (condition) => {
if (!condition) throw 'Assertion failed'
}

const isZeroResult = isZeroValidator(0)
console.log('isZeroResult ===>', isZeroResult)
assert(isZeroResult.name === 'isZero')
assert(isZeroResult.valid === true)
assert(isZeroResult.value === 0)

const isFalseResult = isFalseValidator(true)
console.log('isFalseResult ===>', isFalseResult)
assert(isFalseResult.name === 'isFalse')
assert(isFalseResult.valid === false)
assert(isFalseResult.value === true)

const biggerThanResult = biggerThanValidator(10)(50)
console.log('biggerThanResult ===>', biggerThanResult)
assert(biggerThanResult.name === 'biggerThan')
assert(biggerThanResult.valid === true)
assert(biggerThanResult.value === 50)
assert(biggerThanResult.expected === 'number bigger than 10')

const isFalsyResult = isFalsyValidator(0)
console.log('isFalsyResult ===>', isFalsyResult)
assert(isFalsyResult.name === 'isFalsy')
assert(isFalsyResult.valid === true)
assert(isFalsyResult.value === 0)
assert(isFalsyResult.passed[0].name === 'isZero')

const betweenResult = betweenValidator(10)(20)(9)
console.log('betweenResult ===>', betweenResult)
assert(betweenResult.name === 'betweenValidator')
assert(betweenResult.valid === false)
assert(betweenResult.value === 9)
assert(betweenResult.passed[0].name === 'smallerThan')
```

Also, wasn't sure how to share this with you... hope issue is ok 👍❓

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.