|
1 | 1 | # duckdb-rs
|
2 | 2 |
|
3 |
| -[](https://img.shields.io/crates/d/duckdb) |
4 |
| -[](https://github.com/duckdb/duckdb-rs/actions) |
5 |
| -[](https://deps.rs/repo/github/wangfenjin/duckdb-rs) |
6 |
| -[](https://codecov.io/gh/wangfenjin/duckdb-rs) |
7 | 3 | [](https://crates.io/crates/duckdb)
|
8 |
| -[](https://docs.rs/duckdb) |
| 4 | +[](https://docs.rs/duckdb) |
| 5 | +[](LICENSE) |
| 6 | +[](https://crates.io/crates/duckdb) |
| 7 | +[](https://github.com/duckdb/duckdb-rs/actions) |
9 | 8 |
|
10 |
| -duckdb-rs is an ergonomic wrapper for using [duckdb](https://github.com/duckdb/duckdb) from Rust. It attempts to expose |
11 |
| -an interface similar to [rusqlite](https://github.com/rusqlite/rusqlite). Actually the initial code and even this README is |
12 |
| -forked from rusqlite as duckdb also tries to expose a sqlite3 compatible API. |
| 9 | +duckdb-rs is an ergonomic Rust wrapper for [DuckDB](https://github.com/duckdb/duckdb). |
13 | 10 |
|
14 |
| -```rust |
15 |
| -use duckdb::{params, Connection, Result}; |
| 11 | +You can use it to: |
| 12 | + |
| 13 | +- Query DuckDB with type-safe bindings and an API inspired by [rusqlite](https://github.com/rusqlite/rusqlite). |
| 14 | +- Read and write Arrow, Parquet, JSON, and CSV formats natively. |
| 15 | +- Create DuckDB extensions in Rust with custom scalar and table functions. |
| 16 | + |
| 17 | +## Quickstart |
| 18 | + |
| 19 | +Create a new project and add the `duckdb` crate: |
16 | 20 |
|
17 |
| -// In your project, we need to keep the arrow version same as the version used in duckdb. |
18 |
| -// Refer to https://github.com/duckdb/duckdb-rs/issues/92 |
19 |
| -// You can either: |
20 |
| -use duckdb::arrow::record_batch::RecordBatch; |
21 |
| -// Or in your Cargo.toml, use * as the version; features can be toggled according to your needs |
22 |
| -// arrow = { version = "*", default-features = false, features = ["prettyprint"] } |
23 |
| -// Then you can: |
24 |
| -// use arrow::record_batch::RecordBatch; |
| 21 | +```shell |
| 22 | +cargo new quack-in-rust |
| 23 | +cd quack-in-rust |
| 24 | +cargo add duckdb -F bundled |
| 25 | +``` |
25 | 26 |
|
26 |
| -use duckdb::arrow::util::pretty::print_batches; |
| 27 | +Update `src/main.rs` with the following code: |
27 | 28 |
|
28 |
| -#[derive(Debug)] |
29 |
| -struct Person { |
| 29 | +```rust |
| 30 | +use duckdb::{params, Connection, Result}; |
| 31 | + |
| 32 | +struct Duck { |
30 | 33 | id: i32,
|
31 | 34 | name: String,
|
32 |
| - data: Option<Vec<u8>>, |
33 | 35 | }
|
34 | 36 |
|
35 | 37 | fn main() -> Result<()> {
|
36 | 38 | let conn = Connection::open_in_memory()?;
|
37 | 39 |
|
| 40 | + conn.execute( |
| 41 | + "CREATE TABLE ducks (id INTEGER PRIMARY KEY, name TEXT)", |
| 42 | + [], // empty list of parameters |
| 43 | + )?; |
| 44 | + |
38 | 45 | conn.execute_batch(
|
39 |
| - r"CREATE SEQUENCE seq; |
40 |
| - CREATE TABLE person ( |
41 |
| - id INTEGER PRIMARY KEY DEFAULT NEXTVAL('seq'), |
42 |
| - name TEXT NOT NULL, |
43 |
| - data BLOB |
44 |
| - ); |
45 |
| - ")?; |
46 |
| - |
47 |
| - let me = Person { |
48 |
| - id: 0, |
49 |
| - name: "Steven".to_string(), |
50 |
| - data: None, |
51 |
| - }; |
| 46 | + r#" |
| 47 | + INSERT INTO ducks (id, name) VALUES (1, 'Donald Duck'); |
| 48 | + INSERT INTO ducks (id, name) VALUES (2, 'Scrooge McDuck'); |
| 49 | + "#, |
| 50 | + )?; |
| 51 | + |
52 | 52 | conn.execute(
|
53 |
| - "INSERT INTO person (name, data) VALUES (?, ?)", |
54 |
| - params![me.name, me.data], |
| 53 | + "INSERT INTO ducks (id, name) VALUES (?, ?)", |
| 54 | + params![3, "Darkwing Duck"], |
55 | 55 | )?;
|
56 | 56 |
|
57 |
| - // query table by rows |
58 |
| - let mut stmt = conn.prepare("SELECT id, name, data FROM person")?; |
59 |
| - let person_iter = stmt.query_map([], |row| { |
60 |
| - Ok(Person { |
61 |
| - id: row.get(0)?, |
62 |
| - name: row.get(1)?, |
63 |
| - data: row.get(2)?, |
64 |
| - }) |
65 |
| - })?; |
66 |
| - |
67 |
| - for person in person_iter { |
68 |
| - let p = person.unwrap(); |
69 |
| - println!("ID: {}", p.id); |
70 |
| - println!("Found person {:?}", p); |
| 57 | + let ducks = conn |
| 58 | + .prepare("FROM ducks")? |
| 59 | + .query_map([], |row| { |
| 60 | + Ok(Duck { |
| 61 | + id: row.get(0)?, |
| 62 | + name: row.get(1)?, |
| 63 | + }) |
| 64 | + })? |
| 65 | + .collect::<Result<Vec<_>>>()?; |
| 66 | + |
| 67 | + for duck in ducks { |
| 68 | + println!("{}) {}", duck.id, duck.name); |
71 | 69 | }
|
72 | 70 |
|
73 |
| - // query table by arrow |
74 |
| - let rbs: Vec<RecordBatch> = stmt.query_arrow([])?.collect(); |
75 |
| - print_batches(&rbs).unwrap(); |
76 | 71 | Ok(())
|
77 | 72 | }
|
78 | 73 | ```
|
79 | 74 |
|
| 75 | +Execute the program with `cargo run` and watch DuckDB in action! |
| 76 | + |
80 | 77 | ## Examples
|
81 | 78 |
|
82 | 79 | The following [examples](crates/duckdb/examples) demonstrate various features and use cases of duckdb-rs:
|
@@ -179,24 +176,12 @@ produce your own bindings, use the `buildtime_bindgen` Cargo feature.
|
179 | 176 |
|
180 | 177 | ## Contributing
|
181 | 178 |
|
182 |
| -See to [Contributing.md](CONTRIBUTING.md) |
| 179 | +We welcome contributions! Take a look at [CONTRIBUTING.md](CONTRIBUTING.md) for more information. |
183 | 180 |
|
184 |
| -### Checklist |
185 |
| - |
186 |
| -- Run `cargo +nightly fmt` to ensure your Rust code is correctly formatted. |
187 |
| -- Run `cargo clippy --fix --allow-dirty --all-targets --workspace --all-features -- -D warnings` to fix all clippy issues. |
188 |
| -- Ensure `cargo test --all-targets --workspace --features "modern-full extensions-full"` reports no failures. |
189 |
| - |
190 |
| -### TODOs |
191 |
| - |
192 |
| -- [x] Refactor the ErrorCode part, it's borrowed from rusqlite, we should have our own |
193 |
| -- [ ] Support more type |
194 |
| -- [x] Update duckdb.h |
195 |
| -- [x] Adjust the code examples and documentation |
196 |
| -- [x] Delete unused code / functions |
197 |
| -- [x] Add CI |
198 |
| -- [x] Publish to crate |
| 181 | +Join our [Discord](https://discord.gg/tcvwpjfnZx) to chat with the community in the #rust channel. |
199 | 182 |
|
200 | 183 | ## License
|
201 | 184 |
|
202 |
| -DuckDB and libduckdb-sys are available under the MIT license. See the LICENSE file for more info. |
| 185 | +Copyright 2021-2025 Stichting DuckDB Foundation |
| 186 | + |
| 187 | +Licensed under the [MIT license](LICENSE). |
0 commit comments