supa-seed
Version:
A constraint-aware, framework-agnostic database seeding framework with deep PostgreSQL business logic discovery and MakerKit integration support
229 lines • 7.97 kB
JavaScript
;
/**
* Framework Strategy Registry
* Manages registration and selection of framework strategies
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.StrategyRegistry = void 0;
const logger_1 = require("../../core/utils/logger");
class StrategyRegistry {
constructor(client, options = {}) {
this.strategies = new Map();
this.client = client;
this.options = {
enableFallback: true,
minimumConfidence: 0.3,
debug: false,
...options
};
}
/**
* Register a seeding strategy
*/
async register(strategy) {
try {
await strategy.initialize(this.client);
this.strategies.set(strategy.name, strategy);
if (this.options.debug) {
logger_1.Logger.debug(`Registered strategy: ${strategy.name}`);
}
}
catch (error) {
logger_1.Logger.error(`Failed to register strategy ${strategy.name}:`, error);
throw error;
}
}
/**
* Register multiple strategies
*/
async registerAll(strategies) {
for (const strategy of strategies) {
await this.register(strategy);
}
}
/**
* Unregister a strategy
*/
unregister(strategyName) {
this.strategies.delete(strategyName);
if (this.options.debug) {
logger_1.Logger.debug(`Unregistered strategy: ${strategyName}`);
}
}
/**
* Get all registered strategies
*/
getStrategies() {
return Array.from(this.strategies.values());
}
/**
* Get a specific strategy by name
*/
getStrategy(name) {
return this.strategies.get(name);
}
/**
* Select the best strategy for the given schema
*/
async selectStrategy(schema) {
if (this.strategies.size === 0) {
throw new Error('No strategies registered');
}
const detectionResults = [];
// Run detection on all strategies
for (const strategy of this.strategies.values()) {
try {
const detection = await strategy.detect(schema);
detectionResults.push({ strategy, detection });
if (this.options.debug) {
logger_1.Logger.debug(`Strategy ${strategy.name} confidence: ${detection.confidence}`);
}
}
catch (error) {
logger_1.Logger.warn(`Strategy ${strategy.name} detection failed:`, error);
}
}
if (detectionResults.length === 0) {
throw new Error('No strategies could analyze the schema');
}
// Sort by confidence and priority
detectionResults.sort((a, b) => {
const confidenceDiff = b.detection.confidence - a.detection.confidence;
if (Math.abs(confidenceDiff) > 0.1) {
return confidenceDiff;
}
return b.strategy.getPriority() - a.strategy.getPriority();
});
const bestResult = detectionResults[0];
// Check minimum confidence threshold
if (bestResult.detection.confidence < this.options.minimumConfidence) {
if (this.options.enableFallback) {
const fallbackStrategy = this.findFallbackStrategy();
if (fallbackStrategy) {
logger_1.Logger.warn(`Low confidence (${bestResult.detection.confidence}), using fallback strategy`);
return {
strategy: fallbackStrategy,
detection: {
framework: 'generic',
confidence: 0.1,
detectedFeatures: [],
recommendations: ['Consider manual framework specification']
},
reason: 'fallback_low_confidence'
};
}
}
throw new Error(`No strategy meets minimum confidence threshold (${this.options.minimumConfidence})`);
}
return {
strategy: bestResult.strategy,
detection: bestResult.detection,
reason: 'best_match'
};
}
/**
* Select strategy with manual override
*/
async selectStrategyWithOverride(schema, frameworkOverride) {
if (frameworkOverride) {
const strategy = this.strategies.get(frameworkOverride);
if (strategy) {
const detection = await strategy.detect(schema);
return {
strategy,
detection,
reason: 'manual_override'
};
}
else {
logger_1.Logger.warn(`Override strategy '${frameworkOverride}' not found, falling back to auto-detection`);
}
}
return this.selectStrategy(schema);
}
/**
* Find the fallback strategy (typically generic)
*/
findFallbackStrategy() {
// Look for strategies with 'generic' in the name first
for (const [name, strategy] of this.strategies) {
if (name.toLowerCase().includes('generic')) {
return strategy;
}
}
// Fall back to the strategy with lowest priority
const strategies = Array.from(this.strategies.values());
if (strategies.length === 0)
return undefined;
strategies.sort((a, b) => a.getPriority() - b.getPriority());
return strategies[0];
}
/**
* Get detection results for all strategies
*/
async getAllDetectionResults(schema) {
const results = [];
for (const strategy of this.strategies.values()) {
try {
const detection = await strategy.detect(schema);
results.push({
strategy: strategy.name,
detection
});
}
catch (error) {
logger_1.Logger.warn(`Detection failed for strategy ${strategy.name}:`, error);
results.push({
strategy: strategy.name,
detection: {
framework: 'unknown',
confidence: 0,
detectedFeatures: [],
recommendations: [`Detection failed: ${error.message}`]
}
});
}
}
return results;
}
/**
* Validate that a strategy works with the current schema
*/
async validateStrategy(strategyName, schema) {
const strategy = this.strategies.get(strategyName);
if (!strategy) {
return {
valid: false,
issues: [`Strategy '${strategyName}' not found`],
recommendations: ['Register the strategy first']
};
}
try {
const detection = await strategy.detect(schema);
const recommendations = strategy.getRecommendations();
return {
valid: detection.confidence > 0,
issues: detection.confidence === 0 ? ['Strategy not compatible with schema'] : [],
recommendations
};
}
catch (error) {
return {
valid: false,
issues: [`Strategy validation failed: ${error.message}`],
recommendations: ['Check strategy implementation and schema compatibility']
};
}
}
/**
* Clear all registered strategies
*/
clear() {
this.strategies.clear();
if (this.options.debug) {
logger_1.Logger.debug('Cleared all registered strategies');
}
}
}
exports.StrategyRegistry = StrategyRegistry;
//# sourceMappingURL=strategy-registry.js.map