UNPKG

supa-seed

Version:

A constraint-aware, framework-agnostic database seeding framework with deep PostgreSQL business logic discovery and MakerKit integration support

457 lines 19.4 kB
"use strict"; /** * Domain Pattern Recognition Engines for Epic 2: Smart Platform Detection Engine * Specialized analyzers for each content domain with confidence scoring * Part of Task 2.2.2: Create domain pattern recognition engine with confidence scoring */ Object.defineProperty(exports, "__esModule", { value: true }); exports.domainPatternOrchestrator = exports.DomainPatternAnalysisOrchestrator = exports.GenericDomainAnalyzer = exports.SocialDomainAnalyzer = exports.EcommerceDomainAnalyzer = exports.SaaSDomainAnalyzer = exports.OutdoorDomainAnalyzer = void 0; const logger_1 = require("../../core/utils/logger"); const domain_patterns_1 = require("./domain-patterns"); /** * Base class for domain-specific analyzers */ class BaseDomainAnalyzer { constructor(domain) { this.domain = domain; } /** * Analyze patterns for this domain */ async analyzeDomainPatterns(context) { const patterns = (0, domain_patterns_1.getPatternsForDomain)(this.domain); const matchedPatterns = []; const evidence = []; const reasoning = []; logger_1.Logger.debug(`Analyzing ${patterns.length} patterns for ${this.domain} domain`); // Analyze each pattern for (const pattern of patterns) { const matchResult = await this.analyzePattern(pattern, context); if (matchResult.confidence > 0.1) { // Only include meaningful matches matchedPatterns.push({ pattern, confidence: matchResult.confidence, matchDetails: matchResult.matchDetails }); // Create evidence from pattern match const patternEvidence = this.createEvidenceFromMatch(pattern, matchResult); evidence.push(...patternEvidence); // Add reasoning if (matchResult.confidence > 0.5) { reasoning.push(`${pattern.name}: ${matchResult.confidence.toFixed(2)} confidence (${matchResult.matchDetails.totalMatches} matches)`); } } } // Calculate overall confidence const overallConfidence = this.calculateOverallConfidence(matchedPatterns); // Add domain-specific reasoning reasoning.unshift(`${this.domain.toUpperCase()} domain analysis: ${overallConfidence.toFixed(2)} confidence`); return { domain: this.domain, matchedPatterns, overallConfidence, evidence, reasoning }; } /** * Analyze a single pattern against the schema */ async analyzePattern(pattern, context) { const matchDetails = { matchedTables: [], matchedColumns: [], matchedRelationships: [], matchedBusinessLogic: [], totalMatches: 0 }; // Match table patterns if (pattern.tablePatterns.length > 0) { matchDetails.matchedTables = this.matchTablePatterns(pattern.tablePatterns, context); } // Match column patterns if (pattern.columnPatterns.length > 0) { matchDetails.matchedColumns = await this.matchColumnPatterns(pattern.columnPatterns, context); } // Match relationship patterns if (pattern.relationshipPatterns.length > 0) { matchDetails.matchedRelationships = this.matchRelationshipPatterns(pattern.relationshipPatterns, context); } // Match business logic patterns if (pattern.businessLogicPatterns.length > 0) { matchDetails.matchedBusinessLogic = await this.matchBusinessLogicPatterns(pattern.businessLogicPatterns, context); } // Calculate total matches matchDetails.totalMatches = matchDetails.matchedTables.length + matchDetails.matchedColumns.length + matchDetails.matchedRelationships.length + matchDetails.matchedBusinessLogic.length; // Calculate confidence based on matches and pattern requirements const confidence = this.calculatePatternConfidence(pattern, matchDetails); return { confidence, matchDetails }; } /** * Match table name patterns */ matchTablePatterns(tablePatterns, context) { const matches = []; for (const tablePattern of tablePatterns) { const regex = new RegExp(tablePattern.replace('*', '.*'), 'i'); for (const tableName of context.schema.tableNames) { if (regex.test(tableName) || tableName.toLowerCase().includes(tablePattern.toLowerCase())) { matches.push(tableName); } } } return Array.from(new Set(matches)); // Remove duplicates } /** * Match column patterns across all tables */ async matchColumnPatterns(columnPatterns, context) { const matches = []; // This would typically require schema introspection to get column information // For now, we'll simulate based on common patterns for (const columnPattern of columnPatterns) { // Common column patterns that would be found through schema analysis if (this.isCommonColumnPattern(columnPattern, context)) { matches.push(columnPattern); } } return matches; } /** * Check if a column pattern is commonly found in this type of schema */ isCommonColumnPattern(columnPattern, context) { // This is a simplified implementation // In practice, this would analyze actual column names from schema introspection const commonPatterns = { outdoor: ['make', 'model', 'weight', 'specifications', 'type', 'priority'], saas: ['plan_id', 'subscription_status', 'billing_cycle', 'workspace_id', 'usage_count'], ecommerce: ['sku', 'price', 'inventory_count', 'order_status', 'payment_method'], social: ['like_count', 'follower_id', 'media_url', 'hashtags', 'reaction_type'], generic: ['title', 'description', 'content', 'status', 'created_at'] }; return commonPatterns[this.domain]?.includes(columnPattern) || false; } /** * Match relationship patterns */ matchRelationshipPatterns(relationshipPatterns, context) { const matches = []; for (const relPattern of relationshipPatterns) { for (const relationship of context.schema.relationships) { const fromMatch = relationship.fromTable.toLowerCase().includes(relPattern.fromTable.toLowerCase()); const toMatch = relationship.toTable.toLowerCase().includes(relPattern.toTable.toLowerCase()); if (fromMatch && toMatch) { matches.push(`${relationship.fromTable}->${relationship.toTable}`); } } } return matches; } /** * Match business logic patterns */ async matchBusinessLogicPatterns(businessLogicPatterns, context) { const matches = []; // Check business logic from context if (context.businessLogic) { for (const pattern of businessLogicPatterns) { // Check function names for (const func of context.businessLogic.functions) { if (func.toLowerCase().includes(pattern.toLowerCase())) { matches.push(func); } } // Check triggers for (const trigger of context.businessLogic.triggers) { if (trigger.toLowerCase().includes(pattern.toLowerCase())) { matches.push(trigger); } } // Check policies for (const policy of context.businessLogic.policies) { if (policy.toLowerCase().includes(pattern.toLowerCase())) { matches.push(policy); } } } } return matches; } /** * Calculate confidence for a single pattern match */ calculatePatternConfidence(pattern, matchDetails) { // Check if minimum matches requirement is met if (matchDetails.totalMatches < pattern.minimumMatches) { return 0; } // Calculate weighted confidence based on match types let confidence = 0; // Table matches (highest weight) if (pattern.tablePatterns.length > 0) { const tableMatchRatio = matchDetails.matchedTables.length / pattern.tablePatterns.length; confidence += tableMatchRatio * domain_patterns_1.DOMAIN_CONFIDENCE_WEIGHTS.tablePatterns; } // Column matches if (pattern.columnPatterns.length > 0) { const columnMatchRatio = matchDetails.matchedColumns.length / pattern.columnPatterns.length; confidence += columnMatchRatio * domain_patterns_1.DOMAIN_CONFIDENCE_WEIGHTS.columnPatterns; } // Relationship matches if (pattern.relationshipPatterns.length > 0) { const relMatchRatio = matchDetails.matchedRelationships.length / pattern.relationshipPatterns.length; confidence += relMatchRatio * domain_patterns_1.DOMAIN_CONFIDENCE_WEIGHTS.relationshipPatterns; } // Business logic matches if (pattern.businessLogicPatterns.length > 0) { const bizLogicMatchRatio = matchDetails.matchedBusinessLogic.length / pattern.businessLogicPatterns.length; confidence += bizLogicMatchRatio * domain_patterns_1.DOMAIN_CONFIDENCE_WEIGHTS.businessLogic; } // Apply pattern's confidence weight confidence *= pattern.confidenceWeight; // Boost for exclusive patterns if (pattern.exclusive && confidence > 0.5) { confidence = Math.min(confidence * 1.2, 1.0); } return Math.min(confidence, 1.0); } /** * Calculate overall confidence for the domain */ calculateOverallConfidence(matchedPatterns) { if (matchedPatterns.length === 0) { return 0; } // Weight by pattern priority and confidence let totalWeightedConfidence = 0; let totalWeight = 0; for (const match of matchedPatterns) { const weight = match.pattern.priority * match.confidence; totalWeightedConfidence += weight; totalWeight += match.pattern.priority; } return totalWeight > 0 ? totalWeightedConfidence / totalWeight : 0; } /** * Create evidence objects from pattern matches */ createEvidenceFromMatch(pattern, matchResult) { const evidence = []; // Create evidence for each type of match if (matchResult.matchDetails.matchedTables.length > 0) { evidence.push({ type: 'table_pattern', domain: this.domain, description: `${pattern.name}: Found ${matchResult.matchDetails.matchedTables.length} matching tables`, confidence: matchResult.confidence, weight: pattern.confidenceWeight, supportingData: { tables: matchResult.matchDetails.matchedTables, patterns: [pattern.id] } }); } if (matchResult.matchDetails.matchedColumns.length > 0) { evidence.push({ type: 'column_analysis', domain: this.domain, description: `${pattern.name}: Found ${matchResult.matchDetails.matchedColumns.length} matching columns`, confidence: matchResult.confidence, weight: pattern.confidenceWeight * 0.8, // Slightly lower weight for columns supportingData: { columns: matchResult.matchDetails.matchedColumns, patterns: [pattern.id] } }); } if (matchResult.matchDetails.matchedRelationships.length > 0) { evidence.push({ type: 'relationship_pattern', domain: this.domain, description: `${pattern.name}: Found ${matchResult.matchDetails.matchedRelationships.length} matching relationships`, confidence: matchResult.confidence, weight: pattern.confidenceWeight * 0.9, supportingData: { patterns: matchResult.matchDetails.matchedRelationships } }); } if (matchResult.matchDetails.matchedBusinessLogic.length > 0) { evidence.push({ type: 'business_logic', domain: this.domain, description: `${pattern.name}: Found ${matchResult.matchDetails.matchedBusinessLogic.length} matching business logic patterns`, confidence: matchResult.confidence, weight: pattern.confidenceWeight * 0.7, supportingData: { businessLogic: matchResult.matchDetails.matchedBusinessLogic, patterns: [pattern.id] } }); } return evidence; } } /** * Outdoor Domain Analyzer */ class OutdoorDomainAnalyzer extends BaseDomainAnalyzer { constructor() { super('outdoor'); } } exports.OutdoorDomainAnalyzer = OutdoorDomainAnalyzer; /** * SaaS Domain Analyzer */ class SaaSDomainAnalyzer extends BaseDomainAnalyzer { constructor() { super('saas'); } } exports.SaaSDomainAnalyzer = SaaSDomainAnalyzer; /** * E-commerce Domain Analyzer */ class EcommerceDomainAnalyzer extends BaseDomainAnalyzer { constructor() { super('ecommerce'); } } exports.EcommerceDomainAnalyzer = EcommerceDomainAnalyzer; /** * Social Domain Analyzer */ class SocialDomainAnalyzer extends BaseDomainAnalyzer { constructor() { super('social'); } } exports.SocialDomainAnalyzer = SocialDomainAnalyzer; /** * Generic Domain Analyzer */ class GenericDomainAnalyzer extends BaseDomainAnalyzer { constructor() { super('generic'); } } exports.GenericDomainAnalyzer = GenericDomainAnalyzer; /** * Domain Pattern Analysis Orchestrator * Coordinates analysis across all domain analyzers */ class DomainPatternAnalysisOrchestrator { constructor() { this.analyzers = new Map([ ['outdoor', new OutdoorDomainAnalyzer()], ['saas', new SaaSDomainAnalyzer()], ['ecommerce', new EcommerceDomainAnalyzer()], ['social', new SocialDomainAnalyzer()], ['generic', new GenericDomainAnalyzer()] ]); } /** * Analyze patterns for all domains */ async analyzeAllDomains(context) { const results = []; logger_1.Logger.info('🔍 Starting domain pattern analysis across all domains'); // Run all analyzers in parallel const analysisPromises = Array.from(this.analyzers.entries()).map(async ([domain, analyzer]) => { try { return await analyzer.analyzeDomainPatterns(context); } catch (error) { logger_1.Logger.error(`Failed to analyze ${domain} domain:`, error); return { domain, matchedPatterns: [], overallConfidence: 0, evidence: [], reasoning: [`Analysis failed: ${error.message}`] }; } }); const analysisResults = await Promise.all(analysisPromises); results.push(...analysisResults); // Sort by confidence results.sort((a, b) => b.overallConfidence - a.overallConfidence); logger_1.Logger.info(`✅ Domain pattern analysis completed: ${results.length} domains analyzed`); return results; } /** * Analyze patterns for specific domains only */ async analyzeSpecificDomains(domains, context) { const results = []; logger_1.Logger.info(`🔍 Starting domain pattern analysis for: ${domains.join(', ')}`); for (const domain of domains) { const analyzer = this.analyzers.get(domain); if (analyzer) { try { const result = await analyzer.analyzeDomainPatterns(context); results.push(result); } catch (error) { logger_1.Logger.error(`Failed to analyze ${domain} domain:`, error); results.push({ domain, matchedPatterns: [], overallConfidence: 0, evidence: [], reasoning: [`Analysis failed: ${error.message}`] }); } } } results.sort((a, b) => b.overallConfidence - a.overallConfidence); logger_1.Logger.info(`✅ Specific domain analysis completed: ${results.length} domains analyzed`); return results; } /** * Get quick domain analysis (high-priority patterns only) */ async getQuickDomainAnalysis(context) { // For quick analysis, we'll focus on the most distinctive patterns const quickResults = []; logger_1.Logger.info('⚡ Starting quick domain pattern analysis'); // Check for outdoor domain (most distinctive) const outdoorResult = await this.analyzers.get('outdoor').analyzeDomainPatterns(context); if (outdoorResult.overallConfidence > domain_patterns_1.DOMAIN_CONFIDENCE_THRESHOLDS.moderate) { quickResults.push(outdoorResult); } // Check for e-commerce domain (distinctive patterns) const ecommerceResult = await this.analyzers.get('ecommerce').analyzeDomainPatterns(context); if (ecommerceResult.overallConfidence > domain_patterns_1.DOMAIN_CONFIDENCE_THRESHOLDS.moderate) { quickResults.push(ecommerceResult); } // Check for SaaS domain const saasResult = await this.analyzers.get('saas').analyzeDomainPatterns(context); if (saasResult.overallConfidence > domain_patterns_1.DOMAIN_CONFIDENCE_THRESHOLDS.moderate) { quickResults.push(saasResult); } // Check for social domain const socialResult = await this.analyzers.get('social').analyzeDomainPatterns(context); if (socialResult.overallConfidence > domain_patterns_1.DOMAIN_CONFIDENCE_THRESHOLDS.moderate) { quickResults.push(socialResult); } // Always include generic as fallback const genericResult = await this.analyzers.get('generic').analyzeDomainPatterns(context); quickResults.push(genericResult); quickResults.sort((a, b) => b.overallConfidence - a.overallConfidence); logger_1.Logger.info(`⚡ Quick domain analysis completed: ${quickResults.length} domains considered`); return quickResults; } } exports.DomainPatternAnalysisOrchestrator = DomainPatternAnalysisOrchestrator; /** * Default domain pattern analysis orchestrator instance */ exports.domainPatternOrchestrator = new DomainPatternAnalysisOrchestrator(); //# sourceMappingURL=domain-analyzers.js.map