adds pattern for sanitizing field configs which adds validations all in one place

This commit is contained in:
James
2020-04-18 12:13:56 -04:00
parent b61239507f
commit ee7788be6b
8 changed files with 46 additions and 8 deletions

View File

@@ -0,0 +1,118 @@
const { Schema } = require('mongoose');
const formatBaseSchema = (field) => {
return {
hide: field.hide || false,
localized: field.localized || false,
unique: field.unique || false,
required: (field.required && !field.localized) || false,
default: field.defaultValue || undefined,
};
};
const fieldToSchemaMap = {
number: (field) => {
return { ...formatBaseSchema(field), type: Number };
},
text: (field) => {
return { ...formatBaseSchema(field), type: String };
},
email: (field) => {
return { ...formatBaseSchema(field), type: String };
},
textarea: (field) => {
return { ...formatBaseSchema(field), type: String };
},
wysiwyg: (field) => {
return { ...formatBaseSchema(field), type: String };
},
code: (field) => {
return { ...formatBaseSchema(field), type: String };
},
checkbox: (field) => {
return { ...formatBaseSchema(field), type: Boolean };
},
date: (field) => {
return {
...formatBaseSchema(field),
type: Date,
};
},
upload: (field, config) => {
const schema = {
...formatBaseSchema(field),
type: Schema.Types.ObjectId,
autopopulate: true,
ref: config.upload.labels.singular,
};
return schema;
},
relationship: (field) => {
let schema = {};
if (Array.isArray(field.relationTo)) {
schema.value = {
type: Schema.Types.ObjectId,
autopopulate: true,
refPath: `${field.name}${field.localized ? '.{{LOCALE}}' : ''}.relationTo`,
};
schema.relationTo = { type: String, enum: field.relationTo };
} else {
schema = {
...formatBaseSchema(field),
};
schema.type = Schema.Types.ObjectId;
schema.autopopulate = true;
schema.ref = field.relationTo;
}
if (field.hasMany) {
return {
type: [schema],
localized: field.localized,
};
}
return schema;
},
repeater: (field) => {
const schema = {};
field.fields.forEach((subField) => {
schema[subField.name] = fieldToSchemaMap[subField.type](subField);
});
return [schema];
},
group: (field) => {
// Localization for groups not supported
const schema = {};
field.fields.forEach((subField) => {
schema[subField.name] = fieldToSchemaMap[subField.type](subField);
});
return schema;
},
select: (field) => {
const schema = {
...formatBaseSchema(field),
type: String,
enum: field.options.map((option) => {
if (typeof option === 'object') return option.value;
return option;
}),
};
return field.hasMany ? [schema] : schema;
},
flexible: (field) => {
const flexibleSchema = new Schema({ blockName: String }, { discriminatorKey: 'blockType', _id: false });
return {
type: [flexibleSchema],
localized: field.localized || false,
};
},
};
module.exports = fieldToSchemaMap;

View File

19
src/fields/sanitize.js Normal file
View File

@@ -0,0 +1,19 @@
const { MissingFieldType } = require('../errors');
const validations = require('./validations');
const sanitizeFields = (fields) => {
return fields.map((unsanitizedField) => {
const field = { ...unsanitizedField };
if (!field.type) throw new MissingFieldType(field);
if (typeof field.validation === 'undefined') {
field.validation = validations[field.type];
}
return field;
});
};
module.exports = sanitizeFields;

35
src/fields/validations.js Normal file
View File

@@ -0,0 +1,35 @@
const fieldToValidatorMap = {
number: (field, value) => {
const parsedValue = parseInt(value, 10);
if (typeof parsedValue !== 'number') return false;
if (field.max && parsedValue > field.max) return false;
if (field.min && parsedValue < field.min) return false;
return true;
},
text: (field, value) => {
if (field.maxLength && value.length > field.maxLength) return false;
if (field.minLength && value.length < field.minLength) return false;
return true;
},
email: value => /\S+@\S+\.\S+/.test(value),
textarea: (field, value) => {
if (field.maxLength && value.length > field.maxLength) return false;
if (field.minLength && value.length < field.minLength) return false;
return true;
},
wysiwyg: value => (!!value),
code: value => (!!value),
checkbox: value => Boolean(value),
date: value => value instanceof Date,
upload: value => (!!value),
relationship: value => (!!value),
repeater: value => (!!value),
select: value => (!!value),
flexible: value => (!!value),
};
module.exports = fieldToValidatorMap;