This commit is contained in:
@@ -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()!);
|
||||||
|
|||||||
@@ -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!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user