Skip to content

Commit

Permalink
Merge pull request #162 from duckdb/jray/enum-type-create-get-bind
Browse files Browse the repository at this point in the history
enum type: create, get, & bind
  • Loading branch information
jraymakers authored Feb 22, 2025
2 parents 7f4741c + e42f981 commit 13bccd8
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 8 deletions.
5 changes: 4 additions & 1 deletion api/src/DuckDBPreparedStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { DuckDBResultReader } from './DuckDBResultReader';
import {
BIT,
DuckDBArrayType,
DuckDBEnumType,
DuckDBListType,
DuckDBStructType,
DuckDBType,
Expand Down Expand Up @@ -162,7 +163,9 @@ export class DuckDBPreparedStatement {
public bindBlob(parameterIndex: number, value: Uint8Array) {
duckdb.bind_blob(this.prepared_statement, parameterIndex, value);
}
// TODO: bind ENUM
public bindEnum(parameterIndex: number, value: string, type: DuckDBEnumType) {
this.bindValue(parameterIndex, value, type);
}
public bindArray(
parameterIndex: number,
value: DuckDBArrayValue,
Expand Down
8 changes: 7 additions & 1 deletion api/src/createValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ export function createValue(type: DuckDBType, input: DuckDBValue): Value {
}
throw new Error(`input is not a DuckDBTimestampNanosecondsValue`);
case DuckDBTypeId.ENUM:
throw new Error(`not yet implemented for ENUM`); // TODO: implement when available in 1.2.0
if (typeof input === 'string') {
return duckdb.create_enum_value(
type.toLogicalType().logical_type,
type.indexForValue(input)
);
}
throw new Error(`input is not a string`);
case DuckDBTypeId.LIST:
if (input instanceof DuckDBListValue) {
if (type.valueType.typeId === DuckDBTypeId.ANY) {
Expand Down
7 changes: 6 additions & 1 deletion api/test/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ import {
uuidValue,
version,
} from '../src';
import { replaceSqlNullWithInteger } from './util/replaceSqlNullWithInteger';
import {
ColumnNameAndType,
createTestAllTypesColumnTypes,
Expand All @@ -121,7 +122,6 @@ import {
createTestAllTypesRowObjectsJson,
createTestAllTypesRowsJson,
} from './util/testAllTypes';
import { replaceSqlNullWithInteger } from './util/replaceSqlNullWithInteger';

async function sleep(ms: number): Promise<void> {
return new Promise((resolve) => {
Expand Down Expand Up @@ -408,6 +408,7 @@ describe('api', () => {
{ name: 'timestamp_s', type: TIMESTAMP_S },
{ name: 'timestamp_ms', type: TIMESTAMP_MS },
{ name: 'timestamp_ns', type: TIMESTAMP_NS },
{ name: 'enum', type: ENUM(['fly', 'swim', 'walk']) },
{ name: 'list_int', type: LIST(INTEGER) },
{ name: 'list_dec', type: LIST(DECIMAL(4, 1)) },
{ name: 'list_null', type: LIST(SQLNULL) },
Expand Down Expand Up @@ -442,6 +443,7 @@ describe('api', () => {
prepared.bindTimestampSeconds(i++, TIMESTAMP_S.max);
prepared.bindTimestampMilliseconds(i++, TIMESTAMP_MS.max);
prepared.bindTimestampNanoseconds(i++, TIMESTAMP_NS.max);
prepared.bindEnum(i++, 'swim', ENUM(['fly', 'swim', 'walk']));
prepared.bindList(i++, listValue([100, 200, 300]), LIST(INTEGER));
prepared.bindList(
i++,
Expand Down Expand Up @@ -527,6 +529,9 @@ describe('api', () => {
assertValues(chunk, i++, DuckDBTimestampNanosecondsVector, [
TIMESTAMP_NS.max,
]);
assertValues<string, DuckDBEnum8Vector>(chunk, i++, DuckDBEnum8Vector, [
'swim',
]);
assertValues(chunk, i++, DuckDBListVector, [
listValue([100, 200, 300]),
]);
Expand Down
5 changes: 5 additions & 0 deletions bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -797,8 +797,13 @@ export function create_null_value(): Value;

// DUCKDB_API idx_t duckdb_get_list_size(duckdb_value value);
// DUCKDB_API duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index);

// DUCKDB_API duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value);
export function create_enum_value(logical_type: LogicalType, value: number): Value;

// DUCKDB_API uint64_t duckdb_get_enum_value(duckdb_value value);
export function get_enum_value(value: Value): number;

// DUCKDB_API duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index);

// DUCKDB_API duckdb_logical_type duckdb_create_logical_type(duckdb_type type);
Expand Down
28 changes: 25 additions & 3 deletions bindings/src/duckdb_node_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,8 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
InstanceMethod("get_map_value", &DuckDBNodeAddon::get_map_value),
InstanceMethod("is_null_value", &DuckDBNodeAddon::is_null_value),
InstanceMethod("create_null_value", &DuckDBNodeAddon::create_null_value),
InstanceMethod("create_enum_value", &DuckDBNodeAddon::create_enum_value),
InstanceMethod("get_enum_value", &DuckDBNodeAddon::get_enum_value),

InstanceMethod("create_logical_type", &DuckDBNodeAddon::create_logical_type),
InstanceMethod("logical_type_get_alias", &DuckDBNodeAddon::logical_type_get_alias),
Expand Down Expand Up @@ -3008,8 +3010,29 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {

// DUCKDB_API idx_t duckdb_get_list_size(duckdb_value value);
// DUCKDB_API duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index);

// DUCKDB_API duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value);
// function create_enum_value(logical_type: LogicalType, value: number): Value
Napi::Value create_enum_value(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto logical_type = GetLogicalTypeFromExternal(env, info[0]);
auto input_value = info[1].As<Napi::Number>().Uint32Value();
auto value = duckdb_create_enum_value(logical_type, input_value);
if (!value) {
throw Napi::Error::New(env, "Failed to create enum value");
}
return CreateExternalForValue(env, value);
}

// DUCKDB_API uint64_t duckdb_get_enum_value(duckdb_value value);
// function get_enum_value(value: Value): number
Napi::Value get_enum_value(const Napi::CallbackInfo& info) {
auto env = info.Env();
auto value = GetValueFromExternal(env, info[0]);
auto output_value = duckdb_get_enum_value(value);
return Napi::Number::New(env, output_value);
}

// DUCKDB_API duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index);

// DUCKDB_API duckdb_logical_type duckdb_create_logical_type(duckdb_type type);
Expand Down Expand Up @@ -4121,11 +4144,10 @@ NODE_API_ADDON(DuckDBNodeAddon)
---
411 total functions
232 instance methods
234 instance methods
3 unimplemented instance cache functions
1 unimplemented logical type function
1 unimplemented value creation functions
4 unimplemented value inspection functions
3 unimplemented value inspection functions
13 unimplemented scalar function functions
4 unimplemented scalar function set functions
12 unimplemented aggregate function functions
Expand Down
12 changes: 10 additions & 2 deletions bindings/test/values.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
DECIMAL,
DOUBLE,
ENTRY,
ENUM,
FLOAT,
HUGEINT,
INTEGER,
Expand Down Expand Up @@ -277,8 +278,15 @@ suite('values', () => {
});
test('null', () => {
const null_value = duckdb.create_null_value();
expect(duckdb.is_null_value(null_value)).toEqual(true);
expect(duckdb.is_null_value(null_value)).toBe(true);
const int32_value = duckdb.create_int32(42);
expect(duckdb.is_null_value(int32_value)).toEqual(false);
expect(duckdb.is_null_value(int32_value)).toBe(false);
});
test('enum', () => {
const enum_members = ['fly', 'swim', 'walk'];
const enum_type = duckdb.create_enum_type(enum_members);
const enum_value = duckdb.create_enum_value(enum_type, 1);
expectLogicalType(duckdb.get_value_type(enum_value), ENUM(enum_members, duckdb.Type.UTINYINT));
expect(duckdb.get_enum_value(enum_value)).toBe(1);
});
});

0 comments on commit 13bccd8

Please sign in to comment.