1
- import { getArrowTableSchema } from "./arrow.mjs" ;
1
+ import { getArrowTableSchema , isArrowTable } from "./arrow.mjs" ;
2
2
import { arrow9 as arrow , duckdb } from "./dependencies.mjs" ;
3
3
import { FileAttachment } from "./fileAttachment.mjs" ;
4
+ import { cdn } from "./require.mjs" ;
4
5
5
6
// Adapted from https://observablehq.com/@cmudig /duckdb-client
6
7
// Copyright 2021 CMU Data Interaction Group
@@ -31,9 +32,6 @@ import {FileAttachment} from "./fileAttachment.mjs";
31
32
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
33
// POSSIBILITY OF SUCH DAMAGE.
33
34
34
- // TODO Allow this to be overridden using the Library’s resolver.
35
- const cdn = "https://cdn.observableusercontent.com/npm/" ;
36
-
37
35
export class DuckDBClient {
38
36
constructor ( db ) {
39
37
Object . defineProperties ( this , {
@@ -125,16 +123,22 @@ export class DuckDBClient {
125
123
await db . open ( config ) ;
126
124
await Promise . all (
127
125
Object . entries ( sources ) . map ( async ( [ name , source ] ) => {
128
- if ( "array" in source ) { // array + options
129
- const { array, ...options } = source ;
130
- await insertArray ( db , name , array , options ) ;
126
+ if ( source instanceof FileAttachment ) { // bare file
127
+ await insertFile ( db , name , source ) ;
128
+ } else if ( isArrowTable ( source ) ) { // bare arrow table
129
+ await insertArrowTable ( db , name , source ) ;
130
+ } else if ( Array . isArray ( source ) ) { // bare array of objects
131
+ await insertArray ( db , name , source ) ;
132
+ } else if ( "data" in source ) { // data + options
133
+ const { data, ...options } = source ;
134
+ if ( isArrowTable ( data ) ) {
135
+ await insertArrowTable ( db , name , data , options ) ;
136
+ } else {
137
+ await insertArray ( db , name , data , options ) ;
138
+ }
131
139
} else if ( "file" in source ) { // file + options
132
140
const { file, ...options } = source ;
133
141
await insertFile ( db , name , file , options ) ;
134
- } else if ( source instanceof FileAttachment ) { // bare file
135
- await insertFile ( db , name , source ) ;
136
- } else if ( Array . isArray ( source ) ) { // bare data
137
- await insertArray ( db , name , source ) ;
138
142
} else {
139
143
throw new Error ( `invalid source: ${ source } ` ) ;
140
144
}
@@ -156,36 +160,40 @@ async function insertFile(database, name, file, options) {
156
160
try {
157
161
switch ( file . mimeType ) {
158
162
case "text/csv" :
159
- await connection . insertCSVFromPath ( file . name , {
163
+ return await connection . insertCSVFromPath ( file . name , {
160
164
name,
161
165
schema : "main" ,
162
166
...options
163
167
} ) ;
164
- break ;
165
168
case "application/json" :
166
- await connection . insertJSONFromPath ( file . name , {
169
+ return await connection . insertJSONFromPath ( file . name , {
167
170
name,
168
171
schema : "main" ,
169
172
...options
170
173
} ) ;
171
- break ;
172
174
default :
173
- if ( file . name . endsWith ( ".parquet" ) ) {
174
- await connection . query (
175
+ if ( / \. a r r o w $ / i. test ( file . name ) ) {
176
+ const buffer = new Uint8Array ( await file . arrayBuffer ( ) ) ;
177
+ return await connection . insertArrowFromIPCStream ( buffer , {
178
+ name,
179
+ schema : "main" ,
180
+ ...options
181
+ } ) ;
182
+ }
183
+ if ( / \. p a r q u e t $ / i. test ( file . name ) ) {
184
+ return await connection . query (
175
185
`CREATE VIEW '${ name } ' AS SELECT * FROM parquet_scan('${ file . name } ')`
176
186
) ;
177
- } else {
178
- throw new Error ( `unknown file type: ${ file . mimeType } ` ) ;
179
187
}
188
+ throw new Error ( `unknown file type: ${ file . mimeType } ` ) ;
180
189
}
181
190
} finally {
182
191
await connection . close ( ) ;
183
192
}
184
193
}
185
194
186
- async function insertArray ( database , name , array , options ) {
195
+ async function insertArrowTable ( database , name , table , options ) {
187
196
const arrow = await loadArrow ( ) ;
188
- const table = arrow . tableFromJSON ( array ) ;
189
197
const buffer = arrow . tableToIPC ( table ) ;
190
198
const connection = await database . connect ( ) ;
191
199
try {
@@ -199,6 +207,12 @@ async function insertArray(database, name, array, options) {
199
207
}
200
208
}
201
209
210
+ async function insertArray ( database , name , array , options ) {
211
+ const arrow = await loadArrow ( ) ;
212
+ const table = arrow . tableFromJSON ( array ) ;
213
+ return await insertArrowTable ( database , name , table , options ) ;
214
+ }
215
+
202
216
async function createDuckDB ( ) {
203
217
const duck = await import ( `${ cdn } ${ duckdb . resolve ( ) } ` ) ;
204
218
const bundle = await duck . selectBundle ( {
0 commit comments