UNPKG

rawsql-ts

Version:

[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.

115 lines 5.43 kB
/** * Model-driven JSON mapping structure that mirrors TypeScript model definitions. * This approach provides intuitive, hierarchical mapping that closely resembles the target data structure. */ /** * Convert a model-driven JSON mapping to the traditional JsonMapping format. * This enables backward compatibility with existing PostgresJsonQueryBuilder. */ export function convertModelDrivenMapping(modelMapping) { const protectedStringFields = []; let entityIdCounter = 0; const propertyNameCounters = {}; // Generate unique entity IDs const generateEntityId = () => `entity_${++entityIdCounter}`; // Generate unique property names to avoid JSON key conflicts const generateUniquePropertyName = (baseName) => { if (!propertyNameCounters[baseName]) { propertyNameCounters[baseName] = 0; } propertyNameCounters[baseName]++; return propertyNameCounters[baseName] === 1 ? baseName : `${baseName}_${propertyNameCounters[baseName]}`; }; // Helper function to process structure fields and extract entities const processStructure = (structure, parentId = null) => { const columns = {}; const nestedEntities = []; for (const [fieldName, config] of Object.entries(structure)) { if (typeof config === 'string') { // Simple field mapping: "fieldName": "column_name" columns[fieldName] = config; } else if ('column' in config && typeof config.column === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) { // Enhanced field mapping: "fieldName": { "column": "column_name", "type": "string" } const fieldConfig = config; if (typeof fieldConfig === 'object' && 'column' in fieldConfig) { columns[fieldName] = fieldConfig.column; if (fieldConfig.type === 'string') { protectedStringFields.push(fieldConfig.column); } } } else if ('from' in config && typeof config.from === 'string' && !('type' in config && (config.type === 'object' || config.type === 'array'))) { // Legacy field mapping: "fieldName": { "from": "column_name", "type": "string" } const fieldConfig = config; if (typeof fieldConfig === 'object' && 'from' in fieldConfig) { columns[fieldName] = fieldConfig.from; if (fieldConfig.type === 'string') { protectedStringFields.push(fieldConfig.from); } } } else if ('type' in config && (config.type === 'object' || config.type === 'array')) { // Nested structure: object or array const nestedStructure = config; const uniquePropertyName = generateUniquePropertyName(fieldName); // Generate globally unique entity ID to ensure unique JSON column names const entityId = generateEntityId(); const processedNested = processStructure(nestedStructure.structure, entityId); nestedEntities.push({ id: entityId, // Use unique ID to avoid column conflicts name: fieldName.charAt(0).toUpperCase() + fieldName.slice(1), // Capitalize first letter parentId: parentId || 'root', propertyName: uniquePropertyName, originalPropertyName: fieldName, // Store original name for final mapping relationshipType: nestedStructure.type, columns: processedNested.columns }); // Add nested entities from deeper levels nestedEntities.push(...processedNested.nestedEntities.map(entity => (Object.assign(Object.assign({}, entity), { parentId: entity.parentId === 'root' ? entityId : entity.parentId })))); } } return { columns, nestedEntities }; }; // Process the root structure const processed = processStructure(modelMapping.structure); // Build the traditional JsonMapping const jsonMapping = { rootName: 'root', // Default root name rootEntity: { id: 'root', name: 'Root', columns: processed.columns }, nestedEntities: processed.nestedEntities }; // Add typeInfo for backward compatibility jsonMapping.typeInfo = modelMapping.typeInfo; return { jsonMapping, typeProtection: { protectedStringFields } }; } /** * Validate that a model-driven mapping structure is well-formed. */ export function validateModelDrivenMapping(mapping) { const errors = []; // Validate typeInfo if (!mapping.typeInfo) { errors.push('typeInfo is required'); } else { if (!mapping.typeInfo.interface) { errors.push('typeInfo.interface is required'); } if (!mapping.typeInfo.importPath) { errors.push('typeInfo.importPath is required'); } } // Validate structure if (!mapping.structure || typeof mapping.structure !== 'object') { errors.push('structure is required and must be an object'); } return errors; } //# sourceMappingURL=ModelDrivenJsonMapping.js.map