Working measurement spike for Option C: aggregation runs in a server-side DuckDB instead of shipping every row to the browser. Opt-in via ?engine=duck; the default client-side WASM path is untouched. - routes/perspective.js: POST /perspective/init materializes a version's forecast table into a persistent in-process DuckDB (ATTACH postgres, so 535k rows land in ~1.5s without streaming through Node); POST /perspective/sql executes one Perspective-generated statement, with Arrow IPC output for viewport reads. - ui/src/duckServerHandler.js: VirtualServerHandler that delegates SQL generation to Perspective's own GenericSQLVirtualServerModel and POSTs the result to the server. Adapted from @perspective-dev/client's virtual_servers/duckdb.ts — same SQL model, different transport. - Forecast.jsx: DUCK_MODE branch replaces the heavy /data fetch with /perspective/init, opens the hosted table over a message port, and shows a latency overlay. applyDepth routes through viewer.restore() since the SQL server cannot handle view.set_depth(). Preserved for a future faster-load effort. Findings and the reason this is not the shipped path (no interactive tree expand/collapse) are in pf_perspective_options.md on master. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
39 lines
1.3 KiB
JavaScript
39 lines
1.3 KiB
JavaScript
require('dotenv').config();
|
|
const express = require('express');
|
|
const cors = require('cors');
|
|
const { Pool, types } = require('pg');
|
|
|
|
// Return bigint (oid 20) and numeric (oid 1700) as JS numbers instead of strings,
|
|
// so apache-arrow's tableFromJSON infers Int/Float64 rather than Dictionary<Utf8>.
|
|
types.setTypeParser(20, v => v === null ? null : Number(v));
|
|
types.setTypeParser(1700, v => v === null ? null : Number(v));
|
|
|
|
const app = express();
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
app.use(express.static('public/app'));
|
|
|
|
const pool = new Pool({
|
|
host: process.env.DB_HOST,
|
|
port: parseInt(process.env.DB_PORT) || 5432,
|
|
database: process.env.DB_NAME,
|
|
user: process.env.DB_USER,
|
|
password: process.env.DB_PASSWORD,
|
|
ssl: false
|
|
});
|
|
|
|
pool.on('error', (err) => {
|
|
console.error('pg pool error', err);
|
|
});
|
|
|
|
app.use('/api', require('./routes/tables')(pool));
|
|
app.use('/api', require('./routes/sources')(pool));
|
|
app.use('/api', require('./routes/versions')(pool));
|
|
app.use('/api', require('./routes/operations')(pool));
|
|
app.use('/api', require('./routes/log')(pool));
|
|
app.use('/api', require('./routes/perspective')(pool)); // SPIKE: server-side DuckDB virtual server
|
|
|
|
|
|
const port = process.env.PORT || 3010;
|
|
app.listen(port, '0.0.0.0', () => console.log(`pf_app started on port ${port}`));
|