From e9b28157b8364f5579b36d237ce4a521d8217ba3 Mon Sep 17 00:00:00 2001 From: Jeff Raymakers Date: Sat, 2 Nov 2024 13:58:44 -0700 Subject: [PATCH 1/2] logical type alias and cleanup --- api/src/DuckDBAppender.ts | 4 +- api/src/DuckDBLogicalType.ts | 82 ++++----- api/src/DuckDBResult.ts | 4 +- api/src/DuckDBType.ts | 240 +++++++++++++++++-------- api/src/DuckDBVector.ts | 2 +- bindings/test/utils/expectChunk.ts | 7 +- bindings/test/utils/expectResult.ts | 5 +- bindings/test/utils/withLogicalType.ts | 5 - 8 files changed, 209 insertions(+), 140 deletions(-) delete mode 100644 bindings/test/utils/withLogicalType.ts diff --git a/api/src/DuckDBAppender.ts b/api/src/DuckDBAppender.ts index 531e1768..817ba195 100644 --- a/api/src/DuckDBAppender.ts +++ b/api/src/DuckDBAppender.ts @@ -24,7 +24,9 @@ export class DuckDBAppender { return duckdb.appender_column_count(this.appender); } public columnType(columnIndex: number): DuckDBType { - return DuckDBLogicalType.consumeAsType(duckdb.appender_column_type(this.appender, columnIndex)); + return DuckDBLogicalType.create( + duckdb.appender_column_type(this.appender, columnIndex) + ).asType(); } public endRow() { duckdb.appender_end_row(this.appender); diff --git a/api/src/DuckDBLogicalType.ts b/api/src/DuckDBLogicalType.ts index 16601b6d..2214b9af 100644 --- a/api/src/DuckDBLogicalType.ts +++ b/api/src/DuckDBLogicalType.ts @@ -45,11 +45,6 @@ export class DuckDBLogicalType { protected constructor(logical_type: duckdb.LogicalType) { this.logical_type = logical_type; } - static consumeAsType(logical_type: duckdb.LogicalType): DuckDBType { - const logicalType = DuckDBLogicalType.create(logical_type); - const type = logicalType.asType(); - return type; - } static create(logical_type: duckdb.LogicalType): DuckDBLogicalType { switch (duckdb.get_type_id(logical_type)) { case duckdb.Type.DECIMAL: @@ -147,60 +142,61 @@ export class DuckDBLogicalType { public get typeId(): DuckDBTypeId { return duckdb.get_type_id(this.logical_type) as number as DuckDBTypeId; } - public get alias(): string | null { - return duckdb.logical_type_get_alias(this.logical_type); + public get alias(): string | undefined { + return duckdb.logical_type_get_alias(this.logical_type) || undefined; } public set alias(newAlias: string) { duckdb.logical_type_set_alias(this.logical_type, newAlias); } public asType(): DuckDBType { + const alias = this.alias; switch (this.typeId) { case DuckDBTypeId.BOOLEAN: - return DuckDBBooleanType.instance; + return DuckDBBooleanType.create(alias); case DuckDBTypeId.TINYINT: - return DuckDBTinyIntType.instance; + return DuckDBTinyIntType.create(alias); case DuckDBTypeId.SMALLINT: - return DuckDBSmallIntType.instance; + return DuckDBSmallIntType.create(alias); case DuckDBTypeId.INTEGER: - return DuckDBIntegerType.instance; + return DuckDBIntegerType.create(alias); case DuckDBTypeId.BIGINT: - return DuckDBBigIntType.instance; + return DuckDBBigIntType.create(alias); case DuckDBTypeId.UTINYINT: - return DuckDBUTinyIntType.instance; + return DuckDBUTinyIntType.create(alias); case DuckDBTypeId.USMALLINT: - return DuckDBUSmallIntType.instance; + return DuckDBUSmallIntType.create(alias); case DuckDBTypeId.UINTEGER: - return DuckDBUIntegerType.instance; + return DuckDBUIntegerType.create(alias); case DuckDBTypeId.UBIGINT: - return DuckDBUBigIntType.instance; + return DuckDBUBigIntType.create(alias); case DuckDBTypeId.FLOAT: - return DuckDBFloatType.instance; + return DuckDBFloatType.create(alias); case DuckDBTypeId.DOUBLE: - return DuckDBDoubleType.instance; + return DuckDBDoubleType.create(alias); case DuckDBTypeId.TIMESTAMP: - return DuckDBTimestampType.instance; + return DuckDBTimestampType.create(alias); case DuckDBTypeId.DATE: - return DuckDBDateType.instance; + return DuckDBDateType.create(alias); case DuckDBTypeId.TIME: - return DuckDBTimeType.instance; + return DuckDBTimeType.create(alias); case DuckDBTypeId.INTERVAL: - return DuckDBIntervalType.instance; + return DuckDBIntervalType.create(alias); case DuckDBTypeId.HUGEINT: - return DuckDBHugeIntType.instance; + return DuckDBHugeIntType.create(alias); case DuckDBTypeId.UHUGEINT: - return DuckDBUHugeIntType.instance; + return DuckDBUHugeIntType.create(alias); case DuckDBTypeId.VARCHAR: - return DuckDBVarCharType.instance; + return DuckDBVarCharType.create(alias); case DuckDBTypeId.BLOB: - return DuckDBBlobType.instance; + return DuckDBBlobType.create(alias); case DuckDBTypeId.DECIMAL: throw new Error('Expected override'); case DuckDBTypeId.TIMESTAMP_S: - return DuckDBTimestampSecondsType.instance; + return DuckDBTimestampSecondsType.create(alias); case DuckDBTypeId.TIMESTAMP_MS: - return DuckDBTimestampMillisecondsType.instance; + return DuckDBTimestampMillisecondsType.create(alias); case DuckDBTypeId.TIMESTAMP_NS: - return DuckDBTimestampNanosecondsType.instance; + return DuckDBTimestampNanosecondsType.create(alias); case DuckDBTypeId.ENUM: throw new Error('Expected override'); case DuckDBTypeId.LIST: @@ -212,21 +208,21 @@ export class DuckDBLogicalType { case DuckDBTypeId.ARRAY: throw new Error('Expected override'); case DuckDBTypeId.UUID: - return DuckDBUUIDType.instance; + return DuckDBUUIDType.create(alias); case DuckDBTypeId.UNION: throw new Error('Expected override'); case DuckDBTypeId.BIT: - return DuckDBBitType.instance; + return DuckDBBitType.create(alias); case DuckDBTypeId.TIME_TZ: - return DuckDBTimeTZType.instance; + return DuckDBTimeTZType.create(alias); case DuckDBTypeId.TIMESTAMP_TZ: - return DuckDBTimestampTZType.instance; + return DuckDBTimestampTZType.create(alias); case DuckDBTypeId.ANY: - return DuckDBAnyType.instance; + return DuckDBAnyType.create(alias); case DuckDBTypeId.VARINT: - return DuckDBVarIntType.instance; + return DuckDBVarIntType.create(alias); case DuckDBTypeId.SQLNULL: - return DuckDBSQLNullType.instance; + return DuckDBSQLNullType.create(alias); default: throw new Error(`Unexpected type id: ${this.typeId}`); } @@ -246,7 +242,7 @@ export class DuckDBDecimalLogicalType extends DuckDBLogicalType { ) as number as DuckDBTypeId; } public override asType(): DuckDBDecimalType { - return new DuckDBDecimalType(this.width, this.scale); + return new DuckDBDecimalType(this.width, this.scale, this.alias); } } @@ -271,7 +267,7 @@ export class DuckDBEnumLogicalType extends DuckDBLogicalType { ) as number as DuckDBTypeId; } public override asType(): DuckDBEnumType { - return new DuckDBEnumType(this.values(), this.internalTypeId); + return new DuckDBEnumType(this.values(), this.internalTypeId, this.alias); } } @@ -282,7 +278,7 @@ export class DuckDBListLogicalType extends DuckDBLogicalType { ); } public override asType(): DuckDBListType { - return new DuckDBListType(this.valueType.asType()); + return new DuckDBListType(this.valueType.asType(), this.alias); } } @@ -326,7 +322,7 @@ export class DuckDBStructLogicalType extends DuckDBLogicalType { return valueTypes; } public override asType(): DuckDBStructType { - return new DuckDBStructType(this.entryNames(), this.entryTypes()); + return new DuckDBStructType(this.entryNames(), this.entryTypes(), this.alias); } } @@ -342,7 +338,7 @@ export class DuckDBMapLogicalType extends DuckDBLogicalType { ); } public override asType(): DuckDBMapType { - return new DuckDBMapType(this.keyType.asType(), this.valueType.asType()); + return new DuckDBMapType(this.keyType.asType(), this.valueType.asType(), this.alias); } } @@ -356,7 +352,7 @@ export class DuckDBArrayLogicalType extends DuckDBLogicalType { return duckdb.array_type_array_size(this.logical_type); } public override asType(): DuckDBArrayType { - return new DuckDBArrayType(this.valueType.asType(), this.length); + return new DuckDBArrayType(this.valueType.asType(), this.length, this.alias); } } @@ -400,6 +396,6 @@ export class DuckDBUnionLogicalType extends DuckDBLogicalType { return valueTypes; } public override asType(): DuckDBUnionType { - return new DuckDBUnionType(this.memberTags(), this.memberTypes()); + return new DuckDBUnionType(this.memberTags(), this.memberTypes(), this.alias); } } diff --git a/api/src/DuckDBResult.ts b/api/src/DuckDBResult.ts index caedc981..cd44621d 100644 --- a/api/src/DuckDBResult.ts +++ b/api/src/DuckDBResult.ts @@ -34,9 +34,9 @@ export class DuckDBResult { ); } public columnType(columnIndex: number): DuckDBType { - return DuckDBLogicalType.consumeAsType( + return DuckDBLogicalType.create( duckdb.column_logical_type(this.result, columnIndex) - ); + ).asType(); } public get rowsChanged(): number { return duckdb.rows_changed(this.result); diff --git a/api/src/DuckDBType.ts b/api/src/DuckDBType.ts index b6719d3e..d7fe4ea0 100644 --- a/api/src/DuckDBType.ts +++ b/api/src/DuckDBType.ts @@ -3,8 +3,10 @@ import { quotedIdentifier, quotedString } from './sql'; export abstract class BaseDuckDBType { public readonly typeId: T; - protected constructor(typeId: T) { + public readonly alias?: string; + protected constructor(typeId: T, alias?: string) { this.typeId = typeId; + this.alias = alias; } public toString(): string { return DuckDBTypeId[this.typeId]; @@ -12,170 +14,227 @@ export abstract class BaseDuckDBType { } export class DuckDBBooleanType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.BOOLEAN); + public constructor(alias?: string) { + super(DuckDBTypeId.BOOLEAN, alias); } public static readonly instance = new DuckDBBooleanType(); + public static create(alias?: string): DuckDBBooleanType { + return alias ? new DuckDBBooleanType(alias) : DuckDBBooleanType.instance; + } } export class DuckDBTinyIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TINYINT); + public constructor(alias?: string) { + super(DuckDBTypeId.TINYINT, alias); } public static readonly instance = new DuckDBTinyIntType(); + public static create(alias?: string): DuckDBTinyIntType { + return alias ? new DuckDBTinyIntType(alias) : DuckDBTinyIntType.instance; + } public static readonly Max = 2 ** 7 - 1; public static readonly Min = -(2 ** 7); } export class DuckDBSmallIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.SMALLINT); + public constructor(alias?: string) { + super(DuckDBTypeId.SMALLINT, alias); } public static readonly instance = new DuckDBSmallIntType(); + public static create(alias?: string): DuckDBSmallIntType { + return alias ? new DuckDBSmallIntType(alias) : DuckDBSmallIntType.instance; + } public static readonly Max = 2 ** 15 - 1; public static readonly Min = -(2 ** 15); } export class DuckDBIntegerType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.INTEGER); + public constructor(alias?: string) { + super(DuckDBTypeId.INTEGER, alias); } public static readonly instance = new DuckDBIntegerType(); + public static create(alias?: string): DuckDBIntegerType { + return alias ? new DuckDBIntegerType(alias) : DuckDBIntegerType.instance; + } public static readonly Max = 2 ** 31 - 1; public static readonly Min = -(2 ** 31); } export class DuckDBBigIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.BIGINT); + public constructor(alias?: string) { + super(DuckDBTypeId.BIGINT, alias); } public static readonly instance = new DuckDBBigIntType(); + public static create(alias?: string): DuckDBBigIntType { + return alias ? new DuckDBBigIntType(alias) : DuckDBBigIntType.instance; + } public static readonly Max = 2n ** 63n - 1n; public static readonly Min = -(2n ** 63n); } export class DuckDBUTinyIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.UTINYINT); + public constructor(alias?: string) { + super(DuckDBTypeId.UTINYINT, alias); } public static readonly instance = new DuckDBUTinyIntType(); + public static create(alias?: string): DuckDBUTinyIntType { + return alias ? new DuckDBUTinyIntType(alias) : DuckDBUTinyIntType.instance; + } public static readonly Max = 2 ** 8 - 1; public static readonly Min = 0; } export class DuckDBUSmallIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.USMALLINT); + public constructor(alias?: string) { + super(DuckDBTypeId.USMALLINT, alias); } public static readonly instance = new DuckDBUSmallIntType(); + public static create(alias?: string): DuckDBUSmallIntType { + return alias ? new DuckDBUSmallIntType(alias) : DuckDBUSmallIntType.instance; + } public static readonly Max = 2 ** 16 - 1; public static readonly Min = 0; } export class DuckDBUIntegerType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.UINTEGER); + public constructor(alias?: string) { + super(DuckDBTypeId.UINTEGER, alias); } public static readonly instance = new DuckDBUIntegerType(); + public static create(alias?: string): DuckDBUIntegerType { + return alias ? new DuckDBUIntegerType(alias) : DuckDBUIntegerType.instance; + } public static readonly Max = 2 ** 32 - 1; public static readonly Min = 0; } export class DuckDBUBigIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.UBIGINT); + public constructor(alias?: string) { + super(DuckDBTypeId.UBIGINT, alias); } public static readonly instance = new DuckDBUBigIntType(); + public static create(alias?: string): DuckDBUBigIntType { + return alias ? new DuckDBUBigIntType(alias) : DuckDBUBigIntType.instance; + } public static readonly Max = 2n ** 64n - 1n; public static readonly Min = 0n; } export class DuckDBFloatType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.FLOAT); + public constructor(alias?: string) { + super(DuckDBTypeId.FLOAT, alias); } public static readonly instance = new DuckDBFloatType(); + public static create(alias?: string): DuckDBFloatType { + return alias ? new DuckDBFloatType(alias) : DuckDBFloatType.instance; + } public static readonly Min = Math.fround(-3.4028235e+38); public static readonly Max = Math.fround( 3.4028235e+38); } export class DuckDBDoubleType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.DOUBLE); + public constructor(alias?: string) { + super(DuckDBTypeId.DOUBLE, alias); } public static readonly instance = new DuckDBDoubleType(); + public static create(alias?: string): DuckDBDoubleType { + return alias ? new DuckDBDoubleType(alias) : DuckDBDoubleType.instance; + } public static readonly Min = -Number.MAX_VALUE; public static readonly Max = Number.MAX_VALUE; } export class DuckDBTimestampType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIMESTAMP); + public constructor(alias?: string) { + super(DuckDBTypeId.TIMESTAMP, alias); } public static readonly instance = new DuckDBTimestampType(); + public static create(alias?: string): DuckDBTimestampType { + return alias ? new DuckDBTimestampType(alias) : DuckDBTimestampType.instance; + } } export type DuckDBTimestampMicrosecondsType = DuckDBTimestampType; export const DuckDBTimestampMicrosecondsType = DuckDBTimestampType; export class DuckDBDateType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.DATE); + public constructor(alias?: string) { + super(DuckDBTypeId.DATE, alias); } public static readonly instance = new DuckDBDateType(); + public static create(alias?: string): DuckDBDateType { + return alias ? new DuckDBDateType(alias) : DuckDBDateType.instance; + } } export class DuckDBTimeType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIME); + public constructor(alias?: string) { + super(DuckDBTypeId.TIME, alias); } public static readonly instance = new DuckDBTimeType(); + public static create(alias?: string): DuckDBTimeType { + return alias ? new DuckDBTimeType(alias) : DuckDBTimeType.instance; + } } export class DuckDBIntervalType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.INTERVAL); + public constructor(alias?: string) { + super(DuckDBTypeId.INTERVAL, alias); } public static readonly instance = new DuckDBIntervalType(); + public static create(alias?: string): DuckDBIntervalType { + return alias ? new DuckDBIntervalType(alias) : DuckDBIntervalType.instance; + } } export class DuckDBHugeIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.HUGEINT); + public constructor(alias?: string) { + super(DuckDBTypeId.HUGEINT, alias); } public static readonly instance = new DuckDBHugeIntType(); + public static create(alias?: string): DuckDBHugeIntType { + return alias ? new DuckDBHugeIntType(alias) : DuckDBHugeIntType.instance; + } public static readonly Max = 2n ** 127n - 1n; public static readonly Min = -(2n ** 127n); } export class DuckDBUHugeIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.UHUGEINT); + public constructor(alias?: string) { + super(DuckDBTypeId.UHUGEINT, alias); } public static readonly instance = new DuckDBUHugeIntType(); + public static create(alias?: string): DuckDBUHugeIntType { + return alias ? new DuckDBUHugeIntType(alias) : DuckDBUHugeIntType.instance; + } public static readonly Max = 2n ** 128n - 1n; public static readonly Min = 0n; } export class DuckDBVarCharType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.VARCHAR); + public constructor(alias?: string) { + super(DuckDBTypeId.VARCHAR, alias); } public static readonly instance = new DuckDBVarCharType(); + public static create(alias?: string): DuckDBVarCharType { + return alias ? new DuckDBVarCharType(alias) : DuckDBVarCharType.instance; + } } export class DuckDBBlobType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.BLOB); + public constructor(alias?: string) { + super(DuckDBTypeId.BLOB, alias); } public static readonly instance = new DuckDBBlobType(); + public static create(alias?: string): DuckDBBlobType { + return alias ? new DuckDBBlobType(alias) : DuckDBBlobType.instance; + } } export class DuckDBDecimalType extends BaseDuckDBType { public readonly width: number; public readonly scale: number; - public constructor(width: number, scale: number) { - super(DuckDBTypeId.DECIMAL); + public constructor(width: number, scale: number, alias?: string) { + super(DuckDBTypeId.DECIMAL, alias); this.width = width; this.scale = scale; } @@ -186,31 +245,40 @@ export class DuckDBDecimalType extends BaseDuckDBType { } export class DuckDBTimestampSecondsType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIMESTAMP_S); + public constructor(alias?: string) { + super(DuckDBTypeId.TIMESTAMP_S, alias); } public static readonly instance = new DuckDBTimestampSecondsType(); + public static create(alias?: string): DuckDBTimestampSecondsType { + return alias ? new DuckDBTimestampSecondsType(alias) : DuckDBTimestampSecondsType.instance; + } } export class DuckDBTimestampMillisecondsType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIMESTAMP_MS); + public constructor(alias?: string) { + super(DuckDBTypeId.TIMESTAMP_MS, alias); } public static readonly instance = new DuckDBTimestampMillisecondsType(); + public static create(alias?: string): DuckDBTimestampMillisecondsType { + return alias ? new DuckDBTimestampMillisecondsType(alias) : DuckDBTimestampMillisecondsType.instance; + } } export class DuckDBTimestampNanosecondsType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIMESTAMP_NS); + public constructor(alias?: string) { + super(DuckDBTypeId.TIMESTAMP_NS, alias); } public static readonly instance = new DuckDBTimestampNanosecondsType(); + public static create(alias?: string): DuckDBTimestampNanosecondsType { + return alias ? new DuckDBTimestampNanosecondsType(alias) : DuckDBTimestampNanosecondsType.instance; + } } export class DuckDBEnumType extends BaseDuckDBType { public readonly values: readonly string[]; public readonly internalTypeId: DuckDBTypeId; - public constructor(values: readonly string[], internalTypeId: DuckDBTypeId) { - super(DuckDBTypeId.ENUM); + public constructor(values: readonly string[], internalTypeId: DuckDBTypeId, alias?: string) { + super(DuckDBTypeId.ENUM, alias); this.values = values; this.internalTypeId = internalTypeId; } @@ -221,8 +289,8 @@ export class DuckDBEnumType extends BaseDuckDBType { export class DuckDBListType extends BaseDuckDBType { public readonly valueType: DuckDBType; - public constructor(valueType: DuckDBType) { - super(DuckDBTypeId.LIST); + public constructor(valueType: DuckDBType, alias?: string) { + super(DuckDBTypeId.LIST, alias); this.valueType = valueType; } public toString(): string { @@ -230,16 +298,11 @@ export class DuckDBListType extends BaseDuckDBType { } } -export interface DuckDBStructEntryType { - readonly name: string; - readonly valueType: DuckDBType; -} - export class DuckDBStructType extends BaseDuckDBType { public readonly entryNames: readonly string[]; public readonly entryTypes: readonly DuckDBType[]; - public constructor(entryNames: readonly string[], entryTypes: readonly DuckDBType[]) { - super(DuckDBTypeId.STRUCT); + public constructor(entryNames: readonly string[], entryTypes: readonly DuckDBType[], alias?: string) { + super(DuckDBTypeId.STRUCT, alias); if (entryNames.length !== entryTypes.length) { throw new Error(`Could not create DuckDBStructType: \ entryNames length (${entryNames.length}) does not match entryTypes length (${entryTypes.length})`); @@ -262,8 +325,8 @@ export class DuckDBStructType extends BaseDuckDBType { export class DuckDBMapType extends BaseDuckDBType { public readonly keyType: DuckDBType; public readonly valueType: DuckDBType; - public constructor(keyType: DuckDBType, valueType: DuckDBType) { - super(DuckDBTypeId.MAP); + public constructor(keyType: DuckDBType, valueType: DuckDBType, alias?: string) { + super(DuckDBTypeId.MAP, alias); this.keyType = keyType; this.valueType = valueType; } @@ -275,8 +338,8 @@ export class DuckDBMapType extends BaseDuckDBType { export class DuckDBArrayType extends BaseDuckDBType { public readonly valueType: DuckDBType; public readonly length: number; - public constructor(valueType: DuckDBType, length: number) { - super(DuckDBTypeId.ARRAY); + public constructor(valueType: DuckDBType, length: number, alias?: string) { + super(DuckDBTypeId.ARRAY, alias); this.valueType = valueType; this.length = length; } @@ -286,17 +349,20 @@ export class DuckDBArrayType extends BaseDuckDBType { } export class DuckDBUUIDType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.UUID); + public constructor(alias?: string) { + super(DuckDBTypeId.UUID, alias); } public static readonly instance = new DuckDBUUIDType(); + public static create(alias?: string): DuckDBUUIDType { + return alias ? new DuckDBUUIDType(alias) : DuckDBUUIDType.instance; + } } export class DuckDBUnionType extends BaseDuckDBType { public readonly memberTags: readonly string[]; public readonly memberTypes: readonly DuckDBType[]; - public constructor(memberTags: readonly string[], memberTypes: readonly DuckDBType[]) { - super(DuckDBTypeId.UNION); + public constructor(memberTags: readonly string[], memberTypes: readonly DuckDBType[], alias?: string) { + super(DuckDBTypeId.UNION, alias); if (memberTags.length !== memberTypes.length) { throw new Error(`Could not create DuckDBUnionType: \ tags length (${memberTags.length}) does not match valueTypes length (${memberTypes.length})`); @@ -317,53 +383,71 @@ export class DuckDBUnionType extends BaseDuckDBType { } export class DuckDBBitType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.BIT); + public constructor(alias?: string) { + super(DuckDBTypeId.BIT, alias); } public static readonly instance = new DuckDBBitType(); + public static create(alias?: string): DuckDBBitType { + return alias ? new DuckDBBitType(alias) : DuckDBBitType.instance; + } } export class DuckDBTimeTZType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIME_TZ); + public constructor(alias?: string) { + super(DuckDBTypeId.TIME_TZ, alias); } public toString(): string { return "TIME WITH TIME ZONE"; } public static readonly instance = new DuckDBTimeTZType(); + public static create(alias?: string): DuckDBTimeTZType { + return alias ? new DuckDBTimeTZType(alias) : DuckDBTimeTZType.instance; + } } export class DuckDBTimestampTZType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.TIMESTAMP_TZ); + public constructor(alias?: string) { + super(DuckDBTypeId.TIMESTAMP_TZ, alias); } public toString(): string { return "TIMESTAMP WITH TIME ZONE"; } public static readonly instance = new DuckDBTimestampTZType(); + public static create(alias?: string): DuckDBTimestampTZType { + return alias ? new DuckDBTimestampTZType(alias) : DuckDBTimestampTZType.instance; + } } export class DuckDBAnyType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.ANY); + public constructor(alias?: string) { + super(DuckDBTypeId.ANY, alias); } public static readonly instance = new DuckDBAnyType(); + public static create(alias?: string): DuckDBAnyType { + return alias ? new DuckDBAnyType(alias) : DuckDBAnyType.instance; + } } export class DuckDBVarIntType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.VARINT); + public constructor(alias?: string) { + super(DuckDBTypeId.VARINT, alias); } public static readonly instance = new DuckDBVarIntType(); + public static create(alias?: string): DuckDBVarIntType { + return alias ? new DuckDBVarIntType(alias) : DuckDBVarIntType.instance; + } public static readonly Max: bigint = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368n; public static readonly Min: bigint = -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368n; } export class DuckDBSQLNullType extends BaseDuckDBType { - private constructor() { - super(DuckDBTypeId.SQLNULL); + public constructor(alias?: string) { + super(DuckDBTypeId.SQLNULL, alias); } public static readonly instance = new DuckDBSQLNullType(); + public static create(alias?: string): DuckDBSQLNullType { + return alias ? new DuckDBSQLNullType(alias) : DuckDBSQLNullType.instance; + } } export type DuckDBType = diff --git a/api/src/DuckDBVector.ts b/api/src/DuckDBVector.ts index d216c525..f020ed50 100644 --- a/api/src/DuckDBVector.ts +++ b/api/src/DuckDBVector.ts @@ -264,7 +264,7 @@ export abstract class DuckDBVector { return duckdb.vector_size(); } public static create(vector: duckdb.Vector, itemCount: number, knownType?: DuckDBType): DuckDBVector { - const vectorType = knownType ? knownType : DuckDBLogicalType.consumeAsType(duckdb.vector_get_column_type(vector)); + const vectorType = knownType ? knownType : DuckDBLogicalType.create(duckdb.vector_get_column_type(vector)).asType(); switch (vectorType.typeId) { case DuckDBTypeId.BOOLEAN: return DuckDBBooleanVector.fromRawVector(vector, itemCount); diff --git a/bindings/test/utils/expectChunk.ts b/bindings/test/utils/expectChunk.ts index cb55a8c8..6db1dadb 100644 --- a/bindings/test/utils/expectChunk.ts +++ b/bindings/test/utils/expectChunk.ts @@ -3,7 +3,6 @@ import { expect } from 'vitest'; import { ExpectedChunk, ExpectedColumn } from './ExpectedResult'; import { expectLogicalType } from './expectLogicalType'; import { expectVector } from './expectVector'; -import { withLogicalType } from './withLogicalType'; export function expectChunk(chunk: duckdb.DataChunk, expectedChunk: ExpectedChunk, expectedColumns: ExpectedColumn[]) { const chunkColumnCount = expectedChunk.columnCount ?? expectedColumns.length; @@ -12,12 +11,8 @@ export function expectChunk(chunk: duckdb.DataChunk, expectedChunk: ExpectedChun for (let col = 0; col < expectedChunk.vectors.length; col++) { const expectedVector = expectedChunk.vectors[col]; const vector = duckdb.data_chunk_get_vector(chunk, col); - const expectedLogicalType = expectedColumns[col].logicalType; - withLogicalType(duckdb.vector_get_column_type(vector), - (logical_type) => expectLogicalType(logical_type, expectedLogicalType, `col ${col}`) - ); - + expectLogicalType(duckdb.vector_get_column_type(vector), expectedLogicalType, `col ${col}`); expectVector(vector, expectedVector, expectedLogicalType, `col ${col}`); } } diff --git a/bindings/test/utils/expectResult.ts b/bindings/test/utils/expectResult.ts index 161d902e..1ee7049b 100644 --- a/bindings/test/utils/expectResult.ts +++ b/bindings/test/utils/expectResult.ts @@ -3,7 +3,6 @@ import { expect } from 'vitest'; import { expectChunk } from './expectChunk'; import { ExpectedResult } from './ExpectedResult'; import { expectLogicalType } from './expectLogicalType'; -import { withLogicalType } from './withLogicalType'; export async function expectResult(result: duckdb.Result, expectedResult: ExpectedResult) { expect(duckdb.result_statement_type(result)).toBe(expectedResult.statementType ?? duckdb.StatementType.SELECT); @@ -14,9 +13,7 @@ export async function expectResult(result: duckdb.Result, expectedResult: Expect const expectedColumn = expectedResult.columns[col]; expect(duckdb.column_name(result, col), `${col}`).toBe(expectedColumn.name); expect(duckdb.column_type(result, col), `${col}`).toBe(expectedColumn.logicalType.typeId); - withLogicalType(duckdb.column_logical_type(result, col), - (logical_type) => expectLogicalType(logical_type, expectedColumn.logicalType, `col ${col}`) - ); + expectLogicalType(duckdb.column_logical_type(result, col), expectedColumn.logicalType, `col ${col}`); } for (const expectedChunk of expectedResult.chunks) { const chunk = await duckdb.fetch_chunk(result); diff --git a/bindings/test/utils/withLogicalType.ts b/bindings/test/utils/withLogicalType.ts deleted file mode 100644 index bbc7a282..00000000 --- a/bindings/test/utils/withLogicalType.ts +++ /dev/null @@ -1,5 +0,0 @@ -import duckdb from '@duckdb/node-bindings'; - -export function withLogicalType(logical_type: duckdb.LogicalType, fn: (logical_type: duckdb.LogicalType) => void) { - fn(logical_type); -} From b00b6e2efc6930248bd129fb86552df6025376ea Mon Sep 17 00:00:00 2001 From: Jeff Raymakers Date: Sat, 2 Nov 2024 13:59:22 -0700 Subject: [PATCH 2/2] remove dispose from README --- api/pkgs/@duckdb/node-api/README.md | 116 +++++++++------------------- 1 file changed, 38 insertions(+), 78 deletions(-) diff --git a/api/pkgs/@duckdb/node-api/README.md b/api/pkgs/@duckdb/node-api/README.md index 4635162e..d1ec91b0 100644 --- a/api/pkgs/@duckdb/node-api/README.md +++ b/api/pkgs/@duckdb/node-api/README.md @@ -18,7 +18,6 @@ This is a high-level API meant for applications. It depends on low-level binding Some features are not yet complete: - Friendlier APIs for convering results to common JS data structures. - Friendlier APIs for converting values of specialized and complex DuckDB types to common JS types. -- Automatic memory management (i.e. avoiding the need to call `dispose` manually in most cases). - Appending and binding advanced data types. (Additional DuckDB C API support needed.) - Writing to data chunk vectors. (Directly writing to binary buffers is challenging to support using the Node Addon API.) - User-defined types & functions. (Support for this was added to the DuckDB C API in v1.1.0.) @@ -70,33 +69,18 @@ Set configuration options: const instance = await DuckDBInstance.create('my_duckdb.db', { threads: '4' }); ``` -Dispose: -```ts -await instance.dispose(); -``` - ### Connect ```ts const connection = await instance.connect(); ``` -Dispose: -```ts -await connection.dispose(); -``` - ### Run SQL ```ts const result = await connection.run('from test_all_types()'); ``` -Dispose: -```ts -result.dispose(); -``` - ### Parameterize SQL ```ts @@ -106,12 +90,6 @@ prepared.bindInteger(2, 42); const result = await prepared.run(); ``` -Dispose: -```ts -result.dispose(); -prepared.dispose(); -``` - ### Inspect Result Get column names and types: @@ -155,11 +133,6 @@ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) { } ``` -Dispose data chunk: -```ts -chunk.dispose(); -``` - ### Inspect Data Types ```ts @@ -197,6 +170,11 @@ if (columnType.typeId === DuckDBTypeId.UNION) { const unionMemberTags = columnType.memberTags; const unionMemberTypes = columnType.memberTypes; } + +// For the JSON type (https://duckdb.org/docs/data/json/json_type) +if (columnType.alias === 'JSON') { + const json = JSON.parse(columnValue); +} ``` Every type implements toString, matching DuckDB's type-to-string conversion. @@ -313,25 +291,25 @@ if (columnType.typeId === DuckDBTypeId.UUID) { ### Append To Table ```ts -const createTableResult = await connection.run(`create or replace table target_table(i integer, v varchar)`); -createTableResult.dispose(); +await connection.run(`create or replace table target_table(i integer, v varchar)`); const appender = await connection.createAppender('main', 'target_table'); -try { - appender.appendInteger(42); - appender.appendVarchar('duck'); - appender.endRow(); - appender.appendInteger(123); - appender.appendVarchar('mallard'); - appender.endRow(); - appender.flush(); - appender.appendInteger(17); - appender.appendVarchar('goose'); - appender.endRow(); - appender.close(); // also flushes -} finally { - appender.dispose(); -} + +appender.appendInteger(42); +appender.appendVarchar('duck'); +appender.endRow(); + +appender.appendInteger(123); +appender.appendVarchar('mallard'); +appender.endRow(); + +appender.flush(); + +appender.appendInteger(17); +appender.appendVarchar('goose'); +appender.endRow(); + +appender.close(); // also flushes ``` ### Extract Statements @@ -343,24 +321,15 @@ const extractedStatements = await connection.extractStatements(` drop table numbers; `); const parameterValues = [10, 7]; -try { - const statementCount = extractedStatements.count; - for (let statementIndex = 0; statementIndex < statementCount; statementIndex++) { - const prepared = await extractedStatements.prepare(statementIndex); - try { - let parameterCount = prepared.parameterCount; - for (let parameterIndex = 1; parameterIndex <= parameterCount; parameterIndex++) { - prepared.bindInteger(parameterIndex, parameterValues.shift()); - } - const result = await prepared.run(); - // ... - result.dispose(); - } finally { - prepared.dispose(); - } +const statementCount = extractedStatements.count; +for (let statementIndex = 0; statementIndex < statementCount; statementIndex++) { + const prepared = await extractedStatements.prepare(statementIndex); + let parameterCount = prepared.parameterCount; + for (let parameterIndex = 1; parameterIndex <= parameterCount; parameterIndex++) { + prepared.bindInteger(parameterIndex, parameterValues.shift()); } -} finally { - extractedStatements.dispose(); + const result = await prepared.run(); + // ... } ``` @@ -376,21 +345,12 @@ async function sleep(ms) { } const prepared = await connection.prepare('from range(10_000_000)'); -try { - const pending = prepared.start(); - try { - while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) { - console.log('not ready'); - await sleep(1); - } - console.log('ready'); - const result = await pending.getResult(); - // ... - result.dispose(); - } finally { - pending.dispose(); - } -} finally { - prepared.dispose(); -} +const pending = prepared.start(); +while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) { + console.log('not ready'); + await sleep(1); +} +console.log('ready'); +const result = await pending.getResult(); +// ... ```