UNPKG

carthorse

Version:

A geospatial trail data processing pipeline for building 3D trail databases with elevation data

251 lines 9.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkMasterSchemaVersion = checkMasterSchemaVersion; exports.checkSqliteSchemaVersion = checkSqliteSchemaVersion; exports.checkRequiredSqlFunctions = checkRequiredSqlFunctions; exports.validateRoutingNetwork = validateRoutingNetwork; exports.validateDatabase = validateDatabase; /** * Check PostgreSQL master database schema version */ async function checkMasterSchemaVersion(pgClient) { try { console.log('🔍 Checking master database schema version...'); const result = await pgClient.query(` SELECT version, created_at FROM schema_version ORDER BY created_at DESC LIMIT 1 `); if (result.rows.length === 0) { return { success: false, message: '❌ No schema version found in master database', details: { error: 'schema_version table is empty or missing' } }; } const schemaVersion = result.rows[0]; console.log(`✅ Master schema version: ${schemaVersion.version}`); return { success: true, message: `Master schema version: ${schemaVersion.version}`, details: schemaVersion }; } catch (error) { return { success: false, message: '❌ Failed to check master schema version', details: { error: error instanceof Error ? error.message : String(error) } }; } } /** * Check SQLite database schema version */ async function checkSqliteSchemaVersion(sqlitePath) { try { console.log('🔍 Checking SQLite database schema version...'); const { Database } = require('sqlite3'); const db = new Database(sqlitePath); return new Promise((resolve) => { db.get(` SELECT version, created_at FROM schema_version ORDER BY created_at DESC LIMIT 1 `, (err, row) => { db.close(); if (err) { resolve({ success: false, message: '❌ Failed to check SQLite schema version', details: { error: err instanceof Error ? err.message : String(err) } }); return; } if (!row) { resolve({ success: false, message: '❌ No schema version found in SQLite database', details: { error: 'schema_version table is empty or missing' } }); return; } const schemaVersion = row; console.log(`✅ SQLite schema version: ${schemaVersion.version} - ${schemaVersion.description}`); resolve({ success: true, message: `SQLite schema version: ${schemaVersion.version}`, details: schemaVersion }); }); }); } catch (error) { return { success: false, message: '❌ Failed to check SQLite schema version', details: { error: error instanceof Error ? error.message : String(error) } }; } } /** * Check required PostgreSQL functions exist */ async function checkRequiredSqlFunctions(pgClient) { try { console.log('🔍 Checking required PostgreSQL functions...'); const requiredFunctions = [ // Custom Carthorse functions that must be installed 'detect_trail_intersections' ]; const missingFunctions = []; for (const funcName of requiredFunctions) { try { const result = await pgClient.query(` SELECT proname FROM pg_proc WHERE proname = $1 AND pronamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public') `, [funcName]); if (result.rows.length === 0) { missingFunctions.push(funcName); } } catch (error) { // Function check failed, assume it's missing missingFunctions.push(funcName); } } if (missingFunctions.length > 0) { return { success: false, message: `❌ Missing ${missingFunctions.length} required PostgreSQL functions`, details: { missingFunctions } }; } console.log(`✅ All ${requiredFunctions.length} required PostgreSQL functions are available`); return { success: true, message: `All ${requiredFunctions.length} required PostgreSQL functions are available`, details: { functionCount: requiredFunctions.length } }; } catch (error) { return { success: false, message: '❌ Failed to check required PostgreSQL functions', details: { error: error instanceof Error ? error.message : String(error) } }; } } /** * Validate pgRouting network topology */ async function validateRoutingNetwork(pgClient, stagingSchema) { try { console.log('🔍 Validating pgRouting network topology...'); // Check if ways_noded table exists and has data const waysNodedResult = await pgClient.query(` SELECT COUNT(*) as count FROM ${stagingSchema}.ways_noded `); const waysNodedCount = parseInt(waysNodedResult.rows[0].count); if (waysNodedCount === 0) { return { success: false, message: '❌ No routing edges found in ways_noded table', details: { edgeCount: 0 } }; } // Check if ways_noded_vertices_pgr table exists and has data const verticesResult = await pgClient.query(` SELECT COUNT(*) as count FROM ${stagingSchema}.ways_noded_vertices_pgr `); const verticesCount = parseInt(verticesResult.rows[0].count); if (verticesCount === 0) { return { success: false, message: '❌ No routing vertices found in ways_noded_vertices_pgr table', details: { vertexCount: 0 } }; } // Check for isolated vertices (vertices with no edges) const isolatedVerticesResult = await pgClient.query(` SELECT COUNT(*) as count FROM ${stagingSchema}.ways_noded_vertices_pgr v WHERE NOT EXISTS ( SELECT 1 FROM ${stagingSchema}.ways_noded w WHERE w.source = v.id OR w.target = v.id ) `); const isolatedVerticesCount = parseInt(isolatedVerticesResult.rows[0].count); // Check for disconnected components const componentsResult = await pgClient.query(` SELECT COUNT(DISTINCT component) as component_count FROM pgr_connectedComponents( 'SELECT id, source, target, length_km * 1000 as cost FROM ${stagingSchema}.ways_noded' ) `); const componentCount = parseInt(componentsResult.rows[0].component_count); // Check if network is strongly connected (can reach all nodes from any node) const reachableNodesResult = await pgClient.query(` SELECT COUNT(DISTINCT node) as reachable_count FROM pgr_dijkstra( 'SELECT id, source, target, length_km * 1000 as cost FROM ${stagingSchema}.ways_noded', (SELECT id FROM ${stagingSchema}.ways_noded_vertices_pgr LIMIT 1), (SELECT array_agg(id) FROM ${stagingSchema}.ways_noded_vertices_pgr) ) `); const reachableNodesCount = parseInt(reachableNodesResult.rows[0].reachable_count); const connectivityPercentage = (reachableNodesCount / verticesCount) * 100; console.log(`✅ Network validation completed:`); console.log(` 📍 Vertices: ${verticesCount}`); console.log(` 🛤️ Edges: ${waysNodedCount}`); console.log(` 🔗 Components: ${componentCount}`); console.log(` 🎯 Connectivity: ${connectivityPercentage.toFixed(1)}%`); console.log(` 🚫 Isolated vertices: ${isolatedVerticesCount}`); return { success: true, message: `Network validation passed: ${verticesCount} vertices, ${waysNodedCount} edges, ${connectivityPercentage.toFixed(1)}% connectivity`, details: { vertexCount: verticesCount, edgeCount: waysNodedCount, componentCount, connectivityPercentage, isolatedVerticesCount } }; } catch (error) { return { success: false, message: '❌ Failed to validate routing network', details: { error: error instanceof Error ? error.message : String(error) } }; } } /** * Comprehensive database validation */ async function validateDatabase(pgClient, stagingSchema, sqlitePath) { const results = []; // Check master schema version const masterSchemaResult = await checkMasterSchemaVersion(pgClient); results.push(masterSchemaResult); // Check SQLite schema version if path provided if (sqlitePath) { const sqliteSchemaResult = await checkSqliteSchemaVersion(sqlitePath); results.push(sqliteSchemaResult); } // Check required SQL functions const functionsResult = await checkRequiredSqlFunctions(pgClient); results.push(functionsResult); // Validate routing network const networkResult = await validateRoutingNetwork(pgClient, stagingSchema); results.push(networkResult); return results; } //# sourceMappingURL=database-validation-helpers.js.map