diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-03 21:54:29 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-03 21:55:07 +0100 |
| commit | 89eeeb9075acec512111c9f78ed8158a556e06e4 (patch) | |
| tree | 23ab351a1a6d09255bd12f7866908761f8a473bd /src/lib | |
| parent | 587d8fe65d61b8f7217b4e8850b44e43159c16fb (diff) | |
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/config.js | 9 | ||||
| -rw-r--r-- | src/lib/db.js | 51 | ||||
| -rw-r--r-- | src/lib/stores/widgets.js | 57 |
3 files changed, 89 insertions, 28 deletions
diff --git a/src/lib/config.js b/src/lib/config.js index dbbe7fc..9532cde 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -1,7 +1,10 @@ export const coordinateLength = 4; export const maxSize = Math.pow(16, coordinateLength); -export const supabase = { - url: import.meta.env.VITE_SUPABASE_URL, - key: import.meta.env.VITE_SUPABASE_KEY +export const database = { + host: import.meta.env.VITE_DB_HOST || 'localhost', + port: import.meta.env.VITE_DB_PORT || 5432, + database: import.meta.env.VITE_DB_DATABASE || 'canvas', + user: import.meta.env.VITE_DB_USER || 'canvas', + password: import.meta.env.VITE_DB_PASSWORD }; diff --git a/src/lib/db.js b/src/lib/db.js new file mode 100644 index 0000000..d6adcdf --- /dev/null +++ b/src/lib/db.js @@ -0,0 +1,51 @@ +import pg from 'pg'; +import { database } from '$lib/config'; + +const { Pool } = pg; + +const pool = new Pool(database); + +export async function query(text, params) { + const client = await pool.connect(); + try { + const result = await client.query(text, params); + return result; + } finally { + client.release(); + } +} + +export async function queryWithAbort(text, params, signal) { + if (signal?.aborted) { + throw new Error('Query aborted'); + } + + const client = await pool.connect(); + + const queryPromise = client.query(text, params); + + if (signal) { + const abortPromise = new Promise((_, reject) => { + signal.addEventListener('abort', () => { + client.release(); + reject(new Error('Query aborted')); + }, { once: true }); + }); + + try { + const result = await Promise.race([queryPromise, abortPromise]); + return result; + } finally { + client.release(); + } + } + + try { + const result = await queryPromise; + return result; + } finally { + client.release(); + } +} + +export default pool;
\ No newline at end of file diff --git a/src/lib/stores/widgets.js b/src/lib/stores/widgets.js index 372cad1..2796a7b 100644 --- a/src/lib/stores/widgets.js +++ b/src/lib/stores/widgets.js @@ -1,25 +1,23 @@ import { derived, readable, writable } from 'svelte/store'; -import { createClient } from '@supabase/supabase-js'; -import { supabase } from '$lib/config'; +import { queryWithAbort } from '$lib/db'; import { maxSize } from '$lib/config'; const boxParser = /\(([0-9]+),([0-9]+)\),\(([0-9]+),([0-9]+)\)/; -const client = createClient(supabase.url, supabase.key); export const sensor = writable({ left: 0, top: 0, right: 0, bottom: 0 }); -const getBoxes = function getBoxes({ left, top, right, bottom }) { - const results = [ - `box.ov."((${left},${top}),(${right},${bottom}))"`, - `box.ov."((${left + maxSize},${top + maxSize}),(${right + maxSize},${bottom + maxSize}))"`, - `box.ov."((${left + maxSize},${top}),(${right + maxSize},${bottom}))"`, - `box.ov."((${left},${top + maxSize}),(${right},${bottom + maxSize}))"`, - `box.ov."((${left - maxSize},${top - maxSize}),(${right - maxSize},${bottom - maxSize}))"`, - `box.ov."((${left - maxSize},${top}),(${right - maxSize},${bottom}))"`, - `box.ov."((${left},${top - maxSize}),(${right},${bottom - maxSize}))"` +const getBoxQuery = function getBoxQuery({ left, top, right, bottom }) { + const boxes = [ + `box && box '((${left},${top}),(${right},${bottom}))'`, + `box && box '((${left + maxSize},${top + maxSize}),(${right + maxSize},${bottom + maxSize}))'`, + `box && box '((${left + maxSize},${top}),(${right + maxSize},${bottom}))'`, + `box && box '((${left},${top + maxSize}),(${right},${bottom + maxSize}))'`, + `box && box '((${left - maxSize},${top - maxSize}),(${right - maxSize},${bottom - maxSize}))'`, + `box && box '((${left - maxSize},${top}),(${right - maxSize},${bottom}))'`, + `box && box '((${left},${top - maxSize}),(${right},${bottom - maxSize}))'` ]; - return results; + return `SELECT * FROM widgets WHERE ${boxes.join(' OR ')}`; }; const serialize = function serialize(widget) { @@ -35,13 +33,19 @@ const serialize = function serialize(widget) { }; let ac = null; -export const widgets = derived(sensor, async function ($sensor, set) { - const boxes = getBoxes($sensor); +export const widgets = derived(sensor, async ($sensor, set) => { + const query = getBoxQuery($sensor); ac && ac.abort(); ac = new AbortController(); - const { data } = await client.from('widgets').select().or(boxes.join(',')).abortSignal(ac.signal); - if (data) { - return set(data.map(serialize)); + try { + const { rows } = await queryWithAbort(query, [], ac.signal); + if (rows) { + return set(rows.map(serialize)); + } + } catch (error) { + if (error.message !== 'Query aborted') { + console.error('Error fetching widgets:', error); + } } }); @@ -51,13 +55,16 @@ export const countElements = function countElements(left, top, right, bottom) { (async function () { countAc && countAc.abort(); countAc = new AbortController(); - const { data } = await client - .from('widgets') - .select('*', { head: true, count: 'estimated' }) - .or(`box.ov."((${left},${top}),(${right},${bottom}))"`) - .abortSignal(countAc.signal); - if (data) { - return set(data); + try { + const countQuery = `SELECT COUNT(*) FROM widgets WHERE box && box '((${left},${top}),(${right},${bottom}))'`; + const { rows } = await queryWithAbort(countQuery, [], countAc.signal); + if (rows && rows[0]) { + return set(parseInt(rows[0].count)); + } + } catch (error) { + if (error.message !== 'Query aborted') { + console.error('Error counting widgets:', error); + } } })(); }); |