Ducklings uses Flechette for Arrow support, enabling efficient columnar data operations.
Use queryArrow() to get results as an Arrow Table:
const table = await conn.queryArrow('SELECT * FROM range(1000) t(i)');
console.log(table.numRows); // 1000
console.log(table.numCols); // 1
console.log(table.schema); // Schema information
const table = await conn.queryArrow('SELECT id, name, score FROM users');
// Get number of rows/columns
console.log(table.numRows, table.numCols);
// Get schema information
for (const field of table.schema.fields) {
console.log(field.name, field.type);
}
// Convert to array of objects
const rows = table.toArray();
const table = await conn.queryArrow('SELECT id, name FROM users');
// Get a column by index
const idColumn = table.getChildAt(0);
// Get column values
const ids = [...idColumn];
Arrow data is transferred from the Web Worker using zero-copy ArrayBuffer transfer. This means:
// Large result - transferred efficiently
const table = await conn.queryArrow('SELECT * FROM range(1000000)');
Insert data from Arrow IPC buffers:
import { tableToIPC } from '@uwdata/flechette';
// Create Arrow data
const arrowTable = tableFromArrays({
id: [1, 2, 3],
name: ['Alice', 'Bob', 'Charlie']
});
// Convert to IPC format
const ipcBuffer = tableToIPC(arrowTable, { format: 'stream' });
// Insert into DuckDB
await conn.insertArrowFromIPCStream('users', ipcBuffer);
// Query the data
const rows = await conn.query('SELECT * FROM users');
DuckDB types are mapped to Arrow types:
| DuckDB Type | Arrow Type |
|---|---|
| BOOLEAN | Bool |
| TINYINT | Int8 |
| SMALLINT | Int16 |
| INTEGER | Int32 |
| BIGINT | Int64 |
| FLOAT | Float32 |
| DOUBLE | Float64 |
| VARCHAR | Utf8 |
| DATE | Date32 |
| TIMESTAMP | Timestamp |
| BLOB | Binary |
Ducklings re-exports useful Flechette utilities:
import { tableFromArrays, tableFromIPC, tableToIPC } from '@ducklings/browser';
// Create table from arrays
const table = tableFromArrays({
id: [1, 2, 3],
value: [10.5, 20.5, 30.5]
});
// Serialize to IPC
const ipc = tableToIPC(table, { format: 'stream' });
// Deserialize from IPC
const restored = tableFromIPC(ipc);
Use queryArrow() instead of query() when:
Use query() when:
import {
init,
DuckDB,
tableFromArrays,
tableToIPC
} from '@ducklings/browser';
await init();
const db = new DuckDB();
const conn = await db.connect();
// Create source data as Arrow
const sourceData = tableFromArrays({
product_id: [1, 2, 3, 4, 5],
name: ['Widget', 'Gadget', 'Thing', 'Item', 'Stuff'],
price: [9.99, 19.99, 29.99, 39.99, 49.99]
});
// Insert into DuckDB
const ipc = tableToIPC(sourceData, { format: 'stream' });
await conn.execute('CREATE TABLE products (product_id INT, name VARCHAR, price DOUBLE)');
await conn.insertArrowFromIPCStream('products', ipc);
// Query and get Arrow result
const result = await conn.queryArrow(`
SELECT
name,
price,
price * 1.1 as price_with_tax
FROM products
WHERE price > 20
`);
console.log('High-price products:');
for (const row of result.toArray()) {
console.log(row);
}
await conn.close();
await db.close();