Dependencies
| Feature | Native | JS (Node) | JS (WASM) |
|---|---|---|---|
| Connection & Query | ✅ | ✅ | ✅ |
| Prepared Statements | ✅ | ✅ | ✅ |
| Streaming Results | ✅ | ✅ | ✅ |
| Appender | ✅ | ✅ (Node only) | ❌ |
| Arrow Integration | ✅ | ✅ | ✅ |
| Advanced Types | ⚠️ | ⚠️ | ❌ |
| Type | Native Bind | Native Append | Node Bind | Node Append | WASM Bind |
|---|---|---|---|---|---|
| Decimal | ✅ 128-bit | ✅ 128-bit | ✅ 128-bit | ✅ 128-bit | ❌ |
| Interval | ✅ | ✅ | ✅ | ✅ | ❌ |
| Blob | ✅ | ✅ | ✅ | ✅ | ❌ |
| List | ✅ VARCHAR | ✅ VARCHAR | ✅ VARCHAR (Node only) | ❌ | ❌ |
| Struct | ✅ VARCHAR | ✅ VARCHAR | ✅ VARCHAR (Node only) | ❌ | ❌ |
| Map | ✅ VARCHAR | ✅ VARCHAR | ✅ VARCHAR (Node only) | ❌ | ❌ |
brew install duckdb# Download a release that matches your platform
wget https://github.com/duckdb/duckdb/releases/download/<version>/libduckdb-linux-amd64.zip
unzip libduckdb-linux-amd64.zip
sudo cp libduckdb.so /usr/local/lib/
sudo ldconfiggit clone https://github.com/duckdb/duckdb.git
cd duckdb
mkdir build && cd build
cmake ..
make -j$(nproc)
sudo make install
sudo ldconfigmoon build --target-native -- -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lduckdbnpm install @duckdb/node-api@^1.4.3-r.3npm install @duckdb/duckdb-wasm@^1.33.1-dev18.0connect(on_ready=fn (result) {
match result {
Ok(conn) => {
conn.query(
"select 1 as a, NULL as b, 'duck' as c",
on_done=fn (query_result) {
match query_result {
Ok(result) => {
println("columns: \{result.columns}")
println("rows: \{result.rows}")
println("nulls: \{result.nulls}")
}
Err(err) => println("query failed: \{err}")
}
},
)
conn.close(on_done=fn (closed) {
match closed {
Ok(_) => ()
Err(err) => println("close failed: \{err}")
}
})
}
Err(err) => println("connect failed: \{err}")
}
})conn.query("select 1 as a, 2.5 as b, NULL as c", on_done=fn (query_result) {
match query_result {
Ok(result) => {
let value = result.get_int(0, 0) // Some(1)
let typed = result.to_typed()
let b0 = typed.get_double(0, 1)
let c0 = typed.get_string(0, 2) // None
println("\{value} \{b0} \{c0}")
}
Err(err) => println("query failed: \{err}")
}
})connect(on_ready=fn (result) {
match result {
Ok(conn) => {
conn.query_stream(
"SELECT i FROM RANGE(1000000) tbl(i)",
on_done=fn (stream_result) {
match stream_result {
Ok(stream) => {
let mut total = 0
let done = Ref::new(false)
while !done.val {
stream.next(on_done=fn (chunk_result) {
match chunk_result {
Ok(Some(chunk)) => total = total + chunk.row_count()
Ok(None) => done.val = true
Err(err) => {
done.val = true
println("stream failed: \{err}")
}
}
})
}
stream.close(on_done=fn (_) { () })
println("rows: \{total}")
}
Err(err) => println("stream failed: \{err}")
}
},
)
}
Err(err) => println("connect failed: \{err}")
}
})// Aggregate state to track running totals
pub struct Aggregates {
mut total_rows : Int
mut sum_values : Int
mut min_value : Int?
mut max_value : Int?
}
let agg_ref = Ref::new({ total_rows: 0, sum_values: 0, min_value: None, max_value: None })
let done_ref = Ref::new(false)
conn.query_stream(
"SELECT value FROM measurements",
on_done=fn (stream_result) {
match stream_result {
Ok(stream) => {
while !done_ref.val {
stream.next(on_done=fn (chunk_result) {
match chunk_result {
Ok(Some(chunk)) => {
// Process each row in the chunk
for row = 0; row < chunk.row_count(); row = row + 1 {
match chunk.cell(row, 0) {
Some(v) => {
let value = parse_int(v)
agg_ref.val.total_rows = agg_ref.val.total_rows + 1
agg_ref.val.sum_values = agg_ref.val.sum_values + value
// Update min/max...
}
None => ()
}
}
}
Ok(None) => done_ref.val = true
Err(err) => { done_ref.val = true; println("error: \{err}") }
}
})
}
stream.close(on_done=fn (_) {
println("Total: \{agg_ref.val.total_rows}")
println("Sum: \{agg_ref.val.sum_values}")
})
}
Err(err) => println("stream failed: \{err}")
}
},
)connect(
on_ready=fn (result) { /* ... */ },
backend=JsBackend::Wasm,
)let config = Config::create()
match config.set("memory_limit", "1GB") {
Ok(_) => ()
Err(err) => println("config set failed: \{err}")
}
connect_with_config(
on_ready=fn (result) { /* ... */ },
config=Some(config),
path=":memory:",
)match stmt.bind_int(1, 42) {
Ok(_) =>
match stmt.bind_varchar(2, "hello") {
Ok(_) => ()
Err(e) => println("bind failed: \{e}")
}
Err(e) => println("bind failed: \{e}")
}#external
pub type Appenderfn Appender::append_list_varchar(self : Appender, values : Array[String]) -> Result[Unit, DuckDBError]fn Appender::append_list_varchar_value(self : Appender, values : Array[String]) -> Result[Unit, DuckDBError]#external
pub type ArrowResultfn ArrowResult::get_column_bool_nullable(self : ArrowResult, col : Int) -> (Array[Bool], Array[Bool])fn ArrowResult::get_column_double_nullable(self : ArrowResult, col : Int) -> (Array[Double], Array[Bool])fn ArrowResult::get_column_int32_nullable(self : ArrowResult, col : Int) -> (Array[Int], Array[Bool])fn ArrowResult::get_column_int64_nullable(self : ArrowResult, col : Int) -> (Array[Int], Array[Bool])fn ArrowResult::get_column_string_nullable(self : ArrowResult, col : Int) -> (Array[String], Array[Bool])type CheckConfigfn CheckConfig::new(cases : Int, max_size : Int, seed : Int, max_shrinks : Int, discard_ratio? : Int) -> CheckConfigtype CheckResultpub enum ColumnType {
Invalid
Boolean
TinyInt
SmallInt
Integer
BigInt
UTinyInt
USmallInt
UInteger
UBigInt
Float
Double
Timestamp
Date
Time
Interval
HugeInt
UHugeInt
Varchar
Blob
Decimal
TimestampS
TimestampMs
TimestampNs
Enum
List
Struct
Map
Array
Uuid
Union
Bit
TimeTz
TimestampTz
Any
Bignum
SqlNull
StringLiteral
IntegerLiteral
TimeNs
Unknown(Int)
}#external
pub type Config#external
pub type Connectionfn Connection::create_appender(self : Connection, schema : String, table : String, on_done~ : (Result[Appender, DuckDBError]) -> Unit) -> Unitfn Connection::prepare(self : Connection, sql : String, on_done~ : (Result[PreparedStatement, DuckDBError]) -> Unit) -> Unitfn Connection::query(self : Connection, sql : String, on_done~ : (Result[QueryResult, DuckDBError]) -> Unit) -> Unitfn Connection::query_arrow(self : Connection, sql : String, on_done~ : (Result[ArrowResult, DuckDBError]) -> Unit) -> Unitfn Connection::query_stream(self : Connection, sql : String, on_done~ : (Result[ResultStream, DuckDBError]) -> Unit) -> Unitpub struct Decimal {
width : Int
scale : Int
lower : Int
upper : Int
}pub struct Interval {
months : Int
days : Int
micros : Int64
}#external
pub type PreparedStatementfn PreparedStatement::bind_bigint(self : PreparedStatement, index : Int, value : Int) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_blob(self : PreparedStatement, index : Int, value : Bytes) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_bool(self : PreparedStatement, index : Int, value : Bool) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_date(self : PreparedStatement, index : Int, days : Int) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_decimal(self : PreparedStatement, index : Int, value : Decimal) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_double(self : PreparedStatement, index : Int, value : Double) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_int(self : PreparedStatement, index : Int, value : Int) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_interval(self : PreparedStatement, index : Int, value : Interval) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_list_varchar(self : PreparedStatement, index : Int, values : Array[String]) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_map(self : PreparedStatement, index : Int, map : Map) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_struct(self : PreparedStatement, index : Int, value : Struct) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_timestamp(self : PreparedStatement, index : Int, micros : Int64) -> Result[Unit, DuckDBError]fn PreparedStatement::bind_varchar(self : PreparedStatement, index : Int, value : String) -> Result[Unit, DuckDBError]fn PreparedStatement::close(self : PreparedStatement, on_done~ : (Result[Unit, DuckDBError]) -> Unit) -> Unitfn PreparedStatement::execute(self : PreparedStatement, on_done~ : (Result[QueryResult, DuckDBError]) -> Unit) -> Unitfn PreparedStatement::execute_stream(self : PreparedStatement, on_done~ : (Result[ResultStream, DuckDBError]) -> Unit) -> Unit#external
pub type ResultStreamfn ResultStream::next(self : ResultStream, on_done~ : (Result[DataChunk?, DuckDBError]) -> Unit) -> Unitpub enum Value {
Int(Int)
Double(Double)
Bool(Bool)
String(String)
Date(Int)
Timestamp(Int64)
Decimal(Decimal)
Blob(Bytes)
Null
}fn[A : Show] assert_check(name : String, gen : Gen[A], check : (A) -> Result[Unit, String], config? : CheckConfig, shrink? : (A) -> Iter[A]) -> Unitfn[A : Show] check_with_stats(gen : Gen[A], check : (A) -> (Result[Unit, String], String?), config? : CheckConfig) -> CheckResultfn connect(on_ready~ : (Result[Connection, DuckDBError]) -> Unit, path? : String, backend? : JsBackend) -> Unitfn connect_with_config(on_ready~ : (Result[Connection, DuckDBError]) -> Unit, config : Config?, path? : String, backend? : JsBackend) -> Unitfn date_from_ymd(year : Int, month : Int, day : Int) -> Intfn date_to_days(year : Int, month : Int, day : Int) -> Intfn date_to_ymd(total_days : Int) -> (Int, Int, Int)fn days_in_month(year : Int, month : Int) -> Intfn days_to_ymd(days : Int) -> (Int, Int, Int)fn parse_date(s : String) -> Result[Int, String]fn parse_fraction_to_micros(s : String) -> Intfn parse_time_to_micros(s : String) -> Result[Int64, String]fn parse_timestamp(s : String) -> Result[Int64, String]fn timestamp_from_ymd_hms(year : Int, month : Int, day : Int, hour : Int, minute : Int, second : Int) -> Int64fn timestamp_to_ymd_hms(micros : Int64) -> (Int, Int, Int, Int, Int, Int)Dependencies