const {Schema, model} = require('mongoose');
/**
* Utility class for validating and handling MongoDB schemas in the application.
*/
class ValidateSchema {
/**
* Constructs a ValidateSchema instance based on the provided rules.
* @param {string|Object} rules - A string indicating the collection name to use as schema,
* or an object specifying the Mongoose schema configurations.
* @throws {Error} - Throws an error if the provided rules are invalid or the collection name is not found.
*/
constructor(rules) {
const schemas = API.database.collections;
// Initializing the schema
if (Boolean.isValid(rules).stringFilled()) {
const collection = schemas.find(item => item.name === rules.valueOf());
// If the rules provided is a string with the collection name, and this collection name is a valid name. It will use it as schema.
if (collection) {
this.ModelDB = collection.DB
this._schema = collection.schema;
} else {
throw new Error.Log('common.request_model_schema_not_found', rules);
}
}
if (Boolean.isValid(rules).objectFilled() && !(rules instanceof String)) {
// If the rules provided is an object with the mongoose schema configurations, then it will create a internal schema for the request.
try {
Object.keys(rules).map(key => {
const current = rules[key];
const collection = Boolean.isValid(current).path('collection').stringFilled();
const loadedSchema = collection && Boolean.isValid(schemas).path(collection + '.schema').objectFilled();
if (loadedSchema) {
rules[key].type = loadedSchema;
}
});
this._schema = new Schema(rules, {autoCreate: false, autoIndex: false});
} catch(err) {
throw new Error.Log(err).append('common.request_creating_custom_schema');
}
}
}
/**
* Validates the provided data against the schema and returns the validation result.
* @param {Object} data - The data to be validated against the schema.
* @param {boolean} [returnValidObj=false] - A flag indicating whether to return the validated object.
* @returns {ValidationError|Object} - If `returnValidObj` is true, returns the validated object.
* Otherwise, returns the validation error object.
*/
validate(data, returnValidObj) {
if (!this._schema) return;
if (this.ModelDB) {
this.validObj = new this.ModelDB(data || this);
} else {
const Model = model('ValidateModel', this._schema, null, {overwriteModels: true});
this.validObj = new Model(data || this);
}
this.validationResult = this.validObj.validateSync();
if (returnValidObj) return this.validObj;
return this.validationResult;
}
/**
* Populates the schema fields with their default values if not provided in the input object.
* @param {Object} [customSelf] - The custom object to be populated (optional, uses the instance itself by default).
* @returns {Object} - The populated object with default values.
*/
placeDefault(customSelf) {
const self = customSelf || this;
Object.entries(this._schema.obj).map(([key, field]) => {
const selfCurrent = self[key];
if (!selfCurrent && field.default){
if (Boolean.isValid(field.default).function().eval()) self[key] = field.default();
else self[key] = field.default;
}
});
return self;
}
}
module.exports = ValidateSchema;