Budibase is an open-source low-code platform for creating internal apps in minutes. Supports PostgreSQL, MySQL, MSSQL, MongoDB, Rest API, Docker, K8s 🚀
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

85 lines
2.3 KiB

import { map, reduce, filter, isEmpty, flatten, each, union } from "lodash/fp";
import { compileCode } from "../common/compileCode";
import {
validateFieldParse,
validateTypeConstraints,
} from "../schema/types/index.js"
import { $, isNonEmptyString } from "../common/index.js"
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
),
}
}