@flowlab/all
Version:
A cool library focusing on handling various flows
203 lines (175 loc) • 9.06 kB
text/typescript
// src/core/registry.ts
import {
IExtractor,
ITransformer,
ILoader,
ICleaner,
SourceConfig,
TargetConfig,
PipelineStepConfig,
PipelineContext
} from './interfaces';
import { ConfigurationError, ComponentError } from './errors';
import { FileExtractor } from '../extractors/fileExtractor';
import { ApiExtractor } from '../extractors/apiExtractor';
import { PrismaExtractor } from '../extractors/prismaExtractor';
import { FileLoader } from '../loaders/fileLoader';
import { ApiLoader } from '../loaders/apiLoader';
import { PrismaLoader } from '../loaders/prismaLoader';
import { MappingTransformer } from '../transformers/mappingTransformer';
import { CustomFunctionTransformer } from '../transformers/customFunctionTransformer';
import { MongoExtractor } from '../extractors/mongoExtractor';
import { RedisExtractor } from '../extractors/redisExtractor';
import { MongoLoader } from '../loaders/mongoLoader';
import { RedisLoader } from '../loaders/redisLoader';
import { DefaultValueCleaner, RequiredFieldCleaner } from '../extractors/cleaner';
import { ValidationTransformer } from '../transformers/validationTransformer';
// Define types for constructor signatures
type ExtractorConstructor = new (config: SourceConfig) => IExtractor<any>;
type LoaderConstructor = new (config: TargetConfig) => ILoader<any>;
type TransformerConstructor = new (config: any) => ITransformer<any, any>; // Config might vary
type CleanerConstructor = new (config: any) => ICleaner<any>; // Config might vary
// MARK: - Registry
const extractorRegistry = new Map<string, ExtractorConstructor>();
const transformerRegistry = new Map<string, TransformerConstructor>();
const loaderRegistry = new Map<string, LoaderConstructor>();
const cleanerRegistry = new Map<string, CleanerConstructor>();
// MARK: - Extractors
registerExtractor('prisma', PrismaExtractor as unknown as ExtractorConstructor); // Cast needed due to generic constructor
registerExtractor('postgresql', PrismaExtractor as unknown as ExtractorConstructor);
registerExtractor('mysql', PrismaExtractor as unknown as ExtractorConstructor);
registerExtractor('file', FileExtractor as unknown as ExtractorConstructor);
registerExtractor('api', ApiExtractor as unknown as ExtractorConstructor);
registerExtractor('mongodb', MongoExtractor as unknown as ExtractorConstructor);
registerExtractor('redis', RedisExtractor as unknown as ExtractorConstructor);
// MARK: - Loaders
registerLoader('prisma', PrismaLoader as unknown as LoaderConstructor);
registerLoader('postgresql', PrismaLoader as unknown as LoaderConstructor);
registerLoader('mysql', PrismaLoader as unknown as LoaderConstructor);
//
registerLoader('file', FileLoader as LoaderConstructor);
registerLoader('api', ApiLoader as LoaderConstructor);
registerLoader('mongodb', MongoLoader as LoaderConstructor);
registerLoader('redis', RedisLoader as LoaderConstructor);
// MARK: - Transformers
registerTransformer('mapping', MappingTransformer as TransformerConstructor);
registerTransformer('custom-function', CustomFunctionTransformer as TransformerConstructor);
registerTransformer('validator', ValidationTransformer as TransformerConstructor);
// MARK: - Cleaners
registerCleaner('required-fields', RequiredFieldCleaner as CleanerConstructor);
registerCleaner('default-values', DefaultValueCleaner as CleanerConstructor);
// --- Registration Functions ---
// MARK: - + Extractor
export function registerExtractor(type: string, constructor: ExtractorConstructor): void {
if (extractorRegistry.has(type)) {
console.warn(`[Registry] Overwriting extractor type: ${type}`);
}
extractorRegistry.set(type, constructor);
}
// MARK: - = Transformer
export function registerTransformer(type: string, constructor: TransformerConstructor): void {
if (transformerRegistry.has(type)) {
console.warn(`[Registry] Overwriting transformer type: ${type}`);
}
transformerRegistry.set(type, constructor);
}
// MARK: - Regis Loader
export function registerLoader(type: string, constructor: LoaderConstructor): void {
if (loaderRegistry.has(type)) {
console.warn(`[Registry] Overwriting loader type: ${type}`);
}
loaderRegistry.set(type, constructor);
}
// MARK: - Regis Cleaner
export function registerCleaner(type: string, constructor: CleanerConstructor): void {
if (cleanerRegistry.has(type)) {
console.warn(`[Registry] Overwriting cleaner type: ${type}`);
}
cleanerRegistry.set(type, constructor);
}
// --- Instantiation Functions ---
// MARK: - + Extractor
export function createExtractor<T>(config: SourceConfig): IExtractor<T> {
const Constructor = extractorRegistry.get(config.type);
if (!Constructor) {
throw new ConfigurationError(`Unsupported extractor type: ${config.type}`);
}
try {
return new Constructor(config) as IExtractor<T>;
} catch (error: any) {
throw new ComponentError(`Failed to instantiate extractor type ${config.type}`, Constructor.name, error);
}
}
// MARK: - + Loader
export function createLoader<T>(config: TargetConfig): ILoader<T> {
const Constructor = loaderRegistry.get(config.type);
if (!Constructor) {
throw new ConfigurationError(`Unsupported loader type: ${config.type}`);
}
try {
return new Constructor(config) as ILoader<T>;
} catch (error: any) {
throw new ComponentError(`Failed to instantiate loader type ${config.type}`, Constructor.name, error);
}
}
// MARK: - +Pipeline S
export function createPipelineStep(stepConfig: PipelineStepConfig): ICleaner<any> | ITransformer<any, any> {
let Constructor: CleanerConstructor | TransformerConstructor | undefined;
let config: any = stepConfig; // Use the whole step config initially
let componentType: string = ''; // For error messages
// Determine constructor and config based on step type
if (stepConfig.type === 'clean' && stepConfig.cleaner) {
if (typeof stepConfig.cleaner === 'string') {
componentType = stepConfig.cleaner;
Constructor = cleanerRegistry.get(componentType);
config = stepConfig; // Pass full step config to cleaner constructor potentially
} else {
throw new ConfigurationError(`Cleaner definition must be a string type in step config`, undefined, JSON.stringify(stepConfig));
}
} else if (stepConfig.type === 'transform' && stepConfig.transformer) {
if (typeof stepConfig.transformer === 'string') {
componentType = stepConfig.transformer;
Constructor = transformerRegistry.get(componentType);
config = stepConfig;
} else {
throw new ConfigurationError(`Transformer definition must be a string type in step config`, undefined, JSON.stringify(stepConfig));
}
} else if (stepConfig.type === 'map') {
componentType = 'mapping'; // Assuming 'mapping' is the registered type for MappingTransformer
Constructor = transformerRegistry.get(componentType);
config = stepConfig.rules; // Pass only rules to MappingTransformer constructor usually
if (!config) throw new ConfigurationError(`'map' step requires 'rules' property.`);
} else if (stepConfig.type === 'custom' && stepConfig.customFunctionPath) {
componentType = 'custom-function'; // Special case handled below or by a dedicated transformer
Constructor = transformerRegistry.get(componentType); // Requires CustomFunctionTransformer to be registered
config = stepConfig; // Pass full step config
}
else {
throw new ConfigurationError(`Invalid or incomplete pipeline step configuration: ${JSON.stringify(stepConfig)}`);
}
if (!Constructor) {
throw new ConfigurationError(`Unsupported pipeline step type or component not registered: ${componentType}`);
}
try {
// We might need more specific config extraction depending on constructor needs
return new Constructor(config);
} catch (error: any) {
throw new ComponentError(`Failed to instantiate pipeline step component ${componentType}`, Constructor.name, error);
}
}
// --- Register Built-in Components ---
// This section should be populated as components are created
// Example (will add actual components later):
// import { PrismaExtractor } from '../extractors/prismaExtractor';
// registerExtractor('prisma', PrismaExtractor); // Assuming PrismaExtractor takes generic config
// registerExtractor('postgresql', PrismaExtractor); // Alias
// registerExtractor('mysql', PrismaExtractor); // Alias
// import { MappingTransformer } from '../transformers/mappingTransformer';
// registerTransformer('mapping', MappingTransformer);
// import { PrismaLoader } from '../loaders/prismaLoader';
// registerLoader('prisma', PrismaLoader);
// registerLoader('postgresql', PrismaLoader);
// registerLoader('mysql', PrismaLoader);
// import { RequiredFieldCleaner } from '../transformers/cleaner';
// registerCleaner('required-fields', RequiredFieldCleaner); // Needs config adaptation in createPipelineStep or constructor
console.log('[Registry] Component registry initialized.'); // Log on load