@avidian/duckdb-bun 0.0.0-stage → 1.0.1

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 (231) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +286 -2
  3. package/package.json +96 -4
  4. package/src/bindings/api/appender.ts +288 -0
  5. package/src/bindings/api/data-chunk.ts +58 -0
  6. package/src/bindings/api/database.ts +232 -0
  7. package/src/bindings/api/datetime.ts +158 -0
  8. package/src/bindings/api/index.ts +13 -0
  9. package/src/bindings/api/logical-types.ts +227 -0
  10. package/src/bindings/api/query.ts +616 -0
  11. package/src/bindings/api/scalar-function.ts +274 -0
  12. package/src/bindings/api/table-function.ts +339 -0
  13. package/src/bindings/api/values.ts +546 -0
  14. package/src/bindings/api/vector.ts +266 -0
  15. package/src/bindings/generated/capi.ts +695 -0
  16. package/src/bindings/generated/contract.ts +162 -0
  17. package/src/bindings/index.ts +10 -0
  18. package/src/bindings/runtime/convert.ts +307 -0
  19. package/src/bindings/runtime/diagnostics.ts +45 -0
  20. package/src/bindings/runtime/dispatch.ts +213 -0
  21. package/src/bindings/runtime/exception.ts +103 -0
  22. package/src/bindings/runtime/flags.ts +19 -0
  23. package/src/bindings/runtime/handle.ts +217 -0
  24. package/src/bindings/runtime/kinds.ts +53 -0
  25. package/src/bindings/runtime/marshal.ts +190 -0
  26. package/src/bindings/runtime/native.ts +153 -0
  27. package/src/bindings/runtime/ring.ts +54 -0
  28. package/src/bindings/runtime/scope.ts +133 -0
  29. package/src/bindings/runtime/trace.ts +65 -0
  30. package/src/connection.ts +35 -0
  31. package/src/database.ts +27 -0
  32. package/src/errors.ts +30 -0
  33. package/src/file-assets.d.ts +10 -0
  34. package/src/index.ts +17 -0
  35. package/src/library.ts +83 -0
  36. package/src/neo.ts +16 -0
  37. package/src/reader.ts +47 -0
  38. package/src/statement.ts +61 -0
  39. package/src/types.ts +52 -0
  40. package/src/version.ts +6 -0
  41. package/vendor/node-api/LICENSE +7 -0
  42. package/vendor/node-api/PROVENANCE.md +54 -0
  43. package/vendor/node-api/node-bindings.d.ts +1669 -0
  44. package/vendor/node-api/src/DuckDBAppender.ts +237 -0
  45. package/vendor/node-api/src/DuckDBClientContext.ts +13 -0
  46. package/vendor/node-api/src/DuckDBConnection.ts +315 -0
  47. package/vendor/node-api/src/DuckDBDataChunk.ts +412 -0
  48. package/vendor/node-api/src/DuckDBDataChunkWriter.ts +144 -0
  49. package/vendor/node-api/src/DuckDBExtractedStatements.ts +37 -0
  50. package/vendor/node-api/src/DuckDBInstance.ts +35 -0
  51. package/vendor/node-api/src/DuckDBInstanceCache.ts +29 -0
  52. package/vendor/node-api/src/DuckDBLogicalType.ts +446 -0
  53. package/vendor/node-api/src/DuckDBMaterializedResult.ts +39 -0
  54. package/vendor/node-api/src/DuckDBPendingResult.ts +83 -0
  55. package/vendor/node-api/src/DuckDBPreparedStatement.ts +376 -0
  56. package/vendor/node-api/src/DuckDBPreparedStatementCollection.ts +5 -0
  57. package/vendor/node-api/src/DuckDBPreparedStatementWeakRefCollection.ts +31 -0
  58. package/vendor/node-api/src/DuckDBResult.ts +403 -0
  59. package/vendor/node-api/src/DuckDBResultReader.ts +283 -0
  60. package/vendor/node-api/src/DuckDBScalarFunction.ts +149 -0
  61. package/vendor/node-api/src/DuckDBScalarFunctionBindInfo.ts +34 -0
  62. package/vendor/node-api/src/DuckDBScalarFunctionInfo.ts +34 -0
  63. package/vendor/node-api/src/DuckDBScalarFunctionInitInfo.ts +35 -0
  64. package/vendor/node-api/src/DuckDBTableFunction.ts +149 -0
  65. package/vendor/node-api/src/DuckDBTableFunctionBindInfo.ts +56 -0
  66. package/vendor/node-api/src/DuckDBTableFunctionInfo.ts +36 -0
  67. package/vendor/node-api/src/DuckDBTableFunctionInitInfo.ts +52 -0
  68. package/vendor/node-api/src/DuckDBType.ts +1 -0
  69. package/vendor/node-api/src/DuckDBTypeId.ts +46 -0
  70. package/vendor/node-api/src/DuckDBValueConverter.ts +23 -0
  71. package/vendor/node-api/src/DuckDBValueConverters.ts +461 -0
  72. package/vendor/node-api/src/DuckDBVector.ts +1 -0
  73. package/vendor/node-api/src/JS.ts +11 -0
  74. package/vendor/node-api/src/JSDuckDBValueConverter.ts +85 -0
  75. package/vendor/node-api/src/JSInputTypeForTypeId.ts +101 -0
  76. package/vendor/node-api/src/JSToDuckDBValueConverter.ts +136 -0
  77. package/vendor/node-api/src/JSTypeForTypeId.ts +78 -0
  78. package/vendor/node-api/src/Json.ts +7 -0
  79. package/vendor/node-api/src/JsonDuckDBValueConverter.ts +72 -0
  80. package/vendor/node-api/src/JsonTypeForTypeId.ts +86 -0
  81. package/vendor/node-api/src/ToDuckDBValueConverter.ts +68 -0
  82. package/vendor/node-api/src/ToDuckDBValueConverters.ts +303 -0
  83. package/vendor/node-api/src/configurationOptionDescriptions.ts +13 -0
  84. package/vendor/node-api/src/conversion/bytesFromString.ts +5 -0
  85. package/vendor/node-api/src/conversion/dateTimeStringConversion.ts +343 -0
  86. package/vendor/node-api/src/conversion/displayStringForDuckDBValue.ts +12 -0
  87. package/vendor/node-api/src/conversion/stringFromBlob.ts +48 -0
  88. package/vendor/node-api/src/conversion/stringFromDecimal.ts +129 -0
  89. package/vendor/node-api/src/conversion/varintDecode.ts +42 -0
  90. package/vendor/node-api/src/convertColumnsFromChunks.ts +28 -0
  91. package/vendor/node-api/src/convertColumnsObjectFromChunks.ts +29 -0
  92. package/vendor/node-api/src/convertRowObjectsFromChunks.ts +21 -0
  93. package/vendor/node-api/src/convertRowsFromChunks.ts +16 -0
  94. package/vendor/node-api/src/createConfig.ts +14 -0
  95. package/vendor/node-api/src/createDuckDBValueConverter.ts +17 -0
  96. package/vendor/node-api/src/createResult.ts +15 -0
  97. package/vendor/node-api/src/createValue.ts +355 -0
  98. package/vendor/node-api/src/duckdb.ts +51 -0
  99. package/vendor/node-api/src/enums.ts +7 -0
  100. package/vendor/node-api/src/getColumnsFromChunks.ts +13 -0
  101. package/vendor/node-api/src/getColumnsObjectFromChunks.ts +16 -0
  102. package/vendor/node-api/src/getRowObjectsFromChunks.ts +13 -0
  103. package/vendor/node-api/src/getRowsFromChunks.ts +12 -0
  104. package/vendor/node-api/src/index.ts +3 -0
  105. package/vendor/node-api/src/readValue.ts +31 -0
  106. package/vendor/node-api/src/sleep.ts +5 -0
  107. package/vendor/node-api/src/sql.ts +7 -0
  108. package/vendor/node-api/src/tsconfig.json +7 -0
  109. package/vendor/node-api/src/typeForValue.ts +144 -0
  110. package/vendor/node-api/src/types/BaseDuckDBType.ts +31 -0
  111. package/vendor/node-api/src/types/DuckDBAnyType.ts +13 -0
  112. package/vendor/node-api/src/types/DuckDBArrayType.ts +43 -0
  113. package/vendor/node-api/src/types/DuckDBBigIntType.ts +21 -0
  114. package/vendor/node-api/src/types/DuckDBBigNumType.ts +21 -0
  115. package/vendor/node-api/src/types/DuckDBBitType.ts +13 -0
  116. package/vendor/node-api/src/types/DuckDBBlobType.ts +13 -0
  117. package/vendor/node-api/src/types/DuckDBBooleanType.ts +13 -0
  118. package/vendor/node-api/src/types/DuckDBDateType.ts +29 -0
  119. package/vendor/node-api/src/types/DuckDBDecimalType.ts +46 -0
  120. package/vendor/node-api/src/types/DuckDBDoubleType.ts +21 -0
  121. package/vendor/node-api/src/types/DuckDBEnumType.ts +111 -0
  122. package/vendor/node-api/src/types/DuckDBFloatType.ts +21 -0
  123. package/vendor/node-api/src/types/DuckDBGeometryType.ts +36 -0
  124. package/vendor/node-api/src/types/DuckDBHugeIntType.ts +21 -0
  125. package/vendor/node-api/src/types/DuckDBIntegerLiteralType.ts +13 -0
  126. package/vendor/node-api/src/types/DuckDBIntegerType.ts +21 -0
  127. package/vendor/node-api/src/types/DuckDBIntervalType.ts +13 -0
  128. package/vendor/node-api/src/types/DuckDBListType.ts +35 -0
  129. package/vendor/node-api/src/types/DuckDBMapType.ts +47 -0
  130. package/vendor/node-api/src/types/DuckDBSQLNullType.ts +17 -0
  131. package/vendor/node-api/src/types/DuckDBSmallIntType.ts +21 -0
  132. package/vendor/node-api/src/types/DuckDBStringLiteralType.ts +13 -0
  133. package/vendor/node-api/src/types/DuckDBStructType.ts +104 -0
  134. package/vendor/node-api/src/types/DuckDBTimeNSType.ts +20 -0
  135. package/vendor/node-api/src/types/DuckDBTimeTZType.ts +23 -0
  136. package/vendor/node-api/src/types/DuckDBTimeType.ts +20 -0
  137. package/vendor/node-api/src/types/DuckDBTimestampMillisecondsType.ts +29 -0
  138. package/vendor/node-api/src/types/DuckDBTimestampNanosecondsType.ts +29 -0
  139. package/vendor/node-api/src/types/DuckDBTimestampSecondsType.ts +29 -0
  140. package/vendor/node-api/src/types/DuckDBTimestampTZNanosecondsType.ts +32 -0
  141. package/vendor/node-api/src/types/DuckDBTimestampTZType.ts +32 -0
  142. package/vendor/node-api/src/types/DuckDBTimestampType.ts +32 -0
  143. package/vendor/node-api/src/types/DuckDBTinyIntType.ts +21 -0
  144. package/vendor/node-api/src/types/DuckDBType.ts +86 -0
  145. package/vendor/node-api/src/types/DuckDBUBigIntType.ts +21 -0
  146. package/vendor/node-api/src/types/DuckDBUHugeIntType.ts +21 -0
  147. package/vendor/node-api/src/types/DuckDBUIntegerType.ts +21 -0
  148. package/vendor/node-api/src/types/DuckDBUSmallIntType.ts +21 -0
  149. package/vendor/node-api/src/types/DuckDBUTinyIntType.ts +21 -0
  150. package/vendor/node-api/src/types/DuckDBUUIDType.ts +20 -0
  151. package/vendor/node-api/src/types/DuckDBUnionType.ts +74 -0
  152. package/vendor/node-api/src/types/DuckDBVarCharType.ts +13 -0
  153. package/vendor/node-api/src/types/DuckDBVariantType.ts +13 -0
  154. package/vendor/node-api/src/types/index.ts +44 -0
  155. package/vendor/node-api/src/values/DuckDBArrayValue.ts +18 -0
  156. package/vendor/node-api/src/values/DuckDBBitValue.ts +117 -0
  157. package/vendor/node-api/src/values/DuckDBBlobValue.ts +26 -0
  158. package/vendor/node-api/src/values/DuckDBDateValue.ts +43 -0
  159. package/vendor/node-api/src/values/DuckDBDecimalValue.ts +44 -0
  160. package/vendor/node-api/src/values/DuckDBGeometryValue.ts +30 -0
  161. package/vendor/node-api/src/values/DuckDBIntervalValue.ts +22 -0
  162. package/vendor/node-api/src/values/DuckDBListValue.ts +18 -0
  163. package/vendor/node-api/src/values/DuckDBMapValue.ts +25 -0
  164. package/vendor/node-api/src/values/DuckDBStructValue.ts +22 -0
  165. package/vendor/node-api/src/values/DuckDBTimeNSValue.ts +23 -0
  166. package/vendor/node-api/src/values/DuckDBTimeTZValue.ts +96 -0
  167. package/vendor/node-api/src/values/DuckDBTimeValue.ts +34 -0
  168. package/vendor/node-api/src/values/DuckDBTimestampMillisecondsValue.ts +29 -0
  169. package/vendor/node-api/src/values/DuckDBTimestampNanosecondsValue.ts +28 -0
  170. package/vendor/node-api/src/values/DuckDBTimestampSecondsValue.ts +28 -0
  171. package/vendor/node-api/src/values/DuckDBTimestampTZNanosecondsValue.ts +44 -0
  172. package/vendor/node-api/src/values/DuckDBTimestampTZValue.ts +54 -0
  173. package/vendor/node-api/src/values/DuckDBTimestampValue.ts +45 -0
  174. package/vendor/node-api/src/values/DuckDBTupleValue.ts +22 -0
  175. package/vendor/node-api/src/values/DuckDBUUIDValue.ts +48 -0
  176. package/vendor/node-api/src/values/DuckDBUnionValue.ts +22 -0
  177. package/vendor/node-api/src/values/DuckDBValue.ts +53 -0
  178. package/vendor/node-api/src/values/DuckDBVariantValue.ts +34 -0
  179. package/vendor/node-api/src/values/index.ts +24 -0
  180. package/vendor/node-api/src/vectors/DuckDBArrayVector.ts +107 -0
  181. package/vendor/node-api/src/vectors/DuckDBBigIntVector.ts +75 -0
  182. package/vendor/node-api/src/vectors/DuckDBBigNumVector.ts +98 -0
  183. package/vendor/node-api/src/vectors/DuckDBBitVector.ts +102 -0
  184. package/vendor/node-api/src/vectors/DuckDBBlobVector.ts +112 -0
  185. package/vendor/node-api/src/vectors/DuckDBBooleanVector.ts +84 -0
  186. package/vendor/node-api/src/vectors/DuckDBDateVector.ts +80 -0
  187. package/vendor/node-api/src/vectors/DuckDBDecimal128Vector.ts +107 -0
  188. package/vendor/node-api/src/vectors/DuckDBDecimal16Vector.ts +104 -0
  189. package/vendor/node-api/src/vectors/DuckDBDecimal32Vector.ts +104 -0
  190. package/vendor/node-api/src/vectors/DuckDBDecimal64Vector.ts +104 -0
  191. package/vendor/node-api/src/vectors/DuckDBDoubleVector.ts +68 -0
  192. package/vendor/node-api/src/vectors/DuckDBEnum16Vector.ts +75 -0
  193. package/vendor/node-api/src/vectors/DuckDBEnum32Vector.ts +75 -0
  194. package/vendor/node-api/src/vectors/DuckDBEnum8Vector.ts +75 -0
  195. package/vendor/node-api/src/vectors/DuckDBFloatVector.ts +68 -0
  196. package/vendor/node-api/src/vectors/DuckDBGeometryVector.ts +97 -0
  197. package/vendor/node-api/src/vectors/DuckDBHugeIntVector.ts +89 -0
  198. package/vendor/node-api/src/vectors/DuckDBIntegerVector.ts +75 -0
  199. package/vendor/node-api/src/vectors/DuckDBIntervalVector.ts +100 -0
  200. package/vendor/node-api/src/vectors/DuckDBListVector.ts +221 -0
  201. package/vendor/node-api/src/vectors/DuckDBMapVector.ts +88 -0
  202. package/vendor/node-api/src/vectors/DuckDBSQLNullVector.ts +53 -0
  203. package/vendor/node-api/src/vectors/DuckDBSmallIntVector.ts +75 -0
  204. package/vendor/node-api/src/vectors/DuckDBStructVector.ts +138 -0
  205. package/vendor/node-api/src/vectors/DuckDBTimeNSVector.ts +80 -0
  206. package/vendor/node-api/src/vectors/DuckDBTimeTZVector.ts +80 -0
  207. package/vendor/node-api/src/vectors/DuckDBTimeVector.ts +80 -0
  208. package/vendor/node-api/src/vectors/DuckDBTimestampMillisecondsVector.ts +88 -0
  209. package/vendor/node-api/src/vectors/DuckDBTimestampNanosecondsVector.ts +88 -0
  210. package/vendor/node-api/src/vectors/DuckDBTimestampSecondsVector.ts +88 -0
  211. package/vendor/node-api/src/vectors/DuckDBTimestampTZNanosecondsVector.ts +88 -0
  212. package/vendor/node-api/src/vectors/DuckDBTimestampTZVector.ts +86 -0
  213. package/vendor/node-api/src/vectors/DuckDBTimestampVector.ts +83 -0
  214. package/vendor/node-api/src/vectors/DuckDBTinyIntVector.ts +75 -0
  215. package/vendor/node-api/src/vectors/DuckDBTupleVector.ts +125 -0
  216. package/vendor/node-api/src/vectors/DuckDBUBigIntVector.ts +75 -0
  217. package/vendor/node-api/src/vectors/DuckDBUHugeIntVector.ts +89 -0
  218. package/vendor/node-api/src/vectors/DuckDBUIntegerVector.ts +75 -0
  219. package/vendor/node-api/src/vectors/DuckDBUSmallIntVector.ts +75 -0
  220. package/vendor/node-api/src/vectors/DuckDBUTinyIntVector.ts +75 -0
  221. package/vendor/node-api/src/vectors/DuckDBUUIDVector.ts +89 -0
  222. package/vendor/node-api/src/vectors/DuckDBUnionVector.ts +84 -0
  223. package/vendor/node-api/src/vectors/DuckDBValidity.ts +104 -0
  224. package/vendor/node-api/src/vectors/DuckDBVarCharVector.ts +100 -0
  225. package/vendor/node-api/src/vectors/DuckDBVariantVector.ts +609 -0
  226. package/vendor/node-api/src/vectors/DuckDBVector.ts +33 -0
  227. package/vendor/node-api/src/vectors/createVector.ts +269 -0
  228. package/vendor/node-api/src/vectors/dataAccessors.ts +387 -0
  229. package/vendor/node-api/src/vectors/index.ts +50 -0
  230. package/vendor/node-api/src/vectors/vectorRegistry.ts +24 -0
  231. package/vendor/node-api/src/version.ts +5 -0
@@ -0,0 +1,412 @@
1
+ import duckdb from "../../../src/bindings/index.ts";
2
+ import { DuckDBType } from './DuckDBType';
3
+ import { DuckDBValueConverter } from './DuckDBValueConverter';
4
+ import { ToDuckDBValueConverter } from './ToDuckDBValueConverter';
5
+ import { DuckDBVector } from './DuckDBVector';
6
+ import { DuckDBValue } from './values';
7
+
8
+ export class DuckDBDataChunk {
9
+ public readonly chunk: duckdb.DataChunk;
10
+ private readonly vectors: DuckDBVector[] = [];
11
+ constructor(chunk: duckdb.DataChunk) {
12
+ this.chunk = chunk;
13
+ }
14
+ public static create(
15
+ types: readonly DuckDBType[],
16
+ rowCount?: number
17
+ ): DuckDBDataChunk {
18
+ let chunk: DuckDBDataChunk;
19
+ try {
20
+ chunk = new DuckDBDataChunk(
21
+ duckdb.create_data_chunk(
22
+ types.map((t) => t.toLogicalType().logical_type)
23
+ )
24
+ );
25
+ } catch (cause) {
26
+ // The binding knows the chunk was refused but not which type did it, so
27
+ // name them here. Zero columns is a legitimate chunk, so there is
28
+ // nothing to check on the way out; only the refusal is an error.
29
+ throw new Error(
30
+ `Cannot create a data chunk with these column types: ${types.join(', ')}`,
31
+ { cause }
32
+ );
33
+ }
34
+ if (rowCount != undefined) {
35
+ chunk.rowCount = rowCount;
36
+ }
37
+ return chunk;
38
+ }
39
+ public reset() {
40
+ duckdb.data_chunk_reset(this.chunk);
41
+ }
42
+ public get columnCount(): number {
43
+ return duckdb.data_chunk_get_column_count(this.chunk);
44
+ }
45
+ public get rowCount(): number {
46
+ return duckdb.data_chunk_get_size(this.chunk);
47
+ }
48
+ public set rowCount(count: number) {
49
+ const maxRowCount = duckdb.vector_size();
50
+ if (count > maxRowCount) {
51
+ throw new Error(`A data chunk cannot have more than ${maxRowCount} rows`);
52
+ }
53
+ duckdb.data_chunk_set_size(this.chunk, count);
54
+ // Cached vectors were built for the previous row count, so they are the
55
+ // wrong size now. This matters most for a table function's output chunk,
56
+ // which arrives empty and is sized by the function on every call.
57
+ this.vectors.length = 0;
58
+ }
59
+ /**
60
+ * Refuses a column count that does not match the chunk's.
61
+ *
62
+ * A short array would leave the remaining vectors never written and never
63
+ * flushed while the chunk reports a non-zero row count, and reading or
64
+ * appending it then crashes the process instead of raising.
65
+ */
66
+ private assertColumnCount(count: number) {
67
+ const columnCount = this.columnCount;
68
+ if (count !== columnCount) {
69
+ throw new Error(
70
+ `Provided number of columns (${count}) does not match chunk column count (${columnCount})`
71
+ );
72
+ }
73
+ }
74
+ public getColumnVector(columnIndex: number): DuckDBVector {
75
+ if (this.vectors[columnIndex]) {
76
+ return this.vectors[columnIndex];
77
+ }
78
+ const vector = DuckDBVector.create(
79
+ duckdb.data_chunk_get_vector(this.chunk, columnIndex),
80
+ this.rowCount
81
+ );
82
+ this.vectors[columnIndex] = vector;
83
+ return vector;
84
+ }
85
+ public visitColumnValues(
86
+ columnIndex: number,
87
+ visitValue: (
88
+ value: DuckDBValue,
89
+ rowIndex: number,
90
+ columnIndex: number,
91
+ type: DuckDBType
92
+ ) => void
93
+ ) {
94
+ const vector = this.getColumnVector(columnIndex);
95
+ const type = vector.type;
96
+ for (let rowIndex = 0; rowIndex < vector.itemCount; rowIndex++) {
97
+ visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, type);
98
+ }
99
+ }
100
+ public appendColumnValues(columnIndex: number, values: DuckDBValue[]) {
101
+ this.visitColumnValues(columnIndex, (value) => values.push(value));
102
+ }
103
+ public getColumnValues(columnIndex: number): DuckDBValue[] {
104
+ const values: DuckDBValue[] = [];
105
+ this.appendColumnValues(columnIndex, values);
106
+ return values;
107
+ }
108
+ public convertColumnValues<T>(
109
+ columnIndex: number,
110
+ converter: DuckDBValueConverter<T>
111
+ ): (T | null)[] {
112
+ const convertedValues: (T | null)[] = [];
113
+ this.visitColumnValues(columnIndex, (value, _r, _c, type) =>
114
+ convertedValues.push(converter(value, type, converter))
115
+ );
116
+ return convertedValues;
117
+ }
118
+ public setColumnValues(columnIndex: number, values: readonly DuckDBValue[]) {
119
+ const vector = this.getColumnVector(columnIndex);
120
+ if (vector.itemCount !== values.length) {
121
+ throw new Error(`number of values must equal chunk row count`);
122
+ }
123
+ for (let i = 0; i < values.length; i++) {
124
+ vector.setItem(i, values[i]);
125
+ }
126
+ vector.flush();
127
+ }
128
+ /**
129
+ * `setColumnValues` with each value converted on the way in: the write
130
+ * counterpart of `convertColumnValues`.
131
+ *
132
+ * The column's type comes from its vector, so the converter is the only
133
+ * thing the caller supplies.
134
+ */
135
+ public setColumnValuesConverted<T>(
136
+ columnIndex: number,
137
+ values: readonly (T | null)[],
138
+ converter: ToDuckDBValueConverter<T>
139
+ ) {
140
+ const vector = this.getColumnVector(columnIndex);
141
+ if (vector.itemCount !== values.length) {
142
+ throw new Error(`number of values must equal chunk row count`);
143
+ }
144
+ const { type } = vector;
145
+ try {
146
+ for (let i = 0; i < values.length; i++) {
147
+ vector.setItem(i, converter(values[i] as T, type, converter));
148
+ }
149
+ } catch (cause) {
150
+ throw new Error(`Failed to set column ${columnIndex} (${type})`, {
151
+ cause,
152
+ });
153
+ }
154
+ vector.flush();
155
+ }
156
+ public visitColumns(
157
+ visitColumn: (
158
+ column: DuckDBValue[],
159
+ columnIndex: number,
160
+ type: DuckDBType
161
+ ) => void
162
+ ) {
163
+ const columnCount = this.columnCount;
164
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
165
+ visitColumn(
166
+ this.getColumnValues(columnIndex),
167
+ columnIndex,
168
+ this.getColumnVector(columnIndex).type
169
+ );
170
+ }
171
+ }
172
+ public appendToColumns(columns: (DuckDBValue[] | undefined)[]) {
173
+ const columnCount = this.columnCount;
174
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
175
+ let column = columns[columnIndex];
176
+ if (!column) {
177
+ column = [];
178
+ columns[columnIndex] = column;
179
+ }
180
+ this.appendColumnValues(columnIndex, column);
181
+ }
182
+ }
183
+ public getColumns(): DuckDBValue[][] {
184
+ const columns: DuckDBValue[][] = [];
185
+ this.visitColumns((column) => columns.push(column));
186
+ return columns;
187
+ }
188
+ public convertColumns<T>(converter: DuckDBValueConverter<T>): (T | null)[][] {
189
+ const convertedColumns: (T | null)[][] = [];
190
+ const columnCount = this.columnCount;
191
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
192
+ convertedColumns.push(this.convertColumnValues(columnIndex, converter));
193
+ }
194
+ return convertedColumns;
195
+ }
196
+ public setColumns(columns: readonly (readonly DuckDBValue[])[]) {
197
+ this.assertColumnCount(columns.length);
198
+ if (columns.length > 0) {
199
+ this.rowCount = columns[0].length;
200
+ }
201
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
202
+ this.setColumnValues(columnIndex, columns[columnIndex]);
203
+ }
204
+ }
205
+ /**
206
+ * `setColumns` with each value converted on the way in: the write
207
+ * counterpart of `convertColumns`.
208
+ */
209
+ public setColumnsConverted<T>(
210
+ columns: readonly (readonly (T | null)[])[],
211
+ converter: ToDuckDBValueConverter<T>
212
+ ) {
213
+ this.assertColumnCount(columns.length);
214
+ if (columns.length > 0) {
215
+ this.rowCount = columns[0].length;
216
+ }
217
+ for (let columnIndex = 0; columnIndex < columns.length; columnIndex++) {
218
+ this.setColumnValuesConverted(
219
+ columnIndex,
220
+ columns[columnIndex],
221
+ converter
222
+ );
223
+ }
224
+ }
225
+ public appendToColumnsObject(
226
+ columnNames: readonly string[],
227
+ columnsObject: Record<string, DuckDBValue[] | undefined>
228
+ ) {
229
+ const columnCount = this.columnCount;
230
+ if (columnNames.length !== columnCount) {
231
+ throw new Error(
232
+ `Provided number of column names (${columnNames.length}) does not match column count (${this.columnCount})`
233
+ );
234
+ }
235
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
236
+ const columnName = columnNames[columnIndex];
237
+ let columnValues = columnsObject[columnName];
238
+ if (!columnValues) {
239
+ columnValues = [];
240
+ columnsObject[columnName] = columnValues;
241
+ }
242
+ this.appendColumnValues(columnIndex, columnValues);
243
+ }
244
+ }
245
+ public getColumnsObject(
246
+ columnNames: readonly string[]
247
+ ): Record<string, DuckDBValue[]> {
248
+ const columnsObject: Record<string, DuckDBValue[]> = {};
249
+ this.appendToColumnsObject(columnNames, columnsObject);
250
+ return columnsObject;
251
+ }
252
+ public visitColumnMajor(
253
+ visitValue: (
254
+ value: DuckDBValue,
255
+ rowIndex: number,
256
+ columnIndex: number,
257
+ type: DuckDBType
258
+ ) => void
259
+ ) {
260
+ const columnCount = this.columnCount;
261
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
262
+ this.visitColumnValues(columnIndex, visitValue);
263
+ }
264
+ }
265
+ public visitRowValues(
266
+ rowIndex: number,
267
+ visitValue: (
268
+ value: DuckDBValue,
269
+ rowIndex: number,
270
+ columnIndex: number,
271
+ type: DuckDBType
272
+ ) => void
273
+ ) {
274
+ const columnCount = this.columnCount;
275
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
276
+ const vector = this.getColumnVector(columnIndex);
277
+ visitValue(vector.getItem(rowIndex), rowIndex, columnIndex, vector.type);
278
+ }
279
+ }
280
+ public appendRowValues(rowIndex: number, values: DuckDBValue[]) {
281
+ this.visitRowValues(rowIndex, (value) => values.push(value));
282
+ }
283
+ public getRowValues(rowIndex: number): DuckDBValue[] {
284
+ const values: DuckDBValue[] = [];
285
+ this.appendRowValues(rowIndex, values);
286
+ return values;
287
+ }
288
+ public convertRowValues<T>(
289
+ rowIndex: number,
290
+ converter: DuckDBValueConverter<T>
291
+ ): (T | null)[] {
292
+ const convertedValues: (T | null)[] = [];
293
+ this.visitRowValues(rowIndex, (value, _, columnIndex) =>
294
+ convertedValues.push(
295
+ converter(value, this.getColumnVector(columnIndex).type, converter)
296
+ )
297
+ );
298
+ return convertedValues;
299
+ }
300
+ public visitRows(visitRow: (row: DuckDBValue[], rowIndex: number) => void) {
301
+ const rowCount = this.rowCount;
302
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
303
+ visitRow(this.getRowValues(rowIndex), rowIndex);
304
+ }
305
+ }
306
+ public appendToRows(rows: DuckDBValue[][]) {
307
+ this.visitRows((row) => rows.push(row));
308
+ }
309
+ public getRows(): DuckDBValue[][] {
310
+ const rows: DuckDBValue[][] = [];
311
+ this.appendToRows(rows);
312
+ return rows;
313
+ }
314
+ public convertRows<T>(converter: DuckDBValueConverter<T>): (T | null)[][] {
315
+ const convertedRows: (T | null)[][] = [];
316
+ const rowCount = this.rowCount;
317
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
318
+ convertedRows.push(this.convertRowValues(rowIndex, converter));
319
+ }
320
+ return convertedRows;
321
+ }
322
+ public setRows(rows: readonly (readonly DuckDBValue[])[]) {
323
+ this.rowCount = rows.length;
324
+ const columnCount = this.columnCount;
325
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
326
+ const vector = this.getColumnVector(columnIndex);
327
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
328
+ vector.setItem(rowIndex, rows[rowIndex][columnIndex]);
329
+ }
330
+ vector.flush();
331
+ }
332
+ }
333
+ /**
334
+ * `setRows` with each value converted on the way in: the write counterpart
335
+ * of `convertRows`.
336
+ *
337
+ * Each column's type comes from its vector, so the converter is the only
338
+ * thing the caller supplies.
339
+ */
340
+ public setRowsConverted<T>(
341
+ rows: readonly (readonly (T | null)[])[],
342
+ converter: ToDuckDBValueConverter<T>
343
+ ) {
344
+ this.rowCount = rows.length;
345
+ const columnCount = this.columnCount;
346
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
347
+ const vector = this.getColumnVector(columnIndex);
348
+ const { type } = vector;
349
+ // Wrapped per column rather than per value: a conversion failure names
350
+ // the column it came from without a try/catch in the inner loop.
351
+ try {
352
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
353
+ vector.setItem(
354
+ rowIndex,
355
+ converter(rows[rowIndex][columnIndex] as T, type, converter)
356
+ );
357
+ }
358
+ } catch (cause) {
359
+ throw new Error(`Failed to set column ${columnIndex} (${type})`, {
360
+ cause,
361
+ });
362
+ }
363
+ vector.flush();
364
+ }
365
+ }
366
+ public appendToRowObjects(
367
+ columnNames: readonly string[],
368
+ rowObjects: Record<string, DuckDBValue>[]
369
+ ) {
370
+ const columnCount = this.columnCount;
371
+ if (columnNames.length !== columnCount) {
372
+ throw new Error(
373
+ `Provided number of column names (${columnNames.length}) does not match column count (${this.columnCount})`
374
+ );
375
+ }
376
+ const rowCount = this.rowCount;
377
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
378
+ let rowObject: Record<string, DuckDBValue> = {};
379
+ this.visitRowValues(rowIndex, (value, _, columnIndex) => {
380
+ rowObject[columnNames[columnIndex]] = value;
381
+ });
382
+ rowObjects.push(rowObject);
383
+ }
384
+ }
385
+ public getRowObjects(columnNames: readonly string[]) {
386
+ const rowObjects: Record<string, DuckDBValue>[] = [];
387
+ this.appendToRowObjects(columnNames, rowObjects);
388
+ return rowObjects;
389
+ }
390
+ public visitRowMajor(
391
+ visitValue: (
392
+ value: DuckDBValue,
393
+ rowIndex: number,
394
+ columnIndex: number,
395
+ type: DuckDBType
396
+ ) => void
397
+ ) {
398
+ const rowCount = this.rowCount;
399
+ const columnCount = this.columnCount;
400
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
401
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
402
+ const vector = this.getColumnVector(columnIndex);
403
+ visitValue(
404
+ vector.getItem(rowIndex),
405
+ rowIndex,
406
+ columnIndex,
407
+ vector.type
408
+ );
409
+ }
410
+ }
411
+ }
412
+ }
@@ -0,0 +1,144 @@
1
+ import duckdb from "../../../src/bindings/index.ts";
2
+ import type { DuckDBAppender } from './DuckDBAppender';
3
+ import { DuckDBDataChunk } from './DuckDBDataChunk';
4
+ import { DuckDBType } from './DuckDBType';
5
+ import { ToDuckDBValueConverter } from './ToDuckDBValueConverter';
6
+ import { DuckDBValue } from './values';
7
+
8
+ /** Receives each data chunk a `DuckDBDataChunkWriter` fills. */
9
+ export type DuckDBDataChunkSink = (chunk: DuckDBDataChunk) => void;
10
+
11
+ /**
12
+ * `converter` is optional only when the rows are already `DuckDBValue`s, which
13
+ * is what `T` defaults to. Supply one to write some other representation —
14
+ * `JSToDuckDBValueConverter` for plain JS — and `T` follows from it.
15
+ */
16
+ export type DuckDBDataChunkWriterOptions<T> = {
17
+ /**
18
+ * How many rows each emitted data chunk holds — its `rowCount`. Defaults to
19
+ * the DuckDB vector size, which is also the most a data chunk can hold.
20
+ */
21
+ readonly rowsPerDataChunk?: number;
22
+ } & ([DuckDBValue] extends [T]
23
+ ? { readonly converter?: ToDuckDBValueConverter<T> }
24
+ : { readonly converter: ToDuckDBValueConverter<T> });
25
+
26
+ /**
27
+ * Accumulates rows and emits them as filled data chunks, one per
28
+ * `rowsPerDataChunk` rows, passing each to `sink`.
29
+ *
30
+ * Rows are `DuckDBValue`s by default. Supply a converter to write some other
31
+ * representation; the row type follows from it.
32
+ *
33
+ * const writer = DuckDBDataChunkWriter.forAppender(appender, {
34
+ * converter: JSToDuckDBValueConverter,
35
+ * });
36
+ * for (const row of rows) {
37
+ * writer.appendRow(row);
38
+ * }
39
+ * writer.flush();
40
+ *
41
+ * `flush` emits whatever is buffered, so call it when done: the last chunk is
42
+ * usually a partial one. Rows already grouped into chunk-sized batches need no
43
+ * writer — fill a `DuckDBDataChunk` and pass it to the destination directly.
44
+ */
45
+ export class DuckDBDataChunkWriter<T = DuckDBValue> {
46
+ private readonly types: readonly DuckDBType[];
47
+ private readonly sink: DuckDBDataChunkSink;
48
+ private readonly rowsPerDataChunk: number;
49
+ private readonly converter?: ToDuckDBValueConverter<T>;
50
+ private rows: (T | null)[][] = [];
51
+
52
+ public constructor(
53
+ types: readonly DuckDBType[],
54
+ sink: DuckDBDataChunkSink,
55
+ options: DuckDBDataChunkWriterOptions<T> = {} as DuckDBDataChunkWriterOptions<T>
56
+ ) {
57
+ this.types = types;
58
+ this.sink = sink;
59
+ const maxRowCount = duckdb.vector_size();
60
+ this.rowsPerDataChunk = options.rowsPerDataChunk ?? maxRowCount;
61
+ // Checked here rather than left to the first flush, which is where the
62
+ // chunk itself would refuse it — a whole buffer's worth of rows later.
63
+ if (this.rowsPerDataChunk < 1 || this.rowsPerDataChunk > maxRowCount) {
64
+ throw new Error(
65
+ `rowsPerDataChunk must be between 1 and ${maxRowCount}, got ${this.rowsPerDataChunk}`
66
+ );
67
+ }
68
+ this.converter = options.converter;
69
+ }
70
+
71
+ /**
72
+ * A writer that appends each filled data chunk to `appender`, using the
73
+ * appender's own column types.
74
+ *
75
+ * Equivalent to constructing one with those types and a sink that calls
76
+ * `appendDataChunk`, but with nothing to keep in step by hand.
77
+ */
78
+ public static forAppender<T = DuckDBValue>(
79
+ appender: DuckDBAppender,
80
+ options: DuckDBDataChunkWriterOptions<T> = {} as DuckDBDataChunkWriterOptions<T>
81
+ ): DuckDBDataChunkWriter<T> {
82
+ const types: DuckDBType[] = [];
83
+ const columnCount = appender.columnCount;
84
+ for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
85
+ types.push(appender.columnType(columnIndex));
86
+ }
87
+ return new DuckDBDataChunkWriter<T>(
88
+ types,
89
+ (chunk) => appender.appendDataChunk(chunk),
90
+ options
91
+ );
92
+ }
93
+
94
+ public get bufferedRowCount(): number {
95
+ return this.rows.length;
96
+ }
97
+
98
+ /**
99
+ * Buffers one row, emitting a data chunk once `rowsPerDataChunk` are held.
100
+ *
101
+ * The row is copied, so the same array can be reused across calls.
102
+ */
103
+ public appendRow(values: readonly (T | null)[]): void {
104
+ if (values.length !== this.types.length) {
105
+ throw new Error(
106
+ `Provided number of values (${values.length}) does not match number of types (${this.types.length})`
107
+ );
108
+ }
109
+ this.rows.push(values.slice());
110
+ if (this.rows.length >= this.rowsPerDataChunk) {
111
+ this.flush();
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Emits the buffered rows as one data chunk. A no-op when none are
117
+ * buffered, so it is safe to call more than once.
118
+ *
119
+ * The buffer is emptied either way: if converting the rows fails, or the
120
+ * sink rejects the chunk, those rows are discarded along with the error.
121
+ * Appending afterwards starts a fresh chunk.
122
+ */
123
+ public flush(): void {
124
+ if (this.rows.length === 0) {
125
+ return;
126
+ }
127
+ // Taken before anything that can throw. Left in place, a batch that failed
128
+ // to convert or that the sink rejected would still be buffered, and later
129
+ // appends would grow it past `rowsPerDataChunk` and eventually past what a
130
+ // data chunk can hold at all — by which point the writer can no longer
131
+ // flush and the original error is long gone.
132
+ const rows = this.rows;
133
+ this.rows = [];
134
+ const chunk = DuckDBDataChunk.create(this.types);
135
+ if (this.converter) {
136
+ chunk.setRowsConverted(rows, this.converter);
137
+ } else {
138
+ // Without a converter the options type has already constrained `T` to
139
+ // `DuckDBValue`, which is the only thing that makes this cast sound.
140
+ chunk.setRows(rows as readonly (readonly DuckDBValue[])[]);
141
+ }
142
+ this.sink(chunk);
143
+ }
144
+ }
@@ -0,0 +1,37 @@
1
+ import duckdb from "../../../src/bindings/index.ts";
2
+ import { DuckDBPreparedStatement } from './DuckDBPreparedStatement';
3
+ import { DuckDBPreparedStatementCollection } from './DuckDBPreparedStatementCollection';
4
+
5
+ export class DuckDBExtractedStatements {
6
+ private readonly connection: duckdb.Connection;
7
+ private readonly extracted_statements: duckdb.ExtractedStatements;
8
+ private readonly statement_count: number;
9
+ private readonly preparedStatements?: DuckDBPreparedStatementCollection;
10
+ constructor(
11
+ connection: duckdb.Connection,
12
+ extracted_statements: duckdb.ExtractedStatements,
13
+ statement_count: number,
14
+ preparedStatements?: DuckDBPreparedStatementCollection
15
+ ) {
16
+ this.connection = connection;
17
+ this.extracted_statements = extracted_statements;
18
+ this.statement_count = statement_count;
19
+ this.preparedStatements = preparedStatements;
20
+ }
21
+ public get count(): number {
22
+ return this.statement_count;
23
+ }
24
+ public async prepare(index: number): Promise<DuckDBPreparedStatement> {
25
+ const prepared = new DuckDBPreparedStatement(
26
+ await duckdb.prepare_extracted_statement(
27
+ this.connection,
28
+ this.extracted_statements,
29
+ index
30
+ )
31
+ );
32
+ if (this.preparedStatements) {
33
+ this.preparedStatements.add(prepared);
34
+ }
35
+ return prepared;
36
+ }
37
+ }
@@ -0,0 +1,35 @@
1
+ import duckdb from "../../../src/bindings/index.ts";
2
+ import { createConfig } from './createConfig';
3
+ import { DuckDBConnection } from './DuckDBConnection';
4
+ import { DuckDBInstanceCache } from './DuckDBInstanceCache';
5
+
6
+ export class DuckDBInstance {
7
+ private readonly db: duckdb.Database;
8
+
9
+ constructor(db: duckdb.Database) {
10
+ this.db = db;
11
+ }
12
+
13
+ public static async create(
14
+ path?: string,
15
+ options?: Record<string, string>
16
+ ): Promise<DuckDBInstance> {
17
+ const config = createConfig(options);
18
+ return new DuckDBInstance(await duckdb.open(path, config));
19
+ }
20
+
21
+ public static async fromCache(
22
+ path?: string,
23
+ options?: Record<string, string>
24
+ ): Promise<DuckDBInstance> {
25
+ return DuckDBInstanceCache.singleton.getOrCreateInstance(path, options);
26
+ }
27
+
28
+ public async connect(): Promise<DuckDBConnection> {
29
+ return new DuckDBConnection(await duckdb.connect(this.db));
30
+ }
31
+
32
+ public closeSync() {
33
+ duckdb.close_sync(this.db);
34
+ }
35
+ }
@@ -0,0 +1,29 @@
1
+ import duckdb from "../../../src/bindings/index.ts";
2
+ import { DuckDBInstance } from './DuckDBInstance';
3
+ import { createConfig } from './createConfig';
4
+
5
+ export class DuckDBInstanceCache {
6
+ private readonly cache: duckdb.InstanceCache;
7
+
8
+ constructor() {
9
+ this.cache = duckdb.create_instance_cache();
10
+ }
11
+
12
+ public async getOrCreateInstance(
13
+ path?: string,
14
+ options?: Record<string, string>
15
+ ): Promise<DuckDBInstance> {
16
+ const config = createConfig(options);
17
+ const db = await duckdb.get_or_create_from_cache(this.cache, path, config);
18
+ return new DuckDBInstance(db);
19
+ }
20
+
21
+ private static singletonInstance: DuckDBInstanceCache;
22
+
23
+ public static get singleton(): DuckDBInstanceCache {
24
+ if (!DuckDBInstanceCache.singletonInstance) {
25
+ DuckDBInstanceCache.singletonInstance = new DuckDBInstanceCache();
26
+ }
27
+ return DuckDBInstanceCache.singletonInstance;
28
+ }
29
+ }