@trailstash/ultra
Version:
A web based tool for making MapLibre GL maps with data from sources such as Overpass, GeoJSON, GPX, KML, TCX, etc
92 lines (71 loc) • 2.41 kB
JavaScript
import { geoJsonLayers as layers } from "./common.js";
export const version = "1.32.0";
// global connection singleton
let connInstance = null;
async function initDB() {
// Return the connection directly if already initialized
if (connInstance) return connInstance;
const duckdb = await import(
`https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@${version}/+esm`
);
const JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();
const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);
const worker_url = URL.createObjectURL(
new Blob([`importScripts("${bundle.mainWorker}");`], {
type: "text/javascript",
}),
);
const worker = new Worker(worker_url);
const logger = new duckdb.ConsoleLogger();
const db = new duckdb.AsyncDuckDB(logger, worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
URL.revokeObjectURL(worker_url);
// Open DB to override query & filesystem defaults
await db.open({
// in-memory db, same as default
path: ":memory:",
// Query options to use standard JS types
query: {
castBigIntToDouble: true,
castTimestampToDate: true,
castDecimalToDouble: true,
},
// Filesytem options to force Range requests
filesystem: {
allowFullHTTPReads: false,
reliableHeadRequests: true,
forceFullHTTPReads: false,
},
});
// Establish the connection and store it globally
connInstance = await db.connect();
await connInstance.query(`INSTALL spatial; LOAD spatial;`);
return connInstance;
}
const duckdb = {
source: async function (query, controller, { geomCol = "geometry" }) {
const conn = await initDB();
const jsonQuery = `
WITH _data AS (${query})
SELECT json_object(
'type', 'FeatureCollection',
'features', COALESCE(json_group_array(
json_object(
'type', 'Feature',
'geometry', ST_AsGeoJSON(${geomCol})::JSON,
'properties', to_json(struct_pack(*COLUMNS(* EXCLUDE (${geomCol}))))
)
), '[]'::JSON)
)::VARCHAR AS geojson_string
FROM _data;
`;
const arrowResult = await conn.query(jsonQuery);
const rows = arrowResult.toArray();
const data = JSON.parse(
rows[0].toJSON ? rows[0].toJSON().geojson_string : rows[0].geojson_string,
);
return { type: "geojson", data };
},
layers,
};
export default duckdb;