adds pattern for sanitizing field configs which adds validations all in one place
This commit is contained in:
118
src/fields/mongooseSchemaMap.js
Normal file
118
src/fields/mongooseSchemaMap.js
Normal 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;
|
||||
0
src/fields/sanitations.js
Normal file
0
src/fields/sanitations.js
Normal file
19
src/fields/sanitize.js
Normal file
19
src/fields/sanitize.js
Normal 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
35
src/fields/validations.js
Normal 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;
|
||||
Reference in New Issue
Block a user