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

bit type: create, get, and bind #159

Merged
merged 1 commit into from
Feb 17, 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
6 changes: 5 additions & 1 deletion api/src/DuckDBPreparedStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DuckDBPendingResult } from './DuckDBPendingResult';
import { DuckDBResult } from './DuckDBResult';
import { DuckDBResultReader } from './DuckDBResultReader';
import {
BIT,
DuckDBArrayType,
DuckDBListType,
DuckDBStructType,
Expand All @@ -22,6 +23,7 @@ import { StatementType } from './enums';
import { typeForValue } from './typeForValue';
import {
DuckDBArrayValue,
DuckDBBitValue,
DuckDBDateValue,
DuckDBDecimalValue,
DuckDBIntervalValue,
Expand Down Expand Up @@ -182,7 +184,9 @@ export class DuckDBPreparedStatement {
}
// TODO: bind MAP, UNION
// TODO: bind UUID
// TODO: bind BIT
public bindBit(parameterIndex: number, value: DuckDBBitValue) {
this.bindValue(parameterIndex, value, BIT);
}
public bindNull(parameterIndex: number) {
duckdb.bind_null(this.prepared_statement, parameterIndex);
}
Expand Down
6 changes: 5 additions & 1 deletion api/src/createValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { DuckDBType } from './DuckDBType';
import { DuckDBTypeId } from './DuckDBTypeId';
import {
DuckDBArrayValue,
DuckDBBitValue,
DuckDBBlobValue,
DuckDBDateValue,
DuckDBDecimalValue,
Expand Down Expand Up @@ -191,7 +192,10 @@ export function createValue(type: DuckDBType, input: DuckDBValue): Value {
case DuckDBTypeId.UNION:
throw new Error(`not yet implemented for UNION`); // TODO: implement when available, hopefully in 1.2.0
case DuckDBTypeId.BIT:
throw new Error(`not yet implemented for BIT`); // TODO: implement when available in 1.2.0
if (input instanceof DuckDBBitValue) {
return duckdb.create_bit(input.data);
}
throw new Error(`input is not a DuckDBBitValue`);
case DuckDBTypeId.TIME_TZ:
if (input instanceof DuckDBTimeTZValue) {
return duckdb.create_time_tz_value(input);
Expand Down
43 changes: 23 additions & 20 deletions api/test/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,19 +400,20 @@ describe('api', () => {
test('should support running prepared statements', async () => {
await withConnection(async (connection) => {
const params: ColumnNameAndType[] = [
{ name: 'num', type: INTEGER },
{ name: 'str', type: VARCHAR },
{ name: 'bool', type: BOOLEAN },
{ name: 'timetz', type: TIMETZ },
{ name: 'timestamptz', type: TIMESTAMPTZ },
{ name: 'boolean', type: BOOLEAN },
{ name: 'integer', type: INTEGER },
{ name: 'varchar', type: VARCHAR },
{ name: 'timestamp_s', type: TIMESTAMP_S },
{ name: 'timestamp_ms', type: TIMESTAMP_MS },
{ name: 'timestamp_ns', type: TIMESTAMP_NS },
{ name: 'varint', type: VARINT },
{ name: 'list_int', type: LIST(INTEGER) },
{ name: 'list_dec', type: LIST(DECIMAL(4, 1)) },
{ name: 'struct', type: STRUCT({ 'a': INTEGER, 'b': VARCHAR }) },
{ name: 'array', type: ARRAY(INTEGER, 3) },
{ name: 'bit', type: BIT },
{ name: 'timetz', type: TIMETZ },
{ name: 'timestamptz', type: TIMESTAMPTZ },
{ name: 'varint', type: VARINT },
{ name: 'null_value', type: SQLNULL },
];

Expand All @@ -427,15 +428,12 @@ describe('api', () => {
}

let i = 1;
prepared.bindBoolean(i++, true);
prepared.bindInteger(i++, 10);
prepared.bindVarchar(i++, 'abc');
prepared.bindBoolean(i++, true);
prepared.bindTimeTZ(i++, TIMETZ.max);
prepared.bindTimestampTZ(i++, TIMESTAMPTZ.max);
prepared.bindTimestampSeconds(i++, TIMESTAMP_S.max);
prepared.bindTimestampMilliseconds(i++, TIMESTAMP_MS.max);
prepared.bindTimestampNanoseconds(i++, TIMESTAMP_NS.max);
prepared.bindVarInt(i++, VARINT.max);
prepared.bindList(i++, listValue([100, 200, 300]), LIST(INTEGER));
prepared.bindList(
i++,
Expand All @@ -448,11 +446,15 @@ describe('api', () => {
STRUCT({ 'a': INTEGER, 'b': VARCHAR })
);
prepared.bindArray(i++, arrayValue([100, 200, 300]), ARRAY(INTEGER, 3));
prepared.bindBit(i++, bitValue('0010001001011100010101011010111'));
prepared.bindTimeTZ(i++, TIMETZ.max);
prepared.bindTimestampTZ(i++, TIMESTAMPTZ.max);
prepared.bindVarInt(i++, VARINT.max);
prepared.bindNull(i++);

for (let i = 0; i < params.length; i++) {
let type = params[i].type;
if (i === 1) {
if (type.typeId === DuckDBTypeId.VARCHAR) {
// VARCHAR type is reported incorrectly; see https://github.com/duckdb/duckdb/issues/16137
continue;
}
Expand All @@ -476,6 +478,12 @@ describe('api', () => {
assert.strictEqual(chunk.columnCount, expectedColumns.length);
assert.strictEqual(chunk.rowCount, 1);
let i = 0;
assertValues<boolean, DuckDBBooleanVector>(
chunk,
i++,
DuckDBBooleanVector,
[true]
);
assertValues<number, DuckDBIntegerVector>(
chunk,
i++,
Expand All @@ -488,14 +496,6 @@ describe('api', () => {
DuckDBVarCharVector,
['abc']
);
assertValues<boolean, DuckDBBooleanVector>(
chunk,
i++,
DuckDBBooleanVector,
[true]
);
assertValues(chunk, i++, DuckDBTimeTZVector, [TIMETZ.max]);
assertValues(chunk, i++, DuckDBTimestampTZVector, [TIMESTAMPTZ.max]);
assertValues(chunk, i++, DuckDBTimestampSecondsVector, [
TIMESTAMP_S.max,
]);
Expand All @@ -505,7 +505,6 @@ describe('api', () => {
assertValues(chunk, i++, DuckDBTimestampNanosecondsVector, [
TIMESTAMP_NS.max,
]);
assertValues(chunk, i++, DuckDBVarIntVector, [VARINT.max]);
assertValues(chunk, i++, DuckDBListVector, [
listValue([100, 200, 300]),
]);
Expand All @@ -518,6 +517,10 @@ describe('api', () => {
assertValues(chunk, i++, DuckDBArrayVector, [
arrayValue([100, 200, 300]),
]);
assertValues(chunk, i++, DuckDBBitVector, [bitValue('0010001001011100010101011010111')]);
assertValues(chunk, i++, DuckDBTimeTZVector, [TIMETZ.max]);
assertValues(chunk, i++, DuckDBTimestampTZVector, [TIMESTAMPTZ.max]);
assertValues(chunk, i++, DuckDBVarIntVector, [VARINT.max]);
assertValues<number, DuckDBIntegerVector>(
chunk,
i++,
Expand Down
4 changes: 4 additions & 0 deletions bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,8 @@ export function create_interval(input: Interval): Value;
export function create_blob(data: Uint8Array): Value;

// DUCKDB_API duckdb_value duckdb_create_bit(duckdb_bit input);
export function create_bit(data: Uint8Array): Value;

// DUCKDB_API duckdb_value duckdb_create_uuid(duckdb_uhugeint input);

// DUCKDB_API bool duckdb_get_bool(duckdb_value val);
Expand Down Expand Up @@ -760,6 +762,8 @@ export function get_value_type(value: Value): LogicalType;
export function get_blob(value: Value): Uint8Array;

// DUCKDB_API duckdb_bit duckdb_get_bit(duckdb_value val);
export function get_bit(value: Value): Uint8Array;

// DUCKDB_API duckdb_uhugeint duckdb_get_uuid(duckdb_value val);

// DUCKDB_API char *duckdb_get_varchar(duckdb_value value);
Expand Down
26 changes: 23 additions & 3 deletions bindings/src/duckdb_node_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,7 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
InstanceMethod("create_timestamp_ns", &DuckDBNodeAddon::create_timestamp_ns),
InstanceMethod("create_interval", &DuckDBNodeAddon::create_interval),
InstanceMethod("create_blob", &DuckDBNodeAddon::create_blob),
InstanceMethod("create_bit", &DuckDBNodeAddon::create_bit),
InstanceMethod("get_bool", &DuckDBNodeAddon::get_bool),
InstanceMethod("get_int8", &DuckDBNodeAddon::get_int8),
InstanceMethod("get_uint8", &DuckDBNodeAddon::get_uint8),
Expand All @@ -1200,6 +1201,7 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
InstanceMethod("get_interval", &DuckDBNodeAddon::get_interval),
InstanceMethod("get_value_type", &DuckDBNodeAddon::get_value_type),
InstanceMethod("get_blob", &DuckDBNodeAddon::get_blob),
InstanceMethod("get_bit", &DuckDBNodeAddon::get_bit),
InstanceMethod("get_varchar", &DuckDBNodeAddon::get_varchar),
InstanceMethod("create_struct_value", &DuckDBNodeAddon::create_struct_value),
InstanceMethod("create_list_value", &DuckDBNodeAddon::create_list_value),
Expand Down Expand Up @@ -2609,6 +2611,16 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
}

// DUCKDB_API duckdb_value duckdb_create_bit(duckdb_bit input);
// function create_bit(data: Uint8Array): Value
Napi::Value create_bit(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto array = info[0].As<Napi::Uint8Array>();
auto data = array.Data();
auto size = array.ByteLength();
auto value = duckdb_create_bit({ data, size });
return CreateExternalForValue(env, value);
}

// DUCKDB_API duckdb_value duckdb_create_uuid(duckdb_uhugeint input);

// DUCKDB_API bool duckdb_get_bool(duckdb_value val);
Expand Down Expand Up @@ -2848,6 +2860,14 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
}

// DUCKDB_API duckdb_bit duckdb_get_bit(duckdb_value val);
// function get_bit(value: Value): Uint8Array
Napi::Value get_bit(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto value = GetValueFromExternal(env, info[0]);
auto bit = duckdb_get_bit(value);
return Napi::Buffer<uint8_t>::NewOrCopy(env, bit.data, bit.size);
}

// DUCKDB_API duckdb_uhugeint duckdb_get_uuid(duckdb_value val);

// DUCKDB_API char *duckdb_get_varchar(duckdb_value value);
Expand Down Expand Up @@ -4067,11 +4087,11 @@ NODE_API_ADDON(DuckDBNodeAddon)
---
411 total functions

226 instance methods
228 instance methods
3 unimplemented instance cache functions
1 unimplemented logical type function
4 unimplemented value creation functions
7 unimplemented value inspection functions
3 unimplemented value creation functions
6 unimplemented value inspection functions
13 unimplemented scalar function functions
4 unimplemented scalar function set functions
12 unimplemented aggregate function functions
Expand Down
7 changes: 7 additions & 0 deletions bindings/test/values.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { expectLogicalType } from './utils/expectLogicalType';
import {
ARRAY,
BIGINT,
BIT,
BLOB,
BOOLEAN,
DATE,
Expand Down Expand Up @@ -198,6 +199,12 @@ suite('values', () => {
expectLogicalType(duckdb.get_value_type(blob_value), BLOB);
expect(duckdb.get_blob(blob_value)).toStrictEqual(input);
});
test('bit', () => {
const input = Buffer.from([1, 0b10010001, 0b00101110, 0b00101010, 0b11010111]);
const bit_value = duckdb.create_bit(input);
expectLogicalType(duckdb.get_value_type(bit_value), BIT);
expect(duckdb.get_bit(bit_value)).toStrictEqual(input);
});
test('varchar', () => {
const input = 'varchar_text';
const varchar_value = duckdb.create_varchar(input);
Expand Down