From 8d1547a9830c8caa3d1802046981b7bb0929501d Mon Sep 17 00:00:00 2001 From: Ivo Date: Tue, 1 Jul 2025 18:10:46 +0200 Subject: [PATCH 1/6] feat: load sqlite files dynamically --- src/App.svelte | 117 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 3c24150..64aa683 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -3,6 +3,7 @@ import { Spinner, Alert } from "flowbite-svelte"; import { Heading, P, A } from "flowbite-svelte"; import { Select, Input, Label, Helper } from "flowbite-svelte"; + import { onMount } from "svelte"; import { createDbWorker } from "sql.js-httpvfs"; import { PowerTable } from "@muonw/powertable"; @@ -49,6 +50,9 @@ ); const wasmUrl = new URL("sql.js-httpvfs/dist/sql-wasm.wasm", import.meta.url); + let sqliteFiles = []; + let activeFile = null; + let ptOptions = { footerText: false, footerFilters: false, @@ -57,39 +61,73 @@ parseAs: "unsafe-html", }; - let ptInstructs = [ - { key: "RANK", title: "RANK" }, - { key: "REFERENCE(ID)", title: "REFERENCE(ID)" }, - { key: "TARGET(ID)", title: "TARGET(ID)" }, - // { key: "FORMAT", title: "FORMAT" }, - { key: "LENGTH", title: "LENGTH" }, - // { key: "WEIGHTED", title: "WEIGHTED" }, - { key: "HAMMING-DISTANCE", title: "HAMMING-DISTANCE" }, - { key: "DISTANCE-Z-SCORE", title: "DISTANCE-Z-SCORE" }, - { key: "DISTANCE-P-VALUE", title: "DISTANCE-P-VALUE" }, - { key: "DISTANCE-Z-SCORE(RAND)", title: "DISTANCE-Z-SCORE(RAND)" }, - { key: "JACCARD-INDEX", title: "JACCARD-INDEX" }, - { key: "JACCARD-Z-SCORE", title: "JACCARD-Z-SCORE" }, - { key: "JACCARD-P-VALUE", title: "JACCARD-P-VALUE" }, - { key: "REFERENCE-VARS", title: "REFERENCE-VARS" }, - { key: "TARGET-VARS", title: "TARGET-VARS" }, - { key: "INTERSECT", title: "INTERSECT" }, - { key: "INTERSECT-RATE(%)", title: "INTERSECT-RATE(%)" }, - { key: "COMPLETENESS(%)", title: "COMPLETENESS(%)" }, - { key: "REF-UUID", title: "REF-UUID" }, - { key: "TAR-UUID", title: "TAR-UUID" }, - { key: "REF-UUID-URL", title: "REF-UUID-URL", parseAs: "unsafe-html" }, - { key: "TAR-UUID-URL", title: "TAR-UUID-URL", parseAs: "unsafe-html" }, - ]; + let ptInstructs = []; + + function updateInstructs(data) { + if (data && data.length) { + ptInstructs = Object.keys(data[0]).map((k) => ({ key: k, title: k })); + } else { + ptInstructs = []; + } + } + + async function getSqliteFiles() { + const apiUrl = + "https://api.github.com/repos/CNAG-Biomedical-Informatics/cbi-datahub/contents/sqlite"; + try { + const res = await fetch(apiUrl); + if (!res.ok) return []; + const data = await res.json(); + return data + .filter( + (item) => + item.type === "file" && + (item.name.endsWith(".db") || item.name.endsWith(".sqlite")) + ) + .map((item) => ({ + name: item.name, + url: + item.download_url || + `https://raw.githubusercontent.com/CNAG-Biomedical-Informatics/cbi-datahub/main/sqlite/${item.name}`, + })); + } catch (e) { + console.error(e); + return []; + } + } + + async function loadDb(file) { + activeFile = file.name; + dbUrl = file.url; + const tablesData = await queryDb( + file.url, + "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'" + ); + if (tablesData.result.length) { + const table = tablesData.result[0].name; + sqlQuery = `SELECT * FROM "${table}" LIMIT 20;`; + await runQuery(file.url, sqlQuery); + } else { + sqlQuery = ""; + result = []; + } + } - async function queryDb() { + onMount(async () => { + sqliteFiles = await getSqliteFiles(); + if (sqliteFiles.length) { + await loadDb(sqliteFiles[0]); + } + }); + + async function queryDb(url = dbUrl, query = sqlQuery) { const worker = await createDbWorker( [ { from: "inline", config: { serverMode: "full", - url: dbUrl, + url, requestChunkSize: Number(pageSize), }, }, @@ -97,7 +135,7 @@ workerUrl.toString(), wasmUrl.toString() ); - const result = await worker.db.query(sqlQuery); + const result = await worker.db.query(query); const bytesRead = await worker.worker.bytesRead; const stats = await worker.worker.getStats(); return { result, bytesRead, stats }; @@ -113,14 +151,15 @@ let totalBytes; let totalRequests; - async function runQuery() { + async function runQuery(url = dbUrl, query = sqlQuery) { result = null; querying = true; error = false; - let queryData = pTime(queryDb)(); + let queryData = pTime(() => queryDb(url, query))(); await queryData .then((data) => { result = data.result; + updateInstructs(result); timeTaken = queryData.time; bytesRead = data.bytesRead; totalRequests = data.stats.totalRequests; @@ -137,6 +176,7 @@ console.log("Query Error: ", queryError.message); console.log(queryError); querying = false; + updateInstructs([]); jsonFile = null; }); } @@ -174,6 +214,25 @@ + {#if sqliteFiles.length} +
+ +
+ {/if} +