/** * @fileoverview Schema validation for entities * @file schema.js * @license Apache-2.0 * @version 3.0.0 * * @author Michael Hay <michael.hay@mediumroast.io> * @copyright 2025 Mediumroast, Inc. All rights reserved. */ // Add this import at the top of the file import { isEmpty, isArray } from '../../utils/helpers.js'; export class SchemaValidator { constructor(schemas = {}) { this.schemas = schemas; } /** * Add or update schema * @param {string} entityType - Entity type * @param {Object} schema - Schema definition */ setSchema(entityType, schema) { this.schemas[entityType] = schema; } /** * Validate object against schema * @param {string} entityType - Entity type * @param {Object} obj - Object to validate * @returns {Object} Validation result {valid, errors} */ validate(entityType, obj) { const schema = this.schemas[entityType]; if (!schema) { return { valid: true, errors: [] }; // No schema defined } const errors = []; // Check required fields if (schema.required) { for (const field of schema.required) { if (isEmpty(obj[field])) { errors.push(`Required field [${field}] is missing`); } } } // Check field types if (schema.properties) { for (const [field, def] of Object.entries(schema.properties)) { if (obj[field] !== undefined) { if (def.type === 'string' && typeof obj[field] !== 'string') { errors.push(`Field [${field}] must be a string`); } else if (def.type === 'number' && typeof obj[field] !== 'number') { errors.push(`Field [${field}] must be a number`); } else if (def.type === 'boolean' && typeof obj[field] !== 'boolean') { errors.push(`Field [${field}] must be a boolean`); } else if (def.type === 'array' && !isArray(obj[field])) { errors.push(`Field [${field}] must be an array`); } else if (def.type === 'object' && (typeof obj[field] !== 'object' || obj[field] === null)) { errors.push(`Field [${field}] must be an object`); } // Check enum values if (def.enum && !def.enum.includes(obj[field])) { errors.push(`Field [${field}] must be one of: ${def.enum.join(', ')}`); } // Check pattern if (def.pattern && typeof obj[field] === 'string') { const regex = new RegExp(def.pattern); if (!regex.test(obj[field])) { errors.push(`Field [${field}] does not match required pattern`); } } } } } return { valid: errors.length === 0, errors }; } } // Define schemas const schemas = { Companies: { required: ['name'], properties: { name: { type: 'string' }, company_type: { type: 'string', enum: ['Public', 'Private', 'Non-profit', 'Government', 'Educational'] }, status: { type: 'string', enum: ['Active', 'Inactive', 'Acquired', 'Merged', 'Bankrupt'] }, url: { type: 'string', pattern: '^https?://.+' } // Other fields... } }, Interactions: { required: ['name'], properties: { name: { type: 'string' }, content_type: { type: 'string', enum: ['PDF', 'DOC', 'DOCX', 'TXT', 'HTML', 'PPT', 'PPTX', 'XLS', 'XLSX', 'CSV'] }, status: { type: 'string', enum: ['Draft', 'Published', 'Archived'] }, public: { type: 'boolean' } // Other fields... } }, Studies: { required: ['name'], properties: { name: { type: 'string' }, status: { type: 'string', enum: ['Active', 'Completed', 'Cancelled'] }, public: { type: 'boolean' } // Other fields... } } }; // Create and export validator instance export const validator = new SchemaValidator(schemas);