@simonecoelhosfo/optimizely-mcp-server
Version:
Optimizely MCP Server for AI assistants with integrated CLI tools
152 lines • 5.29 kB
JavaScript
/**
* Entity Table Mapper
*
* Handles conversion between entity names (singular) and table names (plural).
* This solves the mismatch between internal entity references and SQL table names.
*
* Examples:
* - Entity: 'flag' -> Table: 'flags'
* - Entity: 'audience' -> Table: 'audiences'
* - Entity: 'flag_environment' -> Table: 'flag_environments'
*/
import { getLogger } from '../../logging/Logger.js';
const logger = getLogger();
export class EntityTableMapper {
// Explicit mappings for irregular plurals and special cases
entityToTableMap = {
'flag': 'flags',
'event': 'events',
'audience': 'audiences',
'attribute': 'attributes',
'variation': 'variations',
'rule': 'rules',
'ruleset': 'rulesets',
'experiment': 'experiments',
'campaign': 'campaigns',
'page': 'pages',
'extension': 'extensions',
'webhook': 'webhooks',
'collaborator': 'collaborators',
'environment': 'environments',
'flag_environment': 'flag_environments',
'project': 'projects',
'group': 'groups',
'list_attribute': 'list_attributes',
'variable_definition': 'variable_definitions',
'change_history': 'change_history', // Already plural
'experiment_results': 'experiment_results', // Already plural
'results': 'experiment_results', // Map 'results' entity to experiment_results table
'fx_environment': 'fx_environments',
'report': 'reports',
'feature': 'features'
};
// Reverse mapping for table to entity
tableToEntityMap;
constructor() {
// Build reverse mapping
this.tableToEntityMap = {};
for (const [entity, table] of Object.entries(this.entityToTableMap)) {
this.tableToEntityMap[table] = entity;
}
logger.debug(`EntityTableMapper initialized with ${Object.keys(this.entityToTableMap).length} mappings`);
}
/**
* Convert entity name (singular) to table name (plural)
*/
getTableName(entity) {
if (!entity) {
throw new Error('Entity name cannot be empty');
}
// Check explicit mapping first
if (this.entityToTableMap[entity]) {
return this.entityToTableMap[entity];
}
// Handle already plural cases
if (entity.endsWith('s') && this.tableToEntityMap[entity]) {
return entity; // It's already a table name
}
// Default pluralization rules
if (entity.endsWith('y') && !entity.endsWith('ey')) {
// entity -> entities, activity -> activities
return entity.slice(0, -1) + 'ies';
}
else if (entity.endsWith('s') || entity.endsWith('x') || entity.endsWith('ch') || entity.endsWith('sh')) {
// status -> statuses, box -> boxes, match -> matches
return entity + 'es';
}
else {
// Default: just add 's'
return entity + 's';
}
}
/**
* Convert table name (plural) to entity name (singular)
*/
getEntityName(table) {
if (!table) {
throw new Error('Table name cannot be empty');
}
// Check explicit mapping first
if (this.tableToEntityMap[table]) {
return this.tableToEntityMap[table];
}
// Handle already singular cases
if (this.entityToTableMap[table]) {
return table; // It's already an entity name
}
// Reverse pluralization rules
if (table.endsWith('ies') && table.length > 3) {
// entities -> entity, activities -> activity
return table.slice(0, -3) + 'y';
}
else if (table.endsWith('es') &&
(table.endsWith('ses') || table.endsWith('xes') ||
table.endsWith('ches') || table.endsWith('shes'))) {
// statuses -> status, boxes -> box, matches -> match
return table.slice(0, -2);
}
else if (table.endsWith('s') && table.length > 1) {
// Default: remove 's'
return table.slice(0, -1);
}
else {
// Can't determine singular form
return table;
}
}
/**
* Check if a name is an entity name (singular)
*/
isEntityName(name) {
return this.entityToTableMap.hasOwnProperty(name) ||
(!this.tableToEntityMap.hasOwnProperty(name) && !name.endsWith('s'));
}
/**
* Check if a name is a table name (plural)
*/
isTableName(name) {
return this.tableToEntityMap.hasOwnProperty(name) ||
(!this.entityToTableMap.hasOwnProperty(name) && name.endsWith('s'));
}
/**
* Normalize a name to entity form (singular)
*/
toEntityName(name) {
if (this.isEntityName(name)) {
return name;
}
return this.getEntityName(name);
}
/**
* Normalize a name to table form (plural)
*/
toTableName(name) {
if (this.isTableName(name)) {
return name;
}
return this.getTableName(name);
}
}
// Export singleton instance
export const entityTableMapper = new EntityTableMapper();
//# sourceMappingURL=EntityTableMapper.js.map