import React from 'react'; import * as imm from 'immutable'; import * as duckdb from '@duckdb/duckdb-wasm'; import { useDuckDB, useDuckDBResolver } from './database_provider'; type DialerFn = (id?: number) => void; export const poolCtx = React.createContext>(imm.Map()); export const dialerCtx = React.createContext(null); export const useDuckDBConnection = (id?: number): duckdb.AsyncDuckDBConnection | null => React.useContext(poolCtx)?.get(id || 0) || null; export const useDuckDBConnectionDialer = (): DialerFn => React.useContext(dialerCtx)!; type DuckDBConnectionProps = { /// The children children: React.ReactElement | React.ReactElement[]; /// The epoch epoch?: number; }; export const DuckDBConnectionProvider: React.FC = (props: DuckDBConnectionProps) => { const db = useDuckDB(); const resolveDB = useDuckDBResolver(); const [pending, setPending] = React.useState>(imm.List()); const [pool, setPool] = React.useState>(imm.Map()); const inFlight = React.useRef>(new Map()); // Resolve request assuming that the database is ready const dialer = async (id: number) => { if (inFlight.current.get(id)) { return; } const conn = await db!.value!.connect(); setPool(p => p.set(id, conn)); inFlight.current.delete(id); }; // Resolve request or remember as pending const dialerCallback = React.useCallback( (id?: number) => { if (db.value != null) { dialer(id || 0); } else if (!db.resolving()) { resolveDB(); setPending(pending.push(id || 0)); } }, [db], ); // Process pending if possible React.useEffect(() => { if (db.value == null) { return; } const claimed = pending; setPending(imm.List()); for (const id of claimed) { dialer(id); } }, [db, pending]); return ( {props.children} ); };