Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

json result helpers #114

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 66 additions & 14 deletions api/src/DuckDBDataChunk.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import duckdb from '@duckdb/node-bindings';
import { DuckDBType } from './DuckDBType';
import { DuckDBValueConverter } from './DuckDBValueConverter';
import { DuckDBVector } from './DuckDBVector';
import { DuckDBValue } from './values';

Expand Down Expand Up @@ -49,19 +50,32 @@ export class DuckDBDataChunk {
visitValue: (
value: DuckDBValue,
rowIndex: number,
columnIndex: number
columnIndex: number,
type: DuckDBType
) => void
) {
const vector = this.getColumnVector(columnIndex);
const type = vector.type;
for (let rowIndex = 0; rowIndex < vector.itemCount; rowIndex++) {
visitValue(vector.getItem(rowIndex), rowIndex, columnIndex);
visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, type);
}
}
public getColumnValues(columnIndex: number): DuckDBValue[] {
const values: DuckDBValue[] = [];
this.visitColumnValues(columnIndex, (value) => values.push(value));
return values;
}
public convertColumnValues<T>(
columnIndex: number,
converter: DuckDBValueConverter<T>
): T[] {
const convertedValues: T[] = [];
const type = this.getColumnVector(columnIndex).type;
this.visitColumnValues(columnIndex, (value) =>
convertedValues.push(converter.convertValue(value, type))
);
return convertedValues;
}
public setColumnValues(columnIndex: number, values: readonly DuckDBValue[]) {
const vector = this.getColumnVector(columnIndex);
if (vector.itemCount !== values.length) {
Expand All @@ -73,18 +87,34 @@ export class DuckDBDataChunk {
vector.flush();
}
public visitColumns(
visitColumn: (column: DuckDBValue[], columnIndex: number) => void
visitColumn: (
column: DuckDBValue[],
columnIndex: number,
type: DuckDBType
) => void
) {
const columnCount = this.columnCount;
for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
visitColumn(this.getColumnValues(columnIndex), columnIndex);
visitColumn(
this.getColumnValues(columnIndex),
columnIndex,
this.getColumnVector(columnIndex).type
);
}
}
public getColumns(): DuckDBValue[][] {
const columns: DuckDBValue[][] = [];
this.visitColumns((column) => columns.push(column));
return columns;
}
public convertColumns<T>(converter: DuckDBValueConverter<T>): T[][] {
const convertedColumns: T[][] = [];
const columnCount = this.columnCount;
for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
convertedColumns.push(this.convertColumnValues(columnIndex, converter));
}
return convertedColumns;
}
public setColumns(columns: readonly (readonly DuckDBValue[])[]) {
if (columns.length > 0) {
this.rowCount = columns[0].length;
Expand All @@ -97,7 +127,8 @@ export class DuckDBDataChunk {
visitValue: (
value: DuckDBValue,
rowIndex: number,
columnIndex: number
columnIndex: number,
type: DuckDBType
) => void
) {
const columnCount = this.columnCount;
Expand All @@ -110,23 +141,33 @@ export class DuckDBDataChunk {
visitValue: (
value: DuckDBValue,
rowIndex: number,
columnIndex: number
columnIndex: number,
type: DuckDBType
) => void
) {
const columnCount = this.columnCount;
for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
visitValue(
this.getColumnVector(columnIndex).getItem(rowIndex),
rowIndex,
columnIndex
);
const vector = this.getColumnVector(columnIndex);
visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, vector.type);
}
}
public getRowValues(rowIndex: number): DuckDBValue[] {
const values: DuckDBValue[] = [];
this.visitRowValues(rowIndex, (value) => values.push(value));
return values;
}
public convertRowValues<T>(
rowIndex: number,
converter: DuckDBValueConverter<T>
): T[] {
const convertedValues: T[] = [];
this.visitRowValues(rowIndex, (value, _, columnIndex) =>
convertedValues.push(
converter.convertValue(value, this.getColumnVector(columnIndex).type)
)
);
return convertedValues;
}
public visitRows(visitRow: (row: DuckDBValue[], rowIndex: number) => void) {
const rowCount = this.rowCount;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
Expand All @@ -138,6 +179,14 @@ export class DuckDBDataChunk {
this.visitRows((row) => rows.push(row));
return rows;
}
public convertRows<T>(converter: DuckDBValueConverter<T>): T[][] {
const convertedRows: T[][] = [];
const rowCount = this.rowCount;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
convertedRows.push(this.convertRowValues(rowIndex, converter));
}
return convertedRows;
}
public setRows(rows: readonly (readonly DuckDBValue[])[]) {
this.rowCount = rows.length;
const columnCount = this.columnCount;
Expand All @@ -153,17 +202,20 @@ export class DuckDBDataChunk {
visitValue: (
value: DuckDBValue,
rowIndex: number,
columnIndex: number
columnIndex: number,
type: DuckDBType
) => void
) {
const rowCount = this.rowCount;
const columnCount = this.columnCount;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
const vector = this.getColumnVector(columnIndex);
visitValue(
this.getColumnVector(columnIndex).getItem(rowIndex),
vector.getItem(rowIndex),
rowIndex,
columnIndex
columnIndex,
vector.type
);
}
}
Expand Down
29 changes: 29 additions & 0 deletions api/src/DuckDBResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { DuckDBDataChunk } from './DuckDBDataChunk';
import { DuckDBLogicalType } from './DuckDBLogicalType';
import { DuckDBType } from './DuckDBType';
import { DuckDBTypeId } from './DuckDBTypeId';
import { DuckDBValueToJsonConverter, Json } from './DuckDBValueToJsonConverter';
import { convertColumnsFromChunks } from './convertColumnsFromChunks';
import { convertColumnsObjectFromChunks } from './convertColumnsObjectFromChunks';
import { convertRowObjectsFromChunks } from './convertRowObjectsFromChunks';
import { convertRowsFromChunks } from './convertRowsFromChunks';
import { ResultReturnType, StatementType } from './enums';
import { getColumnsFromChunks } from './getColumnsFromChunks';
import { getColumnsObjectFromChunks } from './getColumnsObjectFromChunks';
Expand Down Expand Up @@ -99,16 +104,40 @@ export class DuckDBResult {
const chunks = await this.fetchAllChunks();
return getColumnsFromChunks(chunks);
}
public async getColumnsJson(): Promise<Json[][]> {
const chunks = await this.fetchAllChunks();
return convertColumnsFromChunks(chunks, DuckDBValueToJsonConverter.default);
}
public async getColumnsObject(): Promise<Record<string, DuckDBValue[]>> {
const chunks = await this.fetchAllChunks();
return getColumnsObjectFromChunks(chunks, this.deduplicatedColumnNames());
}
public async getColumnsObjectJson(): Promise<Record<string, Json[]>> {
const chunks = await this.fetchAllChunks();
return convertColumnsObjectFromChunks(
chunks,
this.deduplicatedColumnNames(),
DuckDBValueToJsonConverter.default
);
}
public async getRows(): Promise<DuckDBValue[][]> {
const chunks = await this.fetchAllChunks();
return getRowsFromChunks(chunks);
}
public async getRowsJson(): Promise<Json[][]> {
const chunks = await this.fetchAllChunks();
return convertRowsFromChunks(chunks, DuckDBValueToJsonConverter.default);
}
public async getRowObjects(): Promise<Record<string, DuckDBValue>[]> {
const chunks = await this.fetchAllChunks();
return getRowObjectsFromChunks(chunks, this.deduplicatedColumnNames());
}
public async getRowObjectsJson(): Promise<Record<string, Json>[]> {
const chunks = await this.fetchAllChunks();
return convertRowObjectsFromChunks(
chunks,
this.deduplicatedColumnNames(),
DuckDBValueToJsonConverter.default
);
}
}
42 changes: 40 additions & 2 deletions api/src/DuckDBResultReader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { convertColumnsFromChunks } from './convertColumnsFromChunks';
import { convertColumnsObjectFromChunks } from './convertColumnsObjectFromChunks';
import { convertRowObjectsFromChunks } from './convertRowObjectsFromChunks';
import { convertRowsFromChunks } from './convertRowsFromChunks';
import { DuckDBDataChunk } from './DuckDBDataChunk';
import { DuckDBLogicalType } from './DuckDBLogicalType';
import { DuckDBResult } from './DuckDBResult';
import { DuckDBType } from './DuckDBType';
import { DuckDBTypeId } from './DuckDBTypeId';
import { DuckDBValueToJsonConverter, Json } from './DuckDBValueToJsonConverter';
import { ResultReturnType, StatementType } from './enums';
import { getColumnsFromChunks } from './getColumnsFromChunks';
import { getColumnsObjectFromChunks } from './getColumnsObjectFromChunks';
Expand Down Expand Up @@ -163,15 +168,48 @@ export class DuckDBResultReader {
return getColumnsFromChunks(this.chunks);
}

public getColumnsJson(): Json[][] {
return convertColumnsFromChunks(
this.chunks,
DuckDBValueToJsonConverter.default
);
}

public getColumnsObject(): Record<string, DuckDBValue[]> {
return getColumnsObjectFromChunks(this.chunks, this.deduplicatedColumnNames());
return getColumnsObjectFromChunks(
this.chunks,
this.deduplicatedColumnNames()
);
}

public getColumnsObjectJson(): Record<string, Json[]> {
return convertColumnsObjectFromChunks(
this.chunks,
this.deduplicatedColumnNames(),
DuckDBValueToJsonConverter.default
);
}

public getRows(): DuckDBValue[][] {
return getRowsFromChunks(this.chunks);
}

public getRowObjecs(): Record<string, DuckDBValue>[] {
public getRowsJson(): Json[][] {
return convertRowsFromChunks(
this.chunks,
DuckDBValueToJsonConverter.default
);
}

public getRowObjects(): Record<string, DuckDBValue>[] {
return getRowObjectsFromChunks(this.chunks, this.deduplicatedColumnNames());
}

public getRowObjectsJson(): Record<string, Json>[] {
return convertRowObjectsFromChunks(
this.chunks,
this.deduplicatedColumnNames(),
DuckDBValueToJsonConverter.default
);
}
}
15 changes: 15 additions & 0 deletions api/src/DuckDBType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ export function LIST(valueType: DuckDBType, alias?: string): DuckDBListType {
export class DuckDBStructType extends BaseDuckDBType<DuckDBTypeId.STRUCT> {
public readonly entryNames: readonly string[];
public readonly entryTypes: readonly DuckDBType[];
public readonly entryIndexes: Readonly<Record<string, number>>;
public constructor(
entryNames: readonly string[],
entryTypes: readonly DuckDBType[],
Expand All @@ -588,10 +589,21 @@ export class DuckDBStructType extends BaseDuckDBType<DuckDBTypeId.STRUCT> {
}
this.entryNames = entryNames;
this.entryTypes = entryTypes;
const entryIndexes: Record<string, number> = {};
for (let i = 0; i < entryNames.length; i++) {
entryIndexes[entryNames[i]] = i;
}
this.entryIndexes = entryIndexes;
}
public get entryCount() {
return this.entryNames.length;
}
public indexForEntry(entryName: string): number {
return this.entryIndexes[entryName];
}
public typeForEntry(entryName: string): DuckDBType {
return this.entryTypes[this.entryIndexes[entryName]];
}
public toString(): string {
const parts: string[] = [];
for (let i = 0; i < this.entryNames.length; i++) {
Expand Down Expand Up @@ -727,6 +739,9 @@ export class DuckDBUnionType extends BaseDuckDBType<DuckDBTypeId.UNION> {
public memberIndexForTag(tag: string): number {
return this.tagMemberIndexes[tag];
}
public memberTypeForTag(tag: string): DuckDBType {
return this.memberTypes[this.tagMemberIndexes[tag]];
}
public get memberCount() {
return this.memberTags.length;
}
Expand Down
6 changes: 6 additions & 0 deletions api/src/DuckDBValueConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DuckDBType } from './DuckDBType';
import { DuckDBValue } from './values';

export interface DuckDBValueConverter<T> {
convertValue(value: DuckDBValue, type: DuckDBType): T;
}
Loading
Loading