@@ -16,7 +16,9 @@ This is a high-level API meant for applications. It depends on low-level binding
16
16
### Roadmap
17
17
18
18
Some features are not yet complete:
19
- - Friendlier APIs for consuming advanced data types and values, especially converting them to strings.
19
+ - Friendlier APIs for convering results to common JS data structures.
20
+ - Friendlier APIs for converting values of specialized and complex DuckDB types to common JS types.
21
+ - Automatic memory management (i.e. avoiding the need to call ` dispose ` manually in most cases).
20
22
- Appending and binding advanced data types. (Additional DuckDB C API support needed.)
21
23
- Writing to data chunk vectors. (Directly writing to binary buffers is challenging to support using the Node Addon API.)
22
24
- User-defined types & functions. (Support for this was added to the DuckDB C API in v1.1.0.)
@@ -163,89 +165,149 @@ chunk.dispose();
163
165
``` ts
164
166
import { DuckDBTypeId } from ' @duckdb/node-api' ;
165
167
166
- function typeToString(dataType ) {
167
- switch (dataType .typeId ) {
168
- case DuckDBTypeId .ARRAY :
169
- return ` ${typeToString (dataType .valueType )}[${dataType .length }] ` ;
170
- case DuckDBTypeId .DECIMAL :
171
- return ` DECIMAL(${dataType .width },${dataType .scale }) ` ;
172
- case DuckDBTypeId .ENUM :
173
- return ` ENUM(${dataType .values .map (
174
- value => ` '${value .replace (` ' ` , ` '' ` )}' `
175
- ).join (' , ' )}) ` ;
176
- case DuckDBTypeId .LIST :
177
- return ` ${typeToString (dataType .valueType )}[] ` ;
178
- case DuckDBTypeId .MAP :
179
- return ` MAP(${typeToString (dataType .keyType )}, ${typeToString (dataType .valueType )}) ` ;
180
- case DuckDBTypeId .STRUCT :
181
- return ` STRUCT(${dataType .entries .map (
182
- entry => ` "${entry .name .replace (` " ` , ` "" ` )}" ${typeToString (entry .valueType )} `
183
- ).join (' , ' )}) ` ;
184
- case DuckDBTypeId .UNION :
185
- return ` UNION(${dataType .alternatives .map (
186
- alt => ` "${alt .tag .replace (` " ` , ` "" ` )}" ${typeToString (alt .valueType )} `
187
- ).join (' , ' )}) ` ;
188
- default :
189
- return DuckDBTypeId [dataType .typeId ];
190
- }
168
+ if (columnType .typeId === DuckDBTypeId .ARRAY ) {
169
+ const arrayValueType = columnType .valueType ;
170
+ const arrayLength = columnType .length ;
171
+ }
172
+
173
+ if (columnType .typeId === DuckDBTypeId .DECIMAL ) {
174
+ const decimalWidth = columnType .width ;
175
+ const decimalScale = columnType .scale ;
176
+ }
177
+
178
+ if (columnType .typeId === DuckDBTypeId .ENUM ) {
179
+ const enumValues = columnType .values ;
180
+ }
181
+
182
+ if (columnType .typeId === DuckDBTypeId .LIST ) {
183
+ const listValueType = columnType .valueType ;
184
+ }
185
+
186
+ if (columnType .typeId === DuckDBTypeId .MAP ) {
187
+ const mapKeyType = columnType .keyType ;
188
+ const mapValueType = columnType .valueType ;
189
+ }
190
+
191
+ if (columnType .typeId === DuckDBTypeId .STRUCT ) {
192
+ const structEntryNames = columnType .names ;
193
+ const structEntryTypes = columnType .valueTypes ;
194
+ }
195
+
196
+ if (columnType .typeId === DuckDBTypeId .UNION ) {
197
+ const unionMemberTags = columnType .memberTags ;
198
+ const unionMemberTypes = columnType .memberTypes ;
191
199
}
192
200
```
193
201
194
- While the example above demonstrates how to access the properties of data type objects, there is a much simpler way to convert them to strings:
202
+ Every type implements toString, matching DuckDB's type-to-string conversion.
195
203
196
204
``` ts
197
- const dataTypeString = dataType .toString ();
205
+ const typeString = columnType .toString ();
198
206
```
199
207
200
208
### Inspect Data Values
201
209
202
210
``` ts
203
211
import { DuckDBTypeId } from ' @duckdb/node-api' ;
204
212
205
- function valueToString(value , dataType ) {
206
- switch (dataType .typeId ) {
207
- case DuckDBTypeId .ARRAY :
208
- return value
209
- ? ` [${Array .from ({ length: dataType .length }).map (
210
- (_ , i ) => valueToString (value .getItem (i ), dataType .valueType )
211
- ).join (' , ' )}] `
212
- : ' null' ;
213
- case DuckDBTypeId .DECIMAL :
214
- return JSON .stringify (value , replacer );
215
- case DuckDBTypeId .INTERVAL :
216
- return JSON .stringify (value , replacer );
217
- case DuckDBTypeId .LIST :
218
- return value
219
- ? ` [${Array .from ({ length: value .itemCount }).map (
220
- (_ , i ) => valueToString (value .getItem (i ), dataType .valueType )
221
- ).join (' , ' )}] `
222
- : ' null' ;
223
- case DuckDBTypeId .MAP :
224
- return value
225
- ? ` { ${value .map (
226
- (entry ) => ` ${valueToString (entry .key , dataType .keyType )}=${valueToString (entry .value , dataType .valueType )} `
227
- ).join (' , ' )} } `
228
- : ' null' ;
229
- case DuckDBTypeId .STRUCT :
230
- return value
231
- ? ` { ${value .map (
232
- (entry , i ) => ` '${entry .name .replace (` ' ` , ` '' ` )}': ${valueToString (entry .value , dataType .entries [i ].valueType )} `
233
- ).join (' , ' )} } `
234
- : ' null' ;
235
- case DuckDBTypeId .TIME_TZ :
236
- return JSON .stringify (value , replacer );
237
- case DuckDBTypeId .UNION :
238
- return value
239
- ? valueToString (value .value , dataType .alternatives .find ((alt ) => alt .tag === value .tag ).valueType )
240
- : ' null' ;
241
- default :
242
- return String (value );
243
- }
213
+ if (columnType .typeId === DuckDBTypeId .ARRAY ) {
214
+ const arrayItems = columnValue .items ; // array of values
215
+ const arrayString = columnValue .toString ();
216
+ }
217
+
218
+ if (columnType .typeId === DuckDBTypeId .BIT ) {
219
+ const bools = columnValue .toBools (); // array of booleans
220
+ const bits = columnValue .toBits (); // arrary of 0s and 1s
221
+ const bitString = columnValue .toString (); // string of '0's and '1's
222
+ }
223
+
224
+ if (columnType .typeId === DuckDBTypeId .BLOB ) {
225
+ const blobBytes = columnValue .bytes ; // Uint8Array
226
+ const blobString = columnValue .toString ();
227
+ }
228
+
229
+ if (columnType .typeId === DuckDBTypeId .DATE ) {
230
+ const dateDays = columnValue .days ;
231
+ const dateString = columnValue .toString ();
232
+ }
233
+
234
+ if (columnType .typeId === DuckDBTypeId .DECIMAL ) {
235
+ const decimalWidth = columnValue .width ;
236
+ const decimalScale = columnValue .scale ;
237
+ const decimalValue = columnValue .value ; // bigint (raw fixed-point integer; `scale` indicates number of fractional digits)
238
+ const decimalString = columnValue .toString ();
239
+ }
240
+
241
+ if (columnType .typeId === DuckDBTypeId .INTERVAL ) {
242
+ const intervalMonths = columnValue .months ;
243
+ const intervalDays = columnValue .days ;
244
+ const intervalMicros = columnValue .micros ; // bigint
245
+ const intervalString = columnValue .toString ();
244
246
}
245
247
246
- function replacer(key , value ) {
247
- return typeof value === " bigint" ? { $bigint: value .toString () } : value ;
248
+ if (columnType .typeId === DuckDBTypeId .LIST ) {
249
+ const listItems = columnValue .items ; // array of values
250
+ const listString = columnValue .toString ();
248
251
}
252
+
253
+ if (columnType .typeId === DuckDBTypeId .MAP ) {
254
+ const mapEntries = columnValue .entries ; // array of { key, value }
255
+ const mapString = columnValue .toString ();
256
+ }
257
+
258
+ if (columnType .typeId === DuckDBTypeId .STRUCT ) {
259
+ const structEntries = columnValue .entries ; // { name1: value1, name2: value2, ... }
260
+ const structString = columnValue .toString ();
261
+ }
262
+
263
+ if (columnType .typeId === DuckDBTypeId .TIMESTAMP_MS ) {
264
+ const timestampMillis = columnValue .milliseconds ; // bigint
265
+ const timestampMillisString = columnValue .toString ();
266
+ }
267
+
268
+ if (columnType .typeId === DuckDBTypeId .TIMESTAMP_NS ) {
269
+ const timestampNanos = columnValue .nanoseconds ; // bigint
270
+ const timestampNanosString = columnValue .toString ();
271
+ }
272
+
273
+ if (columnType .typeId === DuckDBTypeId .TIMESTAMP_S ) {
274
+ const timestampSecs = columnValue .seconds ; // bigint
275
+ const timestampSecsString = columnValue .toString ();
276
+ }
277
+
278
+ if (columnType .typeId === DuckDBTypeId .TIMESTAMP_TZ ) {
279
+ const timestampTZMicros = columnValue .micros ; // bigint
280
+ const timestampTZString = columnValue .toString ();
281
+ }
282
+
283
+ if (columnType .typeId === DuckDBTypeId .TIMESTAMP ) {
284
+ const timestampMicros = columnValue .micros ; // bigint
285
+ const timestampString = columnValue .toString ();
286
+ }
287
+
288
+ if (columnType .typeId === DuckDBTypeId .TIME_TZ ) {
289
+ const timeTZMicros = columnValue .microseconds ;
290
+ const timeTZOffset = columnValue .offset ;
291
+ const timeTZString = columnValue .toString ();
292
+ }
293
+
294
+ if (columnType .typeId === DuckDBTypeId .TIME ) {
295
+ const timeMicros = columnValue .microseconds ; // bigint
296
+ const timeString = columnValue .toString ();
297
+ }
298
+
299
+ if (columnType .typeId === DuckDBTypeId .UNION ) {
300
+ const unionTag = columnValue .tag ;
301
+ const unionValue = columnValue .value ;
302
+ const unionValueString = columnValue .toString ();
303
+ }
304
+
305
+ if (columnType .typeId === DuckDBTypeId .UUID ) {
306
+ const uuidHugeint = columnValue .hugeint ; // bigint
307
+ const uuidString = columnValue .toString ();
308
+ }
309
+
310
+ // other values are represented as null, boolean, number, bigint, or string
249
311
```
250
312
251
313
### Append To Table
0 commit comments