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>
This commit is contained in:
145
backend/utils/modelErrors.js
Normal file
145
backend/utils/modelErrors.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
Reference in New Issue
Block a user