Skip to content

Commit 291b600

Browse files
authored
Merge pull request #157 from duckdb/jray/create-and-get-decimal
create and get decimal
2 parents 37ef62b + 0509923 commit 291b600

File tree

5 files changed

+82
-29
lines changed

5 files changed

+82
-29
lines changed

api/src/createValue.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
DuckDBArrayValue,
66
DuckDBBlobValue,
77
DuckDBDateValue,
8+
DuckDBDecimalValue,
89
DuckDBIntervalValue,
910
DuckDBListValue,
1011
DuckDBStructValue,
@@ -113,7 +114,10 @@ export function createValue(type: DuckDBType, input: DuckDBValue): Value {
113114
}
114115
throw new Error(`input is not a DuckDBBlobValue`);
115116
case DuckDBTypeId.DECIMAL:
116-
throw new Error(`not yet implemented for DECIMAL`); // TODO: implement when available in 1.2.0
117+
if (input instanceof DuckDBDecimalValue) {
118+
return duckdb.create_decimal(input);
119+
}
120+
throw new Error(`input is not a DuckDBDecimalValue`);
117121
case DuckDBTypeId.TIMESTAMP_S:
118122
throw new Error(`not yet implemented for TIMESTAMP_S`); // TODO: implement when available in 1.2.0
119123
case DuckDBTypeId.TIMESTAMP_MS:

api/test/api.test.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -407,33 +407,40 @@ describe('api', () => {
407407
$timetz as timetz, \
408408
$varint as varint, \
409409
$list as list, \
410+
$list_dec as list_dec, \
410411
$struct as struct, \
411412
$array as array, \
412413
$null as null_value'
413414
);
414-
assert.strictEqual(prepared.parameterCount, 9);
415+
assert.strictEqual(prepared.parameterCount, 10);
415416
assert.strictEqual(prepared.parameterName(1), 'num');
416417
assert.strictEqual(prepared.parameterName(2), 'str');
417418
assert.strictEqual(prepared.parameterName(3), 'bool');
418419
assert.strictEqual(prepared.parameterName(4), 'timetz');
419420
assert.strictEqual(prepared.parameterName(5), 'varint');
420421
assert.strictEqual(prepared.parameterName(6), 'list');
421-
assert.strictEqual(prepared.parameterName(7), 'struct');
422-
assert.strictEqual(prepared.parameterName(8), 'array');
423-
assert.strictEqual(prepared.parameterName(9), 'null');
422+
assert.strictEqual(prepared.parameterName(7), 'list_dec');
423+
assert.strictEqual(prepared.parameterName(8), 'struct');
424+
assert.strictEqual(prepared.parameterName(9), 'array');
425+
assert.strictEqual(prepared.parameterName(10), 'null');
424426
prepared.bindInteger(1, 10);
425427
prepared.bindVarchar(2, 'abc');
426428
prepared.bindBoolean(3, true);
427429
prepared.bindTimeTZ(4, TIMETZ.max);
428430
prepared.bindVarInt(5, VARINT.max);
429431
prepared.bindList(6, listValue([100, 200, 300]), LIST(INTEGER));
430-
prepared.bindStruct(
432+
prepared.bindList(
431433
7,
434+
listValue([decimalValue(9876n, 4, 1), decimalValue(5432n, 4, 1)]),
435+
LIST(DECIMAL(4, 1))
436+
);
437+
prepared.bindStruct(
438+
8,
432439
structValue({ 'a': 42, 'b': 'duck' }),
433440
STRUCT({ 'a': INTEGER, 'b': VARCHAR })
434441
);
435-
prepared.bindArray(8, arrayValue([100, 200, 300]), ARRAY(INTEGER, 3));
436-
prepared.bindNull(9);
442+
prepared.bindArray(9, arrayValue([100, 200, 300]), ARRAY(INTEGER, 3));
443+
prepared.bindNull(10);
437444
assert.equal(prepared.parameterTypeId(1), DuckDBTypeId.INTEGER);
438445
assert.deepEqual(prepared.parameterType(1), INTEGER);
439446
// See https://github.com/duckdb/duckdb/issues/16137
@@ -447,12 +454,14 @@ describe('api', () => {
447454
assert.deepEqual(prepared.parameterType(5), VARINT);
448455
assert.equal(prepared.parameterTypeId(6), DuckDBTypeId.LIST);
449456
assert.deepEqual(prepared.parameterType(6), LIST(INTEGER));
450-
assert.equal(prepared.parameterTypeId(7), DuckDBTypeId.STRUCT);
451-
assert.deepEqual(prepared.parameterType(7), STRUCT({ 'a': INTEGER, 'b': VARCHAR }));
452-
assert.equal(prepared.parameterTypeId(8), DuckDBTypeId.ARRAY);
453-
assert.deepEqual(prepared.parameterType(8), ARRAY(INTEGER, 3));
454-
assert.equal(prepared.parameterTypeId(9), DuckDBTypeId.SQLNULL);
455-
assert.deepEqual(prepared.parameterType(9), SQLNULL);
457+
assert.equal(prepared.parameterTypeId(7), DuckDBTypeId.LIST);
458+
assert.deepEqual(prepared.parameterType(7), LIST(DECIMAL(4, 1)));
459+
assert.equal(prepared.parameterTypeId(8), DuckDBTypeId.STRUCT);
460+
assert.deepEqual(prepared.parameterType(8), STRUCT({ 'a': INTEGER, 'b': VARCHAR }));
461+
assert.equal(prepared.parameterTypeId(9), DuckDBTypeId.ARRAY);
462+
assert.deepEqual(prepared.parameterType(9), ARRAY(INTEGER, 3));
463+
assert.equal(prepared.parameterTypeId(10), DuckDBTypeId.SQLNULL);
464+
assert.deepEqual(prepared.parameterType(10), SQLNULL);
456465
const result = await prepared.run();
457466
assertColumns(result, [
458467
{ name: 'num', type: INTEGER },
@@ -461,14 +470,15 @@ describe('api', () => {
461470
{ name: 'timetz', type: TIMETZ },
462471
{ name: 'varint', type: VARINT },
463472
{ name: 'list', type: LIST(INTEGER) },
473+
{ name: 'list_dec', type: LIST(DECIMAL(4, 1)) },
464474
{ name: 'struct', type: STRUCT({ 'a': INTEGER, 'b': VARCHAR }) },
465475
{ name: 'array', type: ARRAY(INTEGER, 3) },
466476
{ name: 'null_value', type: INTEGER },
467477
]);
468478
const chunk = await result.fetchChunk();
469479
assert.isDefined(chunk);
470480
if (chunk) {
471-
assert.strictEqual(chunk.columnCount, 9);
481+
assert.strictEqual(chunk.columnCount, 10);
472482
assert.strictEqual(chunk.rowCount, 1);
473483
assertValues<number, DuckDBIntegerVector>(
474484
chunk,
@@ -491,15 +501,18 @@ describe('api', () => {
491501
assertValues(chunk, 3, DuckDBTimeTZVector, [TIMETZ.max]);
492502
assertValues(chunk, 4, DuckDBVarIntVector, [VARINT.max]);
493503
assertValues(chunk, 5, DuckDBListVector, [listValue([100, 200, 300])]);
494-
assertValues(chunk, 6, DuckDBStructVector, [
504+
assertValues(chunk, 6, DuckDBListVector, [
505+
listValue([decimalValue(9876n, 4, 1), decimalValue(5432n, 4, 1)]),
506+
]);
507+
assertValues(chunk, 7, DuckDBStructVector, [
495508
structValue({ 'a': 42, 'b': 'duck' }),
496509
]);
497-
assertValues(chunk, 7, DuckDBArrayVector, [
510+
assertValues(chunk, 8, DuckDBArrayVector, [
498511
arrayValue([100, 200, 300]),
499512
]);
500513
assertValues<number, DuckDBIntegerVector>(
501514
chunk,
502-
8,
515+
9,
503516
DuckDBIntegerVector,
504517
[null]
505518
);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ export function create_uhugeint(input: bigint): Value;
640640
export function create_varint(input: bigint): Value;
641641

642642
// DUCKDB_API duckdb_value duckdb_create_decimal(duckdb_decimal input);
643+
export function create_decimal(input: Decimal): Value;
643644

644645
// DUCKDB_API duckdb_value duckdb_create_float(float input);
645646
export function create_float(input: number): Value;
@@ -710,6 +711,7 @@ export function get_uhugeint(value: Value): bigint;
710711
export function get_varint(value: Value): bigint;
711712

712713
// DUCKDB_API duckdb_decimal duckdb_get_decimal(duckdb_value val);
714+
export function get_decimal(value: Value): Decimal;
713715

714716
// DUCKDB_API float duckdb_get_float(duckdb_value val);
715717
export function get_float(value: Value): number;

bindings/src/duckdb_node_bindings.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
11431143
InstanceMethod("create_hugeint", &DuckDBNodeAddon::create_hugeint),
11441144
InstanceMethod("create_uhugeint", &DuckDBNodeAddon::create_uhugeint),
11451145
InstanceMethod("create_varint", &DuckDBNodeAddon::create_varint),
1146+
InstanceMethod("create_decimal", &DuckDBNodeAddon::create_decimal),
11461147
InstanceMethod("create_float", &DuckDBNodeAddon::create_float),
11471148
InstanceMethod("create_double", &DuckDBNodeAddon::create_double),
11481149
InstanceMethod("create_date", &DuckDBNodeAddon::create_date),
@@ -1163,6 +1164,7 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
11631164
InstanceMethod("get_hugeint", &DuckDBNodeAddon::get_hugeint),
11641165
InstanceMethod("get_uhugeint", &DuckDBNodeAddon::get_uhugeint),
11651166
InstanceMethod("get_varint", &DuckDBNodeAddon::get_varint),
1167+
InstanceMethod("get_decimal", &DuckDBNodeAddon::get_decimal),
11661168
InstanceMethod("get_float", &DuckDBNodeAddon::get_float),
11671169
InstanceMethod("get_double", &DuckDBNodeAddon::get_double),
11681170
InstanceMethod("get_date", &DuckDBNodeAddon::get_date),
@@ -2461,6 +2463,14 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
24612463
}
24622464

24632465
// DUCKDB_API duckdb_value duckdb_create_decimal(duckdb_decimal input);
2466+
// function create_decimal(input: Decimal): Value
2467+
Napi::Value create_decimal(const Napi::CallbackInfo& info) {
2468+
auto env = info.Env();
2469+
auto decimal_obj = info[0].As<Napi::Object>();
2470+
auto decimal = GetDecimalFromObject(env, decimal_obj);
2471+
auto value = duckdb_create_decimal(decimal);
2472+
return CreateExternalForValue(env, value);
2473+
}
24642474

24652475
// DUCKDB_API duckdb_value duckdb_create_float(float input);
24662476
// function create_float(input: number): Value
@@ -2655,6 +2665,13 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
26552665
}
26562666

26572667
// DUCKDB_API duckdb_decimal duckdb_get_decimal(duckdb_value val);
2668+
// function get_decimal(value: Value): Decimal
2669+
Napi::Value get_decimal(const Napi::CallbackInfo& info) {
2670+
auto env = info.Env();
2671+
auto value = GetValueFromExternal(env, info[0]);
2672+
auto decimal = duckdb_get_decimal(value);
2673+
return MakeDecimalObject(env, decimal);
2674+
}
26582675

26592676
// DUCKDB_API float duckdb_get_float(duckdb_value val);
26602677
// function get_float(value: Value): number
@@ -3962,11 +3979,11 @@ NODE_API_ADDON(DuckDBNodeAddon)
39623979
---
39633980
411 total functions
39643981
3965-
216 instance methods
3982+
218 instance methods
39663983
3 unimplemented instance cache functions
39673984
1 unimplemented logical type function
3968-
9 unimplemented value creation functions
3969-
12 unimplemented value inspection functions
3985+
8 unimplemented value creation functions
3986+
11 unimplemented value inspection functions
39703987
13 unimplemented scalar function functions
39713988
4 unimplemented scalar function set functions
39723989
12 unimplemented aggregate function functions

bindings/test/values.test.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import duckdb from '@duckdb/node-bindings';
1+
import duckdb, {
2+
Date_,
3+
Decimal,
4+
Interval,
5+
Time,
6+
Timestamp,
7+
TimeTZ,
8+
} from '@duckdb/node-bindings';
29
import { expect, suite, test } from 'vitest';
310
import { expectLogicalType } from './utils/expectLogicalType';
411
import {
@@ -7,6 +14,7 @@ import {
714
BLOB,
815
BOOLEAN,
916
DATE,
17+
DECIMAL,
1018
DOUBLE,
1119
ENTRY,
1220
FLOAT,
@@ -26,7 +34,7 @@ import {
2634
USMALLINT,
2735
UTINYINT,
2836
VARCHAR,
29-
VARINT
37+
VARINT,
3038
} from './utils/expectedLogicalTypes';
3139

3240
suite('values', () => {
@@ -97,11 +105,20 @@ suite('values', () => {
97105
expect(duckdb.get_uhugeint(uhugeint_value)).toBe(input);
98106
});
99107
test('varint', () => {
100-
const input = -((((2n ** 10n + 11n) * (2n ** 64n) + (2n ** 9n + 7n)) * (2n ** 64n)) + (2n ** 8n + 5n));
108+
const input = -(
109+
((2n ** 10n + 11n) * 2n ** 64n + (2n ** 9n + 7n)) * 2n ** 64n +
110+
(2n ** 8n + 5n)
111+
);
101112
const varint_value = duckdb.create_varint(input);
102113
expectLogicalType(duckdb.get_value_type(varint_value), VARINT);
103114
expect(duckdb.get_varint(varint_value)).toBe(input);
104115
});
116+
test('decimal', () => {
117+
const input: Decimal = { width: 9, scale: 4, value: 987654321n };
118+
const decimal_value = duckdb.create_decimal(input);
119+
expectLogicalType(duckdb.get_value_type(decimal_value), DECIMAL(9, 4, duckdb.Type.INTEGER));
120+
expect(duckdb.get_decimal(decimal_value)).toStrictEqual(input);
121+
});
105122
test('float', () => {
106123
const input = 3.4028234663852886e38;
107124
const float_value = duckdb.create_float(input);
@@ -115,31 +132,31 @@ suite('values', () => {
115132
expect(duckdb.get_double(double_value)).toBe(input);
116133
});
117134
test('date', () => {
118-
const input = { days: 2147483646 };
135+
const input: Date_ = { days: 2147483646 };
119136
const date_value = duckdb.create_date(input);
120137
expectLogicalType(duckdb.get_value_type(date_value), DATE);
121138
expect(duckdb.get_date(date_value)).toStrictEqual(input);
122139
});
123140
test('time', () => {
124-
const input = { micros: 86400000000n };
141+
const input: Time = { micros: 86400000000n };
125142
const time_value = duckdb.create_time(input);
126143
expectLogicalType(duckdb.get_value_type(time_value), TIME);
127144
expect(duckdb.get_time(time_value)).toStrictEqual(input);
128145
});
129146
test('time_tz', () => {
130-
const input = { bits: 1449551462400115198n };
147+
const input: TimeTZ = { bits: 1449551462400115198n };
131148
const time_tz_value = duckdb.create_time_tz_value(input);
132149
expectLogicalType(duckdb.get_value_type(time_tz_value), TIME_TZ);
133150
expect(duckdb.get_time_tz(time_tz_value)).toStrictEqual(input);
134151
});
135152
test('timestamp', () => {
136-
const input = { micros: 9223372036854775806n };
153+
const input: Timestamp = { micros: 9223372036854775806n };
137154
const timestamp_value = duckdb.create_timestamp(input);
138155
expectLogicalType(duckdb.get_value_type(timestamp_value), TIMESTAMP);
139156
expect(duckdb.get_timestamp(timestamp_value)).toStrictEqual(input);
140157
});
141158
test('interval', () => {
142-
const input = { months: 999, days: 999, micros: 999999999n };
159+
const input: Interval = { months: 999, days: 999, micros: 999999999n };
143160
const interval_value = duckdb.create_interval(input);
144161
expectLogicalType(duckdb.get_value_type(interval_value), INTERVAL);
145162
expect(duckdb.get_interval(interval_value)).toStrictEqual(input);

0 commit comments

Comments
 (0)