Files
adopt-a-street/backend/utils/modelErrors.js
William Valentin 07a80b718b feat: complete Post model standardized error handling
- Add comprehensive error handling to Post model with ValidationError, NotFoundError
- Fix Post model toJSON method duplicate type field bug
- Update Post test suite with proper mocking for all CouchDB service methods
- All 23 Post model tests now passing
- Complete standardized error handling implementation for User, Report, and Post models
- Add modelErrors utility with structured error classes and logging

🤖 Generated with AI Assistant

Co-Authored-By: AI Assistant <noreply@ai-assistant.com>
2025-11-03 09:43:46 -08:00

145 lines
3.7 KiB
JavaScript

/**
* Standardized error classes and utilities for model operations
* Provides consistent error handling across all models
*/
class ModelError extends Error {
constructor(message, code = 'MODEL_ERROR', context = {}) {
super(message);
this.name = 'ModelError';
this.code = code;
this.context = context;
this.timestamp = new Date().toISOString();
}
toJSON() {
return {
name: this.name,
message: this.message,
code: this.code,
context: this.context,
timestamp: this.timestamp
};
}
}
class ValidationError extends ModelError {
constructor(message, field = null, value = null) {
super(message, 'VALIDATION_ERROR', { field, value });
this.name = 'ValidationError';
}
}
class NotFoundError extends ModelError {
constructor(resource, id = null) {
const message = id ? `${resource} with id '${id}' not found` : `${resource} not found`;
super(message, 'NOT_FOUND', { resource, id });
this.name = 'NotFoundError';
}
}
class DatabaseError extends ModelError {
constructor(operation, originalError) {
const message = `Database operation '${operation}' failed: ${originalError.message}`;
super(message, 'DATABASE_ERROR', {
operation,
originalError: originalError.message,
stack: originalError.stack
});
this.name = 'DatabaseError';
}
}
class DuplicateError extends ModelError {
constructor(resource, field, value) {
const message = `${resource} with ${field} '${value}' already exists`;
super(message, 'DUPLICATE_ERROR', { resource, field, value });
this.name = 'DuplicateError';
}
}
class AuthenticationError extends ModelError {
constructor(message = 'Authentication failed') {
super(message, 'AUTHENTICATION_ERROR');
this.name = 'AuthenticationError';
}
}
class AuthorizationError extends ModelError {
constructor(action = 'perform this action') {
super(`Not authorized to ${action}`, 'AUTHORIZATION_ERROR');
this.name = 'AuthorizationError';
}
}
/**
* Error logging utility with context
*/
function logModelError(error, operation, model, additionalContext = {}) {
const errorInfo = {
timestamp: new Date().toISOString(),
model,
operation,
error: {
name: error.name,
message: error.message,
code: error.code,
context: error.context
},
...additionalContext
};
console.error(`[MODEL_ERROR] ${model}.${operation}:`, errorInfo);
// In production, you might want to send this to a logging service
if (process.env.NODE_ENV === 'production') {
// Production logging logic here
console.error('Production error logged:', JSON.stringify(errorInfo, null, 2));
}
}
/**
* Wrapper for async model operations with consistent error handling
*/
async function withErrorHandling(operation, errorContext) {
try {
return await operation();
} catch (error) {
// Always log the error for debugging
logModelError(error, errorContext.operation, errorContext.model, errorContext);
// If it's already one of our custom errors, just rethrow
if (error instanceof ModelError) {
throw error;
}
// For backward compatibility, rethrow the original error
// This ensures existing tests and code continue to work
throw error;
}
}
/**
* Create error context object for consistent logging
*/
function createErrorContext(model, operation, additional = {}) {
return {
model,
operation,
timestamp: new Date().toISOString(),
...additional
};
}
module.exports = {
ModelError,
ValidationError,
NotFoundError,
DatabaseError,
DuplicateError,
AuthenticationError,
AuthorizationError,
logModelError,
withErrorHandling,
createErrorContext
};