import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, inject, input, signal, viewChild, } from '@angular/core'; import { Skeleton } from 'primeng/skeleton'; import { Table, TableLazyLoadEvent, TableModule } from 'primeng/table'; import { Column, DuckdbService } from '../duckdb.service'; @Component({ selector: 'app-file-viewer', standalone: true, imports: [TableModule, Skeleton], template: ` @if (file() && columns().length > 0) { @for (col of columns; track $index) { {{ col.name }} } @for (col of columns; track $index) { {{ rowData[col.name] }} } @for (col of columns; track $index) { } } `, styleUrl: './file-viewer.component.css', changeDetection: ChangeDetectionStrategy.OnPush, }) export class FileViewerComponent { file = input(); private duckdbService = inject(DuckdbService); private cdr = inject(ChangeDetectorRef); // Can't be computed since effect has to run first so file exists in duckdb protected columns = signal([]); private table = viewChild(Table); // TODO: Basically make this an array of the same length as the number of rows, but an empty array. // We'll then store the actual current values in a separate array, then use the offset + row index // to get the actual value. This is so we don't store a crazy amount of data. // Alternative is to store current page data in the array (but keep the array length), and clear out the array each // time the page changes. protected currentValue = signal([]); constructor() { effect(async () => { const file = this.file(); if (file) { await this.duckdbService.addFile(file); this.columns.set(await this.duckdbService.getColumns(file)); const rows = await this.duckdbService.getRows( file, 0, 100, this.columns(), [], [], ); const newValue = Array.from({ length: Number(rows.totalRows) }); this.currentValue.set(newValue); } }); } protected async onLazyLoad(event: TableLazyLoadEvent) { const file = this.file(); if (file) { const rows = await this.duckdbService.getRows( file, event.first ?? 0, event.rows ?? 0, this.columns(), [], [], ); // First clear out existing data, don't want to risk loading entire file into memory this.currentValue().fill(undefined); // Can't update the current value, otherwise we get an infinite loop this.currentValue().splice(event.first!, event.rows!, ...rows.rows); this.cdr.markForCheck(); } } }