forked from tsai/budibase
5 changed files with 148 additions and 8 deletions
@ -0,0 +1,86 @@ |
|||
const { map, reduce, filter, isEmpty, flatten, each, union } = require("lodash/fp"); |
|||
const { compileCode } = require("../common/compileCode"); |
|||
const { validateFieldParse, validateTypeConstraints } = require("../schema/types"); |
|||
import { |
|||
validateFieldParse, |
|||
validateTypeConstraints, |
|||
} from "../schema/types/index.js" |
|||
import { $, isNonEmptyString } from "../common/index.mjs" |
|||
|
|||
const fieldParseError = (fieldName, value) => ({ |
|||
fields: [fieldName], |
|||
message: `Could not parse field ${fieldName}:${value}`, |
|||
}) |
|||
|
|||
const validateAllFieldParse = (record, model) => |
|||
$(model.fields, [ |
|||
map(f => ({ name: f.name, parseResult: validateFieldParse(f, record) })), |
|||
reduce((errors, f) => { |
|||
if (f.parseResult.success) return errors |
|||
errors.push(fieldParseError(f.name, f.parseResult.value)) |
|||
return errors |
|||
}, []), |
|||
]) |
|||
|
|||
const validateAllTypeConstraints = (record, model) => { |
|||
const errors = [] |
|||
for (const field of model.fields) { |
|||
$(validateTypeConstraints(field, record), [ |
|||
filter(isNonEmptyString), |
|||
map(m => ({ message: m, fields: [field.name] })), |
|||
each(e => errors.push(e)), |
|||
]) |
|||
} |
|||
return errors |
|||
} |
|||
|
|||
const runRecordValidationRules = (record, model) => { |
|||
const runValidationRule = rule => { |
|||
const isValid = compileCode(rule.expressionWhenValid) |
|||
const expressionContext = { record } |
|||
return isValid(expressionContext) |
|||
? { valid: true } |
|||
: { |
|||
valid: false, |
|||
fields: rule.invalidFields, |
|||
message: rule.messageWhenInvalid, |
|||
} |
|||
} |
|||
|
|||
return $(model.validationRules, [ |
|||
map(runValidationRule), |
|||
flatten, |
|||
filter(r => r.valid === false), |
|||
map(r => ({ fields: r.fields, message: r.message })), |
|||
]) |
|||
} |
|||
|
|||
export const validateRecord = (schema, record) => { |
|||
const model = schema.findModel(record._modelId) |
|||
const fieldParseFails = validateAllFieldParse(record, model) |
|||
|
|||
// non parsing would cause further issues - exit here
|
|||
if (!isEmpty(fieldParseFails)) { |
|||
return { isValid: false, errors: fieldParseFails } |
|||
} |
|||
|
|||
const recordValidationRuleFails = runRecordValidationRules(record, model) |
|||
const typeContraintFails = validateAllTypeConstraints(record, model) |
|||
|
|||
if ( |
|||
isEmpty(fieldParseFails) && |
|||
isEmpty(recordValidationRuleFails) && |
|||
isEmpty(typeContraintFails) |
|||
) { |
|||
return { isValid: true, errors: [] } |
|||
} |
|||
|
|||
return { |
|||
isValid: false, |
|||
errors: union( |
|||
fieldParseFails, |
|||
typeContraintFails, |
|||
recordValidationRuleFails |
|||
), |
|||
} |
|||
} |
|||
Loading…
Reference in new issue