|
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