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();
}
}
}