qmemory
Version:
A comprehensive production-ready Node.js utility library with MongoDB document operations, user ownership enforcement, Express.js HTTP utilities, environment-aware logging, and in-memory storage. Features 96%+ test coverage with comprehensive error handli
169 lines (155 loc) • 6.18 kB
JavaScript
/**
* Field Naming and Collection Utilities
* Standardized field name normalization and collection name generation
*
* This module provides utilities for consistent field naming conventions and
* automatic collection name derivation, supporting database schema consistency
* and API parameter standardization across the application.
*
* Design philosophy:
* - Consistent naming: Convert between different case conventions automatically
* - Database compatibility: Generate snake_case names for database storage
* - Collection naming: Derive pluralized collection names from function names
* - API standardization: Normalize field names for consistent API responses
*/
/**
* Convert camelCase/PascalCase to snake_case for storage fields
*
* This function transforms JavaScript naming conventions (camelCase, PascalCase)
* into database-friendly snake_case format. Essential for consistent field
* naming when storing data that originates from JavaScript objects.
*
* @param {string} paramName - Field name in camelCase or PascalCase format
* @returns {string} Field name converted to snake_case format
*
* @example
* normalizeFieldName('firstName') // returns 'first_name'
* normalizeFieldName('userID') // returns 'user_i_d'
* normalizeFieldName('createDate') // returns 'create_date'
* normalizeFieldName('isActive') // returns 'is_active'
*/
function normalizeFieldName(paramName) {
if (typeof paramName !== 'string' || !paramName.trim()) {
throw new Error('Parameter name must be a non-empty string');
}
return paramName
.replace(/([A-Z])/g, '_$1')
.toLowerCase()
.replace(/^_/, '');
}
/**
* Derive a pluralized, snake_case collection name from a function name
*
* This function automatically generates appropriate MongoDB collection names
* from function names, following common pluralization rules and snake_case
* conventions. Useful for automatically determining collection names in
* generic database operations.
*
* @param {string} functionName - Function name to derive collection name from
* @returns {string} Pluralized snake_case collection name
*
* @example
* getCollectionName('createUser') // returns 'create_users'
* getCollectionName('findCompany') // returns 'find_companies'
* getCollectionName('listCategory') // returns 'list_categories'
* getCollectionName('getAddress') // returns 'get_addresses'
*/
function getCollectionName(functionName) {
if (typeof functionName !== 'string' || !functionName.trim()) {
throw new Error('Function name must be a non-empty string');
}
const snakeCase = functionName
.replace(/([A-Z])/g, '_$1')
.toLowerCase()
.replace(/^_/, '');
// Handle pluralization rules
if (snakeCase.endsWith('y')) {
return snakeCase.slice(0, -1) + 'ies';
}
if (snakeCase.endsWith('s')) {
return snakeCase;
}
return snakeCase + 's';
}
/**
* Convert snake_case back to camelCase
*
* Utility function for converting database field names back to JavaScript
* naming conventions when retrieving data from storage.
*
* @param {string} snakeCaseName - Field name in snake_case format
* @returns {string} Field name converted to camelCase format
*
* @example
* denormalizeFieldName('first_name') // returns 'firstName'
* denormalizeFieldName('user_id') // returns 'userId'
* denormalizeFieldName('created_at') // returns 'createdAt'
*/
function denormalizeFieldName(snakeCaseName) {
if (typeof snakeCaseName !== 'string' || !snakeCaseName.trim()) {
throw new Error('Snake case name must be a non-empty string');
}
return snakeCaseName.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
}
/**
* Normalize an entire object's field names to snake_case
*
* Recursively processes an object to convert all field names from camelCase
* to snake_case, useful for preparing JavaScript objects for database storage.
*
* @param {Object} obj - Object with camelCase field names
* @returns {Object} Object with snake_case field names
*
* @example
* const input = { firstName: 'John', lastName: 'Doe', userInfo: { isActive: true } };
* normalizeObjectFields(input);
* // returns { first_name: 'John', last_name: 'Doe', user_info: { is_active: true } }
*/
function normalizeObjectFields(obj) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
return obj;
}
const normalized = {};
for (const [key, value] of Object.entries(obj)) {
const normalizedKey = normalizeFieldName(key);
normalized[normalizedKey] = typeof value === 'object' && value !== null && !Array.isArray(value)
? normalizeObjectFields(value)
: value;
}
return normalized;
}
/**
* Denormalize an entire object's field names back to camelCase
*
* Recursively processes an object to convert all field names from snake_case
* back to camelCase, useful for converting database records to JavaScript objects.
*
* @param {Object} obj - Object with snake_case field names
* @returns {Object} Object with camelCase field names
*
* @example
* const input = { first_name: 'John', last_name: 'Doe', user_info: { is_active: true } };
* denormalizeObjectFields(input);
* // returns { firstName: 'John', lastName: 'Doe', userInfo: { isActive: true } }
*/
function denormalizeObjectFields(obj) {
if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
return obj;
}
const denormalized = {};
for (const [key, value] of Object.entries(obj)) {
const denormalizedKey = denormalizeFieldName(key);
denormalized[denormalizedKey] = typeof value === 'object' && value !== null && !Array.isArray(value)
? denormalizeObjectFields(value)
: value;
}
return denormalized;
}
// Export field utilities using object shorthand for clean module interface
module.exports = {
normalizeFieldName, // convert camelCase/PascalCase to snake_case
getCollectionName, // derive pluralized snake_case collection names
denormalizeFieldName, // convert snake_case back to camelCase
normalizeObjectFields, // normalize entire objects to snake_case
denormalizeObjectFields // denormalize entire objects back to camelCase
};