@haybarn/node-api 1.5.3-rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +1224 -0
  3. package/lib/DuckDBAppender.d.ts +51 -0
  4. package/lib/DuckDBAppender.js +149 -0
  5. package/lib/DuckDBBindInfo.d.ts +12 -0
  6. package/lib/DuckDBBindInfo.js +33 -0
  7. package/lib/DuckDBClientContext.d.ts +6 -0
  8. package/lib/DuckDBClientContext.js +17 -0
  9. package/lib/DuckDBConnection.d.ts +49 -0
  10. package/lib/DuckDBConnection.js +208 -0
  11. package/lib/DuckDBDataChunk.d.ts +41 -0
  12. package/lib/DuckDBDataChunk.js +223 -0
  13. package/lib/DuckDBExtractedStatements.d.ts +12 -0
  14. package/lib/DuckDBExtractedStatements.js +31 -0
  15. package/lib/DuckDBFunctionInfo.d.ts +10 -0
  16. package/lib/DuckDBFunctionInfo.js +29 -0
  17. package/lib/DuckDBInstance.d.ts +10 -0
  18. package/lib/DuckDBInstance.js +30 -0
  19. package/lib/DuckDBInstanceCache.d.ts +8 -0
  20. package/lib/DuckDBInstanceCache.js +28 -0
  21. package/lib/DuckDBLogicalType.d.ts +66 -0
  22. package/lib/DuckDBLogicalType.js +328 -0
  23. package/lib/DuckDBMaterializedResult.d.ts +9 -0
  24. package/lib/DuckDBMaterializedResult.js +24 -0
  25. package/lib/DuckDBPendingResult.d.ts +18 -0
  26. package/lib/DuckDBPendingResult.js +60 -0
  27. package/lib/DuckDBPreparedStatement.d.ts +72 -0
  28. package/lib/DuckDBPreparedStatement.js +219 -0
  29. package/lib/DuckDBPreparedStatementCollection.d.ts +4 -0
  30. package/lib/DuckDBPreparedStatementCollection.js +2 -0
  31. package/lib/DuckDBPreparedStatementWeakRefCollection.d.ts +9 -0
  32. package/lib/DuckDBPreparedStatementWeakRefCollection.js +28 -0
  33. package/lib/DuckDBResult.d.ts +57 -0
  34. package/lib/DuckDBResult.js +229 -0
  35. package/lib/DuckDBResultReader.d.ts +68 -0
  36. package/lib/DuckDBResultReader.js +203 -0
  37. package/lib/DuckDBScalarFunction.d.ts +33 -0
  38. package/lib/DuckDBScalarFunction.js +83 -0
  39. package/lib/DuckDBType.d.ts +373 -0
  40. package/lib/DuckDBType.js +930 -0
  41. package/lib/DuckDBTypeId.d.ts +42 -0
  42. package/lib/DuckDBTypeId.js +47 -0
  43. package/lib/DuckDBValueConverter.d.ts +3 -0
  44. package/lib/DuckDBValueConverter.js +2 -0
  45. package/lib/DuckDBValueConverters.d.ts +47 -0
  46. package/lib/DuckDBValueConverters.js +214 -0
  47. package/lib/DuckDBVector.d.ts +596 -0
  48. package/lib/DuckDBVector.js +2525 -0
  49. package/lib/JS.d.ts +3 -0
  50. package/lib/JS.js +2 -0
  51. package/lib/JSDuckDBValueConverter.d.ts +3 -0
  52. package/lib/JSDuckDBValueConverter.js +49 -0
  53. package/lib/Json.d.ts +3 -0
  54. package/lib/Json.js +2 -0
  55. package/lib/JsonDuckDBValueConverter.d.ts +3 -0
  56. package/lib/JsonDuckDBValueConverter.js +49 -0
  57. package/lib/configurationOptionDescriptions.d.ts +1 -0
  58. package/lib/configurationOptionDescriptions.js +16 -0
  59. package/lib/conversion/bytesFromString.d.ts +1 -0
  60. package/lib/conversion/bytesFromString.js +7 -0
  61. package/lib/conversion/dateTimeStringConversion.d.ts +20 -0
  62. package/lib/conversion/dateTimeStringConversion.js +238 -0
  63. package/lib/conversion/displayStringForDuckDBValue.d.ts +2 -0
  64. package/lib/conversion/displayStringForDuckDBValue.js +13 -0
  65. package/lib/conversion/stringFromBlob.d.ts +4 -0
  66. package/lib/conversion/stringFromBlob.js +45 -0
  67. package/lib/conversion/stringFromDecimal.d.ts +18 -0
  68. package/lib/conversion/stringFromDecimal.js +80 -0
  69. package/lib/convertColumnsFromChunks.d.ts +3 -0
  70. package/lib/convertColumnsFromChunks.js +16 -0
  71. package/lib/convertColumnsObjectFromChunks.d.ts +3 -0
  72. package/lib/convertColumnsObjectFromChunks.js +19 -0
  73. package/lib/convertRowObjectsFromChunks.d.ts +3 -0
  74. package/lib/convertRowObjectsFromChunks.js +17 -0
  75. package/lib/convertRowsFromChunks.d.ts +3 -0
  76. package/lib/convertRowsFromChunks.js +13 -0
  77. package/lib/createConfig.d.ts +2 -0
  78. package/lib/createConfig.js +19 -0
  79. package/lib/createDuckDBValueConverter.d.ts +3 -0
  80. package/lib/createDuckDBValueConverter.js +15 -0
  81. package/lib/createResult.d.ts +3 -0
  82. package/lib/createResult.js +17 -0
  83. package/lib/createValue.d.ts +4 -0
  84. package/lib/createValue.js +222 -0
  85. package/lib/duckdb.d.ts +33 -0
  86. package/lib/duckdb.js +54 -0
  87. package/lib/enums.d.ts +5 -0
  88. package/lib/enums.js +9 -0
  89. package/lib/getColumnsFromChunks.d.ts +3 -0
  90. package/lib/getColumnsFromChunks.js +10 -0
  91. package/lib/getColumnsObjectFromChunks.d.ts +3 -0
  92. package/lib/getColumnsObjectFromChunks.js +10 -0
  93. package/lib/getRowObjectsFromChunks.d.ts +3 -0
  94. package/lib/getRowObjectsFromChunks.js +10 -0
  95. package/lib/getRowsFromChunks.d.ts +3 -0
  96. package/lib/getRowsFromChunks.js +10 -0
  97. package/lib/index.d.ts +3 -0
  98. package/lib/index.js +41 -0
  99. package/lib/sleep.d.ts +1 -0
  100. package/lib/sleep.js +8 -0
  101. package/lib/sql.d.ts +2 -0
  102. package/lib/sql.js +10 -0
  103. package/lib/typeForValue.d.ts +3 -0
  104. package/lib/typeForValue.js +91 -0
  105. package/lib/values/DuckDBArrayValue.d.ts +7 -0
  106. package/lib/values/DuckDBArrayValue.js +18 -0
  107. package/lib/values/DuckDBBitValue.d.ts +16 -0
  108. package/lib/values/DuckDBBitValue.js +103 -0
  109. package/lib/values/DuckDBBlobValue.d.ts +8 -0
  110. package/lib/values/DuckDBBlobValue.js +26 -0
  111. package/lib/values/DuckDBDateValue.d.ts +16 -0
  112. package/lib/values/DuckDBDateValue.js +39 -0
  113. package/lib/values/DuckDBDecimalValue.d.ts +19 -0
  114. package/lib/values/DuckDBDecimalValue.js +44 -0
  115. package/lib/values/DuckDBIntervalValue.d.ts +9 -0
  116. package/lib/values/DuckDBIntervalValue.js +22 -0
  117. package/lib/values/DuckDBListValue.d.ts +7 -0
  118. package/lib/values/DuckDBListValue.js +18 -0
  119. package/lib/values/DuckDBMapValue.d.ts +11 -0
  120. package/lib/values/DuckDBMapValue.js +18 -0
  121. package/lib/values/DuckDBStructValue.d.ts +7 -0
  122. package/lib/values/DuckDBStructValue.js +22 -0
  123. package/lib/values/DuckDBTimeNSValue.d.ts +9 -0
  124. package/lib/values/DuckDBTimeNSValue.js +20 -0
  125. package/lib/values/DuckDBTimeTZValue.d.ts +35 -0
  126. package/lib/values/DuckDBTimeTZValue.js +65 -0
  127. package/lib/values/DuckDBTimeValue.d.ts +12 -0
  128. package/lib/values/DuckDBTimeValue.js +33 -0
  129. package/lib/values/DuckDBTimestampMillisecondsValue.d.ts +13 -0
  130. package/lib/values/DuckDBTimestampMillisecondsValue.js +31 -0
  131. package/lib/values/DuckDBTimestampNanosecondsValue.d.ts +13 -0
  132. package/lib/values/DuckDBTimestampNanosecondsValue.js +30 -0
  133. package/lib/values/DuckDBTimestampSecondsValue.d.ts +13 -0
  134. package/lib/values/DuckDBTimestampSecondsValue.js +30 -0
  135. package/lib/values/DuckDBTimestampTZValue.d.ts +16 -0
  136. package/lib/values/DuckDBTimestampTZValue.js +41 -0
  137. package/lib/values/DuckDBTimestampValue.d.ts +18 -0
  138. package/lib/values/DuckDBTimestampValue.js +41 -0
  139. package/lib/values/DuckDBUUIDValue.d.ts +19 -0
  140. package/lib/values/DuckDBUUIDValue.js +40 -0
  141. package/lib/values/DuckDBUnionValue.d.ts +8 -0
  142. package/lib/values/DuckDBUnionValue.js +22 -0
  143. package/lib/values/DuckDBValue.d.ts +20 -0
  144. package/lib/values/DuckDBValue.js +2 -0
  145. package/lib/values/index.d.ts +20 -0
  146. package/lib/values/index.js +36 -0
  147. package/lib/version.d.ts +1 -0
  148. package/lib/version.js +10 -0
  149. package/package.json +15 -0
package/README.md ADDED
@@ -0,0 +1,1224 @@
1
+ # Haybarn Node API
2
+
3
+ A high-level Node API for [Haybarn](https://github.com/Query-farm-haybarn/haybarn),
4
+ a derived distribution of [DuckDB](https://duckdb.org/) (powered by DuckDB),
5
+ published by Query Farm LLC.
6
+
7
+ It depends on low-level bindings that adhere closely to
8
+ [DuckDB's C API](https://duckdb.org/docs/api/c/overview), available separately
9
+ as [@haybarn/node-bindings](https://www.npmjs.com/package/@haybarn/node-bindings).
10
+
11
+ Forked from [@duckdb/node-api](https://www.npmjs.com/package/@duckdb/node-api);
12
+ the API surface (class names, methods, return shapes) is unchanged, so the only
13
+ migration step is swapping the import:
14
+
15
+ ```ts
16
+ - import { DuckDBInstance } from '@duckdb/node-api';
17
+ + import { DuckDBInstance } from '@haybarn/node-api';
18
+ ```
19
+
20
+ Haybarn is independent of and not endorsed by the DuckDB Foundation. DuckDB is
21
+ a trademark of the DuckDB Foundation.
22
+
23
+ ## Features
24
+
25
+ ### Main Differences from [duckdb-node](https://www.npmjs.com/package/duckdb)
26
+ * Native support for Promises; no need for separate [duckdb-async](https://www.npmjs.com/package/duckdb-async) wrapper.
27
+ * DuckDB-specific API; not based on the [SQLite Node API](https://www.npmjs.com/package/sqlite3).
28
+ * Lossless & efficent support for values of all [DuckDB data types](https://duckdb.org/docs/sql/data_types/overview).
29
+ * Wraps [released DuckDB binaries](https://github.com/duckdb/duckdb/releases) instead of rebuilding DuckDB.
30
+ * Built on [DuckDB's C API](https://duckdb.org/docs/api/c/overview); exposes more functionality.
31
+
32
+ ### Roadmap
33
+
34
+ Some features are not yet complete. See the [issues list on GitHub](https://github.com/duckdb/duckdb-node-neo/issues)
35
+ for the most up-to-date roadmap.
36
+
37
+ ### Supported Platforms
38
+
39
+ - Linux arm64 glibc
40
+ - Linux arm64 musl
41
+ - Linux x64 glibc
42
+ - Linux x64 musl
43
+ - Mac OS X (Darwin) arm64 (Apple Silicon)
44
+ - Mac OS X (Darwin) x64 (Intel)
45
+ - Windows (Win32) arm64
46
+ - Windows (Win32) x64
47
+
48
+ ## Examples
49
+
50
+ ### Get Basic Information
51
+
52
+ ```ts
53
+ import duckdb from '@haybarn/node-api';
54
+
55
+ console.log(duckdb.version());
56
+
57
+ console.log(duckdb.configurationOptionDescriptions());
58
+ ```
59
+
60
+ ### Connect
61
+
62
+ ```ts
63
+ import { DuckDBConnection } from '@haybarn/node-api';
64
+
65
+ const connection = await DuckDBConnection.create();
66
+ ```
67
+
68
+ This uses the default instance.
69
+ For advanced usage, you can create instances explicitly.
70
+
71
+ ### Create Instance
72
+
73
+ ```ts
74
+ import { DuckDBInstance } from '@haybarn/node-api';
75
+ ```
76
+
77
+ Create with an in-memory database:
78
+ ```ts
79
+ const instance = await DuckDBInstance.create(':memory:');
80
+ ```
81
+
82
+ Equivalent to the above:
83
+ ```ts
84
+ const instance = await DuckDBInstance.create();
85
+ ```
86
+
87
+ Read from and write to a database file, which is created if needed:
88
+ ```ts
89
+ const instance = await DuckDBInstance.create('my_duckdb.db');
90
+ ```
91
+
92
+ Set [configuration options](https://duckdb.org/docs/stable/configuration/overview.html#configuration-reference):
93
+ ```ts
94
+ const instance = await DuckDBInstance.create('my_duckdb.db', {
95
+ threads: '4'
96
+ });
97
+ ```
98
+
99
+ ### Instance Cache
100
+
101
+ Multiple instances in the same process should not
102
+ attach the same database.
103
+
104
+ To prevent this, an instance cache can be used:
105
+ ```ts
106
+ const instance = await DuckDBInstance.fromCache('my_duckdb.db');
107
+ ```
108
+
109
+ This uses the default instance cache. For advanced usage, you can create
110
+ instance caches explicitly:
111
+ ```ts
112
+ import { DuckDBInstanceCache } from '@haybarn/node-api';
113
+
114
+ const cache = new DuckDBInstanceCache();
115
+ const instance = await cache.getOrCreateInstance('my_duckdb.db');
116
+ ```
117
+
118
+ ### Connect to Instance
119
+
120
+ ```ts
121
+ const connection = await instance.connect();
122
+ ```
123
+
124
+ ### Disconnect
125
+
126
+ Connections will be disconnected automatically soon after their reference
127
+ is dropped, but you can also disconnect explicitly if and when you want:
128
+
129
+ ```ts
130
+ connection.disconnectSync();
131
+ ```
132
+
133
+ or, equivalently:
134
+
135
+ ```ts
136
+ connection.closeSync();
137
+ ```
138
+
139
+ ### Run SQL
140
+
141
+ ```ts
142
+ const result = await connection.run('from test_all_types()');
143
+ ```
144
+
145
+ ### Parameterize SQL
146
+
147
+ ```ts
148
+ const prepared = await connection.prepare('select $1, $2, $3');
149
+ prepared.bindVarchar(1, 'duck');
150
+ prepared.bindInteger(2, 42);
151
+ prepared.bindList(3, listValue([10, 11, 12]), LIST(INTEGER));
152
+ // OR, with type inference: prepared.bindList(3, [10, 11, 12]);
153
+ const result = await prepared.run();
154
+ ```
155
+
156
+ or:
157
+
158
+ ```ts
159
+ const prepared = await connection.prepare('select $a, $b, $c');
160
+ prepared.bind({
161
+ 'a': 'duck',
162
+ 'b': 42,
163
+ 'c': listValue([10, 11, 12]),
164
+ }, {
165
+ 'a': VARCHAR,
166
+ 'b': INTEGER,
167
+ 'c': LIST(INTEGER),
168
+ });
169
+ const result = await prepared.run();
170
+ ```
171
+
172
+ or even:
173
+
174
+ ```ts
175
+ const result = await connection.run('select $a, $b, $c', {
176
+ 'a': 'duck',
177
+ 'b': 42,
178
+ 'c': listValue([10, 11, 12]),
179
+ }, {
180
+ 'a': VARCHAR,
181
+ 'b': INTEGER,
182
+ 'c': LIST(INTEGER),
183
+ });
184
+ ```
185
+
186
+ Unspecified types will be inferred:
187
+
188
+ ```ts
189
+ const result = await connection.run('select $a, $b, $c', {
190
+ 'a': 'duck',
191
+ 'b': 42,
192
+ 'c': listValue([10, 11, 12]),
193
+ });
194
+ ```
195
+
196
+ ### Specifying Values
197
+
198
+ Values of many data types are represented using one of the JS primitives
199
+ `boolean`, `number`, `bigint`, or `string`.
200
+ Also, any type can have `null` values.
201
+
202
+ Values of some data types need to be constructed using special functions.
203
+ These are:
204
+
205
+ | Type | Function |
206
+ | ---- | -------- |
207
+ | `ARRAY` | `arrayValue` |
208
+ | `BIT` | `bitValue` |
209
+ | `BLOB` | `blobValue` |
210
+ | `DATE` | `dateValue` |
211
+ | `DECIMAL` | `decimalValue` |
212
+ | `INTERVAL` | `intervalValue` |
213
+ | `LIST` | `listValue` |
214
+ | `MAP` | `mapValue` |
215
+ | `STRUCT` | `structValue` |
216
+ | `TIME` | `timeValue` |
217
+ | `TIMETZ` | `timeTZValue` |
218
+ | `TIMESTAMP` | `timestampValue` |
219
+ | `TIMESTAMPTZ` | `timestampTZValue` |
220
+ | `TIMESTAMP_S` | `timestampSecondsValue` |
221
+ | `TIMESTAMP_MS` | `timestampMillisValue` |
222
+ | `TIMESTAMP_NS` | `timestampNanosValue` |
223
+ | `UNION` | `unionValue` |
224
+ | `UUID` | `uuidValue` |
225
+
226
+ ### Stream Results
227
+
228
+ Streaming results evaluate lazily when rows are read.
229
+
230
+ ```ts
231
+ const result = await connection.stream('from range(10_000)');
232
+ ```
233
+
234
+ ### Inspect Result Metadata
235
+
236
+ Get column names and types:
237
+ ```ts
238
+ const columnNames = result.columnNames();
239
+ const columnTypes = result.columnTypes();
240
+ ```
241
+
242
+ ### Read Result Data
243
+
244
+ Run and read all data:
245
+ ```ts
246
+ const reader = await connection.runAndReadAll('from test_all_types()');
247
+ const rows = reader.getRows();
248
+ // OR: const columns = reader.getColumns();
249
+ ```
250
+
251
+ Stream and read up to (at least) some number of rows:
252
+ ```ts
253
+ const reader = await connection.streamAndReadUntil(
254
+ 'from range(5000)',
255
+ 1000
256
+ );
257
+ const rows = reader.getRows();
258
+ // rows.length === 2048. (Rows are read in chunks of 2048.)
259
+ ```
260
+
261
+ Read rows incrementally:
262
+ ```ts
263
+ const reader = await connection.streamAndRead('from range(5000)');
264
+ reader.readUntil(2000);
265
+ // reader.currentRowCount === 2048 (Rows are read in chunks of 2048.)
266
+ // reader.done === false
267
+ reader.readUntil(4000);
268
+ // reader.currentRowCount === 4096
269
+ // reader.done === false
270
+ reader.readUntil(6000);
271
+ // reader.currentRowCount === 5000
272
+ // reader.done === true
273
+ ```
274
+
275
+ ### Get Result Data
276
+
277
+ Result data can be retrieved in a variety of forms:
278
+
279
+ ```ts
280
+ const reader = await connection.runAndReadAll(
281
+ 'from range(3) select range::int as i, 10 + i as n'
282
+ );
283
+
284
+ const rows = reader.getRows();
285
+ // [ [0, 10], [1, 11], [2, 12] ]
286
+
287
+ const rowObjects = reader.getRowObjects();
288
+ // [ { i: 0, n: 10 }, { i: 1, n: 11 }, { i: 2, n: 12 } ]
289
+
290
+ const columns = reader.getColumns();
291
+ // [ [0, 1, 2], [10, 11, 12] ]
292
+
293
+ const columnsObject = reader.getColumnsObject();
294
+ // { i: [0, 1, 2], n: [10, 11, 12] }
295
+ ```
296
+
297
+ ### Convert Result Data
298
+
299
+ By default, data values that cannot be represented as JS built-ins
300
+ are returned as specialized JS objects; see `Inspect Data Values` below.
301
+
302
+ To retrieve data in a different form, such as JS built-ins or values that
303
+ can be losslessly serialized to JSON, use the `JS` or `Json` forms of the
304
+ above result data methods.
305
+
306
+ Custom converters can be supplied as well. See the implementations of
307
+ [JSDuckDBValueConverter](https://github.com/duckdb/duckdb-node-neo/blob/main/api/src/JSDuckDBValueConverter.ts)
308
+ and [JsonDuckDBValueConverters](https://github.com/duckdb/duckdb-node-neo/blob/main/api/src/JsonDuckDBValueConverter.ts)
309
+ for how to do this.
310
+
311
+ Examples (using the `Json` forms):
312
+
313
+ ```ts
314
+ const reader = await connection.runAndReadAll(
315
+ 'from test_all_types() select bigint, date, interval limit 2'
316
+ );
317
+
318
+ const rows = reader.getRowsJson();
319
+ // [
320
+ // [
321
+ // "-9223372036854775808",
322
+ // "5877642-06-25 (BC)",
323
+ // { "months": 0, "days": 0, "micros": "0" }
324
+ // ],
325
+ // [
326
+ // "9223372036854775807",
327
+ // "5881580-07-10",
328
+ // { "months": 999, "days": 999, "micros": "999999999" }
329
+ // ]
330
+ // ]
331
+
332
+ const rowObjects = reader.getRowObjectsJson();
333
+ // [
334
+ // {
335
+ // "bigint": "-9223372036854775808",
336
+ // "date": "5877642-06-25 (BC)",
337
+ // "interval": { "months": 0, "days": 0, "micros": "0" }
338
+ // },
339
+ // {
340
+ // "bigint": "9223372036854775807",
341
+ // "date": "5881580-07-10",
342
+ // "interval": { "months": 999, "days": 999, "micros": "999999999" }
343
+ // }
344
+ // ]
345
+
346
+ const columns = reader.getColumnsJson();
347
+ // [
348
+ // [ "-9223372036854775808", "9223372036854775807" ],
349
+ // [ "5877642-06-25 (BC)", "5881580-07-10" ],
350
+ // [
351
+ // { "months": 0, "days": 0, "micros": "0" },
352
+ // { "months": 999, "days": 999, "micros": "999999999" }
353
+ // ]
354
+ // ]
355
+
356
+ const columnsObject = reader.getColumnsObjectJson();
357
+ // {
358
+ // "bigint": [ "-9223372036854775808", "9223372036854775807" ],
359
+ // "date": [ "5877642-06-25 (BC)", "5881580-07-10" ],
360
+ // "interval": [
361
+ // { "months": 0, "days": 0, "micros": "0" },
362
+ // { "months": 999, "days": 999, "micros": "999999999" }
363
+ // ]
364
+ // }
365
+ ```
366
+
367
+ These methods handle nested types as well:
368
+
369
+ ```ts
370
+ const reader = await connection.runAndReadAll(
371
+ 'from test_all_types() select int_array, struct, map, "union" limit 2'
372
+ );
373
+
374
+ const rows = reader.getRowsJson();
375
+ // [
376
+ // [
377
+ // [],
378
+ // { "a": null, "b": null },
379
+ // [],
380
+ // { "tag": "name", "value": "Frank" }
381
+ // ],
382
+ // [
383
+ // [ 42, 999, null, null, -42],
384
+ // { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" },
385
+ // [
386
+ // { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },
387
+ // { "key": "key2", "value": "goose" }
388
+ // ],
389
+ // { "tag": "age", "value": 5 }
390
+ // ]
391
+ // ]
392
+
393
+ const rowObjects = reader.getRowObjectsJson();
394
+ // [
395
+ // {
396
+ // "int_array": [],
397
+ // "struct": { "a": null, "b": null },
398
+ // "map": [],
399
+ // "union": { "tag": "name", "value": "Frank" }
400
+ // },
401
+ // {
402
+ // "int_array": [ 42, 999, null, null, -42 ],
403
+ // "struct": { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" },
404
+ // "map": [
405
+ // { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },
406
+ // { "key": "key2", "value": "goose" }
407
+ // ],
408
+ // "union": { "tag": "age", "value": 5 }
409
+ // }
410
+ // ]
411
+
412
+ const columns = reader.getColumnsJson();
413
+ // [
414
+ // [
415
+ // [],
416
+ // [42, 999, null, null, -42]
417
+ // ],
418
+ // [
419
+ // { "a": null, "b": null },
420
+ // { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" }
421
+ // ],
422
+ // [
423
+ // [],
424
+ // [
425
+ // { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },
426
+ // { "key": "key2", "value": "goose"}
427
+ // ]
428
+ // ],
429
+ // [
430
+ // { "tag": "name", "value": "Frank" },
431
+ // { "tag": "age", "value": 5 }
432
+ // ]
433
+ // ]
434
+
435
+ const columnsObject = reader.getColumnsObjectJson();
436
+ // {
437
+ // "int_array": [
438
+ // [],
439
+ // [42, 999, null, null, -42]
440
+ // ],
441
+ // "struct": [
442
+ // { "a": null, "b": null },
443
+ // { "a": 42, "b": "🦆🦆🦆🦆🦆🦆" }
444
+ // ],
445
+ // "map": [
446
+ // [],
447
+ // [
448
+ // { "key": "key1", "value": "🦆🦆🦆🦆🦆🦆" },
449
+ // { "key": "key2", "value": "goose" }
450
+ // ]
451
+ // ],
452
+ // "union": [
453
+ // { "tag": "name", "value": "Frank" },
454
+ // { "tag": "age", "value": 5 }
455
+ // ]
456
+ // }
457
+ ```
458
+
459
+ Column names and types can also be serialized to JSON:
460
+ ```ts
461
+ const columnNamesAndTypes = reader.columnNamesAndTypesJson();
462
+ // {
463
+ // "columnNames": [
464
+ // "int_array",
465
+ // "struct",
466
+ // "map",
467
+ // "union"
468
+ // ],
469
+ // "columnTypes": [
470
+ // {
471
+ // "typeId": 24,
472
+ // "valueType": {
473
+ // "typeId": 4
474
+ // }
475
+ // },
476
+ // {
477
+ // "typeId": 25,
478
+ // "entryNames": [
479
+ // "a",
480
+ // "b"
481
+ // ],
482
+ // "entryTypes": [
483
+ // {
484
+ // "typeId": 4
485
+ // },
486
+ // {
487
+ // "typeId": 17
488
+ // }
489
+ // ]
490
+ // },
491
+ // {
492
+ // "typeId": 26,
493
+ // "keyType": {
494
+ // "typeId": 17
495
+ // },
496
+ // "valueType": {
497
+ // "typeId": 17
498
+ // }
499
+ // },
500
+ // {
501
+ // "typeId": 28,
502
+ // "memberTags": [
503
+ // "name",
504
+ // "age"
505
+ // ],
506
+ // "memberTypes": [
507
+ // {
508
+ // "typeId": 17
509
+ // },
510
+ // {
511
+ // "typeId": 3
512
+ // }
513
+ // ]
514
+ // }
515
+ // ]
516
+ // }
517
+
518
+ const columnNameAndTypeObjects = reader.columnNameAndTypeObjectsJson();
519
+ // [
520
+ // {
521
+ // "columnName": "int_array",
522
+ // "columnType": {
523
+ // "typeId": 24,
524
+ // "valueType": {
525
+ // "typeId": 4
526
+ // }
527
+ // }
528
+ // },
529
+ // {
530
+ // "columnName": "struct",
531
+ // "columnType": {
532
+ // "typeId": 25,
533
+ // "entryNames": [
534
+ // "a",
535
+ // "b"
536
+ // ],
537
+ // "entryTypes": [
538
+ // {
539
+ // "typeId": 4
540
+ // },
541
+ // {
542
+ // "typeId": 17
543
+ // }
544
+ // ]
545
+ // }
546
+ // },
547
+ // {
548
+ // "columnName": "map",
549
+ // "columnType": {
550
+ // "typeId": 26,
551
+ // "keyType": {
552
+ // "typeId": 17
553
+ // },
554
+ // "valueType": {
555
+ // "typeId": 17
556
+ // }
557
+ // }
558
+ // },
559
+ // {
560
+ // "columnName": "union",
561
+ // "columnType": {
562
+ // "typeId": 28,
563
+ // "memberTags": [
564
+ // "name",
565
+ // "age"
566
+ // ],
567
+ // "memberTypes": [
568
+ // {
569
+ // "typeId": 17
570
+ // },
571
+ // {
572
+ // "typeId": 3
573
+ // }
574
+ // ]
575
+ // }
576
+ // }
577
+ // ]
578
+ ```
579
+
580
+ ### Fetch Chunks
581
+
582
+ Fetch all chunks:
583
+ ```ts
584
+ const chunks = await result.fetchAllChunks();
585
+ ```
586
+
587
+ Fetch one chunk at a time:
588
+ ```ts
589
+ const chunks = [];
590
+ while (true) {
591
+ const chunk = await result.fetchChunk();
592
+ // Last chunk will have zero rows.
593
+ if (chunk.rowCount === 0) {
594
+ break;
595
+ }
596
+ chunks.push(chunk);
597
+ }
598
+ ```
599
+
600
+ For materialized (non-streaming) results, chunks can be read by index:
601
+ ```ts
602
+ const rowCount = result.rowCount;
603
+ const chunkCount = result.chunkCount;
604
+ for (let i = 0; i < chunkCount; i++) {
605
+ const chunk = result.getChunk(i);
606
+ // ...
607
+ }
608
+ ```
609
+
610
+ Get chunk data:
611
+ ```ts
612
+ const rows = chunk.getRows();
613
+
614
+ const rowObjects = chunk.getRowObjects(result.deduplicatedColumnNames());
615
+
616
+ const columns = chunk.getColumns();
617
+
618
+ const columnsObject =
619
+ chunk.getColumnsObject(result.deduplicatedColumnNames());
620
+ ```
621
+
622
+ Get chunk data (one value at a time)
623
+ ```ts
624
+ const columns = [];
625
+ const columnCount = chunk.columnCount;
626
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
627
+ const columnValues = [];
628
+ const columnVector = chunk.getColumnVector(columnIndex);
629
+ const itemCount = columnVector.itemCount;
630
+ for (let itemIndex = 0; itemIndex < itemCount; itemIndex++) {
631
+ const value = columnVector.getItem(itemIndex);
632
+ columnValues.push(value);
633
+ }
634
+ columns.push(columnValues);
635
+ }
636
+ ```
637
+
638
+ ### Inspect Data Types
639
+
640
+ ```ts
641
+ import { DuckDBTypeId } from '@haybarn/node-api';
642
+
643
+ if (columnType.typeId === DuckDBTypeId.ARRAY) {
644
+ const arrayValueType = columnType.valueType;
645
+ const arrayLength = columnType.length;
646
+ }
647
+
648
+ if (columnType.typeId === DuckDBTypeId.DECIMAL) {
649
+ const decimalWidth = columnType.width;
650
+ const decimalScale = columnType.scale;
651
+ }
652
+
653
+ if (columnType.typeId === DuckDBTypeId.ENUM) {
654
+ const enumValues = columnType.values;
655
+ }
656
+
657
+ if (columnType.typeId === DuckDBTypeId.LIST) {
658
+ const listValueType = columnType.valueType;
659
+ }
660
+
661
+ if (columnType.typeId === DuckDBTypeId.MAP) {
662
+ const mapKeyType = columnType.keyType;
663
+ const mapValueType = columnType.valueType;
664
+ }
665
+
666
+ if (columnType.typeId === DuckDBTypeId.STRUCT) {
667
+ const structEntryNames = columnType.names;
668
+ const structEntryTypes = columnType.valueTypes;
669
+ }
670
+
671
+ if (columnType.typeId === DuckDBTypeId.UNION) {
672
+ const unionMemberTags = columnType.memberTags;
673
+ const unionMemberTypes = columnType.memberTypes;
674
+ }
675
+
676
+ // For the JSON type (https://duckdb.org/docs/data/json/json_type)
677
+ if (columnType.alias === 'JSON') {
678
+ const json = JSON.parse(columnValue);
679
+ }
680
+ ```
681
+
682
+ Every type implements toString.
683
+ The result is both human-friendly and readable by DuckDB in an appropriate expression.
684
+
685
+ ```ts
686
+ const typeString = columnType.toString();
687
+ ```
688
+
689
+ ### Inspect Data Values
690
+
691
+ ```ts
692
+ import { DuckDBTypeId } from '@haybarn/node-api';
693
+
694
+ if (columnType.typeId === DuckDBTypeId.ARRAY) {
695
+ const arrayItems = columnValue.items; // array of values
696
+ const arrayString = columnValue.toString();
697
+ }
698
+
699
+ if (columnType.typeId === DuckDBTypeId.BIT) {
700
+ const bools = columnValue.toBools(); // array of booleans
701
+ const bits = columnValue.toBits(); // arrary of 0s and 1s
702
+ const bitString = columnValue.toString(); // string of '0's and '1's
703
+ }
704
+
705
+ if (columnType.typeId === DuckDBTypeId.BLOB) {
706
+ const blobBytes = columnValue.bytes; // Uint8Array
707
+ const blobString = columnValue.toString();
708
+ }
709
+
710
+ if (columnType.typeId === DuckDBTypeId.DATE) {
711
+ const dateDays = columnValue.days;
712
+ const dateString = columnValue.toString();
713
+ const { year, month, day } = columnValue.toParts();
714
+ }
715
+
716
+ if (columnType.typeId === DuckDBTypeId.DECIMAL) {
717
+ const decimalWidth = columnValue.width;
718
+ const decimalScale = columnValue.scale;
719
+ // Scaled-up value. Represented number is value/(10^scale).
720
+ const decimalValue = columnValue.value; // bigint
721
+ const decimalString = columnValue.toString();
722
+ const decimalDouble = columnValue.toDouble();
723
+ }
724
+
725
+ if (columnType.typeId === DuckDBTypeId.INTERVAL) {
726
+ const intervalMonths = columnValue.months;
727
+ const intervalDays = columnValue.days;
728
+ const intervalMicros = columnValue.micros; // bigint
729
+ const intervalString = columnValue.toString();
730
+ }
731
+
732
+ if (columnType.typeId === DuckDBTypeId.LIST) {
733
+ const listItems = columnValue.items; // array of values
734
+ const listString = columnValue.toString();
735
+ }
736
+
737
+ if (columnType.typeId === DuckDBTypeId.MAP) {
738
+ const mapEntries = columnValue.entries; // array of { key, value }
739
+ const mapString = columnValue.toString();
740
+ }
741
+
742
+ if (columnType.typeId === DuckDBTypeId.STRUCT) {
743
+ // { name1: value1, name2: value2, ... }
744
+ const structEntries = columnValue.entries;
745
+ const structString = columnValue.toString();
746
+ }
747
+
748
+ if (columnType.typeId === DuckDBTypeId.TIMESTAMP_MS) {
749
+ const timestampMillis = columnValue.milliseconds; // bigint
750
+ const timestampMillisString = columnValue.toString();
751
+ }
752
+
753
+ if (columnType.typeId === DuckDBTypeId.TIMESTAMP_NS) {
754
+ const timestampNanos = columnValue.nanoseconds; // bigint
755
+ const timestampNanosString = columnValue.toString();
756
+ }
757
+
758
+ if (columnType.typeId === DuckDBTypeId.TIMESTAMP_S) {
759
+ const timestampSecs = columnValue.seconds; // bigint
760
+ const timestampSecsString = columnValue.toString();
761
+ }
762
+
763
+ if (columnType.typeId === DuckDBTypeId.TIMESTAMP_TZ) {
764
+ const timestampTZMicros = columnValue.micros; // bigint
765
+ const timestampTZString = columnValue.toString();
766
+ const {
767
+ date: { year, month, day },
768
+ time: { hour, min, sec, micros },
769
+ } = columnValue.toParts();
770
+ }
771
+
772
+ if (columnType.typeId === DuckDBTypeId.TIMESTAMP) {
773
+ const timestampMicros = columnValue.micros; // bigint
774
+ const timestampString = columnValue.toString();
775
+ const {
776
+ date: { year, month, day },
777
+ time: { hour, min, sec, micros },
778
+ } = columnValue.toParts();
779
+ }
780
+
781
+ if (columnType.typeId === DuckDBTypeId.TIME_TZ) {
782
+ const timeTZMicros = columnValue.micros; // bigint
783
+ const timeTZOffset = columnValue.offset;
784
+ const timeTZString = columnValue.toString();
785
+ const {
786
+ time: { hour, min, sec, micros },
787
+ offset,
788
+ } = columnValue.toParts();
789
+ }
790
+
791
+ if (columnType.typeId === DuckDBTypeId.TIME) {
792
+ const timeMicros = columnValue.micros; // bigint
793
+ const timeString = columnValue.toString();
794
+ const { hour, min, sec, micros } = columnValue.toParts();
795
+ }
796
+
797
+ if (columnType.typeId === DuckDBTypeId.UNION) {
798
+ const unionTag = columnValue.tag;
799
+ const unionValue = columnValue.value;
800
+ const unionValueString = columnValue.toString();
801
+ }
802
+
803
+ if (columnType.typeId === DuckDBTypeId.UUID) {
804
+ const uuidHugeint = columnValue.hugeint; // bigint
805
+ const uuidString = columnValue.toString();
806
+ }
807
+
808
+ // other possible values are: null, boolean, number, bigint, or string
809
+ ```
810
+
811
+ ### Displaying Timezones
812
+
813
+ Converting a TIMESTAMP_TZ value to a string depends on a timezone offset.
814
+ By default, this is set to the offset for the local timezone when the Node
815
+ process is started.
816
+
817
+ To change it, set the `timezoneOffsetInMinutes`
818
+ property of `DuckDBTimestampTZValue`:
819
+
820
+ ```ts
821
+ DuckDBTimestampTZValue.timezoneOffsetInMinutes = -8 * 60;
822
+ const pst = DuckDBTimestampTZValue.Epoch.toString();
823
+ // 1969-12-31 16:00:00-08
824
+
825
+ DuckDBTimestampTZValue.timezoneOffsetInMinutes = +1 * 60;
826
+ const cet = DuckDBTimestampTZValue.Epoch.toString();
827
+ // 1970-01-01 01:00:00+01
828
+ ```
829
+
830
+ Note that the timezone offset used for this string
831
+ conversion is distinct from the `TimeZone` setting of DuckDB.
832
+
833
+ The following sets this offset to match the `TimeZone` setting of DuckDB:
834
+
835
+ ```ts
836
+ const reader = await connection.runAndReadAll(
837
+ `select (timezone(current_timestamp) / 60)::int`
838
+ );
839
+ DuckDBTimestampTZValue.timezoneOffsetInMinutes =
840
+ reader.getColumns()[0][0];
841
+ ```
842
+
843
+ ### Append To Table
844
+
845
+ ```ts
846
+ await connection.run(
847
+ `create or replace table target_table(i integer, v varchar)`
848
+ );
849
+
850
+ const appender = await connection.createAppender('target_table');
851
+
852
+ appender.appendInteger(42);
853
+ appender.appendVarchar('duck');
854
+ appender.endRow();
855
+
856
+ appender.appendInteger(123);
857
+ appender.appendVarchar('mallard');
858
+ appender.endRow();
859
+
860
+ appender.flushSync();
861
+
862
+ appender.appendInteger(17);
863
+ appender.appendVarchar('goose');
864
+ appender.endRow();
865
+
866
+ appender.closeSync(); // also flushes
867
+ ```
868
+
869
+ ### Append Data Chunk
870
+
871
+ ```ts
872
+ await connection.run(
873
+ `create or replace table target_table(i integer, v varchar)`
874
+ );
875
+
876
+ const appender = await connection.createAppender('target_table');
877
+
878
+ const chunk = DuckDBDataChunk.create([INTEGER, VARCHAR]);
879
+ chunk.setColumns([
880
+ [42, 123, 17],
881
+ ['duck', 'mallad', 'goose'],
882
+ ]);
883
+ // OR:
884
+ // chunk.setRows([
885
+ // [42, 'duck'],
886
+ // [123, 'mallard'],
887
+ // [17, 'goose'],
888
+ // ]);
889
+
890
+ appender.appendDataChunk(chunk);
891
+ appender.flushSync();
892
+ ```
893
+
894
+ See "Specifying Values" above for how to supply values to the appender.
895
+
896
+ ### Scalar Functions
897
+
898
+ ```ts
899
+ connection.registerScalarFunction(
900
+ DuckDBScalarFunction.create({
901
+ name: 'my_add',
902
+ mainFunction: (info, input, output) => {
903
+ const v0 = input.getColumnVector(0);
904
+ const v1 = input.getColumnVector(1);
905
+ for (let rowIndex = 0; rowIndex < input.rowCount; rowIndex++) {
906
+ output.setItem(
907
+ rowIndex,
908
+ v0.getItem(rowIndex) + v1.getItem(rowIndex)
909
+ );
910
+ }
911
+ output.flush();
912
+ },
913
+ returnType: INTEGER,
914
+ parameterTypes: [INTEGER, INTEGER],
915
+ })
916
+ );
917
+ const reader = await connection.runAndReadAll('select my_add(2, 3)');
918
+ const rows = reader.getRows();
919
+ // [ [ 5 ] ]
920
+ ```
921
+
922
+ ### Extract Statements
923
+
924
+ ```ts
925
+ const extractedStatements = await connection.extractStatements(`
926
+ create or replace table numbers as from range(?);
927
+ from numbers where range < ?;
928
+ drop table numbers;
929
+ `);
930
+ const parameterValues = [10, 7];
931
+ const statementCount = extractedStatements.count;
932
+ for (let stmtIndex = 0; stmtIndex < statementCount; stmtIndex++) {
933
+ const prepared = await extractedStatements.prepare(stmtIndex);
934
+ let parameterCount = prepared.parameterCount;
935
+ for (let paramIndex = 1; paramIndex <= parameterCount; paramIndex++) {
936
+ prepared.bindInteger(paramIndex, parameterValues.shift());
937
+ }
938
+ const result = await prepared.run();
939
+ // ...
940
+ }
941
+ ```
942
+
943
+ ### Control Evaluation of Tasks
944
+
945
+ DuckDB splits work into relatively short tasks. By controlling the
946
+ evaluation of these tasks explicitly, better cooperative multithreading
947
+ can be accomplished. This is especially important for maximum throughput
948
+ in the Node environment, which has a small, fixed number of threads for
949
+ running asynchronous work.
950
+ (See https://docs.libuv.org/en/stable/threadpool.html)
951
+
952
+ Below is a low-level way of controlling the evaluation of processing.
953
+ See the "startThenRead" and "startStreamThenRead" methods for helpers
954
+ that do much of this for you.
955
+
956
+ ```ts
957
+ import { DuckDBPendingResultState } from '@haybarn/node-api';
958
+
959
+ async function sleep(ms) {
960
+ return new Promise((resolve) => {
961
+ setTimeout(resolve, ms);
962
+ });
963
+ }
964
+
965
+ const prepared = await connection.prepare('from range(10_000_000)');
966
+ const pending = prepared.startStream();
967
+ while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) {
968
+ console.log('not ready');
969
+ await sleep(1);
970
+ }
971
+ console.log('ready');
972
+ const result = await pending.getResult();
973
+ // ...
974
+ ```
975
+
976
+ Equivalently, using `startStreamThenRead`:
977
+
978
+ ```ts
979
+ const reader = await connection.startStreamThenRead(sql);
980
+ ```
981
+
982
+ ### Ways to run SQL
983
+
984
+ ```ts
985
+ // Run to completion but don't yet retrieve any rows.
986
+ // Optionally take values to bind to SQL parameters,
987
+ // and (optionally) types of those parameters,
988
+ // either as an array (for positional parameters),
989
+ // or an object keyed by parameter name.
990
+ const result = await connection.run(sql);
991
+ const result = await connection.run(sql, values);
992
+ const result = await connection.run(sql, values, types);
993
+
994
+ // Run to completion but don't yet retrieve any rows.
995
+ // Wrap in a DuckDBDataReader for convenient data retrieval.
996
+ const reader = await connection.runAndRead(sql);
997
+ const reader = await connection.runAndRead(sql, values);
998
+ const reader = await connection.runAndRead(sql, values, types);
999
+
1000
+ // Run to completion, wrap in a reader, and read all rows.
1001
+ const reader = await connection.runAndReadAll(sql);
1002
+ const reader = await connection.runAndReadAll(sql, values);
1003
+ const reader = await connection.runAndReadAll(sql, values, types);
1004
+
1005
+ // Run to completion, wrap in a reader, and read at least
1006
+ // the given number of rows. (Rows are read in chunks, so more than
1007
+ // the target may be read.)
1008
+ const reader = await connection.runAndReadUntil(sql, targetRowCount);
1009
+ const reader =
1010
+ await connection.runAndReadAll(sql, targetRowCount, values);
1011
+ const reader =
1012
+ await connection.runAndReadAll(sql, targetRowCount, values, types);
1013
+
1014
+ // Create a streaming result and don't yet retrieve any rows.
1015
+ const result = await connection.stream(sql);
1016
+ const result = await connection.stream(sql, values);
1017
+ const result = await connection.stream(sql, values, types);
1018
+
1019
+ // Create a streaming result and don't yet retrieve any rows.
1020
+ // Wrap in a DuckDBDataReader for convenient data retrieval.
1021
+ const reader = await connection.streamAndRead(sql);
1022
+ const reader = await connection.streamAndRead(sql, values);
1023
+ const reader = await connection.streamAndRead(sql, values, types);
1024
+
1025
+ // Create a streaming result, wrap in a reader, and read all rows.
1026
+ const reader = await connection.streamAndReadAll(sql);
1027
+ const reader = await connection.streamAndReadAll(sql, values);
1028
+ const reader = await connection.streamAndReadAll(sql, values, types);
1029
+
1030
+ // Create a streaming result, wrap in a reader, and read at least
1031
+ // the given number of rows.
1032
+ const reader = await connection.streamAndReadUntil(sql, targetRowCount);
1033
+ const reader =
1034
+ await connection.streamAndReadUntil(sql, targetRowCount, values);
1035
+ const reader =
1036
+ await connection.streamAndReadUntil(sql, targetRowCount, values, types);
1037
+
1038
+ // Prepared Statements
1039
+
1040
+ // Prepare a possibly-parametered SQL statement to run later.
1041
+ const prepared = await connection.prepare(sql);
1042
+
1043
+ // Bind values to the parameters.
1044
+ prepared.bind(values);
1045
+ prepared.bind(values, types);
1046
+
1047
+ // Run the prepared statement. These mirror the methods on the connection.
1048
+ const result = prepared.run();
1049
+
1050
+ const reader = prepared.runAndRead();
1051
+ const reader = prepared.runAndReadAll();
1052
+ const reader = prepared.runAndReadUntil(targetRowCount);
1053
+
1054
+ const result = prepared.stream();
1055
+
1056
+ const reader = prepared.streamAndRead();
1057
+ const reader = prepared.streamAndReadAll();
1058
+ const reader = prepared.streamAndReadUntil(targetRowCount);
1059
+
1060
+ // Pending Results
1061
+
1062
+ // Create a pending result.
1063
+ const pending = await connection.start(sql);
1064
+ const pending = await connection.start(sql, values);
1065
+ const pending = await connection.start(sql, values, types);
1066
+
1067
+ // The methods beginning with "startThenRead" provide some, but not full,
1068
+ // cooperative multithreading. They use pending results to split processing
1069
+ // into short tasks, but they fully materialize the result, which can
1070
+ // take some time (and memory). For full cooperative multithreading,
1071
+ // see the "startStreamThenRead" methods below.
1072
+ const reader = await connection.startThenRead(sql);
1073
+ const reader = await connection.startThenRead(sql, values);
1074
+ const reader = await connection.startThenRead(sql, values, types);
1075
+
1076
+ const reader = await connection.startThenReadAll(sql);
1077
+ const reader = await connection.startThenReadAll(sql, values);
1078
+ const reader = await connection.startThenReadAll(sql, values, types);
1079
+
1080
+ const reader = await connection.startThenReadUntil(sql, targetRowCount);
1081
+ const reader =
1082
+ await connection.startThenReadUntil(sql, targetRowCount, values);
1083
+ const reader =
1084
+ await connection.startThenReadUntil(sql, targetRowCount, values, types);
1085
+
1086
+ // Create a pending, streaming result.
1087
+ const pending = await connection.startStream(sql);
1088
+ const pending = await connection.startStream(sql, values);
1089
+ const pending = await connection.startStream(sql, values, types);
1090
+
1091
+ // The methods beginning with "startStreamThenRead" are the best options
1092
+ // for cooperative multithreading. By creating a streaming result, they
1093
+ // prevent the result from being fully materialized. By using a pending
1094
+ // result, they split processing into short tasks, preventing any single
1095
+ // task from occupying a thread for too long.
1096
+ const reader = await connection.startStreamThenRead(sql);
1097
+ const reader = await connection.startStreamThenRead(sql, values);
1098
+ const reader = await connection.startStreamThenRead(sql, values, types);
1099
+
1100
+ const reader = await connection.startStreamThenReadAll(sql);
1101
+ const reader = await connection.startStreamThenReadAll(sql, values);
1102
+ const reader =
1103
+ await connection.startStreamThenReadAll(sql, values, types);
1104
+
1105
+ const reader =
1106
+ await connection.startStreamThenReadUntil(sql, targetRowCount);
1107
+ const reader =
1108
+ await connection.startStreamThenReadUntil(sql, targetRowCount, values);
1109
+ const reader = await connection.startStreamThenReadUntil(
1110
+ sql, targetRowCount, values, types);
1111
+
1112
+ // Create a pending result from a prepared statement.
1113
+ const pending = await prepared.start();
1114
+ const pending = await prepared.startStream();
1115
+
1116
+ while (pending.runTask() !== DuckDBPendingResultState.RESULT_READY) {
1117
+ // optionally sleep or do other work between tasks
1118
+ }
1119
+
1120
+ // Or, run tasks (cooperatively) until the result is ready.
1121
+ await pending.runAllTasks();
1122
+
1123
+ // Retrieve the result. If not yet READY, will run until it is.
1124
+ const result = await pending.getResult();
1125
+
1126
+ const reader = await pending.read();
1127
+ const reader = await pending.readAll();
1128
+ const reader = await pending.readUntil(targetRowCount);
1129
+ ```
1130
+
1131
+ ### Ways to get result data
1132
+
1133
+ ```ts
1134
+ // From a result
1135
+
1136
+ // Asynchronously retrieve data for all rows:
1137
+ const columns = await result.getColumns();
1138
+ const columnsJS = await result.getColumnsJS();
1139
+ const columnsJson = await result.getColumnsJson();
1140
+ const columnsObject = await result.getColumnsObject();
1141
+ const columnsObjectJS = await result.getColumnsObjectJS();
1142
+ const columnsObjectJson = await result.getColumnsObjectJson();
1143
+ const rows = await result.getRows();
1144
+ const rowsJS = await result.getRowsJS();
1145
+ const rowsJson = await result.getRowsJson();
1146
+ const rowObjects = await result.getRowObjects();
1147
+ const rowObjectsJS = await result.getRowObjectsJS();
1148
+ const rowObjectsJson = await result.getRowObjectsJson();
1149
+
1150
+ // Asynchronous iterators can be used to retrieve partial data:
1151
+ for await (const chunk of result) {
1152
+ // ...
1153
+ }
1154
+
1155
+ // Each chunk can be converted to rows:
1156
+ for await (const rows of result.yieldRows()) {
1157
+ // ...
1158
+ }
1159
+ // See also variations of "yieldRow" for returning row objects
1160
+ // (instead of row arrays), and with JS, JSON, or custom conversion.
1161
+
1162
+ // From a reader
1163
+
1164
+ // First, (asynchronously) read some rows:
1165
+ await reader.readAll();
1166
+ // or:
1167
+ await reader.readUntil(targetRowCount);
1168
+
1169
+ // Then, (synchronously) get result data for the rows read:
1170
+ const columns = reader.getColumns();
1171
+ const columnsJS = reader.getColumnsJS();
1172
+ const columnsJson = reader.getColumnsJson();
1173
+ const columnsObject = reader.getColumnsObject();
1174
+ const columnsObjectJS = reader.getColumnsObjectJS();
1175
+ const columnsObjectJson = reader.getColumnsObjectJson();
1176
+ const rows = reader.getRows();
1177
+ const rowsJS = reader.getRowsJS();
1178
+ const rowsJson = reader.getRowsJson();
1179
+ const rowObjects = reader.getRowObjects();
1180
+ const rowObjectsJS = reader.getRowObjectsJS();
1181
+ const rowObjectsJson = reader.getRowObjectsJson();
1182
+
1183
+ // Individual values can also be read directly:
1184
+ const value = reader.value(columnIndex, rowIndex);
1185
+
1186
+ // Using chunks
1187
+
1188
+ // If desired, one or more chunks can be fetched from a result:
1189
+ const chunk = await result.fetchChunk();
1190
+ const chunks = await result.fetchAllChunks();
1191
+
1192
+ // And then data can be retrieved from each chunk:
1193
+ const columnValues = chunk.getColumnValues(columnIndex);
1194
+ const columns = chunk.getColumns();
1195
+ const rowValues = chunk.getRowValues(rowIndex);
1196
+ const rows = chunk.getRows();
1197
+
1198
+ // Or, values can be visited:
1199
+ chunk.visitColumnValues(columnIndex,
1200
+ (value, rowIndex, columnIndex, type) => { /* ... */ }
1201
+ );
1202
+ chunk.visitColumns((column, columnIndex, type) => { /* ... */ });
1203
+ chunk.visitColumnMajor(
1204
+ (value, rowIndex, columnIndex, type) => { /* ... */ }
1205
+ );
1206
+ chunk.visitRowValues(rowIndex,
1207
+ (value, rowIndex, columnIndex, type) => { /* ... */ }
1208
+ );
1209
+ chunk.visitRows((row, rowIndex) => { /* ... */ });
1210
+ chunk.visitRowMajor(
1211
+ (value, rowIndex, columnIndex, type) => { /* ... */ }
1212
+ );
1213
+
1214
+ // Or converted:
1215
+ // The `converter` argument implements `DuckDBValueConverter`,
1216
+ // which has the single method convertValue(value, type).
1217
+ const columnValues = chunk.convertColumnValues(columnIndex, converter);
1218
+ const columns = chunk.convertColumns(converter);
1219
+ const rowValues = chunk.convertRowValues(rowIndex, converter);
1220
+ const rows = chunk.convertRows(converter);
1221
+
1222
+ // The reader abstracts these low-level chunk manipulations
1223
+ // and is recommended for most cases.
1224
+ ```