Add basic table sorting
All checks were successful
build / build (push) Successful in 1m20s

This commit is contained in:
2025-04-25 07:39:39 +09:30
parent cc5bbb9b6a
commit d225ff9048
2 changed files with 25 additions and 7 deletions

View File

@@ -7,6 +7,11 @@ export interface Column {
type: string; type: string;
} }
export interface SortColumn {
name: string;
sortType: 'asc' | 'desc';
}
export interface RowsResponse { export interface RowsResponse {
rows: any[]; rows: any[];
totalRows: bigint; totalRows: bigint;
@@ -98,6 +103,7 @@ export class DuckdbService {
start: number, start: number,
numRows: number, numRows: number,
columns: Column[], columns: Column[],
sorts: SortColumn[],
filters: unknown[], filters: unknown[],
aggregations: unknown[], aggregations: unknown[],
): Promise<RowsResponse> { ): Promise<RowsResponse> {
@@ -107,9 +113,12 @@ export class DuckdbService {
`SELECT COUNT(1) totalRows FROM ${sanitisedFileName(file)}`, `SELECT COUNT(1) totalRows FROM ${sanitisedFileName(file)}`,
); );
const { totalRows } = totalRowResponse.get(0)?.toJSON()!; const { totalRows } = totalRowResponse.get(0)?.toJSON()!;
const response = await conn.query( let query = `SELECT ${columns.map((column) => `"${column.name}"`).join(', ')} FROM ${sanitisedFileName(file)} `;
`SELECT ${columns.map((column) => `"${column.name}"`).join(', ')} FROM ${sanitisedFileName(file)} LIMIT ${numRows} OFFSET ${start}`, if (sorts.length > 0) {
); query += ` ORDER BY ${sorts.map((sort) => `"${sort.name}" ${sort.sortType}`).join(', ')}`;
}
query += ` LIMIT ${numRows} OFFSET ${start}`;
const response = await conn.query(query);
const rows = []; const rows = [];
for (let i = 0; i < response.numRows; i++) { for (let i = 0; i < response.numRows; i++) {
rows.push(response.get(i)?.toJSON()!); rows.push(response.get(i)?.toJSON()!);

View File

@@ -20,6 +20,7 @@ import { Column, DuckdbService } from '../duckdb.service';
template: ` template: `
@if (file() && columns().length > 0) { @if (file() && columns().length > 0) {
<p-table <p-table
sortMode="multiple"
[reorderableColumns]="true" [reorderableColumns]="true"
[resizableColumns]="true" [resizableColumns]="true"
columnResizeMode="expand" columnResizeMode="expand"
@@ -37,8 +38,12 @@ import { Column, DuckdbService } from '../duckdb.service';
<ng-template #header let-columns> <ng-template #header let-columns>
<tr> <tr>
@for (col of columns; track $index) { @for (col of columns; track $index) {
<th pReorderableColumn pResizableColumn> <th
{{ col.name }} pReorderableColumn
pResizableColumn
[pSortableColumn]="col.name"
>
{{ col.name }} <p-sortIcon [field]="col.name" />
</th> </th>
} }
</tr> </tr>
@@ -71,7 +76,6 @@ export class FileViewerComponent {
file = input<File | undefined>(); file = input<File | undefined>();
private duckdbService = inject(DuckdbService); private duckdbService = inject(DuckdbService);
private cdr = inject(ChangeDetectorRef);
// Can't be computed since effect has to run first so file exists in duckdb // Can't be computed since effect has to run first so file exists in duckdb
protected columns = signal<Column[]>([]); protected columns = signal<Column[]>([]);
@@ -92,6 +96,7 @@ export class FileViewerComponent {
this.columns(), this.columns(),
[], [],
[], [],
[],
); );
const newValue = Array.from({ length: Number(rows.totalRows) }); const newValue = Array.from({ length: Number(rows.totalRows) });
this.currentValue.set(newValue); this.currentValue.set(newValue);
@@ -107,6 +112,10 @@ export class FileViewerComponent {
event.first ?? 0, event.first ?? 0,
event.rows ?? 0, event.rows ?? 0,
this.columns(), this.columns(),
event.multiSortMeta?.map((meta) => ({
name: meta.field,
sortType: meta.order < 0 ? 'desc' : 'asc',
})) ?? [],
[], [],
[], [],
); );
@@ -122,7 +131,7 @@ export class FileViewerComponent {
} }
// Can't update the current value, otherwise we get an infinite loop // Can't update the current value, otherwise we get an infinite loop
this.currentValue().splice(event.first!, event.rows!, ...rows.rows); this.currentValue().splice(event.first!, event.rows!, ...rows.rows);
this.cdr.markForCheck(); event.forceUpdate!();
} }
} }
} }