carthorse
Version:
A geospatial trail data processing pipeline for building 3D trail databases with elevation data
88 lines • 4.88 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RouteCacheService = void 0;
const crypto_1 = __importDefault(require("crypto"));
class RouteCacheService {
constructor(pgClient, cacheSchema) {
this.pg = pgClient;
this.cacheSchema = cacheSchema;
}
async ensureSchemaAndTables() {
// Create schema and tables with indexes if not exist
await this.pg.query(`CREATE SCHEMA IF NOT EXISTS ${this.cacheSchema}`);
await this.pg.query(`
CREATE TABLE IF NOT EXISTS ${this.cacheSchema}.ksp_paths_cache (
graph_sig TEXT NOT NULL,
start_node INTEGER NOT NULL,
end_node INTEGER NOT NULL,
k INTEGER NOT NULL,
constraints_sig TEXT NOT NULL,
paths JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY(graph_sig, start_node, end_node, k, constraints_sig)
)
`);
await this.pg.query(`CREATE INDEX IF NOT EXISTS idx_${this.cacheSchema}_ksp_paths_start ON ${this.cacheSchema}.ksp_paths_cache(start_node)`);
await this.pg.query(`CREATE INDEX IF NOT EXISTS idx_${this.cacheSchema}_ksp_paths_end ON ${this.cacheSchema}.ksp_paths_cache(end_node)`);
await this.pg.query(`CREATE INDEX IF NOT EXISTS idx_${this.cacheSchema}_ksp_paths_graph ON ${this.cacheSchema}.ksp_paths_cache(graph_sig)`);
await this.pg.query(`
CREATE TABLE IF NOT EXISTS ${this.cacheSchema}.reachable_nodes_cache (
graph_sig TEXT NOT NULL,
start_node INTEGER NOT NULL,
max_distance_km REAL NOT NULL,
results JSONB NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY(graph_sig, start_node, max_distance_km)
)
`);
await this.pg.query(`CREATE INDEX IF NOT EXISTS idx_${this.cacheSchema}_reachable_start ON ${this.cacheSchema}.reachable_nodes_cache(start_node)`);
await this.pg.query(`CREATE INDEX IF NOT EXISTS idx_${this.cacheSchema}_reachable_graph ON ${this.cacheSchema}.reachable_nodes_cache(graph_sig)`);
}
async computeGraphSignature(stagingSchema, region, bbox) {
// Use edge count, vertex count, sum(length_km) as a compact signature of the routing graph
const stats = await this.pg.query(`
WITH e AS (
SELECT COUNT(*)::bigint AS edges, COALESCE(SUM(length_km), 0)::double precision AS total_len
FROM ${stagingSchema}.ways_noded
), v AS (
SELECT COUNT(*)::bigint AS vertices
FROM ${stagingSchema}.ways_noded_vertices_pgr
)
SELECT e.edges, v.vertices, e.total_len
FROM e, v
`);
const row = stats.rows[0] || { edges: 0, vertices: 0, total_len: 0 };
const bboxPart = bbox ? bbox.join(',') : 'nobbox';
const raw = `${region}|${bboxPart}|${row.edges}|${row.vertices}|${row.total_len}`;
return crypto_1.default.createHash('md5').update(raw).digest('hex');
}
async getKspPaths(graphSig, startNode, endNode, k, constraintsSig) {
const res = await this.pg.query(`SELECT paths FROM ${this.cacheSchema}.ksp_paths_cache WHERE graph_sig = $1 AND start_node = $2 AND end_node = $3 AND k = $4 AND constraints_sig = $5`, [graphSig, startNode, endNode, k, constraintsSig]);
if (res.rows.length === 0)
return null;
return { paths: res.rows[0].paths };
}
async setKspPaths(graphSig, startNode, endNode, k, constraintsSig, paths) {
await this.pg.query(`INSERT INTO ${this.cacheSchema}.ksp_paths_cache (graph_sig, start_node, end_node, k, constraints_sig, paths)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (graph_sig, start_node, end_node, k, constraints_sig)
DO UPDATE SET paths = EXCLUDED.paths, created_at = NOW()`, [graphSig, startNode, endNode, k, constraintsSig, JSON.stringify(paths)]);
}
async getReachableNodes(graphSig, startNode, maxDistanceKm) {
const res = await this.pg.query(`SELECT results FROM ${this.cacheSchema}.reachable_nodes_cache WHERE graph_sig = $1 AND start_node = $2 AND max_distance_km = $3`, [graphSig, startNode, maxDistanceKm]);
if (res.rows.length === 0)
return null;
return { results: res.rows[0].results };
}
async setReachableNodes(graphSig, startNode, maxDistanceKm, results) {
await this.pg.query(`INSERT INTO ${this.cacheSchema}.reachable_nodes_cache (graph_sig, start_node, max_distance_km, results)
VALUES ($1, $2, $3, $4)
ON CONFLICT (graph_sig, start_node, max_distance_km)
DO UPDATE SET results = EXCLUDED.results, created_at = NOW()`, [graphSig, startNode, maxDistanceKm, JSON.stringify(results)]);
}
}
exports.RouteCacheService = RouteCacheService;
//# sourceMappingURL=route-cache.js.map