Skip to content

Commit 13bccd8

Browse files
authored
Merge pull request #162 from duckdb/jray/enum-type-create-get-bind
enum type: create, get, & bind
2 parents 7f4741c + e42f981 commit 13bccd8

File tree

6 files changed

+57
-8
lines changed

6 files changed

+57
-8
lines changed

api/src/DuckDBPreparedStatement.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { DuckDBResultReader } from './DuckDBResultReader';
88
import {
99
BIT,
1010
DuckDBArrayType,
11+
DuckDBEnumType,
1112
DuckDBListType,
1213
DuckDBStructType,
1314
DuckDBType,
@@ -162,7 +163,9 @@ export class DuckDBPreparedStatement {
162163
public bindBlob(parameterIndex: number, value: Uint8Array) {
163164
duckdb.bind_blob(this.prepared_statement, parameterIndex, value);
164165
}
165-
// TODO: bind ENUM
166+
public bindEnum(parameterIndex: number, value: string, type: DuckDBEnumType) {
167+
this.bindValue(parameterIndex, value, type);
168+
}
166169
public bindArray(
167170
parameterIndex: number,
168171
value: DuckDBArrayValue,

api/src/createValue.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ export function createValue(type: DuckDBType, input: DuckDBValue): Value {
140140
}
141141
throw new Error(`input is not a DuckDBTimestampNanosecondsValue`);
142142
case DuckDBTypeId.ENUM:
143-
throw new Error(`not yet implemented for ENUM`); // TODO: implement when available in 1.2.0
143+
if (typeof input === 'string') {
144+
return duckdb.create_enum_value(
145+
type.toLogicalType().logical_type,
146+
type.indexForValue(input)
147+
);
148+
}
149+
throw new Error(`input is not a string`);
144150
case DuckDBTypeId.LIST:
145151
if (input instanceof DuckDBListValue) {
146152
if (type.valueType.typeId === DuckDBTypeId.ANY) {

api/test/api.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ import {
111111
uuidValue,
112112
version,
113113
} from '../src';
114+
import { replaceSqlNullWithInteger } from './util/replaceSqlNullWithInteger';
114115
import {
115116
ColumnNameAndType,
116117
createTestAllTypesColumnTypes,
@@ -121,7 +122,6 @@ import {
121122
createTestAllTypesRowObjectsJson,
122123
createTestAllTypesRowsJson,
123124
} from './util/testAllTypes';
124-
import { replaceSqlNullWithInteger } from './util/replaceSqlNullWithInteger';
125125

126126
async function sleep(ms: number): Promise<void> {
127127
return new Promise((resolve) => {
@@ -408,6 +408,7 @@ describe('api', () => {
408408
{ name: 'timestamp_s', type: TIMESTAMP_S },
409409
{ name: 'timestamp_ms', type: TIMESTAMP_MS },
410410
{ name: 'timestamp_ns', type: TIMESTAMP_NS },
411+
{ name: 'enum', type: ENUM(['fly', 'swim', 'walk']) },
411412
{ name: 'list_int', type: LIST(INTEGER) },
412413
{ name: 'list_dec', type: LIST(DECIMAL(4, 1)) },
413414
{ name: 'list_null', type: LIST(SQLNULL) },
@@ -442,6 +443,7 @@ describe('api', () => {
442443
prepared.bindTimestampSeconds(i++, TIMESTAMP_S.max);
443444
prepared.bindTimestampMilliseconds(i++, TIMESTAMP_MS.max);
444445
prepared.bindTimestampNanoseconds(i++, TIMESTAMP_NS.max);
446+
prepared.bindEnum(i++, 'swim', ENUM(['fly', 'swim', 'walk']));
445447
prepared.bindList(i++, listValue([100, 200, 300]), LIST(INTEGER));
446448
prepared.bindList(
447449
i++,
@@ -527,6 +529,9 @@ describe('api', () => {
527529
assertValues(chunk, i++, DuckDBTimestampNanosecondsVector, [
528530
TIMESTAMP_NS.max,
529531
]);
532+
assertValues<string, DuckDBEnum8Vector>(chunk, i++, DuckDBEnum8Vector, [
533+
'swim',
534+
]);
530535
assertValues(chunk, i++, DuckDBListVector, [
531536
listValue([100, 200, 300]),
532537
]);

bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,13 @@ export function create_null_value(): Value;
797797

798798
// DUCKDB_API idx_t duckdb_get_list_size(duckdb_value value);
799799
// DUCKDB_API duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index);
800+
800801
// DUCKDB_API duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value);
802+
export function create_enum_value(logical_type: LogicalType, value: number): Value;
803+
801804
// DUCKDB_API uint64_t duckdb_get_enum_value(duckdb_value value);
805+
export function get_enum_value(value: Value): number;
806+
802807
// DUCKDB_API duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index);
803808

804809
// DUCKDB_API duckdb_logical_type duckdb_create_logical_type(duckdb_type type);

bindings/src/duckdb_node_bindings.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,8 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
12131213
InstanceMethod("get_map_value", &DuckDBNodeAddon::get_map_value),
12141214
InstanceMethod("is_null_value", &DuckDBNodeAddon::is_null_value),
12151215
InstanceMethod("create_null_value", &DuckDBNodeAddon::create_null_value),
1216+
InstanceMethod("create_enum_value", &DuckDBNodeAddon::create_enum_value),
1217+
InstanceMethod("get_enum_value", &DuckDBNodeAddon::get_enum_value),
12161218

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

30093011
// DUCKDB_API idx_t duckdb_get_list_size(duckdb_value value);
30103012
// DUCKDB_API duckdb_value duckdb_get_list_child(duckdb_value value, idx_t index);
3013+
30113014
// DUCKDB_API duckdb_value duckdb_create_enum_value(duckdb_logical_type type, uint64_t value);
3015+
// function create_enum_value(logical_type: LogicalType, value: number): Value
3016+
Napi::Value create_enum_value(const Napi::CallbackInfo& info) {
3017+
auto env = info.Env();
3018+
auto logical_type = GetLogicalTypeFromExternal(env, info[0]);
3019+
auto input_value = info[1].As<Napi::Number>().Uint32Value();
3020+
auto value = duckdb_create_enum_value(logical_type, input_value);
3021+
if (!value) {
3022+
throw Napi::Error::New(env, "Failed to create enum value");
3023+
}
3024+
return CreateExternalForValue(env, value);
3025+
}
3026+
30123027
// DUCKDB_API uint64_t duckdb_get_enum_value(duckdb_value value);
3028+
// function get_enum_value(value: Value): number
3029+
Napi::Value get_enum_value(const Napi::CallbackInfo& info) {
3030+
auto env = info.Env();
3031+
auto value = GetValueFromExternal(env, info[0]);
3032+
auto output_value = duckdb_get_enum_value(value);
3033+
return Napi::Number::New(env, output_value);
3034+
}
3035+
30133036
// DUCKDB_API duckdb_value duckdb_get_struct_child(duckdb_value value, idx_t index);
30143037

30153038
// DUCKDB_API duckdb_logical_type duckdb_create_logical_type(duckdb_type type);
@@ -4121,11 +4144,10 @@ NODE_API_ADDON(DuckDBNodeAddon)
41214144
---
41224145
411 total functions
41234146
4124-
232 instance methods
4147+
234 instance methods
41254148
3 unimplemented instance cache functions
41264149
1 unimplemented logical type function
4127-
1 unimplemented value creation functions
4128-
4 unimplemented value inspection functions
4150+
3 unimplemented value inspection functions
41294151
13 unimplemented scalar function functions
41304152
4 unimplemented scalar function set functions
41314153
12 unimplemented aggregate function functions

bindings/test/values.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
DECIMAL,
2222
DOUBLE,
2323
ENTRY,
24+
ENUM,
2425
FLOAT,
2526
HUGEINT,
2627
INTEGER,
@@ -277,8 +278,15 @@ suite('values', () => {
277278
});
278279
test('null', () => {
279280
const null_value = duckdb.create_null_value();
280-
expect(duckdb.is_null_value(null_value)).toEqual(true);
281+
expect(duckdb.is_null_value(null_value)).toBe(true);
281282
const int32_value = duckdb.create_int32(42);
282-
expect(duckdb.is_null_value(int32_value)).toEqual(false);
283+
expect(duckdb.is_null_value(int32_value)).toBe(false);
284+
});
285+
test('enum', () => {
286+
const enum_members = ['fly', 'swim', 'walk'];
287+
const enum_type = duckdb.create_enum_type(enum_members);
288+
const enum_value = duckdb.create_enum_value(enum_type, 1);
289+
expectLogicalType(duckdb.get_value_type(enum_value), ENUM(enum_members, duckdb.Type.UTINYINT));
290+
expect(duckdb.get_enum_value(enum_value)).toBe(1);
283291
});
284292
});

0 commit comments

Comments
 (0)