UNPKG

@simonecoelhosfo/optimizely-mcp-server

Version:

Optimizely MCP Server for AI assistants with integrated CLI tools

947 lines 37 kB
/** * UnifiedFieldResolver - Consolidates all field mapping knowledge for dynamic query resolution * * This class represents the core of Phase 3 Intelligent Flattening Architecture. * It consolidates knowledge from: * - IntelligentPayloadParser (3,750+ field patterns) * - ComprehensiveAutoCorrector (platform-specific corrections) * - FieldMapper (entity-specific mappings) * - FIELDS.generated (complete schema definitions) * * The goal is to handle ANY field variation dynamically without hard-coding. */ import { IntelligentPayloadParser } from '../parsers/IntelligentPayloadParser.js'; import { ComprehensiveAutoCorrector } from '../validation/ComprehensiveAutoCorrector.js'; import { FieldMapper } from '../parsers/FieldMapper.js'; import { FIELDS } from '../generated/fields.generated.js'; import { getLogger } from '../logging/Logger.js'; /** * UnifiedFieldResolver - The core field resolution engine * * This class implements the 5-step resolution process: * 1. Normalize field name variations (camelCase, snake_case, etc.) * 2. Apply synonym mappings (traffic → weight, etc.) * 3. Apply platform-specific corrections * 4. Validate against schema * 5. Determine optimal access strategy */ export class UnifiedFieldResolver { payloadParser; fieldMapper; fieldsSchema; logger = getLogger(); constructor() { this.logger.debug('UnifiedFieldResolver: Initializing field mapping systems...'); this.initializeMappers(); this.logger.debug('UnifiedFieldResolver: Initialization complete'); } /** * Resolve a single field reference to database access strategy * * @param input - Field name as provided by user/agent * @param context - Query context for resolution * @returns Complete field resolution result */ resolveField(input, context) { this.logger.debug(`UnifiedFieldResolver: Resolving field "${input}" for entity "${context.primaryEntity}"`); try { // Validate inputs if (!input || typeof input !== 'string') { throw new Error('Field name must be a non-empty string'); } if (!context || !context.primaryEntity) { throw new Error('Query context with primaryEntity is required'); } // Execute the 5-step resolution process const step1 = this.normalizeFieldName(input, context); this.logger.debug(`Step 1 - Normalized: "${input}""${step1.normalized}"`); const step2 = this.applySynonymMappings(step1.normalized, context); this.logger.debug(`Step 2 - Synonym mapping: "${step1.normalized}""${step2.mapped}"`); const step3 = this.applyPlatformCorrections(step2.mapped, context); this.logger.debug(`Step 3 - Platform correction: "${step2.mapped}""${step3.corrected}"`); const step4 = this.validateAgainstSchema(step3.corrected, context); this.logger.debug(`Step 4 - Schema validation: ${step4.isValid ? 'PASSED' : 'FAILED'}`); if (!step4.isValid) { throw new Error(`Field validation failed: ${step4.errors.join(', ')}`); } const step5 = this.determineAccessStrategy(step4, context); this.logger.debug(`Step 5 - Access strategy: ${step5.requiresFlattening ? 'FLATTENING' : 'DIRECT'}`); // Preserve original input step5.originalInput = input; return step5; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error(`UnifiedFieldResolver: Failed to resolve field "${input}": ${errorMessage}`); throw error; } } /** * Resolve multiple fields in batch for optimal performance * * @param inputs - Array of field names * @param context - Query context for resolution * @returns Batch resolution result */ resolveFields(inputs, context) { this.logger.debug(`UnifiedFieldResolver: Resolving ${inputs.length} fields in batch`); const resolvedFields = []; const unresolvedFields = []; const allJoins = new Set(); const allConditions = new Set(); let requiresFlattening = false; let requiresJsonProcessing = false; // Resolve each field individually for (const input of inputs) { try { const resolved = this.resolveField(input, context); resolvedFields.push(resolved); // Collect JOINs and conditions resolved.requiredJoins?.forEach(join => allJoins.add(join)); resolved.additionalConditions?.forEach(condition => allConditions.add(condition)); // Track complexity flags if (resolved.requiresFlattening) requiresFlattening = true; if (resolved.jsonataExpression) requiresJsonProcessing = true; } catch (error) { this.logger.warn(`Failed to resolve field "${input}": ${error}`); unresolvedFields.push(input); } } // Generate optimization hints const optimizationHints = this.getOptimizationHints(resolvedFields); return { resolvedFields, unresolvedFields, requiredJoins: Array.from(allJoins), additionalConditions: Array.from(allConditions), requiresFlattening, requiresJsonProcessing, optimizationHints }; } /** * Step 1: Normalize field name variations * Handles: camelCase ↔ snake_case ↔ PascalCase ↔ kebab-case */ normalizeFieldName(input, context) { const transformations = []; let normalized = input.trim(); // Track original case for confidence scoring const originalCase = this.detectCaseType(input); transformations.push(`detected_case:${originalCase}`); // Handle camelCase/PascalCase: insert _ before uppercase letters if (/[a-z][A-Z]/.test(normalized)) { normalized = normalized.replace(/([a-z])([A-Z])/g, '$1_$2'); transformations.push('camelCase_to_snake_case'); } // Convert kebab-case to snake_case if (normalized.includes('-')) { normalized = normalized.replace(/-/g, '_'); transformations.push('kebab_case_to_snake_case'); } // Handle multiple underscores if (normalized.includes('__')) { normalized = normalized.replace(/_+/g, '_'); transformations.push('collapsed_multiple_underscores'); } // Convert to lowercase if (normalized !== normalized.toLowerCase()) { normalized = normalized.toLowerCase(); transformations.push('converted_to_lowercase'); } // Remove leading/trailing underscores const beforeTrim = normalized; normalized = normalized.replace(/^_+|_+$/g, ''); if (normalized !== beforeTrim) { transformations.push('removed_leading_trailing_underscores'); } // Calculate confidence based on transformations needed const confidence = this.calculateNormalizationConfidence(input, normalized, transformations); return { normalized, transformations, confidence }; } /** * Detect the case type of input field */ detectCaseType(input) { if (/^[a-z]+(_[a-z]+)*$/.test(input)) return 'snake_case'; if (/^[a-z]+([A-Z][a-z]*)*$/.test(input)) return 'camelCase'; if (/^[A-Z][a-z]*([A-Z][a-z]*)*$/.test(input)) return 'PascalCase'; if (/^[a-z]+(-[a-z]+)*$/.test(input)) return 'kebab-case'; if (/^[A-Z_]+$/.test(input)) return 'UPPER_CASE'; return 'mixed_case'; } /** * Calculate confidence score for normalization */ calculateNormalizationConfidence(original, normalized, transformations) { // Base confidence let confidence = 1.0; // Reduce confidence for each transformation confidence -= transformations.length * 0.05; // Boost confidence for common patterns if (transformations.includes('camelCase_to_snake_case')) confidence += 0.1; if (transformations.includes('kebab_case_to_snake_case')) confidence += 0.1; // Penalize unusual patterns if (transformations.includes('collapsed_multiple_underscores')) confidence -= 0.2; if (original.length < 2) confidence -= 0.3; return Math.max(0.1, Math.min(1.0, confidence)); } /** * Step 2: Apply synonym mappings * Handles: traffic → weight, traffic_allocation → percentage_included, etc. */ applySynonymMappings(normalized, context) { const synonyms = []; let mapped = normalized; let contextInfo = `entity:${context.primaryEntity}`; // Critical synonyms (highest priority) - these solve the original error const criticalSynonyms = this.getCriticalSynonyms(); if (criticalSynonyms[mapped]) { synonyms.push({ from: mapped, to: criticalSynonyms[mapped] }); mapped = criticalSynonyms[mapped]; contextInfo += ',critical_mapping'; } // Entity-specific synonyms const entitySynonyms = this.getEntitySpecificSynonyms(context.primaryEntity); if (entitySynonyms[mapped]) { synonyms.push({ from: mapped, to: entitySynonyms[mapped] }); mapped = entitySynonyms[mapped]; contextInfo += ',entity_specific'; } // Platform-specific synonyms if (context.platform) { const platformSynonyms = this.getPlatformSpecificSynonyms(context.platform); if (platformSynonyms[mapped]) { synonyms.push({ from: mapped, to: platformSynonyms[mapped] }); mapped = platformSynonyms[mapped]; contextInfo += `,platform:${context.platform}`; } } // Common field synonyms (lowest priority) const commonSynonyms = this.getCommonSynonyms(); if (commonSynonyms[mapped]) { synonyms.push({ from: mapped, to: commonSynonyms[mapped] }); mapped = commonSynonyms[mapped]; contextInfo += ',common_mapping'; } return { mapped, synonyms, context: contextInfo }; } /** * Get critical synonyms that solve the "variations.key does not exist" error */ getCriticalSynonyms() { return { // Traffic/Weight synonyms (most critical) 'traffic': 'weight', 'traffic_allocation': 'percentage_included', 'traffic_alloc': 'percentage_included', // Key field synonyms 'flag_key': 'key', 'experiment_key': 'key', 'audience_key': 'key', 'variation_key': 'key', 'rule_key': 'key', 'event_key': 'key', // Status/State synonyms 'is_active': 'enabled', 'is_archived': 'archived', 'state': 'status', 'is_enabled': 'enabled' }; } /** * Get entity-specific synonym mappings */ getEntitySpecificSynonyms(entity) { const mappings = { 'flags': { 'flag_name': 'name', 'flag_desc': 'description', 'flag_status': 'status' }, 'flag': { 'flag_name': 'name', 'flag_desc': 'description', 'flag_status': 'status' }, 'experiments': { 'exp_name': 'name', 'exp_key': 'key', 'experiment_status': 'status' }, 'experiment': { 'exp_name': 'name', 'exp_key': 'key', 'experiment_status': 'status' }, 'variations': { 'var_key': 'key', 'variation_name': 'name', 'var_weight': 'weight' }, 'variation': { 'var_key': 'key', 'variation_name': 'name', 'var_weight': 'weight' }, 'audiences': { 'aud_key': 'key', 'audience_name': 'name' }, 'audience': { 'aud_key': 'key', 'audience_name': 'name' }, 'rules': { 'rule_enabled': 'enabled', 'rule_active': 'enabled' }, 'rule': { 'rule_enabled': 'enabled', 'rule_active': 'enabled' }, 'events': { 'event_name': 'name', 'event_type': 'category' }, 'event': { 'event_name': 'name', 'event_type': 'category' }, 'changes': { 'change_type': 'type', 'change_selector': 'selector' } }; return mappings[entity] || {}; } /** * Get platform-specific synonym mappings */ getPlatformSpecificSynonyms(platform) { const mappings = { 'feature': { 'rollout_percentage': 'traffic_allocation', 'flag_variations': 'variations', 'feature_enabled': 'enabled', 'variable_map': 'variables', 'default_value': 'default_variation_key' }, 'web': { 'holdback_percentage': 'holdback', 'page_targets': 'page_ids', 'url_match': 'url_targeting', 'experiment_changes': 'changes', 'audience_targeting': 'audience_conditions' }, 'custom': {} }; return mappings[platform] || {}; } /** * Get common field synonyms (lowest priority) */ getCommonSynonyms() { return { // Description variants 'desc': 'description', 'summary': 'description', 'details': 'description', // Name variants 'title': 'name', 'label': 'name', 'display_name': 'name', // ID variants 'identifier': 'id', 'uuid': 'id', 'guid': 'id', // Time variants 'created': 'created_time', 'updated': 'updated_time', 'modified': 'last_modified', 'timestamp': 'created_time', // Boolean variants 'active': 'enabled', 'inactive': 'disabled', 'deleted': 'archived' }; } /** * Step 3: Apply platform-specific corrections * Handles differences between Web and Feature Experimentation * Uses ComprehensiveAutoCorrector.autoCorrect() static method */ applyPlatformCorrections(mapped, context) { const corrections = []; let corrected = mapped; const platform = context.platform || 'custom'; try { // Create a mock entity data object for the auto-corrector const mockEntityData = { [mapped]: 'test_value', // The corrector needs some data to work with entity_type: context.primaryEntity, platform: platform }; // Use ComprehensiveAutoCorrector to apply platform-specific corrections const correctionResult = ComprehensiveAutoCorrector.autoCorrect(context.primaryEntity, mockEntityData, { platform: platform }); // Check if any corrections were applied to our field if (correctionResult.correctedData && correctionResult.correctedData[mapped] !== mockEntityData[mapped]) { corrections.push({ type: 'auto_corrector', description: `Applied ComprehensiveAutoCorrector platform-specific correction` }); } // Apply manual platform-specific field corrections const manualCorrections = this.getManualPlatformCorrections(mapped, platform, context.primaryEntity); if (manualCorrections.correctedField !== mapped) { corrected = manualCorrections.correctedField; corrections.push(...manualCorrections.corrections); } } catch (error) { // If auto-corrector fails, continue with manual corrections only this.logger.warn(`ComprehensiveAutoCorrector failed for field "${mapped}": ${error}`); const manualCorrections = this.getManualPlatformCorrections(mapped, platform, context.primaryEntity); corrected = manualCorrections.correctedField; corrections.push(...manualCorrections.corrections); } return { corrected, corrections, platform }; } /** * Apply manual platform-specific field corrections */ getManualPlatformCorrections(field, platform, entity) { const corrections = []; let correctedField = field; // Platform-specific field availability checks const platformExclusiveFields = this.getPlatformExclusiveFields(); // Feature Experimentation exclusive fields if (platform === 'web' && platformExclusiveFields.featureOnly.includes(field)) { corrections.push({ type: 'platform_availability', description: `Field "${field}" is only available in Feature Experimentation, not Web Experimentation` }); } // Web Experimentation exclusive fields if (platform === 'feature' && platformExclusiveFields.webOnly.includes(field)) { corrections.push({ type: 'platform_availability', description: `Field "${field}" is only available in Web Experimentation, not Feature Experimentation` }); } // Platform-specific field name corrections const fieldCorrections = this.getPlatformFieldCorrections(); const platformKey = `${platform}_${entity}`; if (fieldCorrections[platformKey] && fieldCorrections[platformKey][field]) { const newField = fieldCorrections[platformKey][field]; corrections.push({ type: 'platform_field_correction', description: `Platform-specific correction: "${field}""${newField}" for ${platform} ${entity}` }); correctedField = newField; } return { correctedField, corrections }; } /** * Get platform-exclusive field lists */ getPlatformExclusiveFields() { return { featureOnly: [ 'traffic_allocation', 'variable_definitions', 'rollout_rules', 'default_variation_key', 'variables', 'rollout_id', 'sdk_key', 'datafile_url' ], webOnly: [ 'holdback', 'changes', 'url_targeting', 'page_ids', 'activation_mode', 'custom_css', 'custom_js', 'redirect_url' ], common: [ 'id', 'key', 'name', 'description', 'status', 'archived', 'enabled', 'created_time', 'updated_time', 'last_modified', 'project_id', 'account_id', 'audience_conditions', 'audience_ids', 'metrics', 'primary_metric', 'confidence_threshold' ] }; } /** * Get platform-specific field name corrections */ getPlatformFieldCorrections() { return { // Feature Experimentation corrections 'feature_flags': { 'variations': 'variations', // No correction needed - exists as separate table 'rollout': 'traffic_allocation' }, 'feature_experiments': { 'holdback': 'traffic_allocation', // Web field mapped to Feature equivalent 'changes': 'variable_definitions' }, // Web Experimentation corrections 'web_experiments': { 'traffic_allocation': 'holdback', // Feature field mapped to Web equivalent 'variable_definitions': 'changes' }, 'web_flags': { 'rollout_rules': 'url_targeting' } }; } /** * Step 4: Validate against schema * Ensures the field exists and gets type information */ validateAgainstSchema(corrected, context) { const errors = []; const suggestions = []; let isValid = false; let fieldInfo = { name: corrected, path: corrected, type: 'any', isArray: false, isNested: false }; try { // Handle nested field paths (e.g., "variations.key") const pathParts = corrected.split('.'); const rootField = pathParts[0]; const nestedPath = pathParts.slice(1).join('.'); // Get entity schema from FIELDS const entitySchema = this.getEntitySchema(context.primaryEntity); if (!entitySchema) { errors.push(`No schema found for entity type: ${context.primaryEntity}`); suggestions.push(`Available entities: ${Object.keys(this.fieldsSchema).join(', ')}`); return { field: fieldInfo, isValid: false, errors, suggestions }; } // Check if root field exists in schema if (this.isFieldInSchema(rootField, entitySchema)) { isValid = true; fieldInfo.type = this.getFieldType(rootField, entitySchema); fieldInfo.isArray = this.isArrayField(rootField, entitySchema); // Handle nested paths if (nestedPath) { fieldInfo.isNested = true; fieldInfo.path = corrected; // For array fields with nested access, this requires flattening if (fieldInfo.isArray) { fieldInfo.type = this.getNestedFieldType(nestedPath, rootField, entitySchema); } } } else { // Field not found - try fuzzy matching for suggestions isValid = false; errors.push(`Field "${rootField}" not found in ${context.primaryEntity} schema`); const fuzzyMatches = this.findFuzzyMatches(rootField, entitySchema); if (fuzzyMatches.length > 0) { suggestions.push(`Did you mean: ${fuzzyMatches.join(', ')}?`); } // Suggest available fields const availableFields = this.getAvailableFields(entitySchema); suggestions.push(`Available fields: ${availableFields.slice(0, 10).join(', ')}${availableFields.length > 10 ? '...' : ''}`); } } catch (error) { errors.push(`Schema validation error: ${error}`); isValid = false; } return { field: fieldInfo, isValid, errors, suggestions }; } /** * Get entity schema from FIELDS */ getEntitySchema(entity) { // Normalize entity name for schema lookup const normalizedEntity = this.normalizeEntityForSchema(entity); return this.fieldsSchema[normalizedEntity]; } /** * Normalize entity type for schema lookup */ normalizeEntityForSchema(entity) { // Convert plural to singular and handle variations const entityMappings = { 'flags': 'flag', 'flag': 'flag', 'experiments': 'experiment', 'experiment': 'experiment', 'variations': 'variation', 'variation': 'variation', 'audiences': 'audience', 'audience': 'audience', 'rules': 'rule', 'rule': 'rule', 'events': 'event', 'event': 'event', 'attributes': 'attribute', 'attribute': 'attribute', 'pages': 'page', 'page': 'page', 'projects': 'project', 'project': 'project', 'environments': 'environment', 'environment': 'environment', 'rulesets': 'ruleset', 'ruleset': 'ruleset', 'campaigns': 'campaign', 'campaign': 'campaign', 'changes': 'change' }; return entityMappings[entity] || entity; } /** * Check if field exists in entity schema */ isFieldInSchema(field, schema) { if (!schema) return false; // Check required and optional fields const requiredFields = schema.required || []; const optionalFields = schema.optional || []; return requiredFields.includes(field) || optionalFields.includes(field); } /** * Get field type from schema */ getFieldType(field, schema) { if (!schema || !schema.fieldTypes) return 'any'; return schema.fieldTypes[field] || 'any'; } /** * Check if field is an array type */ isArrayField(field, schema) { const fieldType = this.getFieldType(field, schema); return fieldType === 'array'; } /** * Get nested field type for array elements */ getNestedFieldType(nestedPath, rootField, schema) { // For nested paths in arrays, try to infer the type const commonNestedTypes = { 'key': 'string', 'name': 'string', 'id': 'number', 'weight': 'number', 'percentage_included': 'number', 'enabled': 'boolean', 'status': 'string', 'type': 'string' }; const leafField = nestedPath.split('.').pop() || nestedPath; return commonNestedTypes[leafField] || 'any'; } /** * Find fuzzy matches for field name */ findFuzzyMatches(field, schema) { if (!schema) return []; const allFields = [ ...(schema.required || []), ...(schema.optional || []) ]; const matches = []; const fieldLower = field.toLowerCase(); for (const availableField of allFields) { const availableLower = availableField.toLowerCase(); // Exact substring match if (availableLower.includes(fieldLower) || fieldLower.includes(availableLower)) { matches.push(availableField); continue; } // Levenshtein distance for typos if (this.calculateLevenshteinDistance(fieldLower, availableLower) <= 2) { matches.push(availableField); } } return matches.slice(0, 5); // Limit suggestions } /** * Calculate Levenshtein distance for fuzzy matching */ calculateLevenshteinDistance(str1, str2) { const matrix = Array(str2.length + 1).fill(null).map(() => Array(str1.length + 1).fill(null)); for (let i = 0; i <= str1.length; i++) matrix[0][i] = i; for (let j = 0; j <= str2.length; j++) matrix[j][0] = j; for (let j = 1; j <= str2.length; j++) { for (let i = 1; i <= str1.length; i++) { const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1; matrix[j][i] = Math.min(matrix[j][i - 1] + 1, // deletion matrix[j - 1][i] + 1, // insertion matrix[j - 1][i - 1] + indicator // substitution ); } } return matrix[str2.length][str1.length]; } /** * Get all available fields from schema */ getAvailableFields(schema) { if (!schema) return []; return [ ...(schema.required || []), ...(schema.optional || []) ].sort(); } /** * Step 5: Determine optimal access strategy * Decides between direct SQL, JSON_EXTRACT, or flattening */ determineAccessStrategy(validated, context) { const field = validated.field; const requiresFlattening = this.requiresFlattening(validated, context); const sqlAccessor = this.buildSQLAccessor(validated); const jsonataExpression = this.buildJsonataExpression(validated, context); // Determine required JOINs const requiredJoins = this.determineRequiredJoins(field, context); const additionalConditions = this.determineAdditionalConditions(field, context); return { originalInput: field.name, // Will be overridden by caller with actual input canonicalName: field.name, accessPath: field.path, dataType: this.normalizeDataType(field.type), isArray: field.isArray, isNested: field.isNested, requiresFlattening, sqlAccessor, jsonataExpression, requiredJoins, additionalConditions }; } /** * Determine if field requires array flattening */ requiresFlattening(validated, context) { const field = validated.field; // If explicitly requesting individual elements from arrays if (context.needsIndividualElements && field.isArray) { return true; } // Nested field access on arrays requires flattening if (field.isNested && field.isArray) { return true; } // Known array fields that require flattening const arrayFieldsRequiringFlattening = [ 'variations', 'metrics', 'rules', 'changes', 'audience_ids', 'page_ids' ]; const rootField = field.path.split('.')[0]; if (arrayFieldsRequiringFlattening.includes(rootField) && field.path.includes('.')) { return true; } return false; } /** * Build SQL accessor expression */ buildSQLAccessor(validated) { const field = validated.field; // Simple field access if (!field.isNested) { return field.name; } // JSON extraction for nested fields const pathParts = field.path.split('.'); const rootField = pathParts[0]; const jsonPath = pathParts.slice(1).join('.'); // Different JSON extraction patterns based on field structure if (field.isArray) { // Array field access - requires JSON_EXTRACT with array notation return `JSON_EXTRACT(${rootField}, '$[*].${jsonPath}')`; } else { // Object field access - simple JSON_EXTRACT return `JSON_EXTRACT(${rootField}, '$.${jsonPath}')`; } } /** * Build JSONata expression for complex processing */ buildJsonataExpression(validated, context) { const field = validated.field; // Only generate JSONata for complex nested array access if (!field.isNested || !field.isArray) { return undefined; } const pathParts = field.path.split('.'); const rootField = pathParts[0]; const nestedPath = pathParts.slice(1).join('.'); // Generate JSONata expression for array flattening return `$.${rootField}[*].${nestedPath}`; } /** * Determine required database JOINs */ determineRequiredJoins(field, context) { const joins = []; // Known JOIN patterns for specific field types const joinPatterns = { // Variations access from experiments/flags 'variations': `LEFT JOIN variations ON ${context.primaryEntity}.id = variations.${context.primaryEntity.slice(0, -1)}_id`, // Rules access from flags 'rules': `LEFT JOIN rules ON flags.id = rules.flag_id`, // Environment-specific access 'environments': `LEFT JOIN flag_environments ON flags.id = flag_environments.flag_id`, // Metrics access 'metrics': `LEFT JOIN experiment_metrics ON experiments.id = experiment_metrics.experiment_id` }; const rootField = field.path.split('.')[0]; if (joinPatterns[rootField]) { joins.push(joinPatterns[rootField]); } return joins; } /** * Determine additional WHERE conditions */ determineAdditionalConditions(field, context) { const conditions = []; // Platform-specific conditions if (context.platform) { if (context.platform === 'feature') { conditions.push("platform = 'feature'"); } else if (context.platform === 'web') { conditions.push("platform = 'web'"); } } // Project-specific conditions if (context.projectId) { conditions.push(`project_id = '${context.projectId}'`); } return conditions; } /** * Normalize data type names */ normalizeDataType(type) { const typeMap = { 'string': 'string', 'text': 'string', 'varchar': 'string', 'integer': 'number', 'number': 'number', 'float': 'number', 'double': 'number', 'boolean': 'boolean', 'bool': 'boolean', 'array': 'array', 'object': 'object', 'json': 'object' }; return typeMap[type.toLowerCase()] || 'any'; } // Legacy methods are now integrated into determineAccessStrategy - these were placeholder signatures /** * Initialize all field mapping systems * This method integrates existing infrastructure without modifying it */ initializeMappers() { try { // Initialize IntelligentPayloadParser this.payloadParser = new IntelligentPayloadParser(); this.logger.debug('UnifiedFieldResolver: IntelligentPayloadParser initialized'); // Initialize FieldMapper this.fieldMapper = new FieldMapper(); this.logger.debug('UnifiedFieldResolver: FieldMapper initialized'); // Note: ComprehensiveAutoCorrector is a static class - no instantiation needed this.logger.debug('UnifiedFieldResolver: ComprehensiveAutoCorrector available as static class'); // Reference the schema directly this.fieldsSchema = FIELDS; this.logger.debug('UnifiedFieldResolver: FIELDS schema loaded'); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error('UnifiedFieldResolver: Failed to initialize mappers', errorMessage); throw new Error(`Failed to initialize field mapping systems: ${errorMessage}`); } } /** * Get performance optimization hints for query planning */ getOptimizationHints(resolvedFields) { const hasComplexFields = resolvedFields.some(f => f.requiresFlattening || f.jsonataExpression); const hasJoins = resolvedFields.some(f => f.requiredJoins && f.requiredJoins.length > 0); const hasNestedAccess = resolvedFields.some(f => f.isNested); // Determine complexity level let complexityLevel = 'simple'; if (hasComplexFields) { complexityLevel = 'complex'; } else if (hasNestedAccess || hasJoins) { complexityLevel = 'moderate'; } // Can use simple extract if no flattening needed const canUseSimpleExtract = !resolvedFields.some(f => f.requiresFlattening); // Estimate result size impact let resultSizeImpact = 'minimal'; const flatteningFields = resolvedFields.filter(f => f.requiresFlattening).length; if (flatteningFields > 2) { resultSizeImpact = 'significant'; } else if (flatteningFields > 0 || hasJoins) { resultSizeImpact = 'moderate'; } return { canUseSimpleExtract, complexityLevel, resultSizeImpact }; } } //# sourceMappingURL=UnifiedFieldResolver.js.map