LCOV - code coverage report
Current view: top level - dashql-app/src/platform/hyperdb - hyperdb_parquet_export.ts Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 45 45
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import type * as arrow from 'apache-arrow';
       2              : 
       3              : import type { EmbeddedComputeDatabase, EmbeddedExternalDirectoryDatabase, EmbeddedExternalFileDatabase } from '../database/embedded_database.js';
       4              : import { getOPFSRoot } from '../opfs_root.js';
       5              : 
       6              : /// Hyper writes Parquet exports below this OPFS directory, they are read back and removed right after.
       7            1 : export const PARQUET_EXPORT_DIRECTORY = 'exports';
       8            1 : const PARQUET_EXPORT_FILE = 'result.parquet';
       9              : 
      10              : export type ParquetExportDatabase = EmbeddedComputeDatabase & EmbeddedExternalDirectoryDatabase;
      11              : 
      12            1 : export function supportsParquetExport(database: EmbeddedComputeDatabase | null): database is ParquetExportDatabase {
      13            1 :     return database != null && 'registerExternalDirectory' in database && 'removeExternalDirectory' in database;
      14            1 : }
      15              : 
      16              : /// Write an Arrow table as Parquet file to a path below a directory that is mounted read-write
      17            1 : export async function copyArrowTableAsParquet(database: EmbeddedComputeDatabase, table: arrow.Table, path: string): Promise<void> {
      18            1 :     const tableName = `__parquet_copy_${crypto.randomUUID().replace(/-/g, '_')}`;
      19            1 :     const connection = await database.connect({ pooled: true });
      20            1 :     try {
      21            1 :         await connection.insertArrowTable(table, { name: tableName });
      22            1 :         try {
      23            1 :             await connection.execute(`COPY (SELECT * FROM "${tableName}") TO '${path}' WITH (format => 'parquet')`);
      24            1 :         } finally {
      25            1 :             await connection.execute(`DROP TABLE IF EXISTS "${tableName}"`);
      26            1 :         }
      27            1 :     } finally {
      28            1 :         await connection.close();
      29            1 :     }
      30            1 : }
      31              : 
      32              : /// Write an Arrow table as Parquet file to OPFS with Hyper and read the file back.
      33              : /// Hyper only copies into registered targets, so every export mounts its own OPFS directory read-write.
      34            1 : export async function exportArrowTableAsParquet(
      35            1 :     database: ParquetExportDatabase,
      36            1 :     table: arrow.Table,
      37            1 :     getRoot: () => Promise<FileSystemDirectoryHandle> = getOPFSRoot,
      38            1 : ): Promise<Uint8Array> {
      39            1 :     const root = await getRoot();
      40            1 :     const exports = await root.getDirectoryHandle(PARQUET_EXPORT_DIRECTORY, { create: true });
      41            1 :     const id = crypto.randomUUID();
      42            1 :     const directory = await exports.getDirectoryHandle(id, { create: true });
      43            1 :     try {
      44            1 :         const path = await database.registerExternalDirectory(directory, `/mnt/external/parquet-export-${id}`, 'readwrite');
      45            1 :         try {
      46            1 :             await copyArrowTableAsParquet(database, table, `${path}/${PARQUET_EXPORT_FILE}`);
      47            1 :         } finally {
      48            1 :             await database.removeExternalDirectory(path);
      49            1 :         }
      50            1 :         const file = await (await directory.getFileHandle(PARQUET_EXPORT_FILE)).getFile();
      51            1 :         return new Uint8Array(await file.arrayBuffer());
      52            1 :     } finally {
      53            1 :         await exports.removeEntry(id, { recursive: true });
      54            1 :     }
      55            1 : }
      56              : 
      57              : /// A database that writes and reads Parquet files: it mounts directories to write them and files to read them, and
      58              : /// refreshes directory mounts whose files were removed
      59              : export type ParquetDatabase = ParquetExportDatabase & EmbeddedExternalFileDatabase;
      60              : 
      61            1 : export function supportsParquet(database: EmbeddedComputeDatabase | null): database is ParquetDatabase {
      62            1 :     return supportsParquetExport(database) && 'registerExternalFile' in database && 'removeExternalFile' in database
      63            1 :         && 'refreshExternalDirectory' in database;
      64            1 : }
        

Generated by: LCOV version 2.0-1