UNPKG

rawsql-ts

Version:

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

215 lines 9.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonSchemaValidator = void 0; class JsonSchemaValidator { /** * Validates JsonMapping structure against an expected type structure. * Checks if the JsonMapping covers all required properties and relationships. * * @param jsonMapping The JsonMapping configuration to validate * @param expectedStructure The expected type structure to validate against * @returns ValidationResult containing validation status and detailed errors */ static validate(jsonMapping, expectedStructure) { const extractedStructure = this.extractStructureFromJsonMapping(jsonMapping); return this.compareStructures(extractedStructure, expectedStructure); } /** * Validates JsonMapping structure and throws an error if validation fails. * Convenience method for strict validation scenarios. * * @param jsonMapping The JsonMapping configuration to validate * @param expectedStructure The expected type structure to validate against * @throws Error if validation fails with detailed error messages */ static validateStrict(jsonMapping, expectedStructure) { const result = this.validate(jsonMapping, expectedStructure); if (!result.isValid) { const errorMessage = [ 'JsonMapping validation failed:', ...result.errors ].join('\n'); throw new Error(errorMessage); } } /** * Extracts structure information from JsonMapping configuration. * Analyzes rootEntity and nestedEntities to build complete structure map. * * @param jsonMapping The JsonMapping to analyze * @returns ExtractedStructure representing the mapping structure */ static extractStructureFromJsonMapping(jsonMapping) { const structure = {}; // Extract root entity properties if (jsonMapping.rootEntity && jsonMapping.rootEntity.columns) { Object.keys(jsonMapping.rootEntity.columns).forEach(propertyName => { structure[propertyName] = 'primitive'; }); } // Extract nested entities if (jsonMapping.nestedEntities) { // Process direct children of root entity first jsonMapping.nestedEntities .filter((entity) => entity.parentId === jsonMapping.rootEntity.id) .forEach((entity) => { if (entity.propertyName && entity.columns) { if (entity.relationshipType === 'object') { // Single object relationship structure[entity.propertyName] = this.extractNestedEntityStructure(entity, jsonMapping); } else if (entity.relationshipType === 'array') { // Array relationship structure[entity.propertyName] = [this.extractNestedEntityStructure(entity, jsonMapping)]; } } }); } return structure; } /** * Extracts structure from a nested entity, including its children. */ static extractNestedEntityStructure(entity, jsonMapping) { const entityStructure = {}; // Add entity's own columns if (entity.columns) { Object.keys(entity.columns).forEach(propName => { entityStructure[propName] = 'primitive'; }); } // Add nested children of this entity if (jsonMapping.nestedEntities) { jsonMapping.nestedEntities .filter((childEntity) => childEntity.parentId === entity.id) .forEach((childEntity) => { if (childEntity.propertyName && childEntity.columns) { if (childEntity.relationshipType === 'object') { entityStructure[childEntity.propertyName] = this.extractNestedEntityStructure(childEntity, jsonMapping); } else if (childEntity.relationshipType === 'array') { entityStructure[childEntity.propertyName] = [this.extractNestedEntityStructure(childEntity, jsonMapping)]; } } }); } return entityStructure; } /** * Compares extracted structure with expected structure with proper type guards. */ static compareStructures(extracted, expected, path = '') { const errors = []; const missingProperties = []; const extraProperties = []; // Handle primitive comparison if (extracted === 'primitive' && expected === 'primitive') { return { isValid: true, errors: [], missingProperties: [], extraProperties: [] }; } // Handle array types if (Array.isArray(expected) && Array.isArray(extracted)) { if (expected.length > 0 && extracted.length > 0) { const nestedResult = this.compareStructures(extracted[0], expected[0], `${path}[]`); errors.push(...nestedResult.errors); missingProperties.push(...nestedResult.missingProperties); extraProperties.push(...nestedResult.extraProperties); } return { isValid: errors.length === 0, errors, missingProperties, extraProperties }; } // Both should be objects for property comparison if (typeof extracted !== 'object' || typeof expected !== 'object' || Array.isArray(extracted) || Array.isArray(expected) || extracted === null || expected === null) { return { isValid: true, errors: [], missingProperties: [], extraProperties: [] }; } // Now we know both are object types, safe to access properties const extractedObj = extracted; const expectedObj = expected; // Check for missing properties in extracted structure Object.keys(expectedObj).forEach(key => { const currentPath = path ? `${path}.${key}` : key; if (!(key in extractedObj)) { missingProperties.push(currentPath); errors.push(`Missing property: ${currentPath}`); return; } const extractedValue = extractedObj[key]; const expectedValue = expectedObj[key]; // Recursively compare nested structures const nestedResult = this.compareStructures(extractedValue, expectedValue, currentPath); errors.push(...nestedResult.errors); missingProperties.push(...nestedResult.missingProperties); extraProperties.push(...nestedResult.extraProperties); }); // Check for extra properties in extracted structure Object.keys(extractedObj).forEach(key => { const currentPath = path ? `${path}.${key}` : key; if (!(key in expectedObj)) { extraProperties.push(currentPath); // Note: Extra properties are not considered errors in this implementation // as JsonMapping might include additional metadata } }); return { isValid: errors.length === 0, errors, missingProperties, extraProperties }; } /** * Validates JsonMapping structure against a sample object that implements the expected type. * This method extracts structure from the sample object and compares it with JsonMapping. * * @param jsonMapping The JsonMapping configuration to validate * @param sampleObject A sample object that implements the expected interface/type * @returns ValidationResult containing validation status and detailed errors */ static validateAgainstSample(jsonMapping, sampleObject) { const expectedStructure = this.extractStructureFromSample(sampleObject); return this.validate(jsonMapping, expectedStructure); } /** * Validates JsonMapping structure against a sample object and throws an error if validation fails. * Convenience method for strict validation scenarios with sample objects. * * @param jsonMapping The JsonMapping configuration to validate * @param sampleObject A sample object that implements the expected interface/type * @throws Error if validation fails with detailed error messages */ static validateAgainstSampleStrict(jsonMapping, sampleObject) { const result = this.validateAgainstSample(jsonMapping, sampleObject); if (!result.isValid) { const errorMessage = [ 'JsonMapping validation against sample object failed:', ...result.errors ].join('\n'); throw new Error(errorMessage); } } /** * Extracts structure information from a sample object. * Recursively analyzes the object properties to build a structure map. * * @param sampleObject The sample object to analyze * @returns ExpectedTypeStructure representing the object structure */ static extractStructureFromSample(sampleObject) { if (sampleObject === null || sampleObject === undefined) { return 'primitive'; } if (Array.isArray(sampleObject)) { if (sampleObject.length === 0) { return []; } return [this.extractStructureFromSample(sampleObject[0])]; } if (typeof sampleObject === 'object') { const structure = {}; Object.keys(sampleObject).forEach(key => { structure[key] = this.extractStructureFromSample(sampleObject[key]); }); return structure; } // Primitive types (string, number, boolean, etc.) return 'primitive'; } } exports.JsonSchemaValidator = JsonSchemaValidator; //# sourceMappingURL=JsonSchemaValidator.js.map