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

enum type: create, get, & bind #162

Merged
merged 1 commit into from
Feb 22, 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
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);
});
});